From a3cb6c379196ac6a8ab0951bbd4faf89ba756a09 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Jan 2024 02:14:19 +0200 Subject: [PATCH 001/718] Use uintptrs for store contexts --- go.mod | 1 - go.sum | 2 -- pkg/libsignalgo/identitykeystore.go | 20 ++++++------- pkg/libsignalgo/kyberprekeystore.go | 12 ++++---- pkg/libsignalgo/libsignal-ffi.h | 14 +++++----- pkg/libsignalgo/prekeystore.go | 12 ++++---- pkg/libsignalgo/senderkeystore.go | 8 +++--- pkg/libsignalgo/sessionstore.go | 8 +++--- pkg/libsignalgo/signedprekeystore.go | 8 +++--- pkg/libsignalgo/storeutil.go | 42 ++++++++++++++++++++-------- pkg/libsignalgo/update-ffi.sh | 3 ++ 11 files changed, 74 insertions(+), 56 deletions(-) diff --git a/go.mod b/go.mod index 90870ea..d6b4447 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/google/uuid v1.5.0 github.com/gorilla/mux v1.8.0 github.com/lib/pq v1.10.9 - github.com/mattn/go-pointer v0.0.1 github.com/mattn/go-sqlite3 v1.14.19 github.com/prometheus/client_golang v1.18.0 github.com/rs/zerolog v1.31.0 diff --git a/go.sum b/go.sum index 6f025c4..50c663d 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,6 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/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.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index 58c3cdf..bbbc2a6 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -23,11 +23,11 @@ package libsignalgo typedef const SignalProtocolAddress const_address; typedef const SignalPublicKey const_public_key; -extern int signal_get_identity_key_pair_callback(void *store_ctx, SignalPrivateKey **keyp); -extern int signal_get_local_registration_id_callback(void *store_ctx, uint32_t *idp); -extern int signal_save_identity_key_callback(void *store_ctx, const_address *address, const_public_key *public_key); -extern int signal_get_identity_key_callback(void *store_ctx, SignalPublicKey **public_keyp, const_address *address); -extern int signal_is_trusted_identity_callback(void *store_ctx, const_address *address, const_public_key *public_key, unsigned int direction); +extern int signal_get_identity_key_pair_callback(uintptr_t store_ctx, SignalPrivateKey **keyp); +extern int signal_get_local_registration_id_callback(uintptr_t store_ctx, uint32_t *idp); +extern int signal_save_identity_key_callback(uintptr_t store_ctx, const_address *address, const_public_key *public_key); +extern int signal_get_identity_key_callback(uintptr_t store_ctx, SignalPublicKey **public_keyp, const_address *address); +extern int signal_is_trusted_identity_callback(uintptr_t store_ctx, const_address *address, const_public_key *public_key, unsigned int direction); */ import "C" import ( @@ -51,7 +51,7 @@ type IdentityKeyStore interface { } //export signal_get_identity_key_pair_callback -func signal_get_identity_key_pair_callback(storeCtx unsafe.Pointer, keyp **C.SignalPrivateKey) C.int { +func signal_get_identity_key_pair_callback(storeCtx uintptr, keyp **C.SignalPrivateKey) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { key, err := store.GetIdentityKeyPair(ctx) if err != nil { @@ -72,7 +72,7 @@ func signal_get_identity_key_pair_callback(storeCtx unsafe.Pointer, keyp **C.Sig } //export signal_get_local_registration_id_callback -func signal_get_local_registration_id_callback(storeCtx unsafe.Pointer, idp *C.uint32_t) C.int { +func signal_get_local_registration_id_callback(storeCtx uintptr, idp *C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { registrationID, err := store.GetLocalRegistrationID(ctx) if err == nil { @@ -83,7 +83,7 @@ func signal_get_local_registration_id_callback(storeCtx unsafe.Pointer, idp *C.u } //export signal_save_identity_key_callback -func signal_save_identity_key_callback(storeCtx unsafe.Pointer, address *C.const_address, publicKey *C.const_public_key) C.int { +func signal_save_identity_key_callback(storeCtx uintptr, address *C.const_address, publicKey *C.const_public_key) C.int { return wrapStoreCallbackCustomReturn(storeCtx, func(store IdentityKeyStore, ctx context.Context) (int, error) { publicKeyStruct := PublicKey{ptr: (*C.SignalPublicKey)(unsafe.Pointer(publicKey))} cloned, err := publicKeyStruct.Clone() @@ -107,7 +107,7 @@ func signal_save_identity_key_callback(storeCtx unsafe.Pointer, address *C.const } //export signal_get_identity_key_callback -func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp **C.SignalPublicKey, address *C.const_address) C.int { +func signal_get_identity_key_callback(storeCtx uintptr, public_keyp **C.SignalPublicKey, address *C.const_address) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { key, err := store.GetIdentityKey(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}) if err == nil && key != nil { @@ -119,7 +119,7 @@ func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp **C.S } //export signal_is_trusted_identity_callback -func signal_is_trusted_identity_callback(storeCtx unsafe.Pointer, address *C.const_address, public_key *C.const_public_key, direction C.uint) C.int { +func signal_is_trusted_identity_callback(storeCtx uintptr, address *C.const_address, public_key *C.const_public_key, direction C.uint) C.int { return wrapStoreCallbackCustomReturn(storeCtx, func(store IdentityKeyStore, ctx context.Context) (int, error) { trusted, err := store.IsTrustedIdentity(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, &IdentityKey{&PublicKey{ptr: (*C.SignalPublicKey)(unsafe.Pointer(public_key))}}, SignalDirection(direction)) if err != nil { diff --git a/pkg/libsignalgo/kyberprekeystore.go b/pkg/libsignalgo/kyberprekeystore.go index a0204e5..27e9653 100644 --- a/pkg/libsignalgo/kyberprekeystore.go +++ b/pkg/libsignalgo/kyberprekeystore.go @@ -22,9 +22,9 @@ package libsignalgo typedef const SignalKyberPreKeyRecord const_kyber_pre_key_record; -extern int signal_load_kyber_pre_key_callback(void *store_ctx, SignalKyberPreKeyRecord **recordp, uint32_t id); -extern int signal_store_kyber_pre_key_callback(void *store_ctx, uint32_t id, const_kyber_pre_key_record *record); -extern int signal_mark_kyber_pre_key_used_callback(void *store_ctx, uint32_t id); +extern int signal_load_kyber_pre_key_callback(uintptr_t store_ctx, SignalKyberPreKeyRecord **recordp, uint32_t id); +extern int signal_store_kyber_pre_key_callback(uintptr_t store_ctx, uint32_t id, const_kyber_pre_key_record *record); +extern int signal_mark_kyber_pre_key_used_callback(uintptr_t store_ctx, uint32_t id); */ import "C" import ( @@ -39,7 +39,7 @@ type KyberPreKeyStore interface { } //export signal_load_kyber_pre_key_callback -func signal_load_kyber_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalKyberPreKeyRecord, id C.uint32_t) C.int { +func signal_load_kyber_pre_key_callback(storeCtx uintptr, keyp **C.SignalKyberPreKeyRecord, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store KyberPreKeyStore, ctx context.Context) error { key, err := store.LoadKyberPreKey(ctx, uint32(id)) if err == nil && key != nil { @@ -51,7 +51,7 @@ func signal_load_kyber_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.Signal } //export signal_store_kyber_pre_key_callback -func signal_store_kyber_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord *C.const_kyber_pre_key_record) C.int { +func signal_store_kyber_pre_key_callback(storeCtx uintptr, id C.uint32_t, preKeyRecord *C.const_kyber_pre_key_record) C.int { return wrapStoreCallback(storeCtx, func(store KyberPreKeyStore, ctx context.Context) error { record := KyberPreKeyRecord{ptr: (*C.SignalKyberPreKeyRecord)(unsafe.Pointer(preKeyRecord))} cloned, err := record.Clone() @@ -63,7 +63,7 @@ func signal_store_kyber_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, } //export signal_mark_kyber_pre_key_used_callback -func signal_mark_kyber_pre_key_used_callback(storeCtx unsafe.Pointer, id C.uint32_t) C.int { +func signal_mark_kyber_pre_key_used_callback(storeCtx uintptr, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store KyberPreKeyStore, ctx context.Context) error { err := store.MarkKyberPreKeyUsed(ctx, uint32(id)) return err diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 6f2bf57..f41390a 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -277,7 +277,7 @@ typedef int (*SignalLoadSession)(void *store_ctx, SignalSessionRecord **recordp, typedef int (*SignalStoreSession)(void *store_ctx, const SignalProtocolAddress *address, const SignalSessionRecord *record); typedef struct { - void *ctx; + uintptr_t ctx; SignalLoadSession load_session; SignalStoreSession store_session; } SignalSessionStore; @@ -293,7 +293,7 @@ typedef int (*SignalGetIdentityKey)(void *store_ctx, SignalPublicKey **public_ke typedef int (*SignalIsTrustedIdentity)(void *store_ctx, const SignalProtocolAddress *address, const SignalPublicKey *public_key, unsigned int direction); typedef struct { - void *ctx; + uintptr_t ctx; SignalGetIdentityKeyPair get_identity_key_pair; SignalGetLocalRegistrationId get_local_registration_id; SignalSaveIdentityKey save_identity; @@ -308,7 +308,7 @@ typedef int (*SignalStorePreKey)(void *store_ctx, uint32_t id, const SignalPreKe typedef int (*SignalRemovePreKey)(void *store_ctx, uint32_t id); typedef struct { - void *ctx; + uintptr_t ctx; SignalLoadPreKey load_pre_key; SignalStorePreKey store_pre_key; SignalRemovePreKey remove_pre_key; @@ -319,7 +319,7 @@ typedef int (*SignalLoadSignedPreKey)(void *store_ctx, SignalSignedPreKeyRecord typedef int (*SignalStoreSignedPreKey)(void *store_ctx, uint32_t id, const SignalSignedPreKeyRecord *record); typedef struct { - void *ctx; + uintptr_t ctx; SignalLoadSignedPreKey load_signed_pre_key; SignalStoreSignedPreKey store_signed_pre_key; } SignalSignedPreKeyStore; @@ -366,7 +366,7 @@ typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, const Signal typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id); typedef struct { - void *ctx; + uintptr_t ctx; SignalLoadKyberPreKey load_kyber_pre_key; SignalStoreKyberPreKey store_kyber_pre_key; SignalMarkKyberPreKeyUsed mark_kyber_pre_key_used; @@ -387,7 +387,7 @@ typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalSenderKeyRecord**, con typedef int (*SignalStoreSenderKey)(void *store_ctx, const SignalProtocolAddress*, const uint8_t (*distribution_id)[16], const SignalSenderKeyRecord*); typedef struct { - void *ctx; + uintptr_t ctx; SignalLoadSenderKey load_sender_key; SignalStoreSenderKey store_sender_key; } SignalSenderKeyStore; @@ -397,7 +397,7 @@ typedef int (*SignalRead)(void *ctx, uint8_t *buf, uintptr_t buf_len, uintptr_t typedef int (*SignalSkip)(void *ctx, uint64_t amount); typedef struct { - void *ctx; + uintptr_t ctx; SignalRead read; SignalSkip skip; } SignalInputStream; diff --git a/pkg/libsignalgo/prekeystore.go b/pkg/libsignalgo/prekeystore.go index c678ade..a4d7545 100644 --- a/pkg/libsignalgo/prekeystore.go +++ b/pkg/libsignalgo/prekeystore.go @@ -22,9 +22,9 @@ package libsignalgo typedef const SignalPreKeyRecord const_pre_key_record; -extern int signal_load_pre_key_callback(void *store_ctx, SignalPreKeyRecord **recordp, uint32_t id); -extern int signal_store_pre_key_callback(void *store_ctx, uint32_t id, const_pre_key_record *record); -extern int signal_remove_pre_key_callback(void *store_ctx, uint32_t id); +extern int signal_load_pre_key_callback(uintptr_t store_ctx, SignalPreKeyRecord **recordp, uint32_t id); +extern int signal_store_pre_key_callback(uintptr_t store_ctx, uint32_t id, const_pre_key_record *record); +extern int signal_remove_pre_key_callback(uintptr_t store_ctx, uint32_t id); */ import "C" import ( @@ -39,7 +39,7 @@ type PreKeyStore interface { } //export signal_load_pre_key_callback -func signal_load_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalPreKeyRecord, id C.uint32_t) C.int { +func signal_load_pre_key_callback(storeCtx uintptr, keyp **C.SignalPreKeyRecord, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store PreKeyStore, ctx context.Context) error { key, err := store.LoadPreKey(ctx, uint32(id)) if err == nil && key != nil { @@ -51,7 +51,7 @@ func signal_load_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalPreKey } //export signal_store_pre_key_callback -func signal_store_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord *C.const_pre_key_record) C.int { +func signal_store_pre_key_callback(storeCtx uintptr, id C.uint32_t, preKeyRecord *C.const_pre_key_record) C.int { return wrapStoreCallback(storeCtx, func(store PreKeyStore, ctx context.Context) error { record := PreKeyRecord{ptr: (*C.SignalPreKeyRecord)(unsafe.Pointer(preKeyRecord))} cloned, err := record.Clone() @@ -63,7 +63,7 @@ func signal_store_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKe } //export signal_remove_pre_key_callback -func signal_remove_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t) C.int { +func signal_remove_pre_key_callback(storeCtx uintptr, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store PreKeyStore, ctx context.Context) error { return store.RemovePreKey(ctx, uint32(id)) }) diff --git a/pkg/libsignalgo/senderkeystore.go b/pkg/libsignalgo/senderkeystore.go index 3d05fc2..6fdffdb 100644 --- a/pkg/libsignalgo/senderkeystore.go +++ b/pkg/libsignalgo/senderkeystore.go @@ -25,8 +25,8 @@ typedef const SignalProtocolAddress const_address; typedef const SignalSenderKeyRecord const_sender_key_record; typedef const uint8_t const_uuid_bytes[16]; -extern int signal_load_sender_key_callback(void *store_ctx, SignalSenderKeyRecord**, const_address*, const_uuid_bytes*); -extern int signal_store_sender_key_callback(void *store_ctx, const_address*, const_uuid_bytes*, const_sender_key_record*); +extern int signal_load_sender_key_callback(uintptr_t store_ctx, SignalSenderKeyRecord**, const_address*, const_uuid_bytes*); +extern int signal_store_sender_key_callback(uintptr_t store_ctx, const_address*, const_uuid_bytes*, const_sender_key_record*); */ import "C" import ( @@ -42,7 +42,7 @@ type SenderKeyStore interface { } //export signal_load_sender_key_callback -func signal_load_sender_key_callback(storeCtx unsafe.Pointer, recordp **C.SignalSenderKeyRecord, address *C.const_address, distributionIDBytes *C.const_uuid_bytes) C.int { +func signal_load_sender_key_callback(storeCtx uintptr, recordp **C.SignalSenderKeyRecord, address *C.const_address, distributionIDBytes *C.const_uuid_bytes) C.int { return wrapStoreCallback(storeCtx, func(store SenderKeyStore, ctx context.Context) error { distributionID := uuid.UUID(*(*[16]byte)(unsafe.Pointer(distributionIDBytes))) record, err := store.LoadSenderKey(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, distributionID) @@ -55,7 +55,7 @@ func signal_load_sender_key_callback(storeCtx unsafe.Pointer, recordp **C.Signal } //export signal_store_sender_key_callback -func signal_store_sender_key_callback(storeCtx unsafe.Pointer, address *C.const_address, distributionIDBytes *C.const_uuid_bytes, senderKeyRecord *C.const_sender_key_record) C.int { +func signal_store_sender_key_callback(storeCtx uintptr, address *C.const_address, distributionIDBytes *C.const_uuid_bytes, senderKeyRecord *C.const_sender_key_record) C.int { return wrapStoreCallback(storeCtx, func(store SenderKeyStore, ctx context.Context) error { distributionID := uuid.UUID(*(*[16]byte)(unsafe.Pointer(distributionIDBytes))) record := SenderKeyRecord{ptr: (*C.SignalSenderKeyRecord)(unsafe.Pointer(senderKeyRecord))} diff --git a/pkg/libsignalgo/sessionstore.go b/pkg/libsignalgo/sessionstore.go index c02aa58..bf9bea3 100644 --- a/pkg/libsignalgo/sessionstore.go +++ b/pkg/libsignalgo/sessionstore.go @@ -23,8 +23,8 @@ package libsignalgo typedef const SignalSessionRecord const_session_record; typedef const SignalProtocolAddress const_address; -extern int signal_load_session_callback(void *store_ctx, SignalSessionRecord **recordp, const_address *address); -extern int signal_store_session_callback(void *store_ctx, const_address *address, const_session_record *record); +extern int signal_load_session_callback(uintptr_t store_ctx, SignalSessionRecord **recordp, const_address *address); +extern int signal_store_session_callback(uintptr_t store_ctx, const_address *address, const_session_record *record); */ import "C" import ( @@ -38,7 +38,7 @@ type SessionStore interface { } //export signal_load_session_callback -func signal_load_session_callback(storeCtx unsafe.Pointer, recordp **C.SignalSessionRecord, address *C.const_address) C.int { +func signal_load_session_callback(storeCtx uintptr, recordp **C.SignalSessionRecord, address *C.const_address) C.int { return wrapStoreCallback(storeCtx, func(store SessionStore, ctx context.Context) error { record, err := store.LoadSession(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}) if err == nil && record != nil { @@ -50,7 +50,7 @@ func signal_load_session_callback(storeCtx unsafe.Pointer, recordp **C.SignalSes } //export signal_store_session_callback -func signal_store_session_callback(storeCtx unsafe.Pointer, address *C.const_address, sessionRecord *C.const_session_record) C.int { +func signal_store_session_callback(storeCtx uintptr, address *C.const_address, sessionRecord *C.const_session_record) C.int { return wrapStoreCallback(storeCtx, func(store SessionStore, ctx context.Context) error { record := SessionRecord{ptr: (*C.SignalSessionRecord)(unsafe.Pointer(sessionRecord))} cloned, err := record.Clone() diff --git a/pkg/libsignalgo/signedprekeystore.go b/pkg/libsignalgo/signedprekeystore.go index cf3ecca..fa2739a 100644 --- a/pkg/libsignalgo/signedprekeystore.go +++ b/pkg/libsignalgo/signedprekeystore.go @@ -22,8 +22,8 @@ package libsignalgo typedef const SignalSignedPreKeyRecord const_signed_pre_key_record; -extern int signal_load_signed_pre_key_callback(void *store_ctx, SignalSignedPreKeyRecord **recordp, uint32_t id); -extern int signal_store_signed_pre_key_callback(void *store_ctx, uint32_t id, const_signed_pre_key_record *record); +extern int signal_load_signed_pre_key_callback(uintptr_t store_ctx, SignalSignedPreKeyRecord **recordp, uint32_t id); +extern int signal_store_signed_pre_key_callback(uintptr_t store_ctx, uint32_t id, const_signed_pre_key_record *record); */ import "C" import ( @@ -37,7 +37,7 @@ type SignedPreKeyStore interface { } //export signal_load_signed_pre_key_callback -func signal_load_signed_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalSignedPreKeyRecord, id C.uint32_t) C.int { +func signal_load_signed_pre_key_callback(storeCtx uintptr, keyp **C.SignalSignedPreKeyRecord, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store SignedPreKeyStore, ctx context.Context) error { key, err := store.LoadSignedPreKey(ctx, uint32(id)) if err == nil && key != nil { @@ -49,7 +49,7 @@ func signal_load_signed_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.Signa } //export signal_store_signed_pre_key_callback -func signal_store_signed_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord *C.const_signed_pre_key_record) C.int { +func signal_store_signed_pre_key_callback(storeCtx uintptr, id C.uint32_t, preKeyRecord *C.const_signed_pre_key_record) C.int { return wrapStoreCallback(storeCtx, func(store SignedPreKeyStore, ctx context.Context) error { record := SignedPreKeyRecord{ptr: (*C.SignalSignedPreKeyRecord)(unsafe.Pointer(preKeyRecord))} cloned, err := record.Clone() diff --git a/pkg/libsignalgo/storeutil.go b/pkg/libsignalgo/storeutil.go index cc99ddf..4531bb0 100644 --- a/pkg/libsignalgo/storeutil.go +++ b/pkg/libsignalgo/storeutil.go @@ -24,9 +24,7 @@ import "C" import ( "context" "errors" - "unsafe" - - gopointer "github.com/mattn/go-pointer" + "sync" ) type WrappedStore[T any] struct { @@ -34,10 +32,28 @@ type WrappedStore[T any] struct { Ctx *CallbackContext } +var nextUnsafePointer uintptr +var stores = make(map[uintptr]any) +var storesLock sync.RWMutex + +func _putStore(store any) uintptr { + storesLock.Lock() + defer storesLock.Unlock() + nextUnsafePointer++ + stores[nextUnsafePointer] = store + return nextUnsafePointer +} + +func _loadStore(storeCtx uintptr) any { + storesLock.RLock() + defer storesLock.RUnlock() + return stores[storeCtx] +} + type CallbackContext struct { Error error Ctx context.Context - Unrefs []unsafe.Pointer + Unrefs []uintptr } func NewCallbackContext(ctx context.Context) *CallbackContext { @@ -48,19 +64,21 @@ func NewCallbackContext(ctx context.Context) *CallbackContext { } func (ctx *CallbackContext) Unref() { + storesLock.Lock() for _, ptr := range ctx.Unrefs { - gopointer.Unref(ptr) + delete(stores, ptr) } + storesLock.Unlock() } -func wrapStore[T any](ctx *CallbackContext, store T) unsafe.Pointer { - wrappedStore := gopointer.Save(&WrappedStore[T]{Store: store, Ctx: ctx}) +func wrapStore[T any](ctx *CallbackContext, store T) C.uintptr_t { + wrappedStore := _putStore(&WrappedStore[T]{Store: store, Ctx: ctx}) ctx.Unrefs = append(ctx.Unrefs, wrappedStore) - return wrappedStore + return C.uintptr_t(wrappedStore) } -func wrapStoreCallbackCustomReturn[T any](storeCtx unsafe.Pointer, callback func(store T, ctx context.Context) (int, error)) C.int { - wrap := gopointer.Restore(storeCtx).(*WrappedStore[T]) +func wrapStoreCallbackCustomReturn[T any](storeCtx uintptr, callback func(store T, ctx context.Context) (int, error)) C.int { + wrap := _loadStore(storeCtx).(*WrappedStore[T]) retVal, err := callback(wrap.Store, wrap.Ctx.Ctx) if err != nil { wrap.Ctx.Error = err @@ -68,8 +86,8 @@ func wrapStoreCallbackCustomReturn[T any](storeCtx unsafe.Pointer, callback func return C.int(retVal) } -func wrapStoreCallback[T any](storeCtx unsafe.Pointer, callback func(store T, ctx context.Context) error) C.int { - wrap := gopointer.Restore(storeCtx).(*WrappedStore[T]) +func wrapStoreCallback[T any](storeCtx uintptr, callback func(store T, ctx context.Context) error) C.int { + wrap := _loadStore(storeCtx).(*WrappedStore[T]) if err := callback(wrap.Store, wrap.Ctx.Ctx); err != nil { wrap.Ctx.Error = err return -1 diff --git a/pkg/libsignalgo/update-ffi.sh b/pkg/libsignalgo/update-ffi.sh index f0e617a..4d2a243 100755 --- a/pkg/libsignalgo/update-ffi.sh +++ b/pkg/libsignalgo/update-ffi.sh @@ -31,4 +31,7 @@ cd "$ORIGINAL_DIR" cp "${LIBSIGNAL_DIRECTORY}/target/release/libsignal_ffi.a" . cp "${LIBSIGNAL_DIRECTORY}/libsignal-ffi.h" . +#sed 's/void \*store_ctx/uintptr_t store_ctx/g' -i libsignal-ffi.h +sed 's/void \*ctx;/uintptr_t ctx;/g' -i libsignal-ffi.h + echo "Files copied successfully." From 7982b55ab9fa36e79e91a91df574bad75c928cc2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Jan 2024 14:38:29 +0200 Subject: [PATCH 002/718] Remove unused code and move used code around --- main.go | 2 - portal.go | 365 ++++++++++++++++++------------------------------ provisioning.go | 8 -- puppet.go | 95 ++++--------- user.go | 236 +++++++++++++++---------------- 5 files changed, 281 insertions(+), 425 deletions(-) diff --git a/main.go b/main.go index 2db6181..5dc13dd 100644 --- a/main.go +++ b/main.go @@ -75,7 +75,6 @@ type SignalBridge struct { puppets map[uuid.UUID]*Puppet puppetsByCustomMXID map[id.UserID]*Puppet - puppetsByNumber map[string]*Puppet puppetsLock sync.Mutex disappearingMessagesManager *DisappearingMessagesManager @@ -337,7 +336,6 @@ func main() { puppets: make(map[uuid.UUID]*Puppet), puppetsByCustomMXID: make(map[id.UserID]*Puppet), - puppetsByNumber: make(map[string]*Puppet), } br.Bridge = bridge.Bridge{ Name: "mautrix-signal", diff --git a/portal.go b/portal.go index e854b93..431b158 100644 --- a/portal.go +++ b/portal.go @@ -17,11 +17,9 @@ package main import ( - "bytes" "context" "errors" "fmt" - "image" "reflect" "strings" "sync" @@ -37,7 +35,6 @@ import ( "maunium.net/go/mautrix/bridge" "maunium.net/go/mautrix/bridge/bridgeconfig" "maunium.net/go/mautrix/bridge/status" - "maunium.net/go/mautrix/crypto/attachment" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -51,6 +48,113 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) +func (br *SignalBridge) GetPortalByMXID(mxid id.RoomID) *Portal { + br.portalsLock.Lock() + defer br.portalsLock.Unlock() + + portal, ok := br.portalsByMXID[mxid] + if !ok { + dbPortal, err := br.DB.Portal.GetByMXID(context.TODO(), mxid) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get portal from database") + return nil + } + return br.loadPortal(context.TODO(), dbPortal, nil) + } + + return portal +} + +func (br *SignalBridge) GetPortalByChatID(key database.PortalKey) *Portal { + br.portalsLock.Lock() + defer br.portalsLock.Unlock() + // If this PortalKey is for a group, Receiver should be empty + if key.UserID() == uuid.Nil { + key.Receiver = uuid.Nil + } + portal, ok := br.portalsByID[key] + if !ok { + dbPortal, err := br.DB.Portal.GetByChatID(context.TODO(), key) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get portal from database") + return nil + } + return br.loadPortal(context.TODO(), dbPortal, &key) + } + return portal +} + +func (br *SignalBridge) GetAllPortalsWithMXID() []*Portal { + portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get all portals with mxid") + return nil + } + return portals +} + +func (br *SignalBridge) GetAllIPortals() (iportals []bridge.Portal) { + portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get all portals with mxid") + return nil + } + iportals = make([]bridge.Portal, len(portals)) + for i, portal := range portals { + iportals[i] = portal + } + return iportals +} + +func (br *SignalBridge) loadPortal(ctx context.Context, dbPortal *database.Portal, key *database.PortalKey) *Portal { + if dbPortal == nil { + if key == nil { + return nil + } + + dbPortal = br.DB.Portal.New() + dbPortal.PortalKey = *key + err := dbPortal.Insert(ctx) + if err != nil { + br.ZLog.Err(err).Msg("Failed to insert new portal") + return nil + } + } + + portal := br.NewPortal(dbPortal) + + br.portalsByID[portal.PortalKey] = portal + if portal.MXID != "" { + br.portalsByMXID[portal.MXID] = portal + } + + return portal +} + +func (br *SignalBridge) dbPortalsToPortals(dbPortals []*database.Portal, err error) ([]*Portal, error) { + if err != nil { + return nil, err + } + br.portalsLock.Lock() + defer br.portalsLock.Unlock() + + output := make([]*Portal, len(dbPortals)) + for index, dbPortal := range dbPortals { + if dbPortal == nil { + continue + } + + portal, ok := br.portalsByID[dbPortal.PortalKey] + if !ok { + portal = br.loadPortal(context.TODO(), dbPortal, nil) + } + + output[index] = portal + } + + return output, nil +} + type portalSignalMessage struct { evt *events.ChatEvent user *User @@ -78,30 +182,46 @@ type Portal struct { currentlyTyping []id.UserID currentlyTypingLock sync.Mutex - latestReadTimestamp uint64 // Cache the latest read timestamp to avoid unnecessary read receipts - relayUser *User } -const recentMessageBufferSize = 32 +var signalFormatParams *signalfmt.FormatParams +var matrixFormatParams *matrixfmt.HTMLParser + +func (br *SignalBridge) NewPortal(dbPortal *database.Portal) *Portal { + portal := &Portal{ + Portal: dbPortal, + bridge: br, + log: br.ZLog.With().Str("chat_id", dbPortal.ChatID).Logger(), + + signalMessages: make(chan portalSignalMessage, br.Config.Bridge.PortalMessageBuffer), + matrixMessages: make(chan portalMatrixMessage, br.Config.Bridge.PortalMessageBuffer), + } + portal.MsgConv = &msgconv.MessageConverter{ + PortalMethods: portal, + SignalFmtParams: signalFormatParams, + MatrixFmtParams: matrixFormatParams, + ConvertVoiceMessages: true, + MaxFileSize: br.MediaConfig.UploadSize, + } + go portal.messageLoop() + + return portal +} func init() { event.TypeMap[event.StateBridge] = reflect.TypeOf(CustomBridgeInfoContent{}) event.TypeMap[event.StateHalfShotBridge] = reflect.TypeOf(CustomBridgeInfoContent{}) } -// ** Interfaces that Portal implements ** - -var _ bridge.Portal = (*Portal)(nil) - -var _ bridge.ReadReceiptHandlingPortal = (*Portal)(nil) -var _ bridge.TypingPortal = (*Portal)(nil) -var _ bridge.DisappearingPortal = (*Portal)(nil) - -//var _ bridge.MembershipHandlingPortal = (*Portal)(nil) -//var _ bridge.MetaHandlingPortal = (*Portal)(nil) - -// ** bridge.Portal Interface ** +var ( + _ bridge.Portal = (*Portal)(nil) + _ bridge.ReadReceiptHandlingPortal = (*Portal)(nil) + _ bridge.TypingPortal = (*Portal)(nil) + _ bridge.DisappearingPortal = (*Portal)(nil) + //_ bridge.MembershipHandlingPortal = (*Portal)(nil) + //_ bridge.MetaHandlingPortal = (*Portal)(nil) +) func (portal *Portal) IsEncrypted() bool { return portal.Encrypted @@ -199,80 +319,6 @@ func (portal *Portal) UpdateBridgeInfo() { } } -// ** bridge.ChildOverride methods (for SignalBridge in main.go) ** - -func (br *SignalBridge) GetAllPortalsWithMXID() []*Portal { - portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get all portals with mxid") - return nil - } - return portals -} - -func (br *SignalBridge) GetAllIPortals() (iportals []bridge.Portal) { - portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get all portals with mxid") - return nil - } - iportals = make([]bridge.Portal, len(portals)) - for i, portal := range portals { - iportals[i] = portal - } - return iportals -} - -func (br *SignalBridge) dbPortalsToPortals(dbPortals []*database.Portal, err error) ([]*Portal, error) { - if err != nil { - return nil, err - } - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - - output := make([]*Portal, len(dbPortals)) - for index, dbPortal := range dbPortals { - if dbPortal == nil { - continue - } - - portal, ok := br.portalsByID[dbPortal.PortalKey] - if !ok { - portal = br.loadPortal(context.TODO(), dbPortal, nil) - } - - output[index] = portal - } - - return output, nil -} - -// ** Portal Creation and Message Handling ** - -var signalFormatParams *signalfmt.FormatParams -var matrixFormatParams *matrixfmt.HTMLParser - -func (br *SignalBridge) NewPortal(dbPortal *database.Portal) *Portal { - portal := &Portal{ - Portal: dbPortal, - bridge: br, - log: br.ZLog.With().Str("chat_id", dbPortal.ChatID).Logger(), - - signalMessages: make(chan portalSignalMessage, br.Config.Bridge.PortalMessageBuffer), - matrixMessages: make(chan portalMatrixMessage, br.Config.Bridge.PortalMessageBuffer), - } - portal.MsgConv = &msgconv.MessageConverter{ - PortalMethods: portal, - SignalFmtParams: signalFormatParams, - MatrixFmtParams: matrixFormatParams, - ConvertVoiceMessages: true, - MaxFileSize: br.MediaConfig.UploadSize, - } - go portal.messageLoop() - - return portal -} - func (portal *Portal) messageLoop() { for { select { @@ -611,7 +657,7 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Content, sender *User, evtID id.EventID) error { log := zerolog.Ctx(ctx).With(). - Str("action", "send_signal_message"). + Str("action", "send signal message"). Str("event_id", evtID.String()). Str("portal_chat_id", portal.ChatID). Logger() @@ -1174,7 +1220,6 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { } } -// mautrix-go TypingPortal interface func (portal *Portal) HandleMatrixTyping(newTyping []id.UserID) { portal.currentlyTypingLock.Lock() defer portal.currentlyTypingLock.Unlock() @@ -1286,67 +1331,6 @@ func (portal *Portal) encrypt(intent *appservice.IntentAPI, content *event.Conte return event.EventEncrypted, nil } -func (portal *Portal) encryptFileInPlace(data []byte, mimeType string) (string, *event.EncryptedFileInfo) { - if !portal.Encrypted { - return mimeType, nil - } - - file := &event.EncryptedFileInfo{ - EncryptedFile: *attachment.NewEncryptedFile(), - URL: "", - } - file.EncryptInPlace(data) - return "application/octet-stream", file -} - -func (portal *Portal) uploadMediaToMatrix(intent *appservice.IntentAPI, data []byte, content *event.MessageEventContent) error { - uploadMimeType, file := portal.encryptFileInPlace(data, content.Info.MimeType) - - req := mautrix.ReqUploadMedia{ - ContentBytes: data, - ContentType: uploadMimeType, - } - var mxc id.ContentURI - if portal.bridge.Config.Homeserver.AsyncMedia { - uploaded, err := intent.UploadAsync(req) - if err != nil { - return err - } - mxc = uploaded.ContentURI - } else { - uploaded, err := intent.UploadMedia(req) - if err != nil { - return err - } - mxc = uploaded.ContentURI - } - - if file != nil { - file.URL = mxc.CUString() - content.File = file - } else { - content.URL = mxc.CUString() - } - - content.Info.Size = len(data) - if content.Info.Width == 0 && content.Info.Height == 0 && strings.HasPrefix(content.Info.MimeType, "image/") { - cfg, _, _ := image.DecodeConfig(bytes.NewReader(data)) - content.Info.Width, content.Info.Height = cfg.Width, cfg.Height - } - - // This is a hack for bad clients like Element iOS that require a thumbnail (https://github.com/vector-im/element-ios/issues/4004) - if strings.HasPrefix(content.Info.MimeType, "image/") && content.Info.ThumbnailInfo == nil { - infoCopy := *content.Info - content.Info.ThumbnailInfo = &infoCopy - if content.File != nil { - content.Info.ThumbnailFile = file - } else { - content.Info.ThumbnailURL = content.URL - } - } - return nil -} - func (portal *Portal) sendMatrixEvent(intent *appservice.IntentAPI, eventType event.Type, content any, extraContent map[string]any, timestamp int64) (*mautrix.RespSendEvent, error) { wrappedContent := event.Content{Parsed: content, Raw: extraContent} if eventType != event.EventReaction { @@ -1497,81 +1481,10 @@ func (portal *Portal) CreateMatrixRoom(user *User, meta *any) error { return nil } -func (portal *Portal) UpdateInfo(user *User, meta *any) *any { - return nil -} - -// ** Portal loading and fetching ** -var ( - portalCreationDummyEvent = event.Type{Type: "fi.mau.dummy.portal_created", Class: event.MessageEventType} -) - -func (br *SignalBridge) loadPortal(ctx context.Context, dbPortal *database.Portal, key *database.PortalKey) *Portal { - if dbPortal == nil { - if key == nil { - return nil - } - - dbPortal = br.DB.Portal.New() - dbPortal.PortalKey = *key - err := dbPortal.Insert(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Failed to insert new portal") - return nil - } - } - - portal := br.NewPortal(dbPortal) - - br.portalsByID[portal.PortalKey] = portal - if portal.MXID != "" { - br.portalsByMXID[portal.MXID] = portal - } - - return portal -} - -func (br *SignalBridge) GetPortalByMXID(mxid id.RoomID) *Portal { - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - - portal, ok := br.portalsByMXID[mxid] - if !ok { - dbPortal, err := br.DB.Portal.GetByMXID(context.TODO(), mxid) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get portal from database") - return nil - } - return br.loadPortal(context.TODO(), dbPortal, nil) - } - - return portal -} - -func (br *SignalBridge) GetPortalByChatID(key database.PortalKey) *Portal { - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - // If this PortalKey is for a group, Receiver should be empty - if key.UserID() == uuid.Nil { - key.Receiver = uuid.Nil - } - portal, ok := br.portalsByID[key] - if !ok { - dbPortal, err := br.DB.Portal.GetByChatID(context.TODO(), key) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get portal from database") - return nil - } - return br.loadPortal(context.TODO(), dbPortal, &key) - } - return portal -} - func (portal *Portal) getBridgeInfoStateKey() string { return fmt.Sprintf("net.maunium.signal://signal/%s", portal.ChatID) } -// ** DisappearingPortal interface ** func (portal *Portal) ScheduleDisappearing() { portal.bridge.disappearingMessagesManager.ScheduleDisappearingForRoom(context.TODO(), portal.MXID) } diff --git a/provisioning.go b/provisioning.go index 91f30b4..c46f810 100644 --- a/provisioning.go +++ b/provisioning.go @@ -128,8 +128,6 @@ type Response struct { *ResolveIdentifierResponse } -// ** Start New Chat ** // - type ResolveIdentifierResponse struct { RoomID id.RoomID `json:"room_id"` ChatID ResolveIdentifierResponseChatID `json:"chat_id"` @@ -267,8 +265,6 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { }) } -// ** Provisioning session creation and management ** // - func (prov *ProvisioningAPI) mutexForUser(user *User) *sync.Mutex { if _, ok := prov.provisioningMutexes[user.MXID.String()]; !ok { prov.provisioningMutexes[user.MXID.String()] = &sync.Mutex{} @@ -333,8 +329,6 @@ func (prov *ProvisioningAPI) clearSession(ctx context.Context, user *User) { } } -// ** Provisioning API Helpers ** // - func (prov *ProvisioningAPI) loginOrSendError(ctx context.Context, w http.ResponseWriter, user *User) (*provisioningHandle, error) { newSessionLoggedIn, handle, err := prov.newOrExistingSession(user) if err != nil { @@ -381,8 +375,6 @@ func (prov *ProvisioningAPI) checkSessionAndReturnHandle(ctx context.Context, w return handle } -// ** Provisioning API ** // - func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) log := prov.log.With(). diff --git a/puppet.go b/puppet.go index 1992e80..0aafe2d 100644 --- a/puppet.go +++ b/puppet.go @@ -47,10 +47,11 @@ type Puppet struct { var userIDRegex *regexp.Regexp -var _ bridge.Ghost = (*Puppet)(nil) -var _ bridge.GhostWithProfile = (*Puppet)(nil) +var ( + _ bridge.Ghost = (*Puppet)(nil) + _ bridge.GhostWithProfile = (*Puppet)(nil) +) -// ** bridge.Ghost methods ** func (puppet *Puppet) GetMXID() id.UserID { return puppet.MXID } @@ -76,7 +77,6 @@ func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI { return nil } -// ** bridge.GhostWithProfile methods ** func (puppet *Puppet) GetDisplayname() string { return puppet.Name } @@ -85,7 +85,6 @@ func (puppet *Puppet) GetAvatarURL() id.ContentURI { return puppet.AvatarURL } -// ** Puppet creation and fetching methods ** func (br *SignalBridge) NewPuppet(dbPuppet *database.Puppet) *Puppet { return &Puppet{ Puppet: dbPuppet, @@ -153,51 +152,8 @@ func (br *SignalBridge) GetPuppetBySignalID(id uuid.UUID) *Puppet { if err != nil { br.ZLog.Err(err).Msg("Failed to get puppet from database") return nil - } else if dbPuppet == nil { - br.ZLog.Info().Stringer("signal_user_id", id).Msg("Puppet not found in database, creating new entry") - dbPuppet = br.DB.Puppet.New() - dbPuppet.SignalID = id - //dbPuppet.Number = - err = dbPuppet.Insert(context.TODO()) - if err != nil { - br.ZLog.Error().Err(err).Stringer("signal_user_id", id).Msg("Error creating new puppet") - return nil - } - } - puppet = br.NewPuppet(dbPuppet) - br.puppets[puppet.SignalID] = puppet - if puppet.CustomMXID != "" { - br.puppetsByCustomMXID[puppet.CustomMXID] = puppet - } - if puppet.Number != "" { - br.puppetsByNumber[puppet.Number] = puppet - } - } - return puppet -} - -func (br *SignalBridge) GetPuppetByNumber(number string) *Puppet { - br.puppetsLock.Lock() - defer br.puppetsLock.Unlock() - - puppet, ok := br.puppetsByNumber[number] - if !ok { - dbPuppet, err := br.DB.Puppet.GetByNumber(context.TODO(), number) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get puppet from database") - return nil - } else if dbPuppet == nil { - return nil - } - - puppet = br.NewPuppet(dbPuppet) - br.puppets[puppet.SignalID] = puppet - if puppet.CustomMXID != "" { - br.puppetsByCustomMXID[puppet.CustomMXID] = puppet - } - if puppet.Number != "" { - br.puppetsByNumber[puppet.Number] = puppet } + return br.loadPuppet(context.TODO(), dbPuppet, &id) } return puppet } @@ -212,16 +168,8 @@ func (br *SignalBridge) GetPuppetByCustomMXID(mxid id.UserID) *Puppet { if err != nil { br.ZLog.Err(err).Msg("Failed to get puppet from database") return nil - } else if dbPuppet == nil { - return nil - } - - puppet = br.NewPuppet(dbPuppet) - br.puppets[puppet.SignalID] = puppet - br.puppetsByCustomMXID[puppet.CustomMXID] = puppet - if puppet.Number != "" { - br.puppetsByNumber[puppet.Number] = puppet } + return br.loadPuppet(context.TODO(), dbPuppet, nil) } return puppet } @@ -242,6 +190,28 @@ func (br *SignalBridge) FormatPuppetMXID(u uuid.UUID) id.UserID { ) } +func (br *SignalBridge) loadPuppet(ctx context.Context, dbPuppet *database.Puppet, u *uuid.UUID) *Puppet { + if dbPuppet == nil { + if u == nil { + return nil + } + dbPuppet = br.DB.Puppet.New() + dbPuppet.SignalID = *u + err := dbPuppet.Insert(ctx) + if err != nil { + br.ZLog.Error().Err(err).Stringer("signal_user_id", *u).Msg("Failed to insert new puppet") + return nil + } + } + + puppet := br.NewPuppet(dbPuppet) + br.puppets[puppet.SignalID] = puppet + if puppet.CustomMXID != "" { + br.puppetsByCustomMXID[puppet.CustomMXID] = puppet + } + return puppet +} + func (br *SignalBridge) dbPuppetsToPuppets(dbPuppets []*database.Puppet) []*Puppet { br.puppetsLock.Lock() defer br.puppetsLock.Unlock() @@ -253,14 +223,7 @@ func (br *SignalBridge) dbPuppetsToPuppets(dbPuppets []*database.Puppet) []*Pupp } puppet, ok := br.puppets[dbPuppet.SignalID] if !ok { - puppet = br.NewPuppet(dbPuppet) - br.puppets[dbPuppet.SignalID] = puppet - if dbPuppet.Number != "" { - br.puppetsByNumber[dbPuppet.Number] = puppet - } - if dbPuppet.CustomMXID != "" { - br.puppetsByCustomMXID[dbPuppet.CustomMXID] = puppet - } + puppet = br.loadPuppet(context.TODO(), dbPuppet, nil) } output[index] = puppet } diff --git a/user.go b/user.go index 64d654c..53d4d50 100644 --- a/user.go +++ b/user.go @@ -49,6 +49,112 @@ var ( ErrNotLoggedIn = errors.New("not logged in") ) +func (br *SignalBridge) GetUserByMXID(userID id.UserID) *User { + if userID == br.Bot.UserID || br.IsGhost(userID) { + return nil + } + br.usersLock.Lock() + defer br.usersLock.Unlock() + + user, ok := br.usersByMXID[userID] + if !ok { + dbUser, err := br.DB.User.GetByMXID(context.TODO(), userID) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get user from database") + return nil + } + return br.loadUser(context.TODO(), dbUser, &userID) + } + return user +} + +func (br *SignalBridge) GetUserBySignalID(id uuid.UUID) *User { + br.usersLock.Lock() + defer br.usersLock.Unlock() + + user, ok := br.usersBySignalID[id] + if !ok { + dbUser, err := br.DB.User.GetBySignalID(context.TODO(), id) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get user from database") + return nil + } + return br.loadUser(context.TODO(), dbUser, nil) + } + return user +} + +func (br *SignalBridge) GetAllLoggedInUsers() []*User { + br.usersLock.Lock() + defer br.usersLock.Unlock() + + dbUsers, err := br.DB.User.GetAllLoggedIn(context.TODO()) + if err != nil { + br.ZLog.Err(err).Msg("Error getting all logged in users") + return nil + } + users := make([]*User, len(dbUsers)) + + for idx, dbUser := range dbUsers { + user, ok := br.usersByMXID[dbUser.MXID] + if !ok { + user = br.loadUser(context.TODO(), dbUser, nil) + } + users[idx] = user + } + return users +} + +func (br *SignalBridge) loadUser(ctx context.Context, dbUser *database.User, mxid *id.UserID) *User { + if dbUser == nil { + if mxid == nil { + return nil + } + dbUser = br.DB.User.New() + dbUser.MXID = *mxid + err := dbUser.Insert(ctx) + if err != nil { + br.ZLog.Err(err).Msg("Error creating user %s") + return nil + } + } + + user := br.NewUser(dbUser) + br.usersByMXID[user.MXID] = user + if user.SignalID != uuid.Nil { + br.usersBySignalID[user.SignalID] = user + } + if user.ManagementRoom != "" { + br.managementRoomsLock.Lock() + br.managementRooms[user.ManagementRoom] = user + br.managementRoomsLock.Unlock() + } + // TODO this is completely wrong and shouldn't be here at all + // Ensure a puppet is created for this user + newPuppet := br.GetPuppetBySignalID(user.SignalID) + if newPuppet != nil && newPuppet.CustomMXID == "" { + newPuppet.CustomMXID = user.MXID + err := newPuppet.Update(ctx) + if err != nil { + br.ZLog.Err(err).Msg("Error updating puppet for user %s") + } + } + return user +} + +func (br *SignalBridge) NewUser(dbUser *database.User) *User { + user := &User{ + User: dbUser, + bridge: br, + log: br.ZLog.With().Stringer("user_id", dbUser.MXID).Logger(), + + PermissionLevel: br.Config.Bridge.Permissions.Get(dbUser.MXID), + } + user.Admin = user.PermissionLevel >= bridgeconfig.PermissionLevelAdmin + user.BridgeState = br.NewBridgeStateQueue(user) + return user +} + type User struct { *database.User @@ -69,10 +175,10 @@ type User struct { spaceCreateLock sync.Mutex } -var _ bridge.User = (*User)(nil) -var _ status.BridgeStateFiller = (*User)(nil) - -// ** bridge.User Interface ** +var ( + _ bridge.User = (*User)(nil) + _ status.BridgeStateFiller = (*User)(nil) +) func (user *User) GetPermissionLevel() bridgeconfig.PermissionLevel { return user.PermissionLevel @@ -126,93 +232,6 @@ func (user *User) GetIGhost() bridge.Ghost { return p } -// ** User creation and fetching ** - -func (br *SignalBridge) loadUser(ctx context.Context, dbUser *database.User, mxid *id.UserID) *User { - if dbUser == nil { - if mxid == nil { - return nil - } - dbUser = br.DB.User.New() - dbUser.MXID = *mxid - err := dbUser.Insert(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Error creating user %s") - return nil - } - } - - user := br.NewUser(dbUser) - br.usersByMXID[user.MXID] = user - if user.SignalID != uuid.Nil { - br.usersBySignalID[user.SignalID] = user - } - if user.ManagementRoom != "" { - br.managementRoomsLock.Lock() - br.managementRooms[user.ManagementRoom] = user - br.managementRoomsLock.Unlock() - } - // TODO this is completely wrong and shouldn't be here at all - // Ensure a puppet is created for this user - newPuppet := br.GetPuppetBySignalID(user.SignalID) - if newPuppet != nil && newPuppet.CustomMXID == "" { - newPuppet.CustomMXID = user.MXID - err := newPuppet.Update(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Error updating puppet for user %s") - } - } - return user -} - -func (br *SignalBridge) GetUserByMXID(userID id.UserID) *User { - if userID == br.Bot.UserID || br.IsGhost(userID) { - return nil - } - br.usersLock.Lock() - defer br.usersLock.Unlock() - - user, ok := br.usersByMXID[userID] - if !ok { - dbUser, err := br.DB.User.GetByMXID(context.TODO(), userID) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get user from database") - return nil - } - return br.loadUser(context.TODO(), dbUser, &userID) - } - return user -} - -func (br *SignalBridge) GetUserBySignalID(id uuid.UUID) *User { - br.usersLock.Lock() - defer br.usersLock.Unlock() - - user, ok := br.usersBySignalID[id] - if !ok { - dbUser, err := br.DB.User.GetBySignalID(context.TODO(), id) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get user from database") - return nil - } - return br.loadUser(context.TODO(), dbUser, nil) - } - return user -} - -func (br *SignalBridge) NewUser(dbUser *database.User) *User { - user := &User{ - User: dbUser, - bridge: br, - log: br.ZLog.With().Stringer("user_id", dbUser.MXID).Logger(), - - PermissionLevel: br.Config.Bridge.Permissions.Get(dbUser.MXID), - } - user.Admin = user.PermissionLevel >= bridgeconfig.PermissionLevelAdmin - user.BridgeState = br.NewBridgeStateQueue(user) - return user -} - func (user *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) (ok bool) { log := user.log.With().Str("action", "ensure_invited").Stringer("room_id", roomID).Logger() if user.bridge.StateStore.GetMembership(roomID, user.MXID) == event.MembershipJoin { @@ -342,42 +361,16 @@ func (user *User) syncChatDoublePuppetDetails(portal *Portal, justCreated bool) //} } -// ** status.BridgeStateFiller methods ** - func (user *User) GetMXID() id.UserID { return user.MXID } func (user *User) GetRemoteID() string { return user.SignalID.String() } - func (user *User) GetRemoteName() string { return user.SignalUsername } -// ** Startup, connection and shutdown methods ** - -func (br *SignalBridge) getAllLoggedInUsers() []*User { - br.usersLock.Lock() - defer br.usersLock.Unlock() - - dbUsers, err := br.DB.User.GetAllLoggedIn(context.TODO()) - if err != nil { - br.ZLog.Err(err).Msg("Error getting all logged in users") - return nil - } - users := make([]*User, len(dbUsers)) - - for idx, dbUser := range dbUsers { - user, ok := br.usersByMXID[dbUser.MXID] - if !ok { - user = br.loadUser(context.TODO(), dbUser, nil) - } - users[idx] = user - } - return users -} - func (user *User) startupTryConnect(retryCount int) { user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) @@ -523,7 +516,7 @@ func (user *User) clearKeysAndDisconnect() { func (br *SignalBridge) StartUsers() { br.ZLog.Debug().Msg("Starting users") - usersWithToken := br.getAllLoggedInUsers() + usersWithToken := br.GetAllLoggedInUsers() numUsersStarting := 0 for _, u := range usersWithToken { device := u.populateSignalDevice() @@ -684,8 +677,7 @@ func ensureGroupPuppetsAreJoinedToPortal(ctx context.Context, user *User, portal } // Check if ChatID is a groupID (not a UUID), otherwise do nothing else - // TODO: do better than passing around strings and seeing if they are UUIDs or not - if _, err := uuid.Parse(portal.ChatID); err == nil { + if portal.IsPrivateChat() { return nil } user.log.Info().Msgf("Ensuring everyone is joined to room %s, groupID: %s", portal.MXID, portal.ChatID) @@ -984,6 +976,7 @@ func (user *User) disconnectNoLock() (*signalmeow.Device, error) { user.SignalDevice = nil return disconnectedDevice, err } + func (user *User) Disconnect() error { user.Lock() defer user.Unlock() @@ -1002,9 +995,6 @@ func (user *User) Logout() error { return err } -// ** Misc Methods ** - -// Used in CreateMatrixRoom in portal.go func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) { if !user.bridge.Config.Bridge.SyncDirectChatList { return From 6626c647068f2aba72b2a983518816f957835aa0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Jan 2024 14:59:40 +0200 Subject: [PATCH 003/718] Update mautrix-go and add contexts to all Matrix requests --- commands.go | 43 +++++++------- disappearing.go | 2 +- go.mod | 2 +- go.sum | 4 +- main.go | 24 ++++---- messagetracking.go | 27 +++++---- portal.go | 145 +++++++++++++++++++++++---------------------- provisioning.go | 4 +- user.go | 59 +++++++++--------- 9 files changed, 157 insertions(+), 153 deletions(-) diff --git a/commands.go b/commands.go index 9d1c92b..3c954ce 100644 --- a/commands.go +++ b/commands.go @@ -92,7 +92,7 @@ func fnSetRelay(ce *WrappedCommandEvent) { ce.Reply("Only bridge admins are allowed to enable relay mode on this instance of the bridge") } else { ce.Portal.RelayUserID = ce.User.MXID - ce.Portal.Update(context.TODO()) + ce.Portal.Update(ce.Ctx) ce.Reply("Messages from non-logged-in users in this room will now be bridged through your Signal account") } } @@ -114,7 +114,7 @@ func fnUnsetRelay(ce *WrappedCommandEvent) { ce.Reply("Only bridge admins are allowed to enable relay mode on this instance of the bridge") } else { ce.Portal.RelayUserID = "" - ce.Portal.Update(context.TODO()) + ce.Portal.Update(ce.Ctx) ce.Reply("Messages from non-logged-in users will no longer be bridged in this room") } } @@ -133,7 +133,7 @@ func fnDeleteSession(ce *WrappedCommandEvent) { ce.Reply("You're not logged in") return } - ce.User.SignalDevice.ClearKeysAndDisconnect(context.TODO()) + ce.User.SignalDevice.ClearKeysAndDisconnect(ce.Ctx) ce.Reply("Disconnected from Signal") } @@ -223,7 +223,7 @@ func fnPM(ce *WrappedCommandEvent) { ce.Reply("You already have a portal to %s at %s", number, portal.MXID) return } - if err := portal.CreateMatrixRoom(user, nil); err != nil { + if err := portal.CreateMatrixRoom(ce.Ctx, user, nil); err != nil { ce.Reply("Error creating Matrix room for portal to %s", number) ce.Log.Errorln("Error creating Matrix room for portal to %s: %s", number, err) return @@ -246,7 +246,7 @@ func fnSyncSpace(ce *WrappedCommandEvent) { ce.Reply("Personal filtering spaces are not enabled on this instance of the bridge") return } - ctx := ce.ZLog.WithContext(context.TODO()) + ctx := ce.Ctx dmKeys, err := ce.Bridge.DB.Portal.FindPrivateChatsNotInSpace(ctx, ce.User.SignalID) if err != nil { ce.ZLog.Err(err).Msg("Failed to get private chat keys") @@ -320,7 +320,7 @@ func fnLogin(ce *WrappedCommandEvent) { // Next, get the results of finishing registration resp = <-provChan - _, _ = ce.Bot.RedactEvent(ce.RoomID, qrEventID) + _, _ = ce.Bot.RedactEvent(ce.Ctx, ce.RoomID, qrEventID) if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { if resp.Err != nil && strings.HasSuffix(resp.Err.Error(), " EOF") { ce.Reply("Logging in timed out, please try again.") @@ -360,7 +360,7 @@ func fnLogin(ce *WrappedCommandEvent) { ce.Reply("Problem logging in - No SignalID received") return } - err = ce.User.Update(context.TODO()) + err = ce.User.Update(ce.Ctx) if err != nil { ce.ZLog.Err(err).Msg("Failed to save user to database") } @@ -382,7 +382,7 @@ func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevEvent id.Even if len(prevEvent) != 0 { content.SetEdit(prevEvent) } - resp, err := ce.Bot.SendMessageEvent(ce.RoomID, event.EventMessage, &content) + resp, err := ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) if err != nil { ce.Log.Errorln("Failed to send QR code to user:", err) } else if len(prevEvent) == 0 { @@ -401,7 +401,7 @@ func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (id.ContentURI, bot := user.bridge.AS.BotClient() - resp, err := bot.UploadBytes(qrCode, "image/png") + resp, err := bot.UploadBytes(ce.Ctx, qrCode, "image/png") if err != nil { ce.Log.Errorln("Failed to upload QR code:", err) ce.Reply("Failed to upload QR code: %v", err) @@ -410,12 +410,12 @@ func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (id.ContentURI, return resp.ContentURI, true } -func canDeletePortal(portal *Portal, userID id.UserID) bool { +func canDeletePortal(ctx context.Context, portal *Portal, userID id.UserID) bool { if len(portal.MXID) == 0 { return false } - members, err := portal.MainIntent().JoinedMembers(portal.MXID) + members, err := portal.MainIntent().JoinedMembers(ctx, portal.MXID) if err != nil { portal.log.Err(err). Str("user_id", userID.String()). @@ -446,14 +446,14 @@ var cmdDeletePortal = &commands.FullHandler{ } func fnDeletePortal(ce *WrappedCommandEvent) { - if !ce.User.Admin && !canDeletePortal(ce.Portal, ce.User.MXID) { + if !ce.User.Admin && !canDeletePortal(ce.Ctx, ce.Portal, ce.User.MXID) { ce.Reply("Only bridge admins can delete portals with other Matrix users") return } ce.Portal.log.Info().Stringer("user_id", ce.User.MXID).Msg("User requested deletion of portal") ce.Portal.Delete() - ce.Portal.Cleanup(false) + ce.Portal.Cleanup(ce.Ctx, false) } var cmdDeleteAllPortals = &commands.FullHandler{ @@ -474,7 +474,7 @@ func fnDeleteAllPortals(ce *WrappedCommandEvent) { } else { portalsToDelete = portals[:0] for _, portal := range portals { - if canDeletePortal(portal, ce.User.MXID) { + if canDeletePortal(ce.Ctx, portal, ce.User.MXID) { portalsToDelete = append(portalsToDelete, portal) } } @@ -486,7 +486,7 @@ func fnDeleteAllPortals(ce *WrappedCommandEvent) { leave := func(portal *Portal) { if len(portal.MXID) > 0 { - _, _ = portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{ + _, _ = portal.MainIntent().KickUser(ce.Ctx, portal.MXID, &mautrix.ReqKickUser{ Reason: "Deleting portal", UserID: ce.User.MXID, }) @@ -497,8 +497,8 @@ func fnDeleteAllPortals(ce *WrappedCommandEvent) { intent := customPuppet.CustomIntent() leave = func(portal *Portal) { if len(portal.MXID) > 0 { - _, _ = intent.LeaveRoom(portal.MXID) - _, _ = intent.ForgetRoom(portal.MXID) + _, _ = intent.LeaveRoom(ce.Ctx, portal.MXID) + _, _ = intent.ForgetRoom(ce.Ctx, portal.MXID) } } } @@ -509,9 +509,10 @@ func fnDeleteAllPortals(ce *WrappedCommandEvent) { } ce.Reply("Finished deleting portal info. Now cleaning up rooms in background.") + backgroundCtx := context.TODO() go func() { for _, portal := range portalsToDelete { - portal.Cleanup(false) + portal.Cleanup(backgroundCtx, false) } ce.Reply("Finished background cleanup of deleted portal rooms.") }() @@ -528,7 +529,7 @@ var cmdCleanupLostPortals = &commands.FullHandler{ } func fnCleanupLostPortals(ce *WrappedCommandEvent) { - portals, err := ce.Bridge.DB.LostPortal.GetAll(context.TODO()) + portals, err := ce.Bridge.DB.LostPortal.GetAll(ce.Ctx) if err != nil { ce.Reply("Failed to get portals: %v", err) return @@ -544,8 +545,8 @@ func fnCleanupLostPortals(ce *WrappedCommandEvent) { if err == nil { intent = ce.Bridge.GetPuppetBySignalID(dmUUID).DefaultIntent() } - ce.Bridge.CleanupRoom(ce.ZLog, intent, portal.MXID, false) - err = portal.Delete(context.TODO()) + ce.Bridge.CleanupRoom(ce.Ctx, ce.ZLog, intent, portal.MXID, false) + err = portal.Delete(ce.Ctx) if err != nil { ce.ZLog.Err(err).Msg("Failed to delete lost portal from database after cleanup") } diff --git a/disappearing.go b/disappearing.go index 6707b5f..200fb5b 100644 --- a/disappearing.go +++ b/disappearing.go @@ -102,7 +102,7 @@ func (dmm *DisappearingMessagesManager) redactExpiredMessages(ctx context.Contex log.Warn().Stringer("event_id", msg.EventID).Stringer("room_id", msg.RoomID).Msg("Failed to redact message: portal not found") continue } - _, err = portal.MainIntent().RedactEvent(msg.RoomID, msg.EventID, mautrix.ReqRedact{ + _, err = portal.MainIntent().RedactEvent(ctx, msg.RoomID, msg.EventID, mautrix.ReqRedact{ Reason: "Message expired", TxnID: fmt.Sprintf("mxsg_disappear_%s", msg.EventID), }) diff --git a/go.mod b/go.mod index 90870ea..c53ab70 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.19.0 google.golang.org/protobuf v1.32.0 maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.16.3-0.20240103125335-7c45a3d28be2 + maunium.net/go/mautrix v0.16.3-0.20240104125737-88631708a41b nhooyr.io/websocket v1.8.10 ) diff --git a/go.sum b/go.sum index 6f025c4..d113cff 100644 --- a/go.sum +++ b/go.sum @@ -92,7 +92,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.16.3-0.20240103125335-7c45a3d28be2 h1:Tgdv1P3hl6I4BDzHNl4kZ+2VrdpkBJ1F3WOyzFbyHlU= -maunium.net/go/mautrix v0.16.3-0.20240103125335-7c45a3d28be2/go.mod h1:gCgLw/4c1a8QsiOWTdUdXlt5cYdE0rJ9wLeZQKPD58Q= +maunium.net/go/mautrix v0.16.3-0.20240104125737-88631708a41b h1:WWCD0vaAztVrrTRWcTXeOHq9U7HRcP2a1hs+0+guPPg= +maunium.net/go/mautrix v0.16.3-0.20240104125737-88631708a41b/go.mod h1:lI43hRW+/92FCqHLD5bINSPqsWrviZ5MpLl7J3hjvW4= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index 5dc13dd..83f1708 100644 --- a/main.go +++ b/main.go @@ -249,7 +249,7 @@ func (br *SignalBridge) CreatePrivatePortal(roomID id.RoomID, brInviter bridge.U Str("existing_room_id", portal.MXID.String()). Msg("Existing private chat portal found, trying to invite user") - ok := portal.ensureUserInvited(inviter) + ok := portal.ensureUserInvited(ctx, inviter) if !ok { log.Warn().Msg("Failed to invite user to existing private chat portal. Redirecting portal to new room") br.createPrivatePortalFromInvite(ctx, roomID, inviter, puppet, portal) @@ -258,9 +258,9 @@ func (br *SignalBridge) CreatePrivatePortal(roomID id.RoomID, brInviter bridge.U intent := puppet.DefaultIntent() errorMessage := fmt.Sprintf("You already have a private chat portal with me at [%[1]s](https://matrix.to/#/%[1]s)", portal.MXID) errorContent := format.RenderMarkdown(errorMessage, true, false) - _, _ = intent.SendMessageEvent(roomID, event.EventMessage, errorContent) + _, _ = intent.SendMessageEvent(ctx, roomID, event.EventMessage, errorContent) log.Debug().Msg("Leaving ghost from private chat room after accepting invite because we already have a chat with the user") - _, _ = intent.LeaveRoom(roomID) + _, _ = intent.LeaveRoom(ctx, roomID) } func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomID id.RoomID, inviter *User, puppet *Puppet, portal *Portal) { @@ -270,7 +270,7 @@ func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomI // Check if room is already encrypted var existingEncryption event.EncryptionEventContent var encryptionEnabled bool - err := portal.MainIntent().StateEvent(roomID, event.StateEncryption, "", &existingEncryption) + err := portal.MainIntent().StateEvent(ctx, roomID, event.StateEncryption, "", &existingEncryption) if err != nil { log.Err(err).Msg("Failed to check if encryption is enabled in private chat room") } else { @@ -284,16 +284,16 @@ func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomI if br.Config.Bridge.Encryption.Default || encryptionEnabled { log.Debug().Msg("Adding bridge bot to new private chat portal as encryption is enabled") - _, err = intent.InviteUser(roomID, &mautrix.ReqInviteUser{UserID: br.Bot.UserID}) + _, err = intent.InviteUser(ctx, roomID, &mautrix.ReqInviteUser{UserID: br.Bot.UserID}) if err != nil { log.Err(err).Msg("Failed to invite bridge bot to enable e2be") } - err = br.Bot.EnsureJoined(roomID) + err = br.Bot.EnsureJoined(ctx, roomID) if err != nil { log.Err(err).Msg("Failed to join as bridge bot to enable e2be") } if !encryptionEnabled { - _, err = intent.SendStateEvent(roomID, event.StateEncryption, "", portal.getEncryptionEventContent()) + _, err = intent.SendStateEvent(ctx, roomID, event.StateEncryption, "", portal.getEncryptionEventContent()) if err != nil { log.Err(err).Msg("Failed to enable e2be") } @@ -304,23 +304,23 @@ func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomI portal.Encrypted = true } //portal.Topic = PrivateChatTopic - _, _ = portal.MainIntent().SetRoomTopic(portal.MXID, portal.Topic) + _, _ = portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) if portal.shouldSetDMRoomMetadata() { portal.Name = puppet.Name portal.AvatarURL = puppet.AvatarURL portal.AvatarHash = puppet.AvatarHash portal.AvatarSet = puppet.AvatarSet - _, err = portal.MainIntent().SetRoomName(portal.MXID, portal.Name) + _, err = portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) portal.NameSet = err == nil - _, err = portal.MainIntent().SetRoomAvatar(portal.MXID, portal.AvatarURL) + _, err = portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) portal.AvatarSet = err == nil } err = portal.Update(ctx) if err != nil { log.Err(err).Msg("Failed to update portal in database") } - portal.UpdateBridgeInfo() - _, _ = intent.SendNotice(roomID, "Private chat portal created") + portal.UpdateBridgeInfo(ctx) + _, _ = intent.SendNotice(ctx, roomID, "Private chat portal created") log.Info().Msg("Created private chat portal after invite") } diff --git a/messagetracking.go b/messagetracking.go index a51922d..2e03f3b 100644 --- a/messagetracking.go +++ b/messagetracking.go @@ -87,7 +87,7 @@ func errorToStatusReason(err error) (reason event.MessageStatusReason, status ev } } -func (portal *Portal) sendErrorMessage(evt *event.Event, err error, confirmed bool, editID id.EventID) id.EventID { +func (portal *Portal) sendErrorMessage(ctx context.Context, evt *event.Event, err error, confirmed bool, editID id.EventID) id.EventID { if !portal.bridge.Config.Bridge.MessageErrorNotices { return "" } @@ -123,7 +123,7 @@ func (portal *Portal) sendErrorMessage(evt *event.Event, err error, confirmed bo } else { content.SetReply(evt) } - resp, err := portal.sendMainIntentMessage(content) + resp, err := portal.sendMainIntentMessage(ctx, content) if err != nil { portal.log.Err(err).Msg("Failed to send bridging error message") return "" @@ -131,7 +131,7 @@ func (portal *Portal) sendErrorMessage(evt *event.Event, err error, confirmed bo return resp.EventID } -func (portal *Portal) sendStatusEvent(evtID, lastRetry id.EventID, err error, deliveredTo *[]id.UserID) { +func (portal *Portal) sendStatusEvent(ctx context.Context, evtID, lastRetry id.EventID, err error, deliveredTo *[]id.UserID) { if !portal.bridge.Config.Bridge.MessageStatusEvents { return } @@ -158,22 +158,22 @@ func (portal *Portal) sendStatusEvent(evtID, lastRetry id.EventID, err error, de content.Reason, content.Status, _, _, content.Message = errorToStatusReason(err) content.Error = err.Error() } - _, err = intent.SendMessageEvent(portal.MXID, event.BeeperMessageStatus, &content) + _, err = intent.SendMessageEvent(ctx, portal.MXID, event.BeeperMessageStatus, &content) if err != nil { portal.log.Err(err).Msg("Failed to send message status event") } } -func (portal *Portal) sendDeliveryReceipt(eventID id.EventID) { +func (portal *Portal) sendDeliveryReceipt(ctx context.Context, eventID id.EventID) { if portal.bridge.Config.Bridge.DeliveryReceipts { - err := portal.bridge.Bot.SendReceipt(portal.MXID, eventID, event.ReceiptTypeRead, nil) + err := portal.bridge.Bot.SendReceipt(ctx, portal.MXID, eventID, event.ReceiptTypeRead, nil) if err != nil { portal.log.Debug().Err(err).Stringer("event_id", eventID).Msg("Failed to send delivery receipt") } } } -func (portal *Portal) sendMessageMetrics(evt *event.Event, err error, part string, ms *metricSender) { +func (portal *Portal) sendMessageMetrics(ctx context.Context, evt *event.Event, err error, part string, ms *metricSender) { log := portal.log.With(). Str("handling_step", part). Str("event_type", evt.Type.String()). @@ -198,20 +198,20 @@ func (portal *Portal) sendMessageMetrics(evt *event.Event, err error, part strin checkpointStatus := status.ReasonToCheckpointStatus(reason, statusCode) portal.bridge.SendMessageCheckpoint(evt, status.MsgStepRemote, err, checkpointStatus, ms.getRetryNum()) if sendNotice { - ms.setNoticeID(portal.sendErrorMessage(evt, err, isCertain, ms.getNoticeID())) + ms.setNoticeID(portal.sendErrorMessage(ctx, evt, err, isCertain, ms.getNoticeID())) } - portal.sendStatusEvent(origEvtID, evt.ID, err, nil) + portal.sendStatusEvent(ctx, origEvtID, evt.ID, err, nil) } else { portal.log.Debug().Msg("Sending metrics for successfully handled Matrix event") - portal.sendDeliveryReceipt(evt.ID) + portal.sendDeliveryReceipt(ctx, evt.ID) portal.bridge.SendMessageSuccessCheckpoint(evt, status.MsgStepRemote, ms.getRetryNum()) var deliveredTo *[]id.UserID if portal.IsPrivateChat() { deliveredTo = &[]id.UserID{} } - portal.sendStatusEvent(origEvtID, evt.ID, nil, deliveredTo) + portal.sendStatusEvent(ctx, origEvtID, evt.ID, nil, deliveredTo) if prevNotice := ms.popNoticeID(); prevNotice != "" { - _, _ = portal.MainIntent().RedactEvent(portal.MXID, prevNotice, mautrix.ReqRedact{ + _, _ = portal.MainIntent().RedactEvent(ctx, portal.MXID, prevNotice, mautrix.ReqRedact{ Reason: "error resolved", }) } @@ -265,6 +265,7 @@ type metricSender struct { completed bool retryNum int timings *messageTimings + ctx context.Context } func (ms *metricSender) getRetryNum() int { @@ -302,7 +303,7 @@ func (ms *metricSender) sendMessageMetrics(evt *event.Event, err error, part str if !completed && ms.completed { return } - ms.portal.sendMessageMetrics(evt, err, part, ms) + ms.portal.sendMessageMetrics(ms.ctx, evt, err, part, ms) ms.retryNum++ ms.completed = completed } diff --git a/portal.go b/portal.go index 431b158..45c0e53 100644 --- a/portal.go +++ b/portal.go @@ -301,19 +301,19 @@ func (portal *Portal) getBridgeInfo() (string, CustomBridgeInfoContent) { return bridgeInfoStateKey, CustomBridgeInfoContent{bridgeInfo, roomType} } -func (portal *Portal) UpdateBridgeInfo() { +func (portal *Portal) UpdateBridgeInfo(ctx context.Context) { if len(portal.MXID) == 0 { portal.log.Debug().Msg("Not updating bridge info: no Matrix room created") return } portal.log.Debug().Msg("Updating bridge info...") stateKey, content := portal.getBridgeInfo() - _, err := portal.MainIntent().SendStateEvent(portal.MXID, event.StateBridge, stateKey, content) + _, err := portal.MainIntent().SendStateEvent(ctx, portal.MXID, event.StateBridge, stateKey, content) if err != nil { portal.log.Warn().Err(err).Msg("Failed to update m.bridge") } // TODO remove this once https://github.com/matrix-org/matrix-doc/pull/2346 is in spec - _, err = portal.MainIntent().SendStateEvent(portal.MXID, event.StateHalfShotBridge, stateKey, content) + _, err = portal.MainIntent().SendStateEvent(ctx, portal.MXID, event.StateHalfShotBridge, stateKey, content) if err != nil { portal.log.Warn().Err(err).Msg("Failed to update uk.half-shot.bridge") } @@ -334,7 +334,7 @@ func (portal *Portal) handleMatrixMessages(msg portalMatrixMessage) { // If we have no SignalDevice, the bridge isn't logged in properly, // so send BAD_CREDENTIALS so the user knows if !msg.user.SignalDevice.IsDeviceLoggedIn() && !portal.HasRelaybot() { - go portal.sendMessageMetrics(msg.evt, errUserNotLoggedIn, "Ignoring", nil) + go portal.sendMessageMetrics(context.TODO(), msg.evt, errUserNotLoggedIn, "Ignoring", nil) msg.user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) return } @@ -371,7 +371,7 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt start := time.Now() messageAge := timings.totalReceive - ms := metricSender{portal: portal, timings: &timings} + ms := metricSender{portal: portal, timings: &timings, ctx: ctx} log.Debug(). Str("sender", evt.Sender.String()). Dur("age", messageAge). @@ -456,7 +456,7 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt } } - relaybotFormatted := isRelay && portal.addRelaybotFormat(realSenderMXID, evt, content) + relaybotFormatted := isRelay && portal.addRelaybotFormat(ctx, realSenderMXID, evt, content) if content.MsgType == event.MsgNotice && !portal.bridge.Config.Bridge.BridgeNotices { go ms.sendMessageMetrics(evt, errMNoticeDisabled, "Error converting", true) return @@ -523,13 +523,13 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e if dbMessage != nil { if dbMessage.Sender != sender.SignalID { - portal.sendMessageStatusCheckpointFailed(evt, errRedactionTargetSentBySomeoneElse) + portal.sendMessageStatusCheckpointFailed(ctx, evt, errRedactionTargetSentBySomeoneElse) return } msg := signalmeow.DataMessageForDelete(dbMessage.Timestamp) err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) if err != nil { - portal.sendMessageStatusCheckpointFailed(evt, err) + portal.sendMessageStatusCheckpointFailed(ctx, evt, err) log.Err(err).Msg("Failed to send message redaction to Signal") return } @@ -541,7 +541,7 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e } else if len(otherParts) > 0 { // If there are other parts of the message, send a redaction for each of them for _, otherPart := range otherParts { - _, err = portal.MainIntent().RedactEvent(portal.MXID, otherPart.MXID, mautrix.ReqRedact{ + _, err = portal.MainIntent().RedactEvent(ctx, portal.MXID, otherPart.MXID, mautrix.ReqRedact{ Reason: "Other part of Signal message redacted", TxnID: "mxsg_partredact_" + otherPart.MXID.String(), }) @@ -560,16 +560,16 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e } } } - portal.sendMessageStatusCheckpointSuccess(evt) + portal.sendMessageStatusCheckpointSuccess(ctx, evt) } else if dbReaction != nil { if dbReaction.Author != sender.SignalID { - portal.sendMessageStatusCheckpointFailed(evt, errUnreactTargetSentBySomeoneElse) + portal.sendMessageStatusCheckpointFailed(ctx, evt, errUnreactTargetSentBySomeoneElse) return } msg := signalmeow.DataMessageForReaction(dbReaction.Emoji, dbReaction.MsgAuthor, dbReaction.MsgTimestamp, true) err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) if err != nil { - portal.sendMessageStatusCheckpointFailed(evt, err) + portal.sendMessageStatusCheckpointFailed(ctx, evt, err) log.Err(err).Msg("Failed to send reaction redaction to Signal") return } @@ -577,9 +577,9 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e if err != nil { log.Err(err).Msg("Failed to delete redacted reaction from database") } - portal.sendMessageStatusCheckpointSuccess(evt) + portal.sendMessageStatusCheckpointSuccess(ctx, evt) } else { - portal.sendMessageStatusCheckpointFailed(evt, errRedactionTargetNotFound) + portal.sendMessageStatusCheckpointFailed(ctx, evt, errRedactionTargetNotFound) } } @@ -593,11 +593,11 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev relatedEventID := evt.Content.AsReaction().RelatesTo.EventID targetMsg, err := portal.bridge.DB.Message.GetByMXID(ctx, relatedEventID) if err != nil { - portal.sendMessageStatusCheckpointFailed(evt, err) + portal.sendMessageStatusCheckpointFailed(ctx, evt, err) log.Err(err).Msg("Failed to get reaction target message") return } else if targetMsg == nil { - portal.sendMessageStatusCheckpointFailed(evt, errReactionTargetNotFound) + portal.sendMessageStatusCheckpointFailed(ctx, evt, errReactionTargetNotFound) log.Warn().Msg("Reaction target message not found") return } @@ -606,7 +606,7 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev msg := signalmeow.DataMessageForReaction(signalEmoji, targetMsg.Sender, targetMsg.Timestamp, false) err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) if err != nil { - portal.sendMessageStatusCheckpointFailed(evt, err) + portal.sendMessageStatusCheckpointFailed(ctx, evt, err) portal.log.Error().Msgf("Failed to send reaction %s", evt.ID) return } @@ -624,7 +624,7 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev log.Err(err).Msg("Failed to get existing reaction from database") } else if dbReaction != nil { log.Debug().Stringer("existing_event_id", dbReaction.MXID).Msg("Redacting existing reaction after sending new one") - _, err = portal.MainIntent().RedactEvent(portal.MXID, dbReaction.MXID) + _, err = portal.MainIntent().RedactEvent(ctx, portal.MXID, dbReaction.MXID) if err != nil { log.Err(err).Msg("Failed to redact existing reaction") } @@ -652,7 +652,7 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev } } - portal.sendMessageStatusCheckpointSuccess(evt) + portal.sendMessageStatusCheckpointSuccess(ctx, evt) } func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Content, sender *User, evtID id.EventID) error { @@ -681,7 +681,7 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte if err != nil { // check the start of the error string, see if it starts with "No group master key found for group identifier" if strings.HasPrefix(err.Error(), "No group master key found for group identifier") { - portal.MainIntent().SendNotice(portal.MXID, "Missing group encryption key. Please ask a group member to send a message in this chat, then retry sending.") + portal.MainIntent().SendNotice(ctx, portal.MXID, "Missing group encryption key. Please ask a group member to send a message in this chat, then retry sending.") } log.Err(err).Msg("Error sending event to Signal group") return err @@ -709,21 +709,21 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte return err } -func (portal *Portal) sendMessageStatusCheckpointSuccess(evt *event.Event) { - portal.sendDeliveryReceipt(evt.ID) +func (portal *Portal) sendMessageStatusCheckpointSuccess(ctx context.Context, evt *event.Event) { + portal.sendDeliveryReceipt(ctx, evt.ID) portal.bridge.SendMessageSuccessCheckpoint(evt, status.MsgStepRemote, 0) var deliveredTo *[]id.UserID if portal.IsPrivateChat() { deliveredTo = &[]id.UserID{} } - portal.sendStatusEvent(evt.ID, "", nil, deliveredTo) + portal.sendStatusEvent(ctx, evt.ID, "", nil, deliveredTo) } -func (portal *Portal) sendMessageStatusCheckpointFailed(evt *event.Event, err error) { - portal.sendDeliveryReceipt(evt.ID) +func (portal *Portal) sendMessageStatusCheckpointFailed(ctx context.Context, evt *event.Event, err error) { + portal.sendDeliveryReceipt(ctx, evt.ID) portal.bridge.SendMessageErrorCheckpoint(evt, status.MsgStepRemote, err, true, 0) - portal.sendStatusEvent(evt.ID, "", err, nil) + portal.sendStatusEvent(ctx, evt.ID, "", err, nil) } type msgconvContextKey int @@ -741,13 +741,13 @@ func (portal *Portal) UploadMatrixMedia(ctx context.Context, data []byte, fileNa FileName: fileName, } if portal.bridge.Config.Homeserver.AsyncMedia { - uploaded, err := intent.UploadAsync(req) + uploaded, err := intent.UploadAsync(ctx, req) if err != nil { return "", err } return uploaded.ContentURI.CUString(), nil } else { - uploaded, err := intent.UploadMedia(req) + uploaded, err := intent.UploadMedia(ctx, req) if err != nil { return "", err } @@ -760,7 +760,7 @@ func (portal *Portal) DownloadMatrixMedia(ctx context.Context, uriString id.Cont if err != nil { return nil, fmt.Errorf("malformed content URI: %w", err) } - return portal.MainIntent().DownloadBytesContext(ctx, parsedURI) + return portal.MainIntent().DownloadBytes(ctx, parsedURI) } func (portal *Portal) GetData(ctx context.Context) *database.Portal { @@ -899,7 +899,7 @@ func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataM } intent := sender.IntentFor(portal) if existingReaction != nil { - _, err = intent.RedactEvent(portal.MXID, existingReaction.MXID, mautrix.ReqRedact{ + _, err = intent.RedactEvent(ctx, portal.MXID, existingReaction.MXID, mautrix.ReqRedact{ TxnID: "mxsg_unreact_" + existingReaction.MXID.String(), }) if err != nil { @@ -924,7 +924,7 @@ func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataM EventID: targetMsg.MXID, }, } - resp, err := portal.sendMatrixEvent(intent, event.EventReaction, content, nil, int64(ts)) + resp, err := portal.sendMatrixEvent(ctx, intent, event.EventReaction, content, nil, int64(ts)) if err != nil { log.Err(err).Msg("Failed to send reaction") return @@ -971,7 +971,7 @@ func (portal *Portal) handleSignalDelete(sender *Puppet, delete *signalpb.DataMe } intent := sender.IntentFor(portal) for _, part := range targetMsg { - _, err = intent.RedactEvent(portal.MXID, part.MXID, mautrix.ReqRedact{ + _, err = intent.RedactEvent(ctx, portal.MXID, part.MXID, mautrix.ReqRedact{ TxnID: "mxsg_delete_" + part.MXID.String(), }) if err != nil { @@ -998,12 +998,12 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet ctx := log.WithContext(context.TODO()) if portal.MXID == "" { log.Debug().Msg("Creating Matrix room from incoming message") - if err := portal.CreateMatrixRoom(source, nil); err != nil { + if err := portal.CreateMatrixRoom(ctx, source, nil); err != nil { log.Error().Err(err).Msg("Failed to create portal room") return } // FIXME hacky - ensureGroupPuppetsAreJoinedToPortal(context.Background(), source, portal) + ensureGroupPuppetsAreJoinedToPortal(context.TODO(), source, portal) signalmeow.SendContactSyncRequest(context.TODO(), source.SignalDevice) } @@ -1023,7 +1023,7 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet converted.MergeCaption() } for i, part := range converted.Parts { - resp, err := portal.sendMatrixEvent(intent, part.Type, part.Content, part.Extra, int64(converted.Timestamp)) + resp, err := portal.sendMatrixEvent(ctx, intent, part.Type, part.Content, part.Extra, int64(converted.Timestamp)) if err != nil { log.Err(err).Int("part_index", i).Msg("Failed to send message to Matrix") continue @@ -1076,7 +1076,7 @@ func (portal *Portal) handleSignalEditMessage(sender *Puppet, timestamp uint64, "m.new_content": part.Extra, } } - _, err = portal.sendMatrixEvent(intent, part.Type, part.Content, part.Extra, int64(converted.Timestamp)) + _, err = portal.sendMatrixEvent(ctx, intent, part.Type, part.Content, part.Extra, int64(converted.Timestamp)) if err != nil { log.Err(err).Int("part_index", i).Msg("Failed to send edit to Matrix") } @@ -1094,6 +1094,7 @@ func (portal *Portal) handleSignalTypingMessage(sender *Puppet, msg *signalpb.Ty portal.log.Debug().Msg("Dropping typing message in chat with no portal") return } + ctx := context.TODO() intent := sender.IntentFor(portal) // Don't bridge double puppeted typing notifications to avoid echoing if intent.IsCustomPuppet { @@ -1102,9 +1103,9 @@ func (portal *Portal) handleSignalTypingMessage(sender *Puppet, msg *signalpb.Ty var err error switch msg.GetAction() { case signalpb.TypingMessage_STARTED: - _, err = intent.UserTyping(portal.MXID, true, SignalTypingTimeout) + _, err = intent.UserTyping(ctx, portal.MXID, true, SignalTypingTimeout) case signalpb.TypingMessage_STOPPED: - _, err = intent.UserTyping(portal.MXID, false, 0) + _, err = intent.UserTyping(ctx, portal.MXID, false, 0) } if err != nil { portal.log.Err(err). @@ -1132,7 +1133,7 @@ func (portal *Portal) addDisappearingMessage(ctx context.Context, eventID id.Eve portal.bridge.disappearingMessagesManager.AddDisappearingMessage(ctx, eventID, portal.MXID, time.Duration(expireInSeconds)*time.Second, startTimerNow) } -func (portal *Portal) MarkDelivered(msg *database.Message) { +func (portal *Portal) MarkDelivered(ctx context.Context, msg *database.Message) { if !portal.IsPrivateChat() { return } @@ -1144,7 +1145,7 @@ func (portal *Portal) MarkDelivered(msg *database.Message) { Status: status.MsgStatusDelivered, ReportedBy: status.MsgReportedByBridge, }) - portal.sendStatusEvent(msg.MXID, "", nil, &[]id.UserID{portal.MainIntent().UserID}) + portal.sendStatusEvent(ctx, msg.MXID, "", nil, &[]id.UserID{portal.MainIntent().UserID}) } type customReadReceipt struct { @@ -1158,11 +1159,11 @@ type customReadMarkers struct { FullyReadExtra customReadReceipt `json:"com.beeper.fully_read.extra"` } -func (portal *Portal) SendReadReceipt(sender *Puppet, msg *database.Message) error { +func (portal *Portal) SendReadReceipt(ctx context.Context, sender *Puppet, msg *database.Message) error { intent := sender.IntentFor(portal) if intent.IsCustomPuppet { extra := customReadReceipt{DoublePuppetSource: portal.bridge.Name} - return intent.SetReadMarkers(portal.MXID, &customReadMarkers{ + return intent.SetReadMarkers(ctx, portal.MXID, &customReadMarkers{ ReqSetReadMarkers: mautrix.ReqSetReadMarkers{ Read: msg.MXID, FullyRead: msg.MXID, @@ -1171,7 +1172,7 @@ func (portal *Portal) SendReadReceipt(sender *Puppet, msg *database.Message) err FullyReadExtra: extra, }) } else { - return intent.MarkRead(portal.MXID, msg.MXID) + return intent.MarkRead(ctx, portal.MXID, msg.MXID) } } @@ -1210,7 +1211,7 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { if portal.IsPrivateChat() { // this is a 1:1 chat portal.log.Debug().Msgf("Sending Typing event to Signal %s", portal.ChatID) - ctx := context.Background() + ctx := context.TODO() typingMessage := signalmeow.TypingMessage(isTyping) result := signalmeow.SendMessage(ctx, user.SignalDevice, portal.UserID(), typingMessage) if !result.WasSuccessful { @@ -1295,7 +1296,7 @@ func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, } // Don't use portal.sendSignalMessage because we're sending this straight to // who sent the original message, not the portal's ChatID - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) result := signalmeow.SendMessage(ctx, sender.SignalDevice, destination, signalmeow.ReadReceptMessageForTimestamps(messages)) cancel() if !result.WasSuccessful { @@ -1312,11 +1313,11 @@ func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, } } -func (portal *Portal) sendMainIntentMessage(content *event.MessageEventContent) (*mautrix.RespSendEvent, error) { - return portal.sendMatrixEvent(portal.MainIntent(), event.EventMessage, content, nil, 0) +func (portal *Portal) sendMainIntentMessage(ctx context.Context, content *event.MessageEventContent) (*mautrix.RespSendEvent, error) { + return portal.sendMatrixEvent(ctx, portal.MainIntent(), event.EventMessage, content, nil, 0) } -func (portal *Portal) encrypt(intent *appservice.IntentAPI, content *event.Content, eventType event.Type) (event.Type, error) { +func (portal *Portal) encrypt(ctx context.Context, intent *appservice.IntentAPI, content *event.Content, eventType event.Type) (event.Type, error) { if !portal.Encrypted || portal.bridge.Crypto == nil { return eventType, nil } @@ -1331,18 +1332,18 @@ func (portal *Portal) encrypt(intent *appservice.IntentAPI, content *event.Conte return event.EventEncrypted, nil } -func (portal *Portal) sendMatrixEvent(intent *appservice.IntentAPI, eventType event.Type, content any, extraContent map[string]any, timestamp int64) (*mautrix.RespSendEvent, error) { +func (portal *Portal) sendMatrixEvent(ctx context.Context, intent *appservice.IntentAPI, eventType event.Type, content any, extraContent map[string]any, timestamp int64) (*mautrix.RespSendEvent, error) { wrappedContent := event.Content{Parsed: content, Raw: extraContent} if eventType != event.EventReaction { var err error - eventType, err = portal.encrypt(intent, &wrappedContent, eventType) + eventType, err = portal.encrypt(ctx, intent, &wrappedContent, eventType) if err != nil { return nil, err } } - _, _ = intent.UserTyping(portal.MXID, false, 0) - return intent.SendMassagedMessageEvent(portal.MXID, eventType, &wrappedContent, timestamp) + _, _ = intent.UserTyping(ctx, portal.MXID, false, 0) + return intent.SendMassagedMessageEvent(ctx, portal.MXID, eventType, &wrappedContent, timestamp) } func (portal *Portal) getEncryptionEventContent() (evt *event.EncryptionEventContent) { @@ -1360,11 +1361,11 @@ func (portal *Portal) shouldSetDMRoomMetadata() bool { (portal.IsEncrypted() && portal.bridge.Config.Bridge.PrivateChatPortalMeta != "never") } -func (portal *Portal) ensureUserInvited(user *User) bool { - return user.ensureInvited(portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) +func (portal *Portal) ensureUserInvited(ctx context.Context, user *User) bool { + return user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) } -func (portal *Portal) CreateMatrixRoom(user *User, meta *any) error { +func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, meta *any) error { portal.roomCreateLock.Lock() defer portal.roomCreateLock.Unlock() if portal.MXID != "" { @@ -1375,7 +1376,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, meta *any) error { intent := portal.MainIntent() - if err := intent.EnsureRegistered(); err != nil { + if err := intent.EnsureRegistered(ctx); err != nil { portal.log.Error().Err(err).Msg("failed to ensure registered") return err } @@ -1425,7 +1426,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, meta *any) error { // FIXME slightly hacky user.syncPortalInfo(portal) - resp, err := intent.CreateRoom(&mautrix.ReqCreateRoom{ + resp, err := intent.CreateRoom(ctx, &mautrix.ReqCreateRoom{ Visibility: "private", Name: portal.Name, Topic: portal.Topic, @@ -1454,13 +1455,13 @@ func (portal *Portal) CreateMatrixRoom(user *User, meta *any) error { portal.log.Info().Msgf("Created matrix room %s", portal.MXID) if portal.Encrypted && portal.IsPrivateChat() { - err = portal.bridge.Bot.EnsureJoined(portal.MXID, appservice.EnsureJoinedParams{BotOverride: portal.MainIntent().Client}) + err = portal.bridge.Bot.EnsureJoined(ctx, portal.MXID, appservice.EnsureJoinedParams{BotOverride: portal.MainIntent().Client}) if err != nil { portal.log.Error().Err(err).Msg("Failed to ensure bridge bot is joined to private chat portal") } } - user.ensureInvited(portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) + user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) user.syncChatDoublePuppetDetails(portal, true) go portal.addToPersonalSpace(portal.log.WithContext(context.TODO()), user) @@ -1475,7 +1476,7 @@ func (portal *Portal) CreateMatrixRoom(user *User, meta *any) error { } chats := map[id.UserID][]id.RoomID{puppet.MXID: {portal.MXID}} - user.UpdateDirectChats(chats) + user.UpdateDirectChats(ctx, chats) } return nil @@ -1490,11 +1491,11 @@ func (portal *Portal) ScheduleDisappearing() { } func (portal *Portal) addToPersonalSpace(ctx context.Context, user *User) bool { - spaceID := user.GetSpaceRoom() + spaceID := user.GetSpaceRoom(ctx) if len(spaceID) == 0 || user.IsInSpace(ctx, portal.PortalKey) { return false } - _, err := portal.bridge.Bot.SendStateEvent(spaceID, event.StateSpaceChild, portal.MXID.String(), &event.SpaceChildEventContent{ + _, err := portal.bridge.Bot.SendStateEvent(ctx, spaceID, event.StateSpaceChild, portal.MXID.String(), &event.SpaceChildEventContent{ Via: []string{portal.bridge.Config.Homeserver.Domain}, }) if err != nil { @@ -1517,8 +1518,8 @@ func (portal *Portal) HasRelaybot() bool { return portal.bridge.Config.Bridge.Relay.Enabled && len(portal.RelayUserID) > 0 } -func (portal *Portal) addRelaybotFormat(userID id.UserID, evt *event.Event, content *event.MessageEventContent) bool { - member := portal.MainIntent().Member(portal.MXID, userID) +func (portal *Portal) addRelaybotFormat(ctx context.Context, userID id.UserID, evt *event.Event, content *event.MessageEventContent) bool { + member := portal.MainIntent().Member(ctx, portal.MXID, userID) if member == nil { member = &event.MemberEventContent{} } @@ -1565,22 +1566,22 @@ func (portal *Portal) Delete() { portal.bridge.portalsLock.Unlock() } -func (portal *Portal) Cleanup(puppetsOnly bool) { - portal.bridge.CleanupRoom(&portal.log, portal.MainIntent(), portal.MXID, puppetsOnly) +func (portal *Portal) Cleanup(ctx context.Context, puppetsOnly bool) { + portal.bridge.CleanupRoom(ctx, &portal.log, portal.MainIntent(), portal.MXID, puppetsOnly) } -func (br *SignalBridge) CleanupRoom(log *zerolog.Logger, intent *appservice.IntentAPI, mxid id.RoomID, puppetsOnly bool) { +func (br *SignalBridge) CleanupRoom(ctx context.Context, log *zerolog.Logger, intent *appservice.IntentAPI, mxid id.RoomID, puppetsOnly bool) { if len(mxid) == 0 { return } if br.SpecVersions.Supports(mautrix.BeeperFeatureRoomYeeting) { - err := intent.BeeperDeleteRoom(mxid) + err := intent.BeeperDeleteRoom(ctx, mxid) if err == nil || errors.Is(err, mautrix.MNotFound) { return } log.Warn().Err(err).Msg("Failed to delete room using beeper yeet endpoint, falling back to normal behavior") } - members, err := intent.JoinedMembers(mxid) + members, err := intent.JoinedMembers(ctx, mxid) if err != nil { log.Err(err).Msg("Failed to get portal members for cleanup") return @@ -1591,18 +1592,18 @@ func (br *SignalBridge) CleanupRoom(log *zerolog.Logger, intent *appservice.Inte } puppet := br.GetPuppetByMXID(member) if puppet != nil { - _, err = puppet.DefaultIntent().LeaveRoom(mxid) + _, err = puppet.DefaultIntent().LeaveRoom(ctx, mxid) if err != nil { log.Err(err).Msg("Failed to leave as puppet while cleaning up portal") } } else if !puppetsOnly { - _, err = intent.KickUser(mxid, &mautrix.ReqKickUser{UserID: member, Reason: "Deleting portal"}) + _, err = intent.KickUser(ctx, mxid, &mautrix.ReqKickUser{UserID: member, Reason: "Deleting portal"}) if err != nil { log.Err(err).Msg("Failed to kick user while cleaning up portal") } } } - _, err = intent.LeaveRoom(mxid) + _, err = intent.LeaveRoom(ctx, mxid) if err != nil { log.Err(err).Msg("Failed to leave room while cleaning up portal") } diff --git a/provisioning.go b/provisioning.go index c46f810..4630374 100644 --- a/provisioning.go +++ b/provisioning.go @@ -242,7 +242,7 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { portal := user.GetPortalByChatID(resp.ChatID.UUID) if portal.MXID == "" { - if err := portal.CreateMatrixRoom(user, nil); err != nil { + if err := portal.CreateMatrixRoom(r.Context(), user, nil); err != nil { log.Err(err).Msg("error looking up contact") jsonResponse(w, http.StatusInternalServerError, Error{ Success: false, @@ -285,7 +285,7 @@ func (prov *ProvisioningAPI) newOrExistingSession(user *User) (newSessionLoggedI if err != nil { return false, nil, fmt.Errorf("Error logging in: %w", err) } - provisioningCtx, cancel := context.WithCancel(context.Background()) + provisioningCtx, cancel := context.WithCancel(context.TODO()) handle = &provisioningHandle{ context: provisioningCtx, cancel: cancel, diff --git a/user.go b/user.go index 53d4d50..0b13804 100644 --- a/user.go +++ b/user.go @@ -232,7 +232,7 @@ func (user *User) GetIGhost() bridge.Ghost { return p } -func (user *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) (ok bool) { +func (user *User) ensureInvited(ctx context.Context, intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) (ok bool) { log := user.log.With().Str("action", "ensure_invited").Stringer("room_id", roomID).Logger() if user.bridge.StateStore.GetMembership(roomID, user.MXID) == event.MembershipJoin { ok = true @@ -249,7 +249,7 @@ func (user *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, } else { log.Debug().Msg("NOT adding will_auto_accept to invite content") } - _, err := intent.InviteUser(roomID, &mautrix.ReqInviteUser{UserID: user.MXID}, extraContent) + _, err := intent.InviteUser(ctx, roomID, &mautrix.ReqInviteUser{UserID: user.MXID}, extraContent) var httpErr mautrix.HTTPError if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") { user.bridge.StateStore.SetMembership(roomID, user.MXID, event.MembershipJoin) @@ -263,7 +263,7 @@ func (user *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, if customPuppet != nil && customPuppet.CustomIntent() != nil { log.Debug().Msg("ensuring custom puppet is joined") - err = customPuppet.CustomIntent().EnsureJoined(roomID, appservice.EnsureJoinedParams{IgnoreCache: true}) + err = customPuppet.CustomIntent().EnsureJoined(ctx, roomID, appservice.EnsureJoinedParams{IgnoreCache: true}) if err != nil { log.Warn().Err(err).Msg("Failed to auto-join custom puppet") ok = false @@ -274,7 +274,7 @@ func (user *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, return } -func (user *User) GetSpaceRoom() id.RoomID { +func (user *User) GetSpaceRoom(ctx context.Context) id.RoomID { if !user.bridge.Config.Bridge.PersonalFilteringSpaces { return "" } @@ -286,7 +286,7 @@ func (user *User) GetSpaceRoom() id.RoomID { return user.SpaceRoom } - resp, err := user.bridge.Bot.CreateRoom(&mautrix.ReqCreateRoom{ + resp, err := user.bridge.Bot.CreateRoom(ctx, &mautrix.ReqCreateRoom{ Visibility: "private", Name: "Signal", Topic: "Your Signal bridged chats", @@ -317,10 +317,10 @@ func (user *User) GetSpaceRoom() id.RoomID { if err != nil { user.log.Err(err).Msg("Failed to save user in database after creating space room") } - user.ensureInvited(user.bridge.Bot, user.SpaceRoom, false) + user.ensureInvited(ctx, user.bridge.Bot, user.SpaceRoom, false) } } else if !user.spaceMembershipChecked { - user.ensureInvited(user.bridge.Bot, user.SpaceRoom, false) + user.ensureInvited(ctx, user.bridge.Bot, user.SpaceRoom, false) } user.spaceMembershipChecked = true @@ -600,7 +600,7 @@ func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Pupp log.Debug().Str("new_name", name).Msg("updating puppet name") puppet.Name = name puppet.NameSet = false - err = puppet.DefaultIntent().SetDisplayName(name) + err = puppet.DefaultIntent().SetDisplayName(ctx, name) if err != nil { log.Err(err).Msg("error setting display name") return err @@ -629,7 +629,7 @@ func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Pupp puppet.AvatarSet = false puppet.AvatarURL = id.ContentURI{} puppet.AvatarHash = "" - err = puppet.DefaultIntent().SetAvatarURL(id.ContentURI{}) + err = puppet.DefaultIntent().SetAvatarURL(ctx, id.ContentURI{}) if err != nil { log.Err(err).Msg("error clearing avatar url") return err @@ -645,7 +645,7 @@ func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Pupp // If avatar is set, we must have a new avatar image, so update it if newAvatar != nil { log.Debug().Msg("uploading avatar") - avatarURL, err := puppet.DefaultIntent().UploadBytes(newAvatar.Image, newAvatar.ContentType) + avatarURL, err := puppet.DefaultIntent().UploadBytes(ctx, newAvatar.Image, newAvatar.ContentType) if err != nil { log.Err(err).Msg("error uploading avatar") return err @@ -654,7 +654,7 @@ func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Pupp puppet.AvatarSet = true puppet.AvatarHash = newAvatar.Hash - err = puppet.DefaultIntent().SetAvatarURL(avatarURL.ContentURI) + err = puppet.DefaultIntent().SetAvatarURL(ctx, avatarURL.ContentURI) if err != nil { log.Err(err).Msg("error setting avatar URL") return err @@ -670,7 +670,7 @@ func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Pupp func ensureGroupPuppetsAreJoinedToPortal(ctx context.Context, user *User, portal *Portal) error { // Ensure our puppet is joined to the room - err := portal.MainIntent().EnsureJoined(portal.MXID) + err := portal.MainIntent().EnsureJoined(ctx, portal.MXID) if err != nil { user.log.Err(err).Msg("error ensuring joined") return err @@ -696,7 +696,7 @@ func ensureGroupPuppetsAreJoinedToPortal(ctx context.Context, user *User, portal continue } _ = updatePuppetWithSignalContact(context.TODO(), user, memberPuppet, nil) - err = memberPuppet.DefaultIntent().EnsureJoined(portal.MXID) + err = memberPuppet.DefaultIntent().EnsureJoined(ctx, portal.MXID) if err != nil { user.log.Err(err).Msg("error ensuring joined") } @@ -744,7 +744,7 @@ func (user *User) handleReceipt(evt *events.Receipt) { if portal == nil { continue } - err = portal.SendReadReceipt(sender, msg) + err = portal.SendReadReceipt(ctx, sender, msg) if err != nil { log.Err(err).Msg("Failed to send read receipt") } @@ -767,7 +767,7 @@ func (user *User) handleReceipt(evt *events.Receipt) { continue } // There should always only be 1 part, but use the last part to be safe - portal.MarkDelivered(msgs[len(msgs)-1]) + portal.MarkDelivered(ctx, msgs[len(msgs)-1]) } } } @@ -812,7 +812,7 @@ func (user *User) handleReadSelf(evt *events.ReadSelf) { Msg("Bridging own read receipt") portal.ScheduleDisappearing() user.SetLastReadTS(ctx, portal.PortalKey, msg.Timestamp) - err := portal.SendReadReceipt(puppet, msg) + err := portal.SendReadReceipt(ctx, puppet, msg) if err != nil { user.log.Err(err).Stringer("mxid", msg.MXID).Msg("Failed to send read receipt") } @@ -831,9 +831,10 @@ func (user *User) handleContactChange(evt *events.ContactChange) { } func (user *User) syncPortalInfo(portal *Portal) { + ctx := context.TODO() updatePortal := false if !portal.IsPrivateChat() { - group, avatarImage, err := signalmeow.RetrieveGroupAndAvatarByID(context.Background(), user.SignalDevice, portal.GroupID()) + group, avatarImage, err := signalmeow.RetrieveGroupAndAvatarByID(ctx, user.SignalDevice, portal.GroupID()) if err != nil { user.log.Err(err).Msg("error retrieving group") return @@ -861,7 +862,7 @@ func (user *User) syncPortalInfo(portal *Portal) { // avatarImage is only not nil if there's a new avatar to set if avatarImage != nil { user.log.Debug().Msg("Uploading new group avatar") - avatarURL, err := portal.MainIntent().UploadBytes(avatarImage, http.DetectContentType(avatarImage)) + avatarURL, err := portal.MainIntent().UploadBytes(ctx, avatarImage, http.DetectContentType(avatarImage)) if err != nil { user.log.Err(err).Msg("error uploading group avatar") return @@ -875,8 +876,8 @@ func (user *User) syncPortalInfo(portal *Portal) { if portal.MXID != "" { // ensure everyone is invited to the group - portal.ensureUserInvited(user) - _ = ensureGroupPuppetsAreJoinedToPortal(context.Background(), user, portal) + portal.ensureUserInvited(ctx, user) + _ = ensureGroupPuppetsAreJoinedToPortal(context.TODO(), user, portal) go portal.addToPersonalSpace(portal.log.WithContext(context.TODO()), user) } } else if portal.shouldSetDMRoomMetadata() { @@ -895,16 +896,16 @@ func (user *User) syncPortalInfo(portal *Portal) { } if updatePortal { if portal.MXID != "" { - _, err := portal.MainIntent().SetRoomName(portal.MXID, portal.Name) + _, err := portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) if err != nil { user.log.Err(err).Msg("error setting room name") } portal.NameSet = err == nil - _, err = portal.MainIntent().SetRoomTopic(portal.MXID, portal.Topic) + _, err = portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) if err != nil { user.log.Err(err).Msg("error setting room topic") } - _, err = portal.MainIntent().SetRoomAvatar(portal.MXID, portal.AvatarURL) + _, err = portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) if err != nil { user.log.Err(err).Msg("error setting room avatar") } @@ -914,7 +915,7 @@ func (user *User) syncPortalInfo(portal *Portal) { if err != nil { user.log.Err(err).Msg("error updating portal") } - portal.UpdateBridgeInfo() + portal.UpdateBridgeInfo(ctx) } } @@ -945,7 +946,7 @@ func (user *User) eventHandler(rawEvt events.SignalEvent) { } else { content.Body = "Call ended" } - portal.sendMainIntentMessage(content) + portal.sendMainIntentMessage(context.TODO(), content) case *events.ContactChange: user.handleContactChange(evt) case *events.GroupChange: @@ -995,7 +996,7 @@ func (user *User) Logout() error { return err } -func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) { +func (user *User) UpdateDirectChats(ctx context.Context, chats map[id.UserID][]id.RoomID) { if !user.bridge.Config.Bridge.SyncDirectChatList { return } @@ -1021,7 +1022,7 @@ func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) { var err error if user.bridge.Config.Homeserver.Software == bridgeconfig.SoftwareAsmux { urlPath := intent.BuildURL(mautrix.ClientURLPath{"unstable", "com.beeper.asmux", "dms"}) - _, err = intent.MakeFullRequest(mautrix.FullRequest{ + _, err = intent.MakeFullRequest(ctx, mautrix.FullRequest{ Method: method, URL: urlPath, Headers: http.Header{"X-Asmux-Auth": {user.bridge.AS.Registration.AppToken}}, @@ -1030,7 +1031,7 @@ func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) { } else { existingChats := map[id.UserID][]id.RoomID{} - err = intent.GetAccountData(event.AccountDataDirectChats.Type, &existingChats) + err = intent.GetAccountData(ctx, event.AccountDataDirectChats.Type, &existingChats) if err != nil { user.log.Warn().Err(err).Msg("Failed to get m.direct event to update it") return @@ -1046,7 +1047,7 @@ func (user *User) UpdateDirectChats(chats map[id.UserID][]id.RoomID) { } } - err = intent.SetAccountData(event.AccountDataDirectChats.Type, &chats) + err = intent.SetAccountData(ctx, event.AccountDataDirectChats.Type, &chats) } if err != nil { From d4497f53b4e565f3d81949f8fec5de0770d083ff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Jan 2024 15:18:45 +0200 Subject: [PATCH 004/718] Fix some error messages --- pkg/signalmeow/store.go | 10 ++++++++-- user.go | 7 +++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/signalmeow/store.go b/pkg/signalmeow/store.go index e383efb..13c680f 100644 --- a/pkg/signalmeow/store.go +++ b/pkg/signalmeow/store.go @@ -95,11 +95,17 @@ func (c *StoreContainer) scanDevice(row dbutil.Scannable) (*Device, error) { &deviceData.PNI, &pniIdentityKeyPair, &deviceData.PNIRegistrationID, &deviceData.DeviceID, &deviceData.Number, &deviceData.Password, ) - deviceData.ACIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(aciIdentityKeyPair) - deviceData.PNIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(pniIdentityKeyPair) if err != nil { return nil, fmt.Errorf("failed to scan session: %w", err) } + deviceData.ACIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(aciIdentityKeyPair) + if err != nil { + return nil, fmt.Errorf("failed to deserialize ACI identity key pair: %w", err) + } + deviceData.PNIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(pniIdentityKeyPair) + if err != nil { + return nil, fmt.Errorf("failed to deserialize PNI identity key pair: %w", err) + } innerStore := newSQLStore(c, deviceData.ACI) // Assign innerStore to all the interfaces diff --git a/user.go b/user.go index 0b13804..b126693 100644 --- a/user.go +++ b/user.go @@ -571,11 +571,10 @@ func (user *User) populateSignalDevice() *signalmeow.Device { device, err := user.bridge.MeowStore.DeviceByACI(context.TODO(), user.SignalID) if err != nil { - log.Err(err).Msg("problem looking up ACI") + log.Err(err).Msg("Failed to get device from database") return nil - } - if device == nil { - log.Err(ErrNotLoggedIn).Msg("no device found for ACI") + } else if device == nil { + log.Err(ErrNotLoggedIn).Msg("No device found for user") return nil } From bd319db1a728867a1cf5b4b8ac56a1a7a5b765fc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Jan 2024 19:41:20 +0200 Subject: [PATCH 005/718] Clear duplicate double puppet entries before adding unique constraint --- database/upgrades/16-refactor-postgres.sql | 4 ++++ database/upgrades/17-refactor-sqlite.sql | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/database/upgrades/16-refactor-postgres.sql b/database/upgrades/16-refactor-postgres.sql index db2fee6..776aa8d 100644 --- a/database/upgrades/16-refactor-postgres.sql +++ b/database/upgrades/16-refactor-postgres.sql @@ -84,6 +84,10 @@ ALTER TABLE portal ALTER COLUMN expiration_time SET NOT NULL; ALTER TABLE portal ALTER COLUMN relay_user_id SET NOT NULL; -- Add unique constraint to custom_mxid +UPDATE puppet + SET custom_mxid=NULL, access_token='' + WHERE custom_mxid<>'' + AND uuid<>COALESCE((SELECT uuid FROM "user" WHERE mxid=custom_mxid), '00000000-0000-0000-0000-000000000000'); UPDATE puppet SET custom_mxid=NULL WHERE custom_mxid=''; ALTER TABLE puppet ADD CONSTRAINT puppet_custom_mxid_unique UNIQUE(custom_mxid); -- Remove unnecessary nullables in puppet diff --git a/database/upgrades/17-refactor-sqlite.sql b/database/upgrades/17-refactor-sqlite.sql index 2d1a32f..ca55dee 100644 --- a/database/upgrades/17-refactor-sqlite.sql +++ b/database/upgrades/17-refactor-sqlite.sql @@ -148,6 +148,10 @@ CREATE TABLE puppet_new ( CONSTRAINT puppet_custom_mxid_unique UNIQUE(custom_mxid) ); +UPDATE puppet + SET custom_mxid=NULL, access_token='' + WHERE custom_mxid<>'' + AND uuid<>COALESCE((SELECT uuid FROM "user" WHERE mxid=custom_mxid), '00000000-0000-0000-0000-000000000000'); INSERT INTO puppet_new SELECT uuid, number, COALESCE(name, ''), COALESCE(name_quality, 0), COALESCE(avatar_hash, ''), COALESCE(avatar_url, ''), name_set, avatar_set, is_registered, contact_info_set, From a91fc7028c54482ec6c581784d553199dfff93ff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Jan 2024 18:48:16 +0200 Subject: [PATCH 006/718] Update to libsignal 0.37.0 --- .github/workflows/go.yml | 3 --- pkg/libsignalgo/buffer.go | 4 ++-- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 35 ++++++++++++++++++++++++--------- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 678a3e0..844bdba 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,9 +2,6 @@ name: Go on: [push, pull_request] -env: - LIBSIGNAL_REF: "v0.36.1" - jobs: lint: runs-on: ubuntu-latest diff --git a/pkg/libsignalgo/buffer.go b/pkg/libsignalgo/buffer.go index f6e0ef9..2758590 100644 --- a/pkg/libsignalgo/buffer.go +++ b/pkg/libsignalgo/buffer.go @@ -29,13 +29,13 @@ func BorrowedMutableBuffer(length int) C.SignalBorrowedMutableBuffer { data := make([]byte, length) return C.SignalBorrowedMutableBuffer{ base: (*C.uchar)(unsafe.Pointer(&data[0])), - length: C.uintptr_t(len(data)), + length: C.size_t(len(data)), } } func BytesToBuffer(data []byte) C.SignalBorrowedBuffer { buf := C.SignalBorrowedBuffer{ - length: C.uintptr_t(len(data)), + length: C.size_t(len(data)), } if len(data) > 0 { buf.base = (*C.uchar)(unsafe.Pointer(&data[0])) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 126f87b..d47f96a 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 126f87b73c3c3c75e3cc25ff41210f059dd654f2 +Subproject commit d47f96abff97d19a0b125376737655c268dd20b9 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 6f2bf57..5fea70d 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -11,6 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only #include #include +#include #include #include @@ -91,9 +92,9 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalRESERVED_LEN 1 -#define SignalSERVER_SECRET_PARAMS_LEN 2305 +#define SignalSERVER_SECRET_PARAMS_LEN 2689 -#define SignalSERVER_PUBLIC_PARAMS_LEN 417 +#define SignalSERVER_PUBLIC_PARAMS_LEN 641 #define SignalUUID_CIPHERTEXT_LEN 65 @@ -264,12 +265,12 @@ typedef struct SignalValidatingMac SignalValidatingMac; typedef struct { const unsigned char *base; - uintptr_t length; + size_t length; } SignalBorrowedBuffer; typedef struct { unsigned char *base; - uintptr_t length; + size_t length; } SignalOwnedBuffer; typedef int (*SignalLoadSession)(void *store_ctx, SignalSessionRecord **recordp, const SignalProtocolAddress *address); @@ -338,7 +339,7 @@ typedef struct { typedef struct { unsigned char *base; - uintptr_t length; + size_t length; } SignalBorrowedMutableBuffer; typedef SignalKeyPair SignalKyberKeyPair; @@ -374,12 +375,12 @@ typedef struct { typedef struct { const SignalProtocolAddress *const *base; - uintptr_t length; + size_t length; } SignalBorrowedSliceOfProtocolAddress; typedef struct { const SignalSessionRecord *const *base; - uintptr_t length; + size_t length; } SignalBorrowedSliceOfSessionRecord; typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalSenderKeyRecord**, const SignalProtocolAddress*, const uint8_t (*distribution_id)[16]); @@ -392,7 +393,7 @@ typedef struct { SignalStoreSenderKey store_sender_key; } SignalSenderKeyStore; -typedef int (*SignalRead)(void *ctx, uint8_t *buf, uintptr_t buf_len, uintptr_t *amount_read); +typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); typedef int (*SignalSkip)(void *ctx, uint64_t amount); @@ -904,7 +905,7 @@ SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, const Sig SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, const SignalProtocolAddress *destination, const SignalUnidentifiedSenderMessageContent *content, const SignalIdentityKeyStore *identity_key_store); -SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfProtocolAddress recipients, SignalBorrowedSliceOfSessionRecord recipient_sessions, const SignalUnidentifiedSenderMessageContent *content, const SignalIdentityKeyStore *identity_key_store); +SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfProtocolAddress recipients, SignalBorrowedSliceOfSessionRecord recipient_sessions, SignalBorrowedBuffer excluded_recipients, const SignalUnidentifiedSenderMessageContent *content, const SignalIdentityKeyStore *identity_key_store); SignalFfiError *signal_sealed_sender_multi_recipient_message_for_single_recipient(SignalOwnedBuffer *out, SignalBorrowedBuffer encoded_multi_recipient_message); @@ -1176,6 +1177,22 @@ SignalFfiError *signal_backup_auth_credential_presentation_check_valid_contents( SignalFfiError *signal_backup_auth_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, uint64_t now, SignalBorrowedBuffer server_params_bytes); +SignalFfiError *signal_group_send_credential_response_default_expiration_based_on_current_time(uint64_t *out); + +SignalFfiError *signal_group_send_credential_response_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer concatenated_group_member_ciphertexts, const unsigned char (*requester)[SignalUUID_CIPHERTEXT_LEN], uint64_t expiration, const unsigned char (*server_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_group_send_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); + +SignalFfiError *signal_group_send_credential_response_receive(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_aci, uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); + +SignalFfiError *signal_group_send_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_group_send_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_group_send_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_group_send_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, SignalBorrowedBuffer group_members, uint64_t now, const unsigned char (*server_params)[SignalSERVER_SECRET_PARAMS_LEN]); + SignalFfiError *signal_verify_signature(bool *out, SignalBorrowedBuffer cert_pem, SignalBorrowedBuffer body, SignalBorrowedBuffer signature, uint64_t current_timestamp); SignalFfiError *signal_pin_hash_destroy(SignalPinHash *p); From ed7daa088b3b0cb2bb69400907131220ee4dcc4b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 5 Jan 2024 13:44:41 +0200 Subject: [PATCH 007/718] Split signalmeow store and client --- commands.go | 12 +- main.go | 5 +- msgconv/from-matrix.go | 3 +- msgconv/msgconv.go | 2 +- msgconv/urlpreview.go | 4 +- pkg/signalmeow/attachments.go | 4 +- pkg/signalmeow/{device.go => client.go} | 61 +++---- pkg/signalmeow/contact.go | 38 ++-- pkg/signalmeow/devicename.go | 10 +- pkg/signalmeow/groups.go | 109 ++++++------ pkg/signalmeow/keys.go | 56 +++--- pkg/signalmeow/misc.go | 1 + pkg/signalmeow/profile.go | 52 +++--- pkg/signalmeow/provisioning.go | 34 ++-- pkg/signalmeow/receiving.go | 164 ++++++++++-------- pkg/signalmeow/sending.go | 119 +++++++------ pkg/signalmeow/{ => store}/contact_store.go | 2 +- .../{store.go => store/container.go} | 123 ++----------- pkg/signalmeow/store/device.go | 91 ++++++++++ pkg/signalmeow/{ => store}/group_store.go | 12 +- pkg/signalmeow/{ => store}/identity_store.go | 4 +- pkg/signalmeow/{ => store}/prekey_store.go | 83 ++++----- .../{ => store}/profile_key_store.go | 3 +- .../{ => store}/sender_key_store.go | 3 +- pkg/signalmeow/{ => store}/session_store.go | 3 +- .../{ => store}/upgrades/00-latest.sql | 0 .../{ => store}/upgrades/02-groups.sql | 0 .../{ => store}/upgrades/03-contacts.sql | 0 .../{ => store}/upgrades/04-kyber-prekeys.sql | 0 .../upgrades/05-postgres-profile-key.sql | 0 .../{ => store}/upgrades/upgrades.go | 0 pkg/signalmeow/types.go | 9 - pkg/signalmeow/types/identifer.go | 3 + pkg/signalmeow/types/uuid.go | 10 ++ portal.go | 20 +-- provisioning.go | 4 +- user.go | 42 ++--- 37 files changed, 535 insertions(+), 551 deletions(-) rename pkg/signalmeow/{device.go => client.go} (58%) rename pkg/signalmeow/{ => store}/contact_store.go (99%) rename pkg/signalmeow/{store.go => store/container.go} (55%) create mode 100644 pkg/signalmeow/store/device.go rename pkg/signalmeow/{ => store}/group_store.go (87%) rename pkg/signalmeow/{ => store}/identity_store.go (98%) rename pkg/signalmeow/{ => store}/prekey_store.go (73%) rename pkg/signalmeow/{ => store}/profile_key_store.go (99%) rename pkg/signalmeow/{ => store}/sender_key_store.go (99%) rename pkg/signalmeow/{ => store}/session_store.go (99%) rename pkg/signalmeow/{ => store}/upgrades/00-latest.sql (100%) rename pkg/signalmeow/{ => store}/upgrades/02-groups.sql (100%) rename pkg/signalmeow/{ => store}/upgrades/03-contacts.sql (100%) rename pkg/signalmeow/{ => store}/upgrades/04-kyber-prekeys.sql (100%) rename pkg/signalmeow/{ => store}/upgrades/05-postgres-profile-key.sql (100%) rename pkg/signalmeow/{ => store}/upgrades/upgrades.go (100%) create mode 100644 pkg/signalmeow/types/uuid.go diff --git a/commands.go b/commands.go index 3c954ce..ab7ce49 100644 --- a/commands.go +++ b/commands.go @@ -129,11 +129,11 @@ var cmdDeleteSession = &commands.FullHandler{ } func fnDeleteSession(ce *WrappedCommandEvent) { - if !ce.User.SignalDevice.IsDeviceLoggedIn() { + if !ce.User.Client.IsLoggedIn() { ce.Reply("You're not logged in") return } - ce.User.SignalDevice.ClearKeysAndDisconnect(ce.Ctx) + ce.User.Client.ClearKeysAndDisconnect(ce.Ctx) ce.Reply("Disconnected from Signal") } @@ -149,9 +149,9 @@ var cmdPing = &commands.FullHandler{ func fnPing(ce *WrappedCommandEvent) { if ce.User.SignalID == uuid.Nil { ce.Reply("You're not logged in") - } else if !ce.User.SignalDevice.IsDeviceLoggedIn() { + } else if !ce.User.Client.IsLoggedIn() { ce.Reply("You were logged in at some point, but are not anymore") - } else if !ce.User.SignalDevice.Connection.IsConnected() { + } else if !ce.User.Client.IsConnected() { ce.Reply("You're logged into Signal, but not connected to the server") } else { ce.Reply("You're logged into Signal and probably connected to the server") @@ -176,7 +176,7 @@ func fnSetDeviceName(ce *WrappedCommandEvent) { } name := strings.Join(ce.Args, " ") - err := ce.User.SignalDevice.UpdateDeviceName(name) + err := ce.User.Client.UpdateDeviceName(name) if err != nil { ce.Reply("Error setting device name: %v", err) return @@ -203,7 +203,7 @@ func fnPM(ce *WrappedCommandEvent) { user := ce.User number := strings.Join(ce.Args, "") - contact, err := user.SignalDevice.ContactByE164(number) + contact, err := user.Client.ContactByE164(number) if err != nil { ce.Reply("Error looking up number in local contact list: %v", err) return diff --git a/main.go b/main.go index 83f1708..b26edeb 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ import ( "go.mau.fi/mautrix-signal/msgconv/matrixfmt" "go.mau.fi/mautrix-signal/msgconv/signalfmt" "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" ) //go:embed example-config.yaml @@ -58,7 +59,7 @@ type SignalBridge struct { Config *config.Config DB *database.Database Metrics *MetricsHandler - MeowStore *signalmeow.StoreContainer + MeowStore *store.StoreContainer provisioning *ProvisioningAPI @@ -101,7 +102,7 @@ func (br *SignalBridge) Init() { signalmeow.SetLogger(br.ZLog.With().Str("component", "signalmeow").Logger()) br.DB = database.New(br.Bridge.DB) - br.MeowStore = signalmeow.NewStore(br.Bridge.DB, dbutil.ZeroLogger(br.ZLog.With().Str("db_section", "signalmeow").Logger())) + br.MeowStore = store.NewStore(br.Bridge.DB, dbutil.ZeroLogger(br.ZLog.With().Str("db_section", "signalmeow").Logger())) ss := br.Config.Bridge.Provisioning.SharedSecret if len(ss) > 0 && ss != "disable" { diff --git a/msgconv/from-matrix.go b/msgconv/from-matrix.go index d0b0f83..fd89cd6 100644 --- a/msgconv/from-matrix.go +++ b/msgconv/from-matrix.go @@ -32,7 +32,6 @@ import ( "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/msgconv/matrixfmt" - "go.mau.fi/mautrix-signal/pkg/signalmeow" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) @@ -172,7 +171,7 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. return nil, fmt.Errorf("unsupported content type for sticker %s", mime) } } - att, err := signalmeow.UploadAttachment(ctx, mc.GetClient(ctx), data) + att, err := mc.GetClient(ctx).UploadAttachment(ctx, data) if err != nil { log.Err(err).Msg("Failed to upload file") return nil, exerrors.NewDualError(ErrMediaUploadFailed, err) diff --git a/msgconv/msgconv.go b/msgconv/msgconv.go index d22f402..4e926ed 100644 --- a/msgconv/msgconv.go +++ b/msgconv/msgconv.go @@ -36,7 +36,7 @@ type PortalMethods interface { GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote - GetClient(ctx context.Context) *signalmeow.Device + GetClient(ctx context.Context) *signalmeow.Client GetData(ctx context.Context) *database.Portal } diff --git a/msgconv/urlpreview.go b/msgconv/urlpreview.go index 2a14442..168dcb9 100644 --- a/msgconv/urlpreview.go +++ b/msgconv/urlpreview.go @@ -25,11 +25,9 @@ import ( "github.com/rs/zerolog" "github.com/tidwall/gjson" "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" - "go.mau.fi/mautrix-signal/pkg/signalmeow" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) @@ -128,7 +126,7 @@ func (mc *MessageConverter) convertURLPreviewToSignal(ctx context.Context, evt * continue } } - uploaded, err := signalmeow.UploadAttachment(ctx, mc.GetClient(ctx), data) + uploaded, err := mc.GetClient(ctx).UploadAttachment(ctx, data) if err != nil { log.Err(err).Int("preview_index", i).Msg("Failed to reupload URL preview image") continue diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 11371ad..f27b79b 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -114,7 +114,7 @@ func extend(data []byte, paddedLen int) []byte { } } -func UploadAttachment(ctx context.Context, device *Device, body []byte) (*signalpb.AttachmentPointer, error) { +func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb.AttachmentPointer, error) { log := zerolog.Ctx(ctx).With().Str("func", "upload attachment").Logger() keys := random.Bytes(64) // combined AES and MAC keys plaintextLength := uint32(len(body)) @@ -137,7 +137,7 @@ func UploadAttachment(ctx context.Context, device *Device, body []byte) (*signal // Get upload attributes from Signal server attributesPath := "/v3/attachments/form/upload" - username, password := device.Data.BasicAuthCreds() + username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{Username: &username, Password: &password} resp, err := web.SendHTTPRequest(http.MethodGet, attributesPath, opts) if err != nil { diff --git a/pkg/signalmeow/device.go b/pkg/signalmeow/client.go similarity index 58% rename from pkg/signalmeow/device.go rename to pkg/signalmeow/client.go index 2dd2ea1..6dab83f 100644 --- a/pkg/signalmeow/device.go +++ b/pkg/signalmeow/client.go @@ -19,41 +19,20 @@ package signalmeow import ( "context" "errors" - "fmt" "net/url" "sync" - "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) -// Note: right now, the parent `Device` struct is in store.go -type DeviceData struct { - ACIIdentityKeyPair *libsignalgo.IdentityKeyPair - PNIIdentityKeyPair *libsignalgo.IdentityKeyPair - RegistrationID int - PNIRegistrationID int - ACI uuid.UUID - PNI uuid.UUID - DeviceID int - Number string - Password string -} +type Client struct { + Store *store.Device -func (d *DeviceData) BasicAuthCreds() (string, string) { - username := fmt.Sprintf("%s.%d", d.ACI, d.DeviceID) - password := d.Password - return username, password -} - -// DeviceConnection exists on a Device, and holds websockets, cached credentials, -// and other data that is used to communicate with the Signal servers and other clients. -type DeviceConnection struct { - // cached data (not persisted) SenderCertificate *libsignalgo.SenderCertificate GroupCredentials *GroupCredentials GroupCache *GroupCache @@ -61,10 +40,8 @@ type DeviceConnection struct { GroupCallCache *map[string]bool LastContactRequestTime *int64 - // mutexes - EncryptionMutex sync.Mutex + encryptionLock sync.Mutex - // Network interfaces AuthedWS *web.SignalWebsocket UnauthedWS *web.SignalWebsocket WSCancel context.CancelFunc @@ -72,25 +49,25 @@ type DeviceConnection struct { EventHandler func(events.SignalEvent) } -func (d *DeviceConnection) handleEvent(evt events.SignalEvent) { - if d.EventHandler != nil { - d.EventHandler(evt) +func (cli *Client) handleEvent(evt events.SignalEvent) { + if cli.EventHandler != nil { + cli.EventHandler(evt) } } -func (d *DeviceConnection) IsConnected() bool { - if d == nil { +func (cli *Client) IsConnected() bool { + if cli == nil { return false } - return d.AuthedWS.IsConnected() && d.UnauthedWS.IsConnected() + return cli.AuthedWS.IsConnected() && cli.UnauthedWS.IsConnected() } -func (d *DeviceConnection) ConnectAuthedWS(ctx context.Context, data DeviceData, requestHandler web.RequestHandlerFunc) (chan web.SignalWebsocketConnectionStatus, error) { - if d.AuthedWS != nil { +func (cli *Client) ConnectAuthedWS(ctx context.Context, requestHandler web.RequestHandlerFunc) (chan web.SignalWebsocketConnectionStatus, error) { + if cli.AuthedWS != nil { return nil, errors.New("authed websocket already connected") } - username, password := data.BasicAuthCreds() + username, password := cli.Store.BasicAuthCreds() log := zerolog.Ctx(ctx).With(). Str("websocket_type", "authed"). Str("username", username). @@ -103,12 +80,12 @@ func (d *DeviceConnection) ConnectAuthedWS(ctx context.Context, data DeviceData, "&password=" + password authedWS := web.NewSignalWebsocket(path, &username, &password) statusChan := authedWS.Connect(ctx, &requestHandler) - d.AuthedWS = authedWS + cli.AuthedWS = authedWS return statusChan, nil } -func (d *DeviceConnection) ConnectUnauthedWS(ctx context.Context, data DeviceData) (chan web.SignalWebsocketConnectionStatus, error) { - if d.UnauthedWS != nil { +func (cli *Client) ConnectUnauthedWS(ctx context.Context) (chan web.SignalWebsocketConnectionStatus, error) { + if cli.UnauthedWS != nil { return nil, errors.New("unauthed websocket already connected") } @@ -118,6 +95,10 @@ func (d *DeviceConnection) ConnectUnauthedWS(ctx context.Context, data DeviceDat ctx = log.WithContext(ctx) unauthedWS := web.NewSignalWebsocket(web.WebsocketPath, nil, nil) statusChan := unauthedWS.Connect(ctx, nil) - d.UnauthedWS = unauthedWS + cli.UnauthedWS = unauthedWS return statusChan, nil } + +func (cli *Client) IsLoggedIn() bool { + return cli.Store != nil && cli.Store.IsDeviceLoggedIn() +} diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index c979dcb..da7e306 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -34,13 +34,13 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func StoreContactDetailsAsContact(d *Device, contactDetails *signalpb.ContactDetails, avatar *[]byte) (types.Contact, *types.ContactAvatar, error) { +func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.ContactDetails, avatar *[]byte) (types.Contact, *types.ContactAvatar, error) { ctx := context.TODO() parsedUUID, err := uuid.Parse(contactDetails.GetAci()) if err != nil { return types.Contact{}, nil, err } - existingContact, err := d.ContactStore.LoadContact(ctx, parsedUUID) + existingContact, err := cli.Store.ContactStore.LoadContact(ctx, parsedUUID) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error loading contact") return types.Contact{}, nil, err @@ -59,7 +59,7 @@ func StoreContactDetailsAsContact(d *Device, contactDetails *signalpb.ContactDet if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { existingContact.ProfileKey = profileKeyString profileKey := libsignalgo.ProfileKey(profileKeyString) - err = d.ProfileKeyStore.StoreProfileKey(ctx, existingContact.UUID, profileKey) + err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, existingContact.UUID, profileKey) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error storing profile key") //return *existingContact, nil, err @@ -99,7 +99,7 @@ func StoreContactDetailsAsContact(d *Device, contactDetails *signalpb.ContactDet } zlog.Debug().Msgf("StoreContactDetailsAsContact: storing contact for uuid: %v", contactDetails.GetAci()) - storeErr := d.ContactStore.StoreContact(ctx, *existingContact) + storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) if storeErr != nil { zlog.Err(storeErr).Msg("StoreContactDetailsAsContact: error storing contact") return *existingContact, nil, storeErr @@ -107,11 +107,11 @@ func StoreContactDetailsAsContact(d *Device, contactDetails *signalpb.ContactDet return *existingContact, contactAvatar, nil } -func fetchContactThenTryAndUpdateWithProfile(d *Device, profileUuid uuid.UUID, fetchProfileAvatar bool) (*types.Contact, *types.ContactAvatar, error) { +func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID, fetchProfileAvatar bool) (*types.Contact, *types.ContactAvatar, error) { ctx := context.TODO() contactChanged := false - existingContact, err := d.ContactStore.LoadContact(ctx, profileUuid) + existingContact, err := cli.Store.ContactStore.LoadContact(ctx, profileUuid) if err != nil { zlog.Err(err).Msg("fetchContactThenTryAndUpdateWithProfile: error loading contact") return nil, nil, err @@ -129,9 +129,9 @@ func fetchContactThenTryAndUpdateWithProfile(d *Device, profileUuid uuid.UUID, f var profileAvatarImage []byte if fetchProfileAvatar && existingContact.ContactAvatarHash == "" { // We only care about profile avatar if there is no contact avatar - profile, profileAvatarImage, err = RetrieveProfileAndAvatarByID(ctx, d, profileUuid) + profile, profileAvatarImage, err = cli.RetrieveProfileAndAvatarByID(ctx, profileUuid) } else { - profile, err = RetrieveProfileByID(ctx, d, profileUuid) + profile, err = cli.RetrieveProfileByID(ctx, profileUuid) } if err != nil { zlog.Err(err).Msgf("fetchContactThenTryAndUpdateWithProfile: error retrieving profile for uuid: %v", profileUuid) @@ -180,7 +180,7 @@ func fetchContactThenTryAndUpdateWithProfile(d *Device, profileUuid uuid.UUID, f } if contactChanged { - storeErr := d.ContactStore.StoreContact(ctx, *existingContact) + storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) if storeErr != nil { zlog.Err(storeErr).Msg("fetchContactThenTryAndUpdateWithProfile: error storing contact") } @@ -188,9 +188,9 @@ func fetchContactThenTryAndUpdateWithProfile(d *Device, profileUuid uuid.UUID, f return existingContact, profileAvatar, nil } -func (d *Device) UpdateContactE164(uuid uuid.UUID, e164 string) error { +func (cli *Client) UpdateContactE164(uuid uuid.UUID, e164 string) error { ctx := context.TODO() - existingContact, err := d.ContactStore.LoadContact(ctx, uuid) + existingContact, err := cli.Store.ContactStore.LoadContact(ctx, uuid) if err != nil { zlog.Err(err).Msg("UpdateContactE164: error loading contact") return err @@ -206,7 +206,7 @@ func (d *Device) UpdateContactE164(uuid uuid.UUID, e164 string) error { if existingContact.E164 != e164 { zlog.Debug().Msgf("UpdateContactE164: e164 changed for uuid: %v", uuid) existingContact.E164 = e164 - storeErr := d.ContactStore.StoreContact(ctx, *existingContact) + storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) if storeErr != nil { zlog.Err(storeErr).Msg("UpdateContactE164: error storing contact") return storeErr @@ -217,21 +217,21 @@ func (d *Device) UpdateContactE164(uuid uuid.UUID, e164 string) error { // ContactAvatar is only populated if there is no contact avatar, and the profile the avatar has changed // If there is a contact avatar, it will have to have been updated when the contact is sent, we can't fetch on demand -func (d *Device) ContactByIDWithProfileAvatar(uuid uuid.UUID) (*types.Contact, *types.ContactAvatar, error) { +func (cli *Client) ContactByIDWithProfileAvatar(uuid uuid.UUID) (*types.Contact, *types.ContactAvatar, error) { // Update the profile (we can call this liberally, there's a cache backing it) // We can just return the result of this, ContactAvatar will be nil if there's no change or if there is a contact avatar - return fetchContactThenTryAndUpdateWithProfile(d, uuid, true) + return cli.fetchContactThenTryAndUpdateWithProfile(uuid, true) } -func (d *Device) ContactByID(uuid uuid.UUID) (*types.Contact, error) { +func (cli *Client) ContactByID(uuid uuid.UUID) (*types.Contact, error) { // Update the profile (we can call this liberally, there's a cache backing it) - contact, _, err := fetchContactThenTryAndUpdateWithProfile(d, uuid, false) + contact, _, err := cli.fetchContactThenTryAndUpdateWithProfile(uuid, false) return contact, err } -func (d *Device) ContactByE164(e164 string) (*types.Contact, error) { +func (cli *Client) ContactByE164(e164 string) (*types.Contact, error) { ctx := context.TODO() - contact, err := d.ContactStore.LoadContactByE164(ctx, e164) + contact, err := cli.Store.ContactStore.LoadContactByE164(ctx, e164) if err != nil { zlog.Err(err).Msg("ContactByE164 error loading contact") return nil, err @@ -240,7 +240,7 @@ func (d *Device) ContactByE164(e164 string) (*types.Contact, error) { return nil, nil } // Update profile information (we can call this liberally, there's a cache backing it) - contact, _, err = fetchContactThenTryAndUpdateWithProfile(d, contact.UUID, false) + contact, _, err = cli.fetchContactThenTryAndUpdateWithProfile(contact.UUID, false) return contact, err } diff --git a/pkg/signalmeow/devicename.go b/pkg/signalmeow/devicename.go index 5fd9bc9..e253e3a 100644 --- a/pkg/signalmeow/devicename.go +++ b/pkg/signalmeow/devicename.go @@ -43,26 +43,26 @@ func aes256CTR(key, iv, dst, source []byte) { cipher.NewCTR(block, iv).XORKeyStream(dst, source) } -func (d *Device) UpdateDeviceName(name string) error { - encryptedName, err := EncryptDeviceName(name, d.Data.ACIIdentityKeyPair.GetPublicKey()) +func (cli *Client) UpdateDeviceName(name string) error { + encryptedName, err := EncryptDeviceName(name, cli.Store.ACIIdentityKeyPair.GetPublicKey()) if err != nil { return fmt.Errorf("failed to encrypt device name: %w", err) } - err = UpdateDeviceName(d, encryptedName) + err = cli.updateDeviceName(encryptedName) if err != nil { return fmt.Errorf("failed to update device name: %w", err) } return nil } -func UpdateDeviceName(device *Device, encryptedName []byte) error { +func (cli *Client) updateDeviceName(encryptedName []byte) error { reqData, err := json.Marshal(map[string]any{ "deviceName": encryptedName, }) if err != nil { return fmt.Errorf("failed to marshal device name update request: %w", err) } - username, password := device.Data.BasicAuthCreds() + username, password := cli.Store.BasicAuthCreds() resp, err := web.SendHTTPRequest(http.MethodPut, "/v1/accounts/name", &web.HTTPReqOpt{ Body: reqData, Username: &username, diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index cc02906..9446cdd 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -56,8 +56,8 @@ type GroupMember struct { } type Group struct { - groupMasterKey SerializedGroupMasterKey // We should keep this relatively private - GroupIdentifier types.GroupIdentifier // This is what we should use to identify a group outside this file + groupMasterKey types.SerializedGroupMasterKey // We should keep this relatively private + GroupIdentifier types.GroupIdentifier // This is what we should use to identify a group outside this file Title string AvatarPath string @@ -79,14 +79,11 @@ type GroupAuth struct { Password string } -// This is just base64 encoded group master key -type SerializedGroupMasterKey string - -func fetchNewGroupCreds(ctx context.Context, d *Device, today time.Time) (*GroupCredentials, error) { +func (cli *Client) fetchNewGroupCreds(ctx context.Context, today time.Time) (*GroupCredentials, error) { sevenDaysOut := today.Add(7 * 24 * time.Hour) path := fmt.Sprintf("/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d", today.Unix(), sevenDaysOut.Unix()) authRequest := web.CreateWSRequest(http.MethodGet, path, nil, nil, nil) - resp, err := d.Connection.AuthedWS.SendRequest(ctx, authRequest) + resp, err := cli.AuthedWS.SendRequest(ctx, authRequest) if err != nil { zlog.Err(err).Msg("SendRequest error") return nil, err @@ -104,7 +101,7 @@ func fetchNewGroupCreds(ctx context.Context, d *Device, today time.Time) (*Group return nil, err } // make sure pni matches device pni - if creds.PNI != d.Data.PNI { + if creds.PNI != cli.Store.PNI { err := fmt.Errorf("creds.PNI != d.PNI") zlog.Err(err).Msg("creds.PNI != d.PNI") return nil, err @@ -112,12 +109,12 @@ func fetchNewGroupCreds(ctx context.Context, d *Device, today time.Time) (*Group return &creds, nil } -func getCachedAuthorizationForToday(d *Device, today time.Time) *GroupCredential { - if d.Connection.GroupCredentials == nil { +func (cli *Client) getCachedAuthorizationForToday(today time.Time) *GroupCredential { + if cli.GroupCredentials == nil { // No cached credentials return nil } - allCreds := d.Connection.GroupCredentials + allCreds := cli.GroupCredentials // Get the credential for today for _, cred := range allCreds.Credentials { if cred.RedemptionTime == today.Unix() { @@ -128,19 +125,19 @@ func getCachedAuthorizationForToday(d *Device, today time.Time) *GroupCredential return nil } -func GetAuthorizationForToday(ctx context.Context, d *Device, masterKey libsignalgo.GroupMasterKey) (*GroupAuth, error) { +func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsignalgo.GroupMasterKey) (*GroupAuth, error) { // Timestamps for the start of today, and 7 days later today := time.Now().Truncate(24 * time.Hour) - todayCred := getCachedAuthorizationForToday(d, today) + todayCred := cli.getCachedAuthorizationForToday(today) if todayCred == nil { - creds, err := fetchNewGroupCreds(ctx, d, today) + creds, err := cli.fetchNewGroupCreds(ctx, today) if err != nil { zlog.Err(err).Msg("fetchNewGroupCreds error") return nil, err } - d.Connection.GroupCredentials = creds - todayCred = getCachedAuthorizationForToday(d, today) + cli.GroupCredentials = creds + todayCred = cli.getCachedAuthorizationForToday(today) } if todayCred == nil { err := errors.New("Couldn't get credential for today") @@ -160,8 +157,8 @@ func GetAuthorizationForToday(ctx context.Context, d *Device, masterKey libsigna // Receive the auth credential authCredential, err := libsignalgo.ReceiveAuthCredentialWithPni( serverPublicParams(), - d.Data.ACI, - d.Data.PNI, + cli.Store.ACI, + cli.Store.PNI, redemptionTime, *authCredentialResponse, ) @@ -199,7 +196,7 @@ func GetAuthorizationForToday(ctx context.Context, d *Device, masterKey libsigna }, nil } -func masterKeyToBytes(groupMasterKey SerializedGroupMasterKey) libsignalgo.GroupMasterKey { +func masterKeyToBytes(groupMasterKey types.SerializedGroupMasterKey) libsignalgo.GroupMasterKey { // We are very tricksy, groupMasterKey is just base64 encoded group master key :O masterKeyBytes, err := base64.StdEncoding.DecodeString(string(groupMasterKey)) if err != nil { @@ -209,11 +206,11 @@ func masterKeyToBytes(groupMasterKey SerializedGroupMasterKey) libsignalgo.Group return libsignalgo.GroupMasterKey(masterKeyBytes) } -func masterKeyFromBytes(masterKey libsignalgo.GroupMasterKey) SerializedGroupMasterKey { - return SerializedGroupMasterKey(base64.StdEncoding.EncodeToString(masterKey[:])) +func masterKeyFromBytes(masterKey libsignalgo.GroupMasterKey) types.SerializedGroupMasterKey { + return types.SerializedGroupMasterKey(base64.StdEncoding.EncodeToString(masterKey[:])) } -func groupIdentifierFromMasterKey(masterKey SerializedGroupMasterKey) (types.GroupIdentifier, error) { +func groupIdentifierFromMasterKey(masterKey types.SerializedGroupMasterKey) (types.GroupIdentifier, error) { groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(masterKey)) if err != nil { zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") @@ -235,7 +232,7 @@ func groupIdentifierFromMasterKey(masterKey SerializedGroupMasterKey) (types.Gro return gid, nil } -func decryptGroup(encryptedGroup *signalpb.Group, groupMasterKey SerializedGroupMasterKey) (*Group, error) { +func decryptGroup(encryptedGroup *signalpb.Group, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { decryptedGroup := &Group{ groupMasterKey: groupMasterKey, } @@ -336,7 +333,7 @@ func cleanupStringMapping(r rune) rune { return -1 } -func decryptGroupAvatar(encryptedAvatar []byte, groupMasterKey SerializedGroupMasterKey) ([]byte, error) { +func decryptGroupAvatar(encryptedAvatar []byte, groupMasterKey types.SerializedGroupMasterKey) ([]byte, error) { groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) if err != nil { zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") @@ -361,8 +358,8 @@ func groupMetadataForDataMessage(group Group) *signalpb.GroupContextV2 { } } -func fetchGroupByID(ctx context.Context, d *Device, gid types.GroupIdentifier) (*Group, error) { - groupMasterKey, err := d.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) +func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier) (*Group, error) { + groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { zlog.Err(err).Msg("Failed to get group master key") return nil, err @@ -373,7 +370,7 @@ func fetchGroupByID(ctx context.Context, d *Device, gid types.GroupIdentifier) ( return nil, err } masterKeyBytes := masterKeyToBytes(groupMasterKey) - groupAuth, err := GetAuthorizationForToday(ctx, d, masterKeyBytes) + groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) if err != nil { return nil, err } @@ -413,7 +410,7 @@ func fetchGroupByID(ctx context.Context, d *Device, gid types.GroupIdentifier) ( // Store the profile keys in case they're new for _, member := range group.Members { - err = d.ProfileKeyStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) + err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) if err != nil { zlog.Err(err).Msg("DecryptGroup StoreProfileKey error") //return nil, err @@ -422,9 +419,9 @@ func fetchGroupByID(ctx context.Context, d *Device, gid types.GroupIdentifier) ( return group, nil } -func fetchAndDecryptGroupAvatarImage(d *Device, path string, masterKey SerializedGroupMasterKey) ([]byte, error) { +func (cli *Client) fetchAndDecryptGroupAvatarImage(path string, masterKey types.SerializedGroupMasterKey) ([]byte, error) { // Fetch avatar - username, password := d.Data.BasicAuthCreds() + username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, Username: &username, @@ -454,27 +451,27 @@ func fetchAndDecryptGroupAvatarImage(d *Device, path string, masterKey Serialize return decryptedBytes, nil } -func RetrieveGroupByID(ctx context.Context, d *Device, gid types.GroupIdentifier) (*Group, error) { - d.initGroupCache() +func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentifier) (*Group, error) { + cli.initGroupCache() - lastFetched, ok := d.Connection.GroupCache.lastFetched[gid] + lastFetched, ok := cli.GroupCache.lastFetched[gid] if ok && time.Since(lastFetched) < 1*time.Hour { - group, ok := d.Connection.GroupCache.groups[gid] + group, ok := cli.GroupCache.groups[gid] if ok { return group, nil } } - group, err := fetchGroupByID(ctx, d, gid) + group, err := cli.fetchGroupByID(ctx, gid) if err != nil { return nil, err } - d.Connection.GroupCache.groups[gid] = group - d.Connection.GroupCache.lastFetched[gid] = time.Now() + cli.GroupCache.groups[gid] = group + cli.GroupCache.lastFetched[gid] = time.Now() return group, nil } -func RetrieveGroupAndAvatarByID(ctx context.Context, d *Device, gid types.GroupIdentifier) (*Group, []byte, error) { - group, err := RetrieveGroupByID(ctx, d, gid) +func (cli *Client) RetrieveGroupAndAvatarByID(ctx context.Context, gid types.GroupIdentifier) (*Group, []byte, error) { + group, err := cli.RetrieveGroupByID(ctx, gid) if err != nil { return nil, nil, err } @@ -483,38 +480,38 @@ func RetrieveGroupAndAvatarByID(ctx context.Context, d *Device, gid types.GroupI // If there is an avatarPath, and it's different from the cached one, fetch it // (we only return the avatar if it's different from the cached one) var avatarImage []byte - cachedAvatarPath, _ := d.Connection.GroupCache.avatarPaths[gid] + cachedAvatarPath, _ := cli.GroupCache.avatarPaths[gid] if group.AvatarPath != "" && cachedAvatarPath != group.AvatarPath { - avatarImage, err = fetchAndDecryptGroupAvatarImage(d, group.AvatarPath, group.groupMasterKey) + avatarImage, err = cli.fetchAndDecryptGroupAvatarImage(group.AvatarPath, group.groupMasterKey) if err != nil { zlog.Err(err).Msg("error fetching group avatarImage") return nil, nil, err } } - d.Connection.GroupCache.avatarPaths[gid] = group.AvatarPath + cli.GroupCache.avatarPaths[gid] = group.AvatarPath return group, avatarImage, nil } -func InvalidateGroupCache(d *Device, gid types.GroupIdentifier) { - if d.Connection.GroupCache == nil { +func (cli *Client) InvalidateGroupCache(gid types.GroupIdentifier) { + if cli.GroupCache == nil { return } - delete(d.Connection.GroupCache.groups, gid) - delete(d.Connection.GroupCache.lastFetched, gid) + delete(cli.GroupCache.groups, gid) + delete(cli.GroupCache.lastFetched, gid) // Don't delete avatarPaths, they can stay cached } // We should store the group master key in the group store as soon as we see it, // then use the group identifier to refer to groups. As a convenience, we return // the group identifier, which is derived from the group master key. -func StoreMasterKey(ctx context.Context, d *Device, groupMasterKey SerializedGroupMasterKey) (types.GroupIdentifier, error) { +func (cli *Client) StoreMasterKey(ctx context.Context, groupMasterKey types.SerializedGroupMasterKey) (types.GroupIdentifier, error) { groupIdentifier, err := groupIdentifierFromMasterKey(groupMasterKey) if err != nil { zlog.Err(err).Msg("groupIdentifierFromMasterKey error") return "", err } - err = d.GroupStore.StoreMasterKey(ctx, groupIdentifier, groupMasterKey) + err = cli.Store.GroupStore.StoreMasterKey(ctx, groupIdentifier, groupMasterKey) if err != nil { zlog.Err(err).Msg("StoreMasterKey error") return "", err @@ -525,24 +522,24 @@ func StoreMasterKey(ctx context.Context, d *Device, groupMasterKey SerializedGro // We need to track active calls so we don't send too many IncomingSignalMessageCalls // Of course for group calls Signal doesn't tell us *anything* so we're mostly just inferring // So we just jam a new call ID in, and return true if we *think* this is a new incoming call -func (d *Device) UpdateActiveCalls(gid types.GroupIdentifier, callID string) (isActive bool) { - d.initGroupCache() +func (cli *Client) UpdateActiveCalls(gid types.GroupIdentifier, callID string) (isActive bool) { + cli.initGroupCache() // Check to see if we currently have an active call for this group - currentCallID, ok := d.Connection.GroupCache.activeCalls[gid] + currentCallID, ok := cli.GroupCache.activeCalls[gid] if ok { // If we do, then this must be ending the call if currentCallID == callID { - delete(d.Connection.GroupCache.activeCalls, gid) + delete(cli.GroupCache.activeCalls, gid) return false } } - d.Connection.GroupCache.activeCalls[gid] = callID + cli.GroupCache.activeCalls[gid] = callID return true } -func (d *Device) initGroupCache() { - if d.Connection.GroupCache == nil { - d.Connection.GroupCache = &GroupCache{ +func (cli *Client) initGroupCache() { + if cli.GroupCache == nil { + cli.GroupCache = &GroupCache{ groups: make(map[types.GroupIdentifier]*Group), lastFetched: make(map[types.GroupIdentifier]time.Time), avatarPaths: make(map[types.GroupIdentifier]string), diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index c765a17..9df88ba 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -28,6 +28,7 @@ import ( "github.com/google/uuid" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -37,21 +38,21 @@ type GeneratedPreKeys struct { IdentityKey []uint8 } -func GenerateAndRegisterPreKeys(ctx context.Context, device *Device, uuidKind UUIDKind) error { +func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { var identityKeyPair *libsignalgo.IdentityKeyPair - if uuidKind == UUIDKindPNI { - identityKeyPair = device.Data.PNIIdentityKeyPair + if uuidKind == types.UUIDKindPNI { + identityKeyPair = cli.Store.PNIIdentityKeyPair } else { - identityKeyPair = device.Data.ACIIdentityKeyPair + identityKeyPair = cli.Store.ACIIdentityKeyPair } // Generate prekeys - nextPreKeyID, err := device.PreKeyStoreExtras.GetNextPreKeyID(ctx, uuidKind) + nextPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextPreKeyID(ctx, uuidKind) if err != nil { zlog.Err(err).Msg("Error getting next prekey id") return err } - nextKyberPreKeyID, err := device.PreKeyStoreExtras.GetNextKyberPreKeyID(ctx, uuidKind) + nextKyberPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextKyberPreKeyID(ctx, uuidKind) if err != nil { zlog.Err(err).Msg("Error getting next kyber prekey id") return err @@ -62,10 +63,10 @@ func GenerateAndRegisterPreKeys(ctx context.Context, device *Device, uuidKind UU // Persist prekeys // TODO return database errors for _, preKey := range preKeys { - device.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) + cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) } for _, kyberPreKey := range kyberPreKeys { - device.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) + cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) } // Register prekeys @@ -79,12 +80,12 @@ func GenerateAndRegisterPreKeys(ctx context.Context, device *Device, uuidKind UU KyberPreKeys: kyberPreKeys, IdentityKey: identityKey, } - preKeyUsername := device.Data.Number - if device.Data.ACI != uuid.Nil { - preKeyUsername = device.Data.ACI.String() + preKeyUsername := cli.Store.Number + if cli.Store.ACI != uuid.Nil { + preKeyUsername = cli.Store.ACI.String() } - preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, device.Data.DeviceID) - err = RegisterPreKeys(&generatedPreKeys, uuidKind, preKeyUsername, device.Data.Password) + preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, cli.Store.DeviceID) + err = RegisterPreKeys(&generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) if err != nil { zlog.Err(err).Msg("RegisterPreKeys error") return err @@ -93,7 +94,7 @@ func GenerateAndRegisterPreKeys(ctx context.Context, device *Device, uuidKind UU // Mark prekeys as registered // (kyber prekeys don't have "mark as uploaded" we just assume they always are) lastPreKeyID, err := preKeys[len(preKeys)-1].GetID() - err = device.PreKeyStoreExtras.MarkPreKeysAsUploaded(ctx, uuidKind, lastPreKeyID) + err = cli.Store.PreKeyStoreExtras.MarkPreKeysAsUploaded(ctx, uuidKind, lastPreKeyID) if err != nil { zlog.Err(err).Msg("Error marking prekeys as uploaded") @@ -102,7 +103,7 @@ func GenerateAndRegisterPreKeys(ctx context.Context, device *Device, uuidKind UU return err } -func GeneratePreKeys(startKeyId uint, count uint, uuidKind UUIDKind) []*libsignalgo.PreKeyRecord { +func GeneratePreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind) []*libsignalgo.PreKeyRecord { generatedPreKeys := []*libsignalgo.PreKeyRecord{} for i := startKeyId; i < startKeyId+count; i++ { privateKey, err := libsignalgo.GeneratePrivateKey() @@ -120,7 +121,7 @@ func GeneratePreKeys(startKeyId uint, count uint, uuidKind UUIDKind) []*libsigna return generatedPreKeys } -func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind UUIDKind, identityKeyPair *libsignalgo.IdentityKeyPair) []*libsignalgo.KyberPreKeyRecord { +func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind, identityKeyPair *libsignalgo.IdentityKeyPair) []*libsignalgo.KyberPreKeyRecord { generatedKyberPreKeys := []*libsignalgo.KyberPreKeyRecord{} for i := startKeyId; i < startKeyId+count; i++ { kyberPreKeyPair, err := libsignalgo.KyberKeyPairGenerate() @@ -154,7 +155,7 @@ func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind UUIDKind, identi return generatedKyberPreKeys } -func GenerateSignedPreKey(startSignedKeyId uint32, uuidKind UUIDKind, identityKeyPair *libsignalgo.IdentityKeyPair) *libsignalgo.SignedPreKeyRecord { +func GenerateSignedPreKey(startSignedKeyId uint32, uuidKind types.UUIDKind, identityKeyPair *libsignalgo.IdentityKeyPair) *libsignalgo.SignedPreKeyRecord { // Generate a signed prekey privateKey, err := libsignalgo.GeneratePrivateKey() if err != nil { @@ -186,17 +187,6 @@ func GenerateSignedPreKey(startSignedKeyId uint32, uuidKind UUIDKind, identityKe return signedPreKey } -func StoreSignedPreKey(ctx context.Context, device *Device, signedPreKey *libsignalgo.SignedPreKeyRecord, uuidKind UUIDKind) { - // Note: marking as uploaded right now because we're about to upload as part of - // provisioning, and if provisioning fails, we'll just generate a new one - // Also we don't really use the uploaded for anything - device.PreKeyStoreExtras.SaveSignedPreKey(ctx, uuidKind, signedPreKey, true) -} - -func StoreKyberLastResortPreKey(ctx context.Context, device *Device, kyberPreKey *libsignalgo.KyberPreKeyRecord, uuidKind UUIDKind) { - device.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, true) -} - func PreKeyToJSON(preKey *libsignalgo.PreKeyRecord) map[string]interface{} { id, _ := preKey.GetID() publicKey, _ := preKey.GetPublicKey() @@ -234,7 +224,7 @@ func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) map[string]in return kyberPreKeyJson } -func RegisterPreKeys(generatedPreKeys *GeneratedPreKeys, uuidKind UUIDKind, username string, password string) error { +func RegisterPreKeys(generatedPreKeys *GeneratedPreKeys, uuidKind types.UUIDKind, username string, password string) error { // Convert generated prekeys to JSON preKeysJson := []map[string]interface{}{} kyberPreKeysJson := []map[string]interface{}{} @@ -304,14 +294,14 @@ func addBase64PaddingAndDecode(data string) ([]byte, error) { return base64.StdEncoding.DecodeString(data) } -func FetchAndProcessPreKey(ctx context.Context, device *Device, theirUUID uuid.UUID, specificDeviceID int) error { +func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUID, specificDeviceID int) error { // Fetch prekey deviceIDPath := "/*" if specificDeviceID >= 0 { deviceIDPath = "/" + fmt.Sprint(specificDeviceID) } path := "/v2/keys/" + theirUUID.String() + deviceIDPath + "?pq=true" - username, password := device.Data.BasicAuthCreds() + username, password := cli.Store.BasicAuthCreds() resp, err := web.SendHTTPRequest(http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) if err != nil { zlog.Err(err).Msg("Error sending request") @@ -415,8 +405,8 @@ func FetchAndProcessPreKey(ctx context.Context, device *Device, theirUUID uuid.U ctx, preKeyBundle, address, - device.SessionStore, - device.IdentityStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, ) if err != nil { diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 5e89a0f..7a073e7 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -25,6 +25,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) +// Deprecated: global loggers are bad var zlog zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{}).With().Timestamp().Logger() func SetLogger(l zerolog.Logger) { diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 703c76a..713c402 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -64,8 +64,8 @@ type ProfileCache struct { avatarPaths map[string]string } -func ProfileKeyCredentialRequest(ctx context.Context, d *Device, signalACI uuid.UUID) ([]byte, error) { - profileKey, err := ProfileKeyForSignalID(ctx, d, signalACI) +func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uuid.UUID) ([]byte, error) { + profileKey, err := cli.ProfileKeyForSignalID(ctx, signalACI) if err != nil { zlog.Err(err).Msg("ProfileKey error") return nil, err @@ -93,8 +93,8 @@ func ProfileKeyCredentialRequest(ctx context.Context, d *Device, signalACI uuid. return []byte(hexRequest), nil } -func ProfileKeyForSignalID(ctx context.Context, d *Device, signalACI uuid.UUID) (*libsignalgo.ProfileKey, error) { - profileKey, err := d.ProfileKeyStore.LoadProfileKey(ctx, signalACI) +func (cli *Client) ProfileKeyForSignalID(ctx context.Context, signalACI uuid.UUID) (*libsignalgo.ProfileKey, error) { + profileKey, err := cli.Store.ProfileKeyStore.LoadProfileKey(ctx, signalACI) if err != nil { zlog.Err(err).Msg("GetProfileKey error") return nil, err @@ -104,9 +104,9 @@ func ProfileKeyForSignalID(ctx context.Context, d *Device, signalACI uuid.UUID) var errProfileKeyNotFound = errors.New("profile key not found") -func RetrieveProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*Profile, error) { - if d.Connection.ProfileCache == nil { - d.Connection.ProfileCache = &ProfileCache{ +func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) (*Profile, error) { + if cli.ProfileCache == nil { + cli.ProfileCache = &ProfileCache{ profiles: make(map[string]*Profile), errors: make(map[string]*error), lastFetched: make(map[string]time.Time), @@ -116,25 +116,25 @@ func RetrieveProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*P // Check if we have a cached profile that is less than an hour old // or if we have a cached error that is less than an hour old - lastFetched, ok := d.Connection.ProfileCache.lastFetched[signalID.String()] + lastFetched, ok := cli.ProfileCache.lastFetched[signalID.String()] if ok && time.Since(lastFetched) < 1*time.Hour { - profile, ok := d.Connection.ProfileCache.profiles[signalID.String()] + profile, ok := cli.ProfileCache.profiles[signalID.String()] if ok { return profile, nil } - err, ok := d.Connection.ProfileCache.errors[signalID.String()] + err, ok := cli.ProfileCache.errors[signalID.String()] if ok { return nil, *err } } // If we get here, we don't have a cached profile, so fetch it - profile, err := fetchProfileByID(ctx, d, signalID) + profile, err := cli.fetchProfileByID(ctx, signalID) if err != nil { // If we get a 401 or 5xx error, we should not retry until the cache expires if strings.HasPrefix(err.Error(), "401") || strings.HasPrefix(err.Error(), "5") { - d.Connection.ProfileCache.errors[signalID.String()] = &err - d.Connection.ProfileCache.lastFetched[signalID.String()] = time.Now() + cli.ProfileCache.errors[signalID.String()] = &err + cli.ProfileCache.lastFetched[signalID.String()] = time.Now() } return nil, err } @@ -143,14 +143,14 @@ func RetrieveProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*P } // If we get here, we have a valid profile, so cache it - d.Connection.ProfileCache.profiles[signalID.String()] = profile - d.Connection.ProfileCache.lastFetched[signalID.String()] = time.Now() + cli.ProfileCache.profiles[signalID.String()] = profile + cli.ProfileCache.lastFetched[signalID.String()] = time.Now() return profile, nil } -func RetrieveProfileAndAvatarByID(ctx context.Context, d *Device, signalID uuid.UUID) (*Profile, []byte, error) { - profile, err := RetrieveProfileByID(ctx, d, signalID) +func (cli *Client) RetrieveProfileAndAvatarByID(ctx context.Context, signalID uuid.UUID) (*Profile, []byte, error) { + profile, err := cli.RetrieveProfileByID(ctx, signalID) if err != nil { return nil, nil, err } @@ -158,21 +158,21 @@ func RetrieveProfileAndAvatarByID(ctx context.Context, d *Device, signalID uuid. // If there is an avatarPath, and it's different from the cached one, fetch it // (we only return the avatar if it's different from the cached one) var avatarImage []byte - cachedAvatarPath, _ := d.Connection.ProfileCache.avatarPaths[signalID.String()] + cachedAvatarPath, _ := cli.ProfileCache.avatarPaths[signalID.String()] if profile.AvatarPath != "" && cachedAvatarPath != profile.AvatarPath { - avatarImage, err = fetchAndDecryptAvatarImage(d, profile.AvatarPath, &profile.Key) + avatarImage, err = cli.fetchAndDecryptAvatarImage(profile.AvatarPath, &profile.Key) if err != nil { zlog.Err(err).Msg("error fetching profile avatarImage") return nil, nil, err } } - d.Connection.ProfileCache.avatarPaths[signalID.String()] = profile.AvatarPath + cli.ProfileCache.avatarPaths[signalID.String()] = profile.AvatarPath return profile, avatarImage, nil } -func fetchProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*Profile, error) { - profileKey, err := ProfileKeyForSignalID(ctx, d, signalID) +func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*Profile, error) { + profileKey, err := cli.ProfileKeyForSignalID(ctx, signalID) if err != nil { zlog.Err(err).Msg("ProfileKey error") return nil, err @@ -195,7 +195,7 @@ func fetchProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*Prof } base64AccessKey := base64.StdEncoding.EncodeToString(accessKey[:]) - credentialRequest, err := ProfileKeyCredentialRequest(ctx, d, signalID) + credentialRequest, err := cli.ProfileKeyCredentialRequest(ctx, signalID) if err != nil { zlog.Err(err).Msg("ProfileKeyCredentialRequest error") return nil, err @@ -219,7 +219,7 @@ func fetchProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*Prof profileRequest.Headers = append(profileRequest.Headers, "unidentified-access-key:"+base64AccessKey) profileRequest.Headers = append(profileRequest.Headers, "accept-language:en-CA") } - resp, err := d.Connection.UnauthedWS.SendRequest(ctx, profileRequest) + resp, err := cli.UnauthedWS.SendRequest(ctx, profileRequest) if err != nil { zlog.Err(err).Msg("SendRequest error") return nil, err @@ -270,8 +270,8 @@ func fetchProfileByID(ctx context.Context, d *Device, signalID uuid.UUID) (*Prof return &profile, nil } -func fetchAndDecryptAvatarImage(d *Device, avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { - username, password := d.Data.BasicAuthCreds() +func (cli *Client) fetchAndDecryptAvatarImage(avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { + username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, // I guess don't use CDN2 for profiles? Username: &username, diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 49a9c6f..731541d 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -34,6 +34,8 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" "go.mau.fi/mautrix-signal/pkg/signalmeow/wspb" ) @@ -72,11 +74,11 @@ func (s ProvisioningState) String() string { type ProvisioningResponse struct { State ProvisioningState ProvisioningURL string - ProvisioningData *DeviceData + ProvisioningData *store.DeviceData Err error } -func PerformProvisioning(incomingCtx context.Context, deviceStore DeviceStore, deviceName string) chan ProvisioningResponse { +func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceStore, deviceName string) chan ProvisioningResponse { c := make(chan ProvisioningResponse) go func() { defer close(c) @@ -121,10 +123,10 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore DeviceStore, d code := provisioningMessage.ProvisioningCode registrationId := mrand.Intn(16383) + 1 pniRegistrationId := mrand.Intn(16383) + 1 - aciSignedPreKey := GenerateSignedPreKey(1, UUIDKindACI, aciIdentityKeyPair) - pniSignedPreKey := GenerateSignedPreKey(2, UUIDKindPNI, pniIdentityKeyPair) - aciPQLastResortPreKeys := GenerateKyberPreKeys(1, 1, UUIDKindACI, aciIdentityKeyPair) - pniPQLastResortPreKeys := GenerateKyberPreKeys(1, 1, UUIDKindPNI, pniIdentityKeyPair) + aciSignedPreKey := GenerateSignedPreKey(1, types.UUIDKindACI, aciIdentityKeyPair) + pniSignedPreKey := GenerateSignedPreKey(2, types.UUIDKindPNI, pniIdentityKeyPair) + aciPQLastResortPreKeys := GenerateKyberPreKeys(1, 1, types.UUIDKindACI, aciIdentityKeyPair) + pniPQLastResortPreKeys := GenerateKyberPreKeys(1, 1, types.UUIDKindPNI, pniIdentityKeyPair) aciPQLastResortPreKey := aciPQLastResortPreKeys[0] pniPQLastResortPreKey := pniPQLastResortPreKeys[0] deviceResponse, err := confirmDevice( @@ -152,7 +154,7 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore DeviceStore, d deviceId = deviceResponse.DeviceID } - data := &DeviceData{ + data := &store.DeviceData{ ACIIdentityKeyPair: aciIdentityKeyPair, PNIIdentityKeyPair: pniIdentityKeyPair, RegistrationID: registrationId, @@ -183,8 +185,8 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore DeviceStore, d device.ClearDeviceKeys(ctx) // Store identity keys? - address, err := libsignalgo.NewUUIDAddress(device.Data.ACI, uint(device.Data.DeviceID)) - _, err = device.IdentityStore.SaveIdentityKey(ctx, address, device.Data.ACIIdentityKeyPair.GetIdentityKey()) + address, err := libsignalgo.NewUUIDAddress(device.ACI, uint(device.DeviceID)) + _, err = device.IdentityStore.SaveIdentityKey(ctx, address, device.ACIIdentityKeyPair.GetIdentityKey()) if err != nil { zlog.Err(err).Msg("error saving identity key") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} @@ -192,10 +194,10 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore DeviceStore, d } // Store signed prekeys (now that we have a device) - StoreSignedPreKey(ctx, device, aciSignedPreKey, UUIDKindACI) - StoreSignedPreKey(ctx, device, pniSignedPreKey, UUIDKindPNI) - StoreKyberLastResortPreKey(ctx, device, aciPQLastResortPreKey, UUIDKindACI) - StoreKyberLastResortPreKey(ctx, device, pniPQLastResortPreKey, UUIDKindPNI) + device.PreKeyStoreExtras.SaveSignedPreKey(ctx, types.UUIDKindACI, aciSignedPreKey, true) + device.PreKeyStoreExtras.SaveSignedPreKey(ctx, types.UUIDKindPNI, pniSignedPreKey, true) + device.PreKeyStoreExtras.SaveKyberPreKey(ctx, types.UUIDKindACI, aciPQLastResortPreKey, true) + device.PreKeyStoreExtras.SaveKyberPreKey(ctx, types.UUIDKindPNI, pniPQLastResortPreKey, true) // Store our profile key err = device.ProfileKeyStore.StoreProfileKey(ctx, data.ACI, profileKey) @@ -209,8 +211,10 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore DeviceStore, d c <- ProvisioningResponse{State: StateProvisioningDataReceived, ProvisioningData: data} // Generate, store, and register prekeys - err = GenerateAndRegisterPreKeys(ctx, device, UUIDKindACI) - err = GenerateAndRegisterPreKeys(ctx, device, UUIDKindPNI) + // TODO hacky client construction + cli := &Client{Store: device} + err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindACI) + err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindPNI) if err != nil { zlog.Err(err).Msg("error generating and registering prekeys") diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 4b5430a..80b3d14 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -66,16 +66,16 @@ type SignalConnectionStatus struct { Err error } -func StartReceiveLoops(ctx context.Context, d *Device) (chan SignalConnectionStatus, error) { +func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnectionStatus, error) { ctx, cancel := context.WithCancel(ctx) - d.Connection.WSCancel = cancel - authChan, err := d.Connection.ConnectAuthedWS(ctx, d.Data, d.incomingRequestHandler) + cli.WSCancel = cancel + authChan, err := cli.ConnectAuthedWS(ctx, cli.incomingRequestHandler) if err != nil { cancel() return nil, err } zlog.Info().Msg("Authed websocket connecting") - unauthChan, err := d.Connection.ConnectUnauthedWS(ctx, d.Data) + unauthChan, err := cli.ConnectUnauthedWS(ctx) if err != nil { cancel() return nil, err @@ -92,10 +92,6 @@ func StartReceiveLoops(ctx context.Context, d *Device) (chan SignalConnectionSta var currentStatus, lastAuthStatus, lastUnauthStatus web.SignalWebsocketConnectionStatus var lastSentStatus SignalConnectionStatus for { - if d == nil { - zlog.Info().Msg("Device is nil, exiting websocket status loop") - return - } select { case <-ctx.Done(): zlog.Info().Msg("Context done, exiting websocket status loop") @@ -187,7 +183,7 @@ func StartReceiveLoops(ctx context.Context, d *Device) (chan SignalConnectionSta case <-initialConnectChan: zlog.Info().Msg("Both websockets connected, sending contacts sync request") // TODO hacky - SendContactSyncRequest(ctx, d) + cli.SendContactSyncRequest(ctx) return } } @@ -196,15 +192,15 @@ func StartReceiveLoops(ctx context.Context, d *Device) (chan SignalConnectionSta return statusChan, nil } -func StopReceiveLoops(d *Device) error { +func (cli *Client) StopReceiveLoops() error { defer func() { - d.Connection.AuthedWS = nil - d.Connection.UnauthedWS = nil + cli.AuthedWS = nil + cli.UnauthedWS = nil }() - authErr := d.Connection.AuthedWS.Close() - unauthErr := d.Connection.UnauthedWS.Close() - if d.Connection.WSCancel != nil { - d.Connection.WSCancel() + authErr := cli.AuthedWS.Close() + unauthErr := cli.UnauthedWS.Close() + if cli.WSCancel != nil { + cli.WSCancel() } if authErr != nil { return authErr @@ -215,13 +211,31 @@ func StopReceiveLoops(d *Device) error { return nil } +func (cli *Client) ClearKeysAndDisconnect(ctx context.Context) error { + // Essentially logout, clearing sessions and keys, and disconnecting websockets + // but don't clear ACI UUID or profile keys or contacts, or anything else that + // we can reuse if we reassociate with the same Signal account. + // To fully "logout" delete the device from the database. + clearErr := cli.Store.ClearDeviceKeys(ctx) + clearErr2 := cli.Store.ClearPassword(ctx) + stopLoopErr := cli.StopReceiveLoops() + + if clearErr != nil { + return clearErr + } + if clearErr2 != nil { + return clearErr2 + } + return stopLoopErr +} + // If a bridge can't decrypt prekeys, it's probably because the prekeys are broken so force re-registration -func checkDecryptionErrorAndDisconnect(err error, device *Device) { +func (cli *Client) checkDecryptionErrorAndDisconnect(err error) { if err != nil { if strings.Contains(err.Error(), "30: invalid PreKey message: decryption failed") || strings.Contains(err.Error(), "70: invalid signed prekey identifier") { zlog.Warn().Msg("Failed decrypting a PreKey message, probably our prekeys are broken, force re-registration") - disconnectErr := device.ClearKeysAndDisconnect(context.TODO()) + disconnectErr := cli.ClearKeysAndDisconnect(context.TODO()) if disconnectErr != nil { zlog.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") } @@ -229,9 +243,9 @@ func checkDecryptionErrorAndDisconnect(err error, device *Device) { } } -func (d *Device) incomingRequestHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { +func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { if *req.Verb == http.MethodPut && *req.Path == "/api/v1/message" { - return d.incomingAPIMessageHandler(ctx, req) + return cli.incomingAPIMessageHandler(ctx, req) } else if *req.Verb == http.MethodPut && *req.Path == "/api/v1/queue/empty" { zlog.Trace().Msgf("Received queue empty. verb: %v, path: %v", *req.Verb, *req.Path) } else { @@ -242,7 +256,7 @@ func (d *Device) incomingRequestHandler(ctx context.Context, req *signalpb.WebSo }, nil } -func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { +func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { responseCode := 200 envelope := &signalpb.Envelope{} err := proto.Unmarshal(req.Body, envelope) @@ -258,7 +272,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We usmc, err := libsignalgo.SealedSenderDecryptToUSMC( ctx, envelope.GetContent(), - d.IdentityStore, + cli.Store.IdentityStore, ) if err != nil || usmc == nil { if err == nil { @@ -298,7 +312,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We } zlog.Trace().Msgf("SealedSender senderUUID: %v, senderDeviceID: %v", senderUUID, senderDeviceID) - d.UpdateContactE164(senderUUID, senderE164) + cli.UpdateContactE164(senderUUID, senderE164) switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: @@ -307,7 +321,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We ctx, usmcContents, senderAddress, - d.SenderKeyStore, + cli.Store.SenderKeyStore, ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { @@ -334,7 +348,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We case libsignalgo.CiphertextMessageTypePreKey: zlog.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") - result, err = prekeyDecrypt(ctx, senderAddress, usmcContents, d) + result, err = cli.prekeyDecrypt(ctx, senderAddress, usmcContents) if err != nil { zlog.Err(err).Msg("prekeyDecrypt error") } @@ -349,8 +363,8 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We ctx, message, senderAddress, - d.SessionStore, - d.IdentityStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, ) if err != nil { zlog.Err(err).Msg("Sealed sender Whisper Decryption error") @@ -407,13 +421,13 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We if result == nil || responseCode != 200 { zlog.Debug().Msg("Didn't decrypt with specific methods, trying sealedSenderDecrypt") var err error - result, err = sealedSenderDecrypt(ctx, envelope, d) + result, err = cli.sealedSenderDecrypt(ctx, envelope) if err != nil { if strings.Contains(err.Error(), "self send of a sealed sender message") { zlog.Debug().Msg("Message sent by us, ignoring") } else { zlog.Err(err).Msg("sealedSenderDecrypt error") - checkDecryptionErrorAndDisconnect(err, d) + cli.checkDecryptionErrorAndDisconnect(err) } } else { zlog.Trace().Msgf("SealedSender decrypt result - address: %v, content: %v", result.SenderAddress, result.Content) @@ -429,10 +443,10 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We if err != nil { return nil, fmt.Errorf("NewAddress error: %v", err) } - result, err = prekeyDecrypt(ctx, sender, envelope.Content, d) + result, err = cli.prekeyDecrypt(ctx, sender, envelope.Content) if err != nil { zlog.Err(err).Msg("prekeyDecrypt error") - checkDecryptionErrorAndDisconnect(err, d) + cli.checkDecryptionErrorAndDisconnect(err) } else { zlog.Trace().Msgf("prekey decrypt result - address: %v, data: %v", result.SenderAddress, result.Content) } @@ -457,8 +471,8 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We ctx, message, senderAddress, - d.SessionStore, - d.IdentityStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { @@ -522,7 +536,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We ctx, skdm, result.SenderAddress, - d.SenderKeyStore, + cli.Store.SenderKeyStore, ) if err != nil { zlog.Err(err).Msg("ProcessSenderKeyDistributionMessage error") @@ -553,9 +567,9 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We zlog.Warn().Msg("sync message sent destination is nil") } else if content.SyncMessage.Sent.Message != nil { // TODO handle expiration start ts, and maybe the sync message ts? - incomingDataMessage(ctx, d, content.SyncMessage.Sent.Message, d.Data.ACI, destinationUUID) + cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, destinationUUID) } else if content.SyncMessage.Sent.EditMessage != nil { - incomingEditMessage(ctx, d, content.SyncMessage.Sent.EditMessage, d.Data.ACI, destinationUUID) + cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, destinationUUID) } } if content.SyncMessage.Contacts != nil { @@ -577,13 +591,13 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We zlog.Info().Msgf("Signal Contact UUID is nil, skipping: %v", signalContact) continue } - contact, contactAvatar, err := StoreContactDetailsAsContact(d, signalContact, &avatars[i]) + contact, contactAvatar, err := cli.StoreContactDetailsAsContact(signalContact, &avatars[i]) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error") continue } // Model each contact as an incoming contact change message - d.Connection.handleEvent(&events.ContactChange{ + cli.handleEvent(&events.ContactChange{ Contact: contact, Avatar: contactAvatar, }) @@ -591,7 +605,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We } } if content.SyncMessage.Read != nil { - d.Connection.handleEvent(&events.ReadSelf{ + cli.handleEvent(&events.ReadSelf{ Messages: content.SyncMessage.GetRead(), }) } @@ -600,13 +614,13 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We var sendDeliveryReceipt bool if content.DataMessage != nil { - sendDeliveryReceipt = incomingDataMessage(ctx, d, content.DataMessage, theirUUID, theirUUID) + sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirUUID, theirUUID) } else if content.EditMessage != nil { - sendDeliveryReceipt = incomingEditMessage(ctx, d, content.EditMessage, theirUUID, theirUUID) + sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirUUID, theirUUID) } if sendDeliveryReceipt { // TODO send delivery receipts after actually bridging instead of here - err = sendDeliveryReceipts(ctx, d, []uint64{content.DataMessage.GetTimestamp()}, theirUUID) + err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirUUID) if err != nil { zlog.Err(err).Msg("sendDeliveryReceipts error") } @@ -618,7 +632,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We gidBytes := content.TypingMessage.GetGroupId() groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) } - d.Connection.handleEvent(&events.ChatEvent{ + cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ Sender: theirUUID, ChatID: groupOrUserID(groupID, theirUUID), @@ -629,7 +643,7 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We // DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { - d.Connection.handleEvent(&events.Call{ + cli.handleEvent(&events.Call{ Info: events.MessageInfo{ Sender: theirUUID, ChatID: theirUUID.String(), @@ -640,13 +654,13 @@ func (d *Device) incomingAPIMessageHandler(ctx context.Context, req *signalpb.We // Read and delivery receipts if content.ReceiptMessage != nil { - if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirUUID == d.Data.ACI { + if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirUUID == cli.Store.ACI { // Ignore delivery receipts from other own devices return &web.SimpleResponse{ Status: responseCode, }, nil } - d.Connection.handleEvent(&events.Receipt{ + cli.handleEvent(&events.Receipt{ Sender: theirUUID, Content: content.ReceiptMessage, }) @@ -714,7 +728,7 @@ func groupOrUserID(groupID types.GroupIdentifier, userID uuid.UUID) string { return string(groupID) } -func incomingEditMessage(ctx context.Context, device *Device, editMessage *signalpb.EditMessage, messageSender, chatRecipient uuid.UUID) bool { +func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSender, chatRecipient uuid.UUID) bool { // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier var groupRevision int @@ -723,14 +737,14 @@ func incomingEditMessage(ctx context.Context, device *Device, editMessage *signa groupMasterKeyBytes := editMessage.GetDataMessage().GetGroupV2().GetMasterKey() masterKey := masterKeyFromBytes(libsignalgo.GroupMasterKey(groupMasterKeyBytes)) var err error - groupID, err = StoreMasterKey(ctx, device, masterKey) + groupID, err = cli.StoreMasterKey(ctx, masterKey) if err != nil { zlog.Err(err).Msg("StoreMasterKey error") return false } groupRevision = int(editMessage.GetDataMessage().GetGroupV2().GetRevision()) } - device.Connection.handleEvent(&events.ChatEvent{ + cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ Sender: messageSender, ChatID: groupOrUserID(groupID, chatRecipient), @@ -741,11 +755,11 @@ func incomingEditMessage(ctx context.Context, device *Device, editMessage *signa return true } -func incomingDataMessage(ctx context.Context, device *Device, dataMessage *signalpb.DataMessage, messageSender, chatRecipient uuid.UUID) bool { +func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSender, chatRecipient uuid.UUID) bool { // If there's a profile key, save it if dataMessage.ProfileKey != nil { profileKey := libsignalgo.ProfileKey(dataMessage.ProfileKey) - err := device.ProfileKeyStore.StoreProfileKey(ctx, messageSender, profileKey) + err := cli.Store.ProfileKeyStore.StoreProfileKey(ctx, messageSender, profileKey) if err != nil { zlog.Err(err).Msg("StoreProfileKey error") return false @@ -760,7 +774,7 @@ func incomingDataMessage(ctx context.Context, device *Device, dataMessage *signa groupMasterKeyBytes := dataMessage.GetGroupV2().GetMasterKey() masterKey := masterKeyFromBytes(libsignalgo.GroupMasterKey(groupMasterKeyBytes)) var err error - groupID, err = StoreMasterKey(ctx, device, masterKey) + groupID, err = cli.StoreMasterKey(ctx, masterKey) if err != nil { zlog.Err(err).Msg("StoreMasterKey error") return false @@ -771,21 +785,21 @@ func incomingDataMessage(ctx context.Context, device *Device, dataMessage *signa if dataMessage.GetGroupV2().GroupChange != nil { // TODO: don't parse the change for now, just invalidate our cache zlog.Debug().Msgf("Invalidating group %v due to change: %v", groupID, dataMessage.GetGroupV2().GroupChange) - InvalidateGroupCache(device, groupID) + cli.InvalidateGroupCache(groupID) groupHasChanged = true } else if dataMessage.GetGroupV2().GetRevision() > 0 { // Compare revision, and if it's newer, invalidate our cache - ourGroup, err := RetrieveGroupByID(ctx, device, groupID) + ourGroup, err := cli.RetrieveGroupByID(ctx, groupID) if err != nil { zlog.Err(err).Msg("RetrieveGroupByID error") } else if dataMessage.GetGroupV2().GetRevision() > ourGroup.Revision { zlog.Debug().Msgf("Invalidating group %v due to new revision %v > our revision: %v", groupID, dataMessage.GetGroupV2().GetRevision(), ourGroup.Revision) - InvalidateGroupCache(device, groupID) + cli.InvalidateGroupCache(groupID) groupHasChanged = true } } if groupHasChanged { - device.Connection.handleEvent(&events.GroupChange{ + cli.handleEvent(&events.GroupChange{ SenderID: messageSender, Timestamp: dataMessage.GetTimestamp(), GroupID: groupID, @@ -801,14 +815,14 @@ func incomingDataMessage(ctx context.Context, device *Device, dataMessage *signa } // Hacky special case for group calls to cache the state if dataMessage.GroupCallUpdate != nil { - isRinging := device.UpdateActiveCalls(groupID, *dataMessage.GroupCallUpdate.EraId) - device.Connection.handleEvent(&events.Call{ + isRinging := cli.UpdateActiveCalls(groupID, *dataMessage.GroupCallUpdate.EraId) + cli.handleEvent(&events.Call{ Info: evtInfo, Timestamp: dataMessage.GetTimestamp(), IsRinging: isRinging, }) } else { - device.Connection.handleEvent(&events.ChatEvent{ + cli.handleEvent(&events.ChatEvent{ Info: evtInfo, Event: dataMessage, }) @@ -817,11 +831,11 @@ func incomingDataMessage(ctx context.Context, device *Device, dataMessage *signa return true } -func sendDeliveryReceipts(ctx context.Context, device *Device, deliveredTimestamps []uint64, senderUUID uuid.UUID) error { +func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps []uint64, senderUUID uuid.UUID) error { // Send delivery receipts if len(deliveredTimestamps) > 0 { receipt := DeliveredReceiptMessageForTimestamps(deliveredTimestamps) - result := SendMessage(ctx, device, senderUUID, receipt) + result := cli.SendMessage(ctx, senderUUID, receipt) if !result.WasSuccessful { zlog.Error().Msgf("Failed to send delivery receipts: %v", result) } @@ -851,11 +865,11 @@ func serverTrustRootKey() *libsignalgo.PublicKey { return serverTrustRootKey } -func sealedSenderDecrypt(ctx context.Context, envelope *signalpb.Envelope, device *Device) (*DecryptionResult, error) { +func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.Envelope) (*DecryptionResult, error) { localAddress := libsignalgo.NewSealedSenderAddress( - device.Data.Number, - device.Data.ACI, - uint32(device.Data.DeviceID), + cli.Store.Number, + cli.Store.ACI, + uint32(cli.Store.DeviceID), ) timestamp := time.Unix(0, int64(*envelope.Timestamp)) result, err := libsignalgo.SealedSenderDecrypt( @@ -864,10 +878,10 @@ func sealedSenderDecrypt(ctx context.Context, envelope *signalpb.Envelope, devic localAddress, serverTrustRootKey(), timestamp, - device.SessionStore, - device.IdentityStore, - device.PreKeyStore, - device.SignedPreKeyStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, + cli.Store.PreKeyStore, + cli.Store.SignedPreKeyStore, ) if err != nil { @@ -901,7 +915,7 @@ func sealedSenderDecrypt(ctx context.Context, envelope *signalpb.Envelope, devic return DecryptionResult, nil } -func prekeyDecrypt(ctx context.Context, sender *libsignalgo.Address, encryptedContent []byte, device *Device) (*DecryptionResult, error) { +func (cli *Client) prekeyDecrypt(ctx context.Context, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) if err != nil { err = fmt.Errorf("DeserializePreKeyMessage error: %v", err) @@ -916,11 +930,11 @@ func prekeyDecrypt(ctx context.Context, sender *libsignalgo.Address, encryptedCo ctx, preKeyMessage, sender, - device.SessionStore, - device.IdentityStore, - device.PreKeyStore, - device.SignedPreKeyStore, - device.KyberPreKeyStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, + cli.Store.PreKeyStore, + cli.Store.SignedPreKeyStore, + cli.Store.KyberPreKeyStore, ) if err != nil { err = fmt.Errorf("DecryptPreKey error: %v", err) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 3d5114a..0b113cc 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -40,16 +40,16 @@ import ( // Sending -func senderCertificate(ctx context.Context, d *Device) (*libsignalgo.SenderCertificate, error) { - if d.Connection.SenderCertificate != nil { - expiry, err := d.Connection.SenderCertificate.GetExpiration() +func (cli *Client) senderCertificate(ctx context.Context) (*libsignalgo.SenderCertificate, error) { + if cli.SenderCertificate != nil { + expiry, err := cli.SenderCertificate.GetExpiration() if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to check sender certificate expiry") } else if time.Until(expiry) < 1*exfmt.Day { zerolog.Ctx(ctx).Debug().Msg("Sender certificate expired, fetching new one") - d.Connection.SenderCertificate = nil + cli.SenderCertificate = nil } else { - return d.Connection.SenderCertificate, nil + return cli.SenderCertificate, nil } } @@ -58,7 +58,7 @@ func senderCertificate(ctx context.Context, d *Device) (*libsignalgo.SenderCerti } var r response - username, password := d.Data.BasicAuthCreds() + username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{Username: &username, Password: &password} resp, err := web.SendHTTPRequest(http.MethodGet, "/v1/certificate/delivery", opts) if err != nil { @@ -70,7 +70,7 @@ func senderCertificate(ctx context.Context, d *Device) (*libsignalgo.SenderCerti } cert, err := libsignalgo.DeserializeSenderCertificate(r.Certificate) - d.Connection.SenderCertificate = cert + cli.SenderCertificate = cert return cert, err } @@ -143,8 +143,8 @@ func checkForErrorWithSessions(err error, addresses []*libsignalgo.Address, sess return nil } -func howManyOtherDevicesDoWeHave(ctx context.Context, d *Device) int { - addresses, _, err := d.SessionStoreExtras.AllSessionsForUUID(ctx, d.Data.ACI) +func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { + addresses, _, err := cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, cli.Store.ACI) if err != nil { return 0 } @@ -156,25 +156,25 @@ func howManyOtherDevicesDoWeHave(ctx context.Context, d *Device) int { zlog.Err(err).Msg("Error getting deviceID from address") continue } - if deviceID != uint(d.Data.DeviceID) { + if deviceID != uint(cli.Store.DeviceID) { otherDevices++ } } return otherDevices } -func buildMessagesToSend(ctx context.Context, d *Device, recipientUUID uuid.UUID, content *signalpb.Content, unauthenticated bool) ([]MyMessage, error) { +func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.UUID, content *signalpb.Content, unauthenticated bool) ([]MyMessage, error) { // We need to prevent multiple encryption operations from happening at once, or else ratchets can race - d.Connection.EncryptionMutex.Lock() - defer d.Connection.EncryptionMutex.Unlock() + cli.encryptionLock.Lock() + defer cli.encryptionLock.Unlock() messages := []MyMessage{} - addresses, sessionRecords, err := d.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) + addresses, sessionRecords, err := cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) if err == nil && (len(addresses) == 0 || len(sessionRecords) == 0) { // No sessions, make one with prekey - FetchAndProcessPreKey(ctx, d, recipientUUID, -1) - addresses, sessionRecords, err = d.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) + cli.FetchAndProcessPreKey(ctx, recipientUUID, -1) + addresses, sessionRecords, err = cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) } err = checkForErrorWithSessions(err, addresses, sessionRecords) if err != nil { @@ -188,7 +188,7 @@ func buildMessagesToSend(ctx context.Context, d *Device, recipientUUID uuid.UUID } // Don't send to this device that we are sending from - if recipientUUID == d.Data.ACI && recipientDeviceID == uint(d.Data.DeviceID) { + if recipientUUID == cli.Store.ACI && recipientDeviceID == uint(cli.Store.DeviceID) { zlog.Debug().Msgf("Not sending to the device I'm sending from (%v:%v)", recipientUUID, recipientDeviceID) continue } @@ -204,9 +204,9 @@ func buildMessagesToSend(ctx context.Context, d *Device, recipientUUID uuid.UUID var envelopeType int var encryptedPayload []byte if unauthenticated { - envelopeType, encryptedPayload, err = buildSSMessageToSend(ctx, d, recipientAddress, paddedMessage) + envelopeType, encryptedPayload, err = cli.buildSSMessageToSend(ctx, recipientAddress, paddedMessage) } else { - envelopeType, encryptedPayload, err = buildAuthedMessageToSend(ctx, d, recipientAddress, paddedMessage) + envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, recipientAddress, paddedMessage) } destinationRegistrationID, err := sessionRecord.GetRemoteRegistrationID() @@ -225,13 +225,13 @@ func buildMessagesToSend(ctx context.Context, d *Device, recipientUUID uuid.UUID return messages, nil } -func buildAuthedMessageToSend(ctx context.Context, d *Device, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { +func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { cipherTextMessage, err := libsignalgo.Encrypt( ctx, []byte(paddedMessage), recipientAddress, - d.SessionStore, - d.IdentityStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, ) encryptedPayload, err = cipherTextMessage.Serialize() if err != nil { @@ -250,8 +250,8 @@ func buildAuthedMessageToSend(ctx context.Context, d *Device, recipientAddress * return envelopeType, encryptedPayload, nil } -func buildSSMessageToSend(ctx context.Context, d *Device, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { - cert, err := senderCertificate(ctx, d) +func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { + cert, err := cli.senderCertificate(ctx) if err != nil { return 0, nil, err } @@ -260,8 +260,8 @@ func buildSSMessageToSend(ctx context.Context, d *Device, recipientAddress *libs []byte(paddedMessage), recipientAddress, cert, - d.SessionStore, - d.IdentityStore, + cli.Store.SessionStore, + cli.Store.IdentityStore, ) envelopeType = int(signalpb.Envelope_UNIDENTIFIED_SENDER) @@ -393,9 +393,9 @@ func syncMessageFromReadReceiptMessage(receiptMessage *signalpb.ReceiptMessage, } } -func SendContactSyncRequest(ctx context.Context, d *Device) error { +func (cli *Client) SendContactSyncRequest(ctx context.Context) error { currentUnixTime := time.Now().Unix() - lastRequestTime := d.Connection.LastContactRequestTime + lastRequestTime := cli.LastContactRequestTime // If we've requested in the last minute, don't request again if lastRequestTime != nil && currentUnixTime-*lastRequestTime < 60 { zlog.Warn().Msgf("Not sending contact sync request, already sent %v seconds ago", currentUnixTime-*lastRequestTime) @@ -403,12 +403,12 @@ func SendContactSyncRequest(ctx context.Context, d *Device) error { } groupRequest := syncMessageForContactRequest() - _, err := sendContent(ctx, d, d.Data.ACI, uint64(currentUnixTime), groupRequest, 0) + _, err := cli.sendContent(ctx, cli.Store.ACI, uint64(currentUnixTime), groupRequest, 0) if err != nil { zlog.Err(err).Msg("Failed to send contact sync request message to myself (%v)") return err } - d.Connection.LastContactRequestTime = ¤tUnixTime + cli.LastContactRequestTime = ¤tUnixTime return nil } @@ -483,8 +483,8 @@ func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { } } -func SendGroupMessage(ctx context.Context, device *Device, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { - group, err := RetrieveGroupByID(ctx, device, gid) +func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { + group, err := cli.RetrieveGroupByID(ctx, gid) if err != nil { return nil, err } @@ -504,11 +504,11 @@ func SendGroupMessage(ctx context.Context, device *Device, gid types.GroupIdenti FailedToSendTo: []FailedSendResult{}, } for _, member := range group.Members { - if member.UserID == device.Data.ACI { + if member.UserID == cli.Store.ACI { // Don't send normal DataMessages to ourselves continue } - sentUnidentified, err := sendContent(ctx, device, member.UserID, messageTimestamp, content, 0) + sentUnidentified, err := cli.sendContent(ctx, member.UserID, messageTimestamp, content, 0) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ RecipientUUID: member.UserID, @@ -525,14 +525,14 @@ func SendGroupMessage(ctx context.Context, device *Device, gid types.GroupIdenti } // No need to send to ourselves if we don't have any other devices - if howManyOtherDevicesDoWeHave(ctx, device) > 0 { + if cli.howManyOtherDevicesDoWeHave(ctx) > 0 { var syncContent *signalpb.Content if content.GetDataMessage() != nil { syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo) } else if content.GetEditMessage() != nil { syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) } - _, selfSendErr := sendContent(ctx, device, device.Data.ACI, messageTimestamp, syncContent, 0) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0) if selfSendErr != nil { zlog.Err(selfSendErr).Msg("Failed to send sync message to myself (%v)") } @@ -549,7 +549,7 @@ func SendGroupMessage(ctx context.Context, device *Device, gid types.GroupIdenti return result, nil } -func SendMessage(ctx context.Context, device *Device, recipientID uuid.UUID, content *signalpb.Content) SendMessageResult { +func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, content *signalpb.Content) SendMessageResult { // Assemble the content to send var messageTimestamp uint64 if content.GetDataMessage() != nil { @@ -561,7 +561,7 @@ func SendMessage(ctx context.Context, device *Device, recipientID uuid.UUID, con } // Send to the recipient - sentUnidentified, err := sendContent(ctx, device, recipientID, messageTimestamp, content, 0) + sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0) if err != nil { return SendMessageResult{ WasSuccessful: false, @@ -585,7 +585,7 @@ func SendMessage(ctx context.Context, device *Device, recipientID uuid.UUID, con //FetchAndProcessPreKey(ctx, device, device.Data.ACI, -1) // If we have other devices, send Sync messages to them too - if howManyOtherDevicesDoWeHave(ctx, device) > 0 { + if cli.howManyOtherDevicesDoWeHave(ctx) > 0 { var syncContent *signalpb.Content if content.GetDataMessage() != nil { syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result.SuccessfulSendResult) @@ -595,7 +595,7 @@ func SendMessage(ctx context.Context, device *Device, recipientID uuid.UUID, con syncContent = syncMessageFromReadReceiptMessage(content.ReceiptMessage, recipientID) } if syncContent != nil { - _, selfSendErr := sendContent(ctx, device, device.Data.ACI, messageTimestamp, syncContent, 0) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0) if selfSendErr != nil { zlog.Err(selfSendErr).Msg("Failed to send sync message to myself") } @@ -608,9 +608,8 @@ func currentMessageTimestamp() uint64 { return uint64(time.Now().UnixMilli()) } -func sendContent( +func (cli *Client) sendContent( ctx context.Context, - d *Device, recipientUUID uuid.UUID, messageTimestamp uint64, content *signalpb.Content, @@ -621,7 +620,7 @@ func sendContent( // If it's a data message, add our profile key if content.DataMessage != nil { - profileKey, err := ProfileKeyForSignalID(ctx, d, d.Data.ACI) + profileKey, err := cli.ProfileKeyForSignalID(ctx, cli.Store.ACI) if err != nil { zlog.Err(err).Msg("Error getting profile key, not adding to outgoing message") } else { @@ -637,15 +636,15 @@ func sendContent( useUnidentifiedSender := true // Don't use unauthed websocket to send a payload to my own other devices - if recipientUUID == d.Data.ACI { + if recipientUUID == cli.Store.ACI { useUnidentifiedSender = false } - profileKey, err := ProfileKeyForSignalID(ctx, d, recipientUUID) + profileKey, err := cli.ProfileKeyForSignalID(ctx, recipientUUID) if err != nil || profileKey == nil { zlog.Err(err).Msg("Error getting profile key") useUnidentifiedSender = false // Try to self heal by requesting contact sync, though this is slow and not guaranteed to help - SendContactSyncRequest(ctx, d) + cli.SendContactSyncRequest(ctx) } var accessKey *libsignalgo.AccessKey if profileKey != nil { @@ -664,7 +663,7 @@ func sendContent( // Encrypt messages var messages []MyMessage - messages, err = buildMessagesToSend(ctx, d, recipientUUID, content, useUnidentifiedSender) + messages, err = cli.buildMessagesToSend(ctx, recipientUUID, content, useUnidentifiedSender) if err != nil { zlog.Err(err).Msg("Error building messages to send") return false, err @@ -688,10 +687,10 @@ func sendContent( zlog.Trace().Msgf("Sending message to %v over unidentified WS", recipientUUID) base64AccessKey := base64.StdEncoding.EncodeToString(accessKey[:]) request.Headers = append(request.Headers, "unidentified-access-key:"+base64AccessKey) - response, err = d.Connection.UnauthedWS.SendRequest(ctx, request) + response, err = cli.UnauthedWS.SendRequest(ctx, request) } else { zlog.Trace().Msgf("Sending message to %v over authed WS", recipientUUID) - response, err = d.Connection.AuthedWS.SendRequest(ctx, request) + response, err = cli.AuthedWS.SendRequest(ctx, request) } sentUnidentified = useUnidentifiedSender if err != nil { @@ -713,17 +712,17 @@ func sendContent( if needToRetry { var err error if *response.Status == 409 { - err = handle409(ctx, d, recipientUUID, response) + err = cli.handle409(ctx, recipientUUID, response) } else if *response.Status == 410 { - err = handle410(ctx, d, recipientUUID, response) + err = cli.handle410(ctx, recipientUUID, response) } else if *response.Status == 428 { - err = handle428(ctx, d, recipientUUID, response) + err = cli.handle428(ctx, recipientUUID, response) } if err != nil { return false, err } // Try to send again (**RECURSIVELY**) - sentUnidentified, err = sendContent(ctx, d, recipientUUID, messageTimestamp, content, retryCount+1) + sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1) if err != nil { zlog.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err @@ -738,7 +737,7 @@ func sendContent( } // A 409 means our device list was out of date, so we will fix it up -func handle409(ctx context.Context, device *Device, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { +func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { // Decode json body var body map[string]interface{} err := json.Unmarshal(response.Body, &body) @@ -752,7 +751,7 @@ func handle409(ctx context.Context, device *Device, recipientUUID uuid.UUID, res zlog.Debug().Msgf("missing devices found in 409 response: %v", missingDevices) // TODO: establish session with missing devices for _, missingDevice := range missingDevices { - FetchAndProcessPreKey(ctx, device, recipientUUID, int(missingDevice.(float64))) + cli.FetchAndProcessPreKey(ctx, recipientUUID, int(missingDevice.(float64))) } } if body["extraDevices"] != nil { @@ -768,7 +767,7 @@ func handle409(ctx context.Context, device *Device, recipientUUID uuid.UUID, res zlog.Err(err).Msg("NewAddress error") return err } - err = device.SessionStoreExtras.RemoveSession(ctx, recipient) + err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipient) if err != nil { zlog.Err(err).Msg("RemoveSession error") return err @@ -779,7 +778,7 @@ func handle409(ctx context.Context, device *Device, recipientUUID uuid.UUID, res } // A 410 means we have a stale device, so get rid of it -func handle410(ctx context.Context, device *Device, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { +func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { // Decode json body var body map[string]interface{} err := json.Unmarshal(response.Body, &body) @@ -796,12 +795,12 @@ func handle410(ctx context.Context, device *Device, recipientUUID uuid.UUID, res recipientUUID, uint(staleDevice.(float64)), ) - err = device.SessionStoreExtras.RemoveSession(ctx, recipient) + err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipient) if err != nil { zlog.Err(err).Msg("RemoveSession error") return err } - FetchAndProcessPreKey(ctx, device, recipientUUID, int(staleDevice.(float64))) + cli.FetchAndProcessPreKey(ctx, recipientUUID, int(staleDevice.(float64))) } } return err @@ -810,7 +809,7 @@ func handle410(ctx context.Context, device *Device, recipientUUID uuid.UUID, res // We got rate limited. // We ~~will~~ could try sending a "pushChallenge" response, but if that doesn't work we just gotta wait. // TODO: explore captcha response -func handle428(ctx context.Context, device *Device, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { +func (cli *Client) handle428(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { // Decode json body var body map[string]interface{} err := json.Unmarshal(response.Body, &body) diff --git a/pkg/signalmeow/contact_store.go b/pkg/signalmeow/store/contact_store.go similarity index 99% rename from pkg/signalmeow/contact_store.go rename to pkg/signalmeow/store/contact_store.go index 4f74d18..3b7eb73 100644 --- a/pkg/signalmeow/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" diff --git a/pkg/signalmeow/store.go b/pkg/signalmeow/store/container.go similarity index 55% rename from pkg/signalmeow/store.go rename to pkg/signalmeow/store/container.go index 13c680f..1ef0fd5 100644 --- a/pkg/signalmeow/store.go +++ b/pkg/signalmeow/store/container.go @@ -1,20 +1,4 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package signalmeow +package store import ( "context" @@ -23,10 +7,11 @@ import ( "fmt" "github.com/google/uuid" + "github.com/rs/zerolog" "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/upgrades" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store/upgrades" ) var _ DeviceStore = (*StoreContainer)(nil) @@ -41,32 +26,6 @@ type StoreContainer struct { db *dbutil.Database } -// Device is a wrapper for a signalmeow session, including device data, -// and interfaces for operating on the DB within the session. -type Device struct { - Data DeviceData - Connection DeviceConnection - - // NOTE: when adding a new store interface, make sure to assing it below - // (search for "innerStore" further down in this file) - - // libsignalgo store interfaces - PreKeyStore libsignalgo.PreKeyStore - SignedPreKeyStore libsignalgo.SignedPreKeyStore - KyberPreKeyStore libsignalgo.KyberPreKeyStore - IdentityStore libsignalgo.IdentityKeyStore - SessionStore libsignalgo.SessionStore - SenderKeyStore libsignalgo.SenderKeyStore - - // internal store interfaces - PreKeyStoreExtras PreKeyStoreExtras - SessionStoreExtras SessionStoreExtras - ProfileKeyStore ProfileKeyStore - GroupStore GroupStore - ContactStore ContactStore - DeviceStore DeviceStore -} - func NewStore(db *dbutil.Database, log dbutil.DatabaseLogger) *StoreContainer { return &StoreContainer{db: db.Child("signalmeow_version", upgrades.Table, log)} } @@ -87,27 +46,26 @@ func (c *StoreContainer) Upgrade() error { func (c *StoreContainer) scanDevice(row dbutil.Scannable) (*Device, error) { var device Device - deviceData := &device.Data var aciIdentityKeyPair, pniIdentityKeyPair []byte err := row.Scan( - &deviceData.ACI, &aciIdentityKeyPair, &deviceData.RegistrationID, - &deviceData.PNI, &pniIdentityKeyPair, &deviceData.PNIRegistrationID, - &deviceData.DeviceID, &deviceData.Number, &deviceData.Password, + &device.ACI, &aciIdentityKeyPair, &device.RegistrationID, + &device.PNI, &pniIdentityKeyPair, &device.PNIRegistrationID, + &device.DeviceID, &device.Number, &device.Password, ) if err != nil { return nil, fmt.Errorf("failed to scan session: %w", err) } - deviceData.ACIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(aciIdentityKeyPair) + device.ACIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(aciIdentityKeyPair) if err != nil { return nil, fmt.Errorf("failed to deserialize ACI identity key pair: %w", err) } - deviceData.PNIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(pniIdentityKeyPair) + device.PNIIdentityKeyPair, err = libsignalgo.DeserializeIdentityKeyPair(pniIdentityKeyPair) if err != nil { return nil, fmt.Errorf("failed to deserialize PNI identity key pair: %w", err) } - innerStore := newSQLStore(c, deviceData.ACI) + innerStore := newSQLStore(c, device.ACI) // Assign innerStore to all the interfaces device.PreKeyStore = innerStore device.PreKeyStoreExtras = innerStore @@ -183,9 +141,13 @@ func (c *StoreContainer) PutDevice(ctx context.Context, device *DeviceData) erro return ErrDeviceIDMustBeSet } aciIdentityKeyPair, err := device.ACIIdentityKeyPair.Serialize() + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("failed to serialize aci identity key pair") + return err + } pniIdentityKeyPair, err := device.PNIIdentityKeyPair.Serialize() if err != nil { - zlog.Err(err).Msg("failed to serialize identity key pair") + zerolog.Ctx(ctx).Err(err).Msg("failed to serialize pni identity key pair") return err } _, err = c.db.Conn(ctx).ExecContext(ctx, insertDeviceQuery, @@ -194,7 +156,7 @@ func (c *StoreContainer) PutDevice(ctx context.Context, device *DeviceData) erro device.DeviceID, device.Number, device.Password, ) if err != nil { - zlog.Err(err).Msg("failed to insert device") + zerolog.Ctx(ctx).Err(err).Msg("failed to insert device") } return err } @@ -207,58 +169,3 @@ func (c *StoreContainer) DeleteDevice(ctx context.Context, device *DeviceData) e _, err := c.db.Conn(ctx).ExecContext(ctx, deleteDeviceQuery, device.ACI) return err } - -func (d *Device) ClearDeviceKeys(ctx context.Context) error { - // We need to clear out keys associated with the Signal device that no longer has valid credentials - if d == nil { - zlog.Warn().Msg("ClearDeviceKeys called with nil device") - return nil - } - err := d.PreKeyStoreExtras.DeleteAllPreKeys(ctx) - err = d.SessionStoreExtras.RemoveAllSessions(ctx) - return err -} - -func (d *Device) IsDeviceLoggedIn() bool { - return d != nil && - d.Data.ACI != uuid.Nil && - d.Data.DeviceID != 0 && - d.Data.Password != "" -} - -func (d *Device) ClearKeysAndDisconnect(ctx context.Context) error { - // Essentially logout, clearing sessions and keys, and disconnecting websockets - // but don't clear ACI UUID or profile keys or contacts, or anything else that - // we can reuse if we reassociate with the same Signal account. - // To fully "logout" delete the device from the database. - clearErr := d.ClearDeviceKeys(ctx) - d.Data.Password = "" - saveDeviceErr := d.DeviceStore.PutDevice(ctx, &d.Data) - stopLoopErr := StopReceiveLoops(d) - - if clearErr != nil { - return clearErr - } - if saveDeviceErr != nil { - return saveDeviceErr - } - return stopLoopErr -} - -// -// Implementing "Store" interfaces -// - -// SQLStore is basically a StoreContainer with an ACI UUID attached to it, -// reperesenting a store for a single user -type SQLStore struct { - *StoreContainer - ACI uuid.UUID -} - -func newSQLStore(container *StoreContainer, aci uuid.UUID) *SQLStore { - return &SQLStore{ - StoreContainer: container, - ACI: aci, - } -} diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go new file mode 100644 index 0000000..fcc3b39 --- /dev/null +++ b/pkg/signalmeow/store/device.go @@ -0,0 +1,91 @@ +package store + +import ( + "context" + "fmt" + + "github.com/google/uuid" + "github.com/rs/zerolog" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" +) + +// SQLStore is basically a StoreContainer with an ACI UUID attached to it, +// reperesenting a store for a single user +type SQLStore struct { + *StoreContainer + ACI uuid.UUID +} + +func newSQLStore(container *StoreContainer, aci uuid.UUID) *SQLStore { + return &SQLStore{ + StoreContainer: container, + ACI: aci, + } +} + +type DeviceData struct { + ACIIdentityKeyPair *libsignalgo.IdentityKeyPair + PNIIdentityKeyPair *libsignalgo.IdentityKeyPair + RegistrationID int + PNIRegistrationID int + ACI uuid.UUID + PNI uuid.UUID + DeviceID int + Number string + Password string +} + +func (d *DeviceData) BasicAuthCreds() (string, string) { + username := fmt.Sprintf("%s.%d", d.ACI, d.DeviceID) + password := d.Password + return username, password +} + +// Device is a wrapper for a signalmeow session, including device data, +// and interfaces for operating on the DB within the session. +type Device struct { + DeviceData + + // NOTE: when adding a new store interface, make sure to assing it below + // (search for "innerStore" further down in this file) + + // libsignalgo store interfaces + PreKeyStore libsignalgo.PreKeyStore + SignedPreKeyStore libsignalgo.SignedPreKeyStore + KyberPreKeyStore libsignalgo.KyberPreKeyStore + IdentityStore libsignalgo.IdentityKeyStore + SessionStore libsignalgo.SessionStore + SenderKeyStore libsignalgo.SenderKeyStore + + // internal store interfaces + PreKeyStoreExtras PreKeyStoreExtras + SessionStoreExtras SessionStoreExtras + ProfileKeyStore ProfileKeyStore + GroupStore GroupStore + ContactStore ContactStore + DeviceStore DeviceStore +} + +func (d *Device) ClearDeviceKeys(ctx context.Context) error { + // We need to clear out keys associated with the Signal device that no longer has valid credentials + if d == nil { + zerolog.Ctx(ctx).Warn().Msg("ClearDeviceKeys called with nil device") + return nil + } + err := d.PreKeyStoreExtras.DeleteAllPreKeys(ctx) + err = d.SessionStoreExtras.RemoveAllSessions(ctx) + return err +} + +func (d *Device) IsDeviceLoggedIn() bool { + return d != nil && + d.ACI != uuid.Nil && + d.DeviceID != 0 && + d.Password != "" +} + +func (d *Device) ClearPassword(ctx context.Context) error { + d.Password = "" + return d.DeviceStore.PutDevice(ctx, &d.DeviceData) +} diff --git a/pkg/signalmeow/group_store.go b/pkg/signalmeow/store/group_store.go similarity index 87% rename from pkg/signalmeow/group_store.go rename to pkg/signalmeow/store/group_store.go index 9059796..b584296 100644 --- a/pkg/signalmeow/group_store.go +++ b/pkg/signalmeow/store/group_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" @@ -31,12 +31,12 @@ var _ GroupStore = (*SQLStore)(nil) type dbGroup struct { OurAciUuid string GroupIdentifier types.GroupIdentifier - GroupMasterKey SerializedGroupMasterKey + GroupMasterKey types.SerializedGroupMasterKey } type GroupStore interface { - MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (SerializedGroupMasterKey, error) - StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key SerializedGroupMasterKey) error + MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (types.SerializedGroupMasterKey, error) + StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key types.SerializedGroupMasterKey) error } const ( @@ -60,7 +60,7 @@ func scanGroup(row dbutil.Scannable) (*dbGroup, error) { return &g, nil } -func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (SerializedGroupMasterKey, error) { +func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (types.SerializedGroupMasterKey, error) { g, err := scanGroup(s.db.Conn(ctx).QueryRowContext(ctx, getGroupByIDQuery, s.ACI, groupID)) if g == nil { return "", err @@ -69,7 +69,7 @@ func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID typ } } -func (s *SQLStore) StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key SerializedGroupMasterKey) error { +func (s *SQLStore) StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key types.SerializedGroupMasterKey) error { _, err := s.db.Conn(ctx).ExecContext(ctx, upsertGroupMasterKeyQuery, s.ACI, groupID, key) return err } diff --git a/pkg/signalmeow/identity_store.go b/pkg/signalmeow/store/identity_store.go similarity index 98% rename from pkg/signalmeow/identity_store.go rename to pkg/signalmeow/store/identity_store.go index c2311f8..f017681 100644 --- a/pkg/signalmeow/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" @@ -52,7 +52,6 @@ func scanIdentityKeyPair(row dbutil.Scannable) (*libsignalgo.IdentityKeyPair, er var keyPair []byte err := row.Scan(&keyPair) if errors.Is(err, sql.ErrNoRows) { - zlog.Info().Msg("no identity key pair found") return nil, nil } else if err != nil { return nil, err @@ -64,7 +63,6 @@ func scanIdentityKey(row dbutil.Scannable) (*libsignalgo.IdentityKey, error) { var key []byte err := row.Scan(&key) if errors.Is(err, sql.ErrNoRows) { - zlog.Info().Msg("no identity key found") return nil, nil } else if err != nil { return nil, err diff --git a/pkg/signalmeow/prekey_store.go b/pkg/signalmeow/store/prekey_store.go similarity index 73% rename from pkg/signalmeow/prekey_store.go rename to pkg/signalmeow/store/prekey_store.go index 1e4ca97..5f4f572 100644 --- a/pkg/signalmeow/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" @@ -25,6 +25,7 @@ import ( "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) var _ libsignalgo.PreKeyStore = (*SQLStore)(nil) @@ -35,63 +36,63 @@ var _ PreKeyStoreExtras = (*SQLStore)(nil) // TODO: figure out how best to handle ACI vs PNI UUIDs type PreKeyStoreExtras interface { - PreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) - SignedPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) - KyberPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) - SavePreKey(ctx context.Context, uuidKind UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error - SaveSignedPreKey(ctx context.Context, uuidKind UUIDKind, preKey *libsignalgo.SignedPreKeyRecord, markUploaded bool) error - SaveKyberPreKey(ctx context.Context, uuidKind UUIDKind, preKey *libsignalgo.KyberPreKeyRecord, lastResort bool) error - DeletePreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) error - DeleteSignedPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) error - DeleteKyberPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) error - GetNextPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint, error) - GetSignedNextPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint, error) - GetNextKyberPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint, error) - MarkPreKeysAsUploaded(ctx context.Context, uuidKind UUIDKind, upToID uint) error - MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind UUIDKind, upToID uint) error - IsKyberPreKeyLastResort(ctx context.Context, uuidKind UUIDKind, preKeyID int) (bool, error) + PreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) + SignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) + KyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) + SavePreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error + SaveSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.SignedPreKeyRecord, markUploaded bool) error + SaveKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.KyberPreKeyRecord, lastResort bool) error + DeletePreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error + DeleteSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error + DeleteKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error + GetNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) + GetSignedNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) + GetNextKyberPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) + MarkPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error + MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error + IsKyberPreKeyLastResort(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (bool, error) DeleteAllPreKeys(ctx context.Context) error } // libsignalgo.PreKeyStore implementation func (s *SQLStore) LoadPreKey(ctx context.Context, id uint32) (*libsignalgo.PreKeyRecord, error) { - return s.PreKey(ctx, UUIDKindACI, int(id)) + return s.PreKey(ctx, types.UUIDKindACI, int(id)) } func (s *SQLStore) StorePreKey(ctx context.Context, id uint32, preKeyRecord *libsignalgo.PreKeyRecord) error { - return s.SavePreKey(ctx, UUIDKindACI, preKeyRecord, false) + return s.SavePreKey(ctx, types.UUIDKindACI, preKeyRecord, false) } func (s *SQLStore) RemovePreKey(ctx context.Context, id uint32) error { - return s.DeletePreKey(ctx, UUIDKindACI, int(id)) + return s.DeletePreKey(ctx, types.UUIDKindACI, int(id)) } // libsignalgo.SignedPreKeyStore implementation func (s *SQLStore) LoadSignedPreKey(ctx context.Context, id uint32) (*libsignalgo.SignedPreKeyRecord, error) { - return s.SignedPreKey(ctx, UUIDKindACI, int(id)) + return s.SignedPreKey(ctx, types.UUIDKindACI, int(id)) } func (s *SQLStore) StoreSignedPreKey(ctx context.Context, id uint32, signedPreKeyRecord *libsignalgo.SignedPreKeyRecord) error { - return s.SaveSignedPreKey(ctx, UUIDKindACI, signedPreKeyRecord, false) + return s.SaveSignedPreKey(ctx, types.UUIDKindACI, signedPreKeyRecord, false) } func (s *SQLStore) RemoveSignedPreKey(ctx context.Context, id uint32) error { - return s.DeleteSignedPreKey(ctx, UUIDKindACI, int(id)) + return s.DeleteSignedPreKey(ctx, types.UUIDKindACI, int(id)) } // libsignalgo.KyberPreKeyStore implementation func (s *SQLStore) LoadKyberPreKey(ctx context.Context, id uint32) (*libsignalgo.KyberPreKeyRecord, error) { - return s.KyberPreKey(ctx, UUIDKindACI, int(id)) + return s.KyberPreKey(ctx, types.UUIDKindACI, int(id)) } func (s *SQLStore) StoreKyberPreKey(ctx context.Context, id uint32, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord) error { - return s.SaveKyberPreKey(ctx, UUIDKindACI, kyberPreKeyRecord, false) + return s.SaveKyberPreKey(ctx, types.UUIDKindACI, kyberPreKeyRecord, false) } func (s *SQLStore) MarkKyberPreKeyUsed(ctx context.Context, id uint32) error { - isLastResort, err := s.IsKyberPreKeyLastResort(ctx, UUIDKindACI, int(id)) + isLastResort, err := s.IsKyberPreKeyLastResort(ctx, types.UUIDKindACI, int(id)) if err != nil { return err } if !isLastResort { - return s.DeleteKyberPreKey(ctx, UUIDKindACI, int(id)) + return s.DeleteKyberPreKey(ctx, types.UUIDKindACI, int(id)) } return nil } @@ -104,7 +105,7 @@ const ( isLastResortQuery = `SELECT is_last_resort FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND key_id=$2 AND uuid_kind=$3` ) -func (s *SQLStore) KyberPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) { +func (s *SQLStore) KyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) { var record []byte var isLastResort bool err := s.db.Conn(ctx).QueryRowContext(ctx, getKyberPreKeyQuery, s.ACI, preKeyID, uuidKind).Scan(&record, &isLastResort) @@ -117,7 +118,7 @@ func (s *SQLStore) KyberPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID return libsignalgo.DeserializeKyberPreKeyRecord(record) } -func (s *SQLStore) SaveKyberPreKey(ctx context.Context, uuidKind UUIDKind, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord, lastResort bool) error { +func (s *SQLStore) SaveKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord, lastResort bool) error { id, err := kyberPreKeyRecord.GetID() if err != nil { return fmt.Errorf("failed to get kyber prekey record ID: %w", err) @@ -130,12 +131,12 @@ func (s *SQLStore) SaveKyberPreKey(ctx context.Context, uuidKind UUIDKind, kyber return err } -func (s *SQLStore) DeleteKyberPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) error { +func (s *SQLStore) DeleteKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { _, err := s.db.Conn(ctx).ExecContext(ctx, deleteKyberPreKeyQuery, s.ACI, preKeyID, uuidKind) return err } -func (s *SQLStore) GetNextKyberPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint, error) { +func (s *SQLStore) GetNextKyberPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { var lastKeyID sql.NullInt64 err := s.db.Conn(ctx).QueryRowContext(ctx, getLastKyberPreKeyIDQuery, s.ACI, uuidKind).Scan(&lastKeyID) if err != nil { @@ -144,7 +145,7 @@ func (s *SQLStore) GetNextKyberPreKeyID(ctx context.Context, uuidKind UUIDKind) return uint(lastKeyID.Int64) + 1, nil } -func (s *SQLStore) IsKyberPreKeyLastResort(ctx context.Context, uuidKind UUIDKind, preKeyID int) (bool, error) { +func (s *SQLStore) IsKyberPreKeyLastResort(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (bool, error) { var isLastResort bool err := s.db.Conn(ctx).QueryRowContext(ctx, isLastResortQuery, s.ACI, preKeyID, uuidKind).Scan(&isLastResort) if err != nil { @@ -187,15 +188,15 @@ func scanSignedPreKey(row dbutil.Scannable) (*libsignalgo.SignedPreKeyRecord, er return libsignalgo.DeserializeSignedPreKeyRecord(record) } -func (s *SQLStore) PreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) { +func (s *SQLStore) PreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) { return scanPreKey(s.db.Conn(ctx).QueryRowContext(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, false)) } -func (s *SQLStore) SignedPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) { +func (s *SQLStore) SignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) { return scanSignedPreKey(s.db.Conn(ctx).QueryRowContext(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, true)) } -func (s *SQLStore) SavePreKey(ctx context.Context, uuidKind UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error { +func (s *SQLStore) SavePreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error { id, err := preKey.GetID() if err != nil { return fmt.Errorf("failed to get prekey ID: %w", err) @@ -208,7 +209,7 @@ func (s *SQLStore) SavePreKey(ctx context.Context, uuidKind UUIDKind, preKey *li return err } -func (s *SQLStore) SaveSignedPreKey(ctx context.Context, uuidKind UUIDKind, preKey *libsignalgo.SignedPreKeyRecord, markUploaded bool) error { +func (s *SQLStore) SaveSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.SignedPreKeyRecord, markUploaded bool) error { id, err := preKey.GetID() if err != nil { return fmt.Errorf("failed to get signed prekey ID: %w", err) @@ -221,17 +222,17 @@ func (s *SQLStore) SaveSignedPreKey(ctx context.Context, uuidKind UUIDKind, preK return err } -func (s *SQLStore) DeletePreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) error { +func (s *SQLStore) DeletePreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { _, err := s.db.Conn(ctx).ExecContext(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, false) return err } -func (s *SQLStore) DeleteSignedPreKey(ctx context.Context, uuidKind UUIDKind, preKeyID int) error { +func (s *SQLStore) DeleteSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { _, err := s.db.Conn(ctx).ExecContext(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, true) return err } -func (s *SQLStore) GetNextPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint, error) { +func (s *SQLStore) GetNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { var lastKeyID sql.NullInt64 err := s.db.Conn(ctx).QueryRowContext(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, false).Scan(&lastKeyID) if err != nil { @@ -240,7 +241,7 @@ func (s *SQLStore) GetNextPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint return uint(lastKeyID.Int64) + 1, nil } -func (s *SQLStore) GetSignedNextPreKeyID(ctx context.Context, uuidKind UUIDKind) (uint, error) { +func (s *SQLStore) GetSignedNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { var lastKeyID sql.NullInt64 err := s.db.Conn(ctx).QueryRowContext(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, true).Scan(&lastKeyID) if err != nil { @@ -249,12 +250,12 @@ func (s *SQLStore) GetSignedNextPreKeyID(ctx context.Context, uuidKind UUIDKind) return uint(lastKeyID.Int64) + 1, nil } -func (s *SQLStore) MarkPreKeysAsUploaded(ctx context.Context, uuidKind UUIDKind, upToID uint) error { +func (s *SQLStore) MarkPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error { _, err := s.db.Conn(ctx).ExecContext(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, false, upToID) return err } -func (s *SQLStore) MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind UUIDKind, upToID uint) error { +func (s *SQLStore) MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error { _, err := s.db.Conn(ctx).ExecContext(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, true, upToID) return err } diff --git a/pkg/signalmeow/profile_key_store.go b/pkg/signalmeow/store/profile_key_store.go similarity index 99% rename from pkg/signalmeow/profile_key_store.go rename to pkg/signalmeow/store/profile_key_store.go index 54e9777..ba80ebe 100644 --- a/pkg/signalmeow/profile_key_store.go +++ b/pkg/signalmeow/store/profile_key_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" @@ -22,7 +22,6 @@ import ( "errors" "github.com/google/uuid" - "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" diff --git a/pkg/signalmeow/sender_key_store.go b/pkg/signalmeow/store/sender_key_store.go similarity index 99% rename from pkg/signalmeow/sender_key_store.go rename to pkg/signalmeow/store/sender_key_store.go index 7ff5420..9bfa5c2 100644 --- a/pkg/signalmeow/sender_key_store.go +++ b/pkg/signalmeow/store/sender_key_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" @@ -23,7 +23,6 @@ import ( "fmt" "github.com/google/uuid" - "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" diff --git a/pkg/signalmeow/session_store.go b/pkg/signalmeow/store/session_store.go similarity index 99% rename from pkg/signalmeow/session_store.go rename to pkg/signalmeow/store/session_store.go index 2b1d1a6..ca66926 100644 --- a/pkg/signalmeow/session_store.go +++ b/pkg/signalmeow/store/session_store.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package signalmeow +package store import ( "context" @@ -23,7 +23,6 @@ import ( "fmt" "github.com/google/uuid" - "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" diff --git a/pkg/signalmeow/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql similarity index 100% rename from pkg/signalmeow/upgrades/00-latest.sql rename to pkg/signalmeow/store/upgrades/00-latest.sql diff --git a/pkg/signalmeow/upgrades/02-groups.sql b/pkg/signalmeow/store/upgrades/02-groups.sql similarity index 100% rename from pkg/signalmeow/upgrades/02-groups.sql rename to pkg/signalmeow/store/upgrades/02-groups.sql diff --git a/pkg/signalmeow/upgrades/03-contacts.sql b/pkg/signalmeow/store/upgrades/03-contacts.sql similarity index 100% rename from pkg/signalmeow/upgrades/03-contacts.sql rename to pkg/signalmeow/store/upgrades/03-contacts.sql diff --git a/pkg/signalmeow/upgrades/04-kyber-prekeys.sql b/pkg/signalmeow/store/upgrades/04-kyber-prekeys.sql similarity index 100% rename from pkg/signalmeow/upgrades/04-kyber-prekeys.sql rename to pkg/signalmeow/store/upgrades/04-kyber-prekeys.sql diff --git a/pkg/signalmeow/upgrades/05-postgres-profile-key.sql b/pkg/signalmeow/store/upgrades/05-postgres-profile-key.sql similarity index 100% rename from pkg/signalmeow/upgrades/05-postgres-profile-key.sql rename to pkg/signalmeow/store/upgrades/05-postgres-profile-key.sql diff --git a/pkg/signalmeow/upgrades/upgrades.go b/pkg/signalmeow/store/upgrades/upgrades.go similarity index 100% rename from pkg/signalmeow/upgrades/upgrades.go rename to pkg/signalmeow/store/upgrades/upgrades.go diff --git a/pkg/signalmeow/types.go b/pkg/signalmeow/types.go index 5b5fc93..ba8da3f 100644 --- a/pkg/signalmeow/types.go +++ b/pkg/signalmeow/types.go @@ -20,15 +20,6 @@ import ( "github.com/google/uuid" ) -const ( - // UUIDKindACI is the UUID kind for account identifiers. - UUIDKindACI UUIDKind = "aci" - // UUIDKindPNI is the UUID kind for phone number identifiers. - UUIDKindPNI UUIDKind = "pni" -) - -type UUIDKind string - type GroupCredentials struct { Credentials []GroupCredential `json:"credentials"` PNI uuid.UUID `json:"pni"` diff --git a/pkg/signalmeow/types/identifer.go b/pkg/signalmeow/types/identifer.go index 00554bf..334e9bb 100644 --- a/pkg/signalmeow/types/identifer.go +++ b/pkg/signalmeow/types/identifer.go @@ -41,3 +41,6 @@ func (gid GroupIdentifier) Bytes() (raw libsignalgo.GroupIdentifier, err error) } return } + +// This is just base64 encoded group master key +type SerializedGroupMasterKey string diff --git a/pkg/signalmeow/types/uuid.go b/pkg/signalmeow/types/uuid.go new file mode 100644 index 0000000..86271dd --- /dev/null +++ b/pkg/signalmeow/types/uuid.go @@ -0,0 +1,10 @@ +package types + +const ( + // UUIDKindACI is the UUID kind for account identifiers. + UUIDKindACI UUIDKind = "aci" + // UUIDKindPNI is the UUID kind for phone number identifiers. + UUIDKindPNI UUIDKind = "pni" +) + +type UUIDKind string diff --git a/portal.go b/portal.go index 45c0e53..c6cdbd0 100644 --- a/portal.go +++ b/portal.go @@ -331,9 +331,9 @@ func (portal *Portal) messageLoop() { } func (portal *Portal) handleMatrixMessages(msg portalMatrixMessage) { - // If we have no SignalDevice, the bridge isn't logged in properly, + // If we have no Client, the bridge isn't logged in properly, // so send BAD_CREDENTIALS so the user knows - if !msg.user.SignalDevice.IsDeviceLoggedIn() && !portal.HasRelaybot() { + if !msg.user.Client.IsLoggedIn() && !portal.HasRelaybot() { go portal.sendMessageMetrics(context.TODO(), msg.evt, errUserNotLoggedIn, "Ignoring", nil) msg.user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) return @@ -461,7 +461,7 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt go ms.sendMessageMetrics(evt, errMNoticeDisabled, "Error converting", true) return } - ctx = context.WithValue(ctx, msgconvContextKeyClient, sender.SignalDevice) + ctx = context.WithValue(ctx, msgconvContextKeyClient, sender.Client) msg, err := portal.MsgConv.ToSignal(ctx, evt, content, relaybotFormatted) if err != nil { log.Err(err).Msg("Failed to convert message") @@ -669,7 +669,7 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte var err error if portal.IsPrivateChat() { // this is a 1:1 chat - result := signalmeow.SendMessage(ctx, sender.SignalDevice, portal.UserID(), msg) + result := sender.Client.SendMessage(ctx, portal.UserID(), msg) if !result.WasSuccessful { err = result.FailedSendResult.Error log.Err(err).Msg("Error sending event to Signal") @@ -677,7 +677,7 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte } else { // this is a group chat groupID := types.GroupIdentifier(portal.ChatID) - result, err := signalmeow.SendGroupMessage(ctx, sender.SignalDevice, groupID, msg) + result, err := sender.Client.SendGroupMessage(ctx, groupID, msg) if err != nil { // check the start of the error string, see if it starts with "No group master key found for group identifier" if strings.HasPrefix(err.Error(), "No group master key found for group identifier") { @@ -767,8 +767,8 @@ func (portal *Portal) GetData(ctx context.Context) *database.Portal { return portal.Portal } -func (portal *Portal) GetClient(ctx context.Context) *signalmeow.Device { - return ctx.Value(msgconvContextKeyClient).(*signalmeow.Device) +func (portal *Portal) GetClient(ctx context.Context) *signalmeow.Client { + return ctx.Value(msgconvContextKeyClient).(*signalmeow.Client) } func (portal *Portal) GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) { @@ -1004,7 +1004,7 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet } // FIXME hacky ensureGroupPuppetsAreJoinedToPortal(context.TODO(), source, portal) - signalmeow.SendContactSyncRequest(context.TODO(), source.SignalDevice) + source.Client.SendContactSyncRequest(context.TODO()) } existingMessage, err := portal.bridge.DB.Message.GetBySignalID(ctx, sender.SignalID, msg.GetTimestamp(), 0, portal.Receiver) @@ -1213,7 +1213,7 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { portal.log.Debug().Msgf("Sending Typing event to Signal %s", portal.ChatID) ctx := context.TODO() typingMessage := signalmeow.TypingMessage(isTyping) - result := signalmeow.SendMessage(ctx, user.SignalDevice, portal.UserID(), typingMessage) + result := user.Client.SendMessage(ctx, portal.UserID(), typingMessage) if !result.WasSuccessful { portal.log.Err(result.FailedSendResult.Error).Msg("Error sending event to Signal") } @@ -1297,7 +1297,7 @@ func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, // Don't use portal.sendSignalMessage because we're sending this straight to // who sent the original message, not the portal's ChatID ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - result := signalmeow.SendMessage(ctx, sender.SignalDevice, destination, signalmeow.ReadReceptMessageForTimestamps(messages)) + result := sender.Client.SendMessage(ctx, destination, signalmeow.ReadReceptMessageForTimestamps(messages)) cancel() if !result.WasSuccessful { log.Err(result.FailedSendResult.Error). diff --git a/provisioning.go b/provisioning.go index 4630374..805c118 100644 --- a/provisioning.go +++ b/provisioning.go @@ -150,10 +150,10 @@ func (prov *ProvisioningAPI) resolveIdentifier(user *User, phoneNum string) (int if !strings.HasPrefix(phoneNum, "+") { phoneNum = "+" + phoneNum } - if user.SignalDevice == nil { + if user.Client == nil { return http.StatusUnauthorized, nil, fmt.Errorf("Not currently connected to Signal") } - contact, err := user.SignalDevice.ContactByE164(phoneNum) + contact, err := user.Client.ContactByE164(phoneNum) if err != nil { return http.StatusInternalServerError, nil, fmt.Errorf("Error looking up number in local contact list: %w", err) } diff --git a/user.go b/user.go index b126693..275e809 100644 --- a/user.go +++ b/user.go @@ -166,7 +166,7 @@ type User struct { Admin bool PermissionLevel bridgeconfig.PermissionLevel - SignalDevice *signalmeow.Device + Client *signalmeow.Client BridgeState *bridge.BridgeStateQueue bridgeStateLock sync.Mutex @@ -188,7 +188,7 @@ func (user *User) IsLoggedIn() bool { user.Lock() defer user.Unlock() - return user.SignalDevice.IsDeviceLoggedIn() + return user.Client.IsLoggedIn() } func (user *User) GetManagementRoomID() id.RoomID { @@ -338,7 +338,7 @@ func (user *User) syncChatDoublePuppetDetails(portal *Portal, justCreated bool) // TODO: Get chat setting from Signal and sync them here //if justCreated || !user.bridge.Config.Bridge.TagOnlyOnCreate { - // chat, err := user.SignalDevice.Store.ChatSettings.GetChatSettings(portal.Key().ChatID) + // chat, err := user.Client.Store.ChatSettings.GetChatSettings(portal.Key().ChatID) // if err != nil { // user.log.Warn().Err(err).Msgf("Failed to get settings of %s", portal.Key().ChatID) // return @@ -379,7 +379,7 @@ func (user *User) startupTryConnect(retryCount int) { user.log.Debug().Msg("Connecting to Signal") ctx := user.log.WithContext(context.Background()) - statusChan, err := signalmeow.StartReceiveLoops(ctx, user.SignalDevice) + statusChan, err := user.Client.StartReceiveLoops(ctx) if err != nil { user.log.Error().Err(err).Msg("Error connecting on startup") @@ -493,7 +493,7 @@ func (user *User) startupTryConnect(retryCount int) { user.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) case signalmeow.SignalConnectionCleanShutdown: - if user.SignalDevice.IsDeviceLoggedIn() { + if user.Client.IsLoggedIn() { user.log.Debug().Msg("Clean Shutdown - sending no BridgeState") } else { user.log.Debug().Msg("Clean Shutdown, but logged out - Sending BadCredentials BridgeState") @@ -507,7 +507,7 @@ func (user *User) startupTryConnect(retryCount int) { func (user *User) clearKeysAndDisconnect() { // We need to clear out keys associated with the Signal device that no longer has valid credentials user.log.Debug().Msg("Clearing out Signal device keys") - err := user.SignalDevice.ClearKeysAndDisconnect(context.TODO()) + err := user.Client.ClearKeysAndDisconnect(context.TODO()) if err != nil { user.log.Err(err).Msg("Error clearing device keys") } @@ -520,7 +520,7 @@ func (br *SignalBridge) StartUsers() { numUsersStarting := 0 for _, u := range usersWithToken { device := u.populateSignalDevice() - if device == nil || !device.IsDeviceLoggedIn() { + if device == nil || !device.IsLoggedIn() { br.ZLog.Warn().Stringer("user_id", u.MXID).Msg("No device found for user, skipping Connect and sending BadCredentials BridgeState") u.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) continue @@ -557,7 +557,7 @@ func (user *User) Connect() { user.startupTryConnect(0) } -func (user *User) populateSignalDevice() *signalmeow.Device { +func (user *User) populateSignalDevice() *signalmeow.Client { user.Lock() defer user.Unlock() log := user.log.With(). @@ -578,9 +578,11 @@ func (user *User) populateSignalDevice() *signalmeow.Device { return nil } - user.SignalDevice = device - device.Connection.EventHandler = user.eventHandler - return device + user.Client = &signalmeow.Client{ + Store: device, + EventHandler: user.eventHandler, + } + return user.Client } func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Puppet, newContactAvatar *types.ContactAvatar) error { @@ -588,7 +590,7 @@ func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Pupp Str("action", "update puppet with signal contact"). Str("signal_id", puppet.SignalID.String()). Logger() - contact, newProfileAvatar, err := user.SignalDevice.ContactByIDWithProfileAvatar(puppet.SignalID) + contact, newProfileAvatar, err := user.Client.ContactByIDWithProfileAvatar(puppet.SignalID) if err != nil { log.Err(err).Msg("error retrieving contact") return err @@ -680,7 +682,7 @@ func ensureGroupPuppetsAreJoinedToPortal(ctx context.Context, user *User, portal return nil } user.log.Info().Msgf("Ensuring everyone is joined to room %s, groupID: %s", portal.MXID, portal.ChatID) - group, err := signalmeow.RetrieveGroupByID(ctx, user.SignalDevice, types.GroupIdentifier(portal.ChatID)) + group, err := user.Client.RetrieveGroupByID(ctx, types.GroupIdentifier(portal.ChatID)) if err != nil { user.log.Err(err).Msg("error retrieving group") return err @@ -833,7 +835,7 @@ func (user *User) syncPortalInfo(portal *Portal) { ctx := context.TODO() updatePortal := false if !portal.IsPrivateChat() { - group, avatarImage, err := signalmeow.RetrieveGroupAndAvatarByID(ctx, user.SignalDevice, portal.GroupID()) + group, avatarImage, err := user.Client.RetrieveGroupAndAvatarByID(ctx, portal.GroupID()) if err != nil { user.log.Err(err).Msg("error retrieving group") return @@ -966,14 +968,14 @@ func (user *User) GetPortalByChatID(signalID string) *Portal { return user.bridge.GetPortalByChatID(pk) } -func (user *User) disconnectNoLock() (*signalmeow.Device, error) { - if user.SignalDevice == nil { +func (user *User) disconnectNoLock() (*signalmeow.Client, error) { + if user.Client == nil { return nil, ErrNotConnected } - disconnectedDevice := user.SignalDevice - err := signalmeow.StopReceiveLoops(user.SignalDevice) - user.SignalDevice = nil + disconnectedDevice := user.Client + err := user.Client.StopReceiveLoops() + user.Client = nil return disconnectedDevice, err } @@ -990,7 +992,7 @@ func (user *User) Logout() error { defer user.Unlock() user.log.Info().Msg("Logging out of session") loggedOutDevice, err := user.disconnectNoLock() - user.bridge.MeowStore.DeleteDevice(context.TODO(), &loggedOutDevice.Data) + user.bridge.MeowStore.DeleteDevice(context.TODO(), &loggedOutDevice.Store.DeviceData) user.bridge.GetPuppetByCustomMXID(user.MXID).ClearCustomMXID() return err } From fe86faf03e0cc174b2a40d8ba548db32c95a6be7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 5 Jan 2024 17:26:25 +0200 Subject: [PATCH 008/718] Fix automatic double puppeting --- user.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/user.go b/user.go index 275e809..d0e9165 100644 --- a/user.go +++ b/user.go @@ -129,16 +129,6 @@ func (br *SignalBridge) loadUser(ctx context.Context, dbUser *database.User, mxi br.managementRooms[user.ManagementRoom] = user br.managementRoomsLock.Unlock() } - // TODO this is completely wrong and shouldn't be here at all - // Ensure a puppet is created for this user - newPuppet := br.GetPuppetBySignalID(user.SignalID) - if newPuppet != nil && newPuppet.CustomMXID == "" { - newPuppet.CustomMXID = user.MXID - err := newPuppet.Update(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Error updating puppet for user %s") - } - } return user } @@ -567,6 +557,8 @@ func (user *User) populateSignalDevice() *signalmeow.Client { if user.SignalID == uuid.Nil { return nil + } else if user.Client != nil { + return user.Client } device, err := user.bridge.MeowStore.DeviceByACI(context.TODO(), user.SignalID) @@ -582,6 +574,7 @@ func (user *User) populateSignalDevice() *signalmeow.Client { Store: device, EventHandler: user.eventHandler, } + go user.tryAutomaticDoublePuppeting() return user.Client } From c7a3bb861c5e3d89cc266dc60b4f22d751d869ea Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 5 Jan 2024 17:41:01 +0200 Subject: [PATCH 009/718] Fix some todos --- main.go | 3 +-- msgconv/matrixfmt/html.go | 1 - pkg/signalmeow/keys.go | 25 +++++++++++++------------ pkg/signalmeow/provisioning.go | 2 -- user.go | 10 +++++++++- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/main.go b/main.go index b26edeb..b0ab0f5 100644 --- a/main.go +++ b/main.go @@ -142,8 +142,7 @@ func (br *SignalBridge) Init() { if ok { return parsed } - // TODO only get if exists - user := br.GetUserByMXID(userID) + user := br.GetUserByMXIDIfExists(userID) if user != nil && user.SignalID != uuid.Nil { return user.SignalID } diff --git a/msgconv/matrixfmt/html.go b/msgconv/matrixfmt/html.go index 074caff..88dc975 100644 --- a/msgconv/matrixfmt/html.go +++ b/msgconv/matrixfmt/html.go @@ -278,7 +278,6 @@ func (parser *HTMLParser) listToString(node *html.Node, ctx Context) *EntityStri continue } var prefix string - // TODO make bullets and numbering configurable if ordered { indexPadding := indentLength - Digits(counter) if indexPadding < 0 { diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 9df88ba..4313f92 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -26,6 +26,7 @@ import ( "time" "github.com/google/uuid" + "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" @@ -46,34 +47,34 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type identityKeyPair = cli.Store.ACIIdentityKeyPair } - // Generate prekeys nextPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextPreKeyID(ctx, uuidKind) if err != nil { - zlog.Err(err).Msg("Error getting next prekey id") - return err + return fmt.Errorf("failed to get next prekey ID: %w", err) } nextKyberPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextKyberPreKeyID(ctx, uuidKind) if err != nil { - zlog.Err(err).Msg("Error getting next kyber prekey id") - return err + return fmt.Errorf("failed to get next kyber prekey ID: %w", err) } preKeys := GeneratePreKeys(nextPreKeyID, 100, uuidKind) kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, 100, uuidKind, identityKeyPair) - // Persist prekeys - // TODO return database errors for _, preKey := range preKeys { - cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) + err = cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) + if err != nil { + return fmt.Errorf("failed to save prekey: %w", err) + } } for _, kyberPreKey := range kyberPreKeys { - cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) + err = cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) + if err != nil { + return fmt.Errorf("failed to save kyber prekey: %w", err) + } } // Register prekeys identityKey, err := identityKeyPair.GetPublicKey().Serialize() if err != nil { - zlog.Err(err).Msg("Error serializing identity key") - return err + return fmt.Errorf("failed to serialize identity key: %w", err) } generatedPreKeys := GeneratedPreKeys{ PreKeys: preKeys, @@ -97,7 +98,7 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type err = cli.Store.PreKeyStoreExtras.MarkPreKeysAsUploaded(ctx, uuidKind, lastPreKeyID) if err != nil { - zlog.Err(err).Msg("Error marking prekeys as uploaded") + zerolog.Ctx(ctx).Err(err).Msg("Failed to mark prekeys as uploaded") } return err diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 731541d..871a136 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -350,8 +350,6 @@ func confirmDevice( "pniPqLastResortPreKey": pniPQLastResortPreKeyJson, } - // TODO: Set deviceName with "Signal Bridge" or something properly encrypted - jsonBytes, err := json.Marshal(data) if err != nil { zlog.Err(err).Msg("failed to marshal JSON") diff --git a/user.go b/user.go index d0e9165..db71fde 100644 --- a/user.go +++ b/user.go @@ -50,6 +50,14 @@ var ( ) func (br *SignalBridge) GetUserByMXID(userID id.UserID) *User { + return br.maybeGetUserByMXID(userID, &userID) +} + +func (br *SignalBridge) GetUserByMXIDIfExists(userID id.UserID) *User { + return br.maybeGetUserByMXID(userID, nil) +} + +func (br *SignalBridge) maybeGetUserByMXID(userID id.UserID, userIDPtr *id.UserID) *User { if userID == br.Bot.UserID || br.IsGhost(userID) { return nil } @@ -63,7 +71,7 @@ func (br *SignalBridge) GetUserByMXID(userID id.UserID) *User { br.ZLog.Err(err).Msg("Failed to get user from database") return nil } - return br.loadUser(context.TODO(), dbUser, &userID) + return br.loadUser(context.TODO(), dbUser, userIDPtr) } return user } From e2d8a24c998c58cf13a4f411aa32fb34cb896c95 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 5 Jan 2024 20:37:47 +0200 Subject: [PATCH 010/718] Refactor group and user info updating --- commands.go | 2 +- database/portal.go | 30 +- database/puppet.go | 15 +- database/upgrades/00-latest.sql | 5 +- database/upgrades/19-more-portal-metadata.sql | 5 + main.go | 18 +- msgconv/from-signal.go | 20 +- pkg/libsignalgo/profilekey.go | 3 + pkg/signalmeow/contact.go | 103 ++--- pkg/signalmeow/events/message.go | 25 +- pkg/signalmeow/groups.go | 64 +-- pkg/signalmeow/profile.go | 140 +++---- pkg/signalmeow/receiving.go | 46 +-- pkg/signalmeow/sending.go | 2 +- pkg/signalmeow/store/contact_store.go | 21 +- pkg/signalmeow/store/upgrades/00-latest.sql | 2 + .../store/upgrades/06-profile-avatar-path.sql | 2 + pkg/signalmeow/types/contact.go | 7 +- portal.go | 368 ++++++++++++++++-- provisioning.go | 2 +- puppet.go | 343 +++++++++++----- user.go | 236 +---------- 22 files changed, 788 insertions(+), 671 deletions(-) create mode 100644 database/upgrades/19-more-portal-metadata.sql create mode 100644 pkg/signalmeow/store/upgrades/06-profile-avatar-path.sql diff --git a/commands.go b/commands.go index ab7ce49..f859f9c 100644 --- a/commands.go +++ b/commands.go @@ -223,7 +223,7 @@ func fnPM(ce *WrappedCommandEvent) { ce.Reply("You already have a portal to %s at %s", number, portal.MXID) return } - if err := portal.CreateMatrixRoom(ce.Ctx, user, nil); err != nil { + if err := portal.CreateMatrixRoom(ce.Ctx, user, 0); err != nil { ce.Reply("Error creating Matrix room for portal to %s", number) ce.Log.Errorln("Error creating Matrix room for portal to %s: %s", number, err) return diff --git a/database/portal.go b/database/portal.go index 1068fb3..14e40bc 100644 --- a/database/portal.go +++ b/database/portal.go @@ -29,13 +29,14 @@ import ( const ( portalBaseSelect = ` - SELECT chat_id, receiver, mxid, name, topic, avatar_hash, avatar_url, name_set, avatar_set, - revision, encrypted, relay_user_id, expiration_time + SELECT chat_id, receiver, mxid, name, topic, avatar_path, avatar_hash, avatar_url, + name_set, avatar_set, topic_set, revision, encrypted, relay_user_id, expiration_time FROM portal ` getPortalByMXIDQuery = portalBaseSelect + `WHERE mxid=$1` getPortalByChatIDQuery = portalBaseSelect + `WHERE chat_id=$1 AND receiver=$2` getPortalsByReceiver = portalBaseSelect + `WHERE receiver=$1` + getPortalsByUser = portalBaseSelect + `WHERE chat_id=$1` getAllPortalsWithMXIDQuery = portalBaseSelect + `WHERE mxid IS NOT NULL` getChatsNotInSpaceQuery = ` SELECT chat_id FROM portal @@ -44,15 +45,14 @@ const ( ` insertPortalQuery = ` INSERT INTO portal ( - chat_id, receiver, mxid, name, topic, avatar_hash, avatar_url, name_set, avatar_set, - revision, encrypted, relay_user_id, expiration_time - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) + chat_id, receiver, mxid, name, topic, avatar_path, avatar_hash, avatar_url, + name_set, avatar_set, topic_set, revision, encrypted, relay_user_id, expiration_time + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) ` updatePortalQuery = ` UPDATE portal SET - mxid=$3, name=$4, topic=$5, avatar_hash=$6, avatar_url=$7, name_set=$8, - avatar_set=$9, revision=$10, encrypted=$11, relay_user_id=$12, - expiration_time=$13 + mxid=$3, name=$4, topic=$5, avatar_path=$6, avatar_hash=$7, avatar_url=$8, + name_set=$9, avatar_set=$10, topic_set=$11, revision=$12, encrypted=$13, relay_user_id=$14, expiration_time=$15 WHERE chat_id=$1 AND receiver=$2 ` deletePortalQuery = `DELETE FROM portal WHERE chat_id=$1 AND receiver=$2` @@ -93,14 +93,16 @@ type Portal struct { MXID id.RoomID Name string Topic string + AvatarPath string AvatarHash string AvatarURL id.ContentURI NameSet bool AvatarSet bool - Revision int + TopicSet bool + Revision uint32 Encrypted bool RelayUserID id.UserID - ExpirationTime int + ExpirationTime uint32 } func newPortal(qh *dbutil.QueryHelper[*Portal]) *Portal { @@ -115,6 +117,10 @@ func (pq *PortalQuery) GetByChatID(ctx context.Context, pk PortalKey) (*Portal, return pq.QueryOne(ctx, getPortalByChatIDQuery, pk.ChatID, pk.Receiver) } +func (pq *PortalQuery) FindPrivateChatsWith(ctx context.Context, userID uuid.UUID) ([]*Portal, error) { + return pq.QueryMany(ctx, getPortalsByUser, userID.String()) +} + func (pq *PortalQuery) FindPrivateChatsOf(ctx context.Context, receiver uuid.UUID) ([]*Portal, error) { return pq.QueryMany(ctx, getPortalsByReceiver, receiver) } @@ -143,10 +149,12 @@ func (p *Portal) Scan(row dbutil.Scannable) (*Portal, error) { &mxid, &p.Name, &p.Topic, + &p.AvatarPath, &p.AvatarHash, &p.AvatarURL, &p.NameSet, &p.AvatarSet, + &p.TopicSet, &p.Revision, &p.Encrypted, &p.RelayUserID, @@ -166,10 +174,12 @@ func (p *Portal) sqlVariables() []any { dbutil.StrPtr(p.MXID), p.Name, p.Topic, + p.AvatarPath, p.AvatarHash, &p.AvatarURL, p.NameSet, p.AvatarSet, + p.TopicSet, p.Revision, p.Encrypted, p.RelayUserID, diff --git a/database/puppet.go b/database/puppet.go index e6e752b..8c300df 100644 --- a/database/puppet.go +++ b/database/puppet.go @@ -27,7 +27,7 @@ import ( const ( puppetBaseSelect = ` - SELECT uuid, number, name, name_quality, avatar_hash, avatar_url, name_set, avatar_set, + SELECT uuid, number, name, name_quality, avatar_path, avatar_hash, avatar_url, name_set, avatar_set, contact_info_set, is_registered, custom_mxid, access_token FROM puppet ` @@ -37,19 +37,19 @@ const ( getPuppetsWithCustomMXID = puppetBaseSelect + `WHERE custom_mxid<>''` updatePuppetQuery = ` UPDATE puppet SET - number=$2, name=$3, name_quality=$4, avatar_hash=$5, avatar_url=$6, - name_set=$7, avatar_set=$8, contact_info_set=$9, is_registered=$10, - custom_mxid=$11, access_token=$12 + number=$2, name=$3, name_quality=$4, avatar_path=$5, avatar_hash=$6, avatar_url=$7, + name_set=$8, avatar_set=$9, contact_info_set=$10, is_registered=$11, + custom_mxid=$12, access_token=$13 WHERE uuid=$1 ` insertPuppetQuery = ` INSERT INTO puppet ( - uuid, number, name, name_quality, avatar_hash, avatar_url, + uuid, number, name, name_quality, avatar_path, avatar_hash, avatar_url, name_set, avatar_set, contact_info_set, is_registered, custom_mxid, access_token ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) ` ) @@ -65,6 +65,7 @@ type Puppet struct { Number string Name string NameQuality int + AvatarPath string AvatarHash string AvatarURL id.ContentURI NameSet bool @@ -104,6 +105,7 @@ func (p *Puppet) Scan(row dbutil.Scannable) (*Puppet, error) { &number, &p.Name, &p.NameQuality, + &p.AvatarPath, &p.AvatarHash, &p.AvatarURL, &p.NameSet, @@ -127,6 +129,7 @@ func (p *Puppet) sqlVariables() []any { dbutil.StrPtr(p.Number), p.Name, p.NameQuality, + p.AvatarPath, p.AvatarHash, &p.AvatarURL, p.NameSet, diff --git a/database/upgrades/00-latest.sql b/database/upgrades/00-latest.sql index 580eab6..ae8e157 100644 --- a/database/upgrades/00-latest.sql +++ b/database/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v18 (compatible with v17+): Latest revision +-- v0 -> v19 (compatible with v17+): Latest revision CREATE TABLE portal ( chat_id TEXT NOT NULL, @@ -7,10 +7,12 @@ CREATE TABLE portal ( name TEXT NOT NULL, topic TEXT NOT NULL, encrypted BOOLEAN NOT NULL DEFAULT false, + avatar_path TEXT NOT NULL DEFAULT '', avatar_hash TEXT NOT NULL, avatar_url TEXT NOT NULL, name_set BOOLEAN NOT NULL DEFAULT false, avatar_set BOOLEAN NOT NULL DEFAULT false, + topic_set BOOLEAN NOT NULL DEFAULT false, revision INTEGER NOT NULL DEFAULT 0, expiration_time BIGINT NOT NULL, @@ -25,6 +27,7 @@ CREATE TABLE puppet ( number TEXT UNIQUE, name TEXT NOT NULL, name_quality INTEGER NOT NULL, + avatar_path TEXT NOT NULL, avatar_hash TEXT NOT NULL, avatar_url TEXT NOT NULL, name_set BOOLEAN NOT NULL DEFAULT false, diff --git a/database/upgrades/19-more-portal-metadata.sql b/database/upgrades/19-more-portal-metadata.sql new file mode 100644 index 0000000..6230b21 --- /dev/null +++ b/database/upgrades/19-more-portal-metadata.sql @@ -0,0 +1,5 @@ +-- v19 (compatible with v17+): Add more metadata for portals +ALTER TABLE portal ADD COLUMN topic_set BOOLEAN NOT NULL DEFAULT false; +UPDATE portal SET topic_set=true WHERE topic<>''; +ALTER TABLE portal ADD COLUMN avatar_path TEXT NOT NULL DEFAULT ''; +ALTER TABLE puppet ADD COLUMN avatar_path TEXT NOT NULL DEFAULT ''; diff --git a/main.go b/main.go index b0ab0f5..e864633 100644 --- a/main.go +++ b/main.go @@ -303,23 +303,7 @@ func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomI br.AS.StateStore.SetMembership(roomID, br.Bot.UserID, event.MembershipJoin) portal.Encrypted = true } - //portal.Topic = PrivateChatTopic - _, _ = portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) - if portal.shouldSetDMRoomMetadata() { - portal.Name = puppet.Name - portal.AvatarURL = puppet.AvatarURL - portal.AvatarHash = puppet.AvatarHash - portal.AvatarSet = puppet.AvatarSet - _, err = portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) - portal.NameSet = err == nil - _, err = portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) - portal.AvatarSet = err == nil - } - err = portal.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to update portal in database") - } - portal.UpdateBridgeInfo(ctx) + portal.UpdateDMInfo(ctx, true) _, _ = intent.SendNotice(ctx, roomID, "Private chat portal created") log.Info().Msg("Created private chat portal after invite") } diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index afb09d7..03955ae 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -100,7 +100,7 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa Parts: make([]*ConvertedMessagePart, 0, calculateLength(dm)), } if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { - cm.Parts = append(cm.Parts, mc.convertDisappearingTimerChangeToMatrix(ctx, dm)) + cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), true)) // Don't disappear disappearing timer changes cm.DisappearIn = 0 // Don't allow any other parts in a disappearing timer change message @@ -150,22 +150,24 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa return cm } -func (mc *MessageConverter) convertDisappearingTimerChangeToMatrix(ctx context.Context, dm *signalpb.DataMessage) *ConvertedMessagePart { +func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, updatePortal bool) *ConvertedMessagePart { part := &ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, - Body: fmt.Sprintf("Disappearing messages set to %s", exfmt.Duration(time.Duration(dm.GetExpireTimer())*time.Second)), + Body: fmt.Sprintf("Disappearing messages set to %s", exfmt.Duration(time.Duration(timer)*time.Second)), }, } - if dm.GetExpireTimer() == 0 { + if timer == 0 { part.Content.Body = "Disappearing messages disabled" } - portal := mc.GetData(ctx) - portal.ExpirationTime = int(dm.GetExpireTimer()) - err := portal.Update(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") + if updatePortal { + portal := mc.GetData(ctx) + portal.ExpirationTime = timer + err := portal.Update(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") + } } return part } diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index bf3b51a..2cd1000 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -44,6 +44,9 @@ func (pv *ProfileKeyVersion) String() string { } func (pk *ProfileKey) Slice() []byte { + if pk == nil { + return nil + } return (*pk)[:] } diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index da7e306..f45f3e0 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -34,16 +34,16 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.ContactDetails, avatar *[]byte) (types.Contact, *types.ContactAvatar, error) { +func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.ContactDetails, avatar *[]byte) (*types.Contact, error) { ctx := context.TODO() parsedUUID, err := uuid.Parse(contactDetails.GetAci()) if err != nil { - return types.Contact{}, nil, err + return nil, err } existingContact, err := cli.Store.ContactStore.LoadContact(ctx, parsedUUID) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error loading contact") - return types.Contact{}, nil, err + return nil, err } if existingContact == nil { zlog.Debug().Msgf("StoreContactDetailsAsContact: creating new contact for uuid: %v", parsedUUID) @@ -57,8 +57,8 @@ func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.Contact existingContact.E164 = contactDetails.GetNumber() existingContact.ContactName = contactDetails.GetName() if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { - existingContact.ProfileKey = profileKeyString profileKey := libsignalgo.ProfileKey(profileKeyString) + existingContact.ProfileKey = &profileKey err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, existingContact.UUID, profileKey) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error storing profile key") @@ -66,35 +66,19 @@ func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.Contact } } - // Check for avatar changes, and return ContactAvatar if it's changed - var contactAvatar *types.ContactAvatar - avatarHash := "" if avatar != nil && *avatar != nil && len(*avatar) > 0 { - zlog.Debug().Msgf("StoreContactDetailsAsContact: found avatar for uuid: %v", contactDetails.GetAci()) rawHash := sha256.Sum256(*avatar) - avatarHash = hex.EncodeToString(rawHash[:]) - if existingContact.ContactAvatarHash != avatarHash { - zlog.Debug().Msgf("StoreContactDetailsAsContact: avatar changed for uuid: %v", contactDetails.GetAci()) - var contentType string - if avatarDetails := contactDetails.GetAvatar(); avatarDetails != nil && !strings.HasSuffix(avatarDetails.GetContentType(), "/*") { - contentType = *avatarDetails.ContentType - zlog.Debug().Msgf("StoreContactDetailsAsContact: using contentType from details: %v", contentType) - } else { - contentType = http.DetectContentType(*avatar) - zlog.Debug().Msgf("StoreContactDetailsAsContact: using autodetected contentType: %v", contentType) - } - contactAvatar = &types.ContactAvatar{ - Image: *avatar, - ContentType: contentType, - Hash: avatarHash, - } - existingContact.ContactAvatarHash = avatarHash + avatarHash := hex.EncodeToString(rawHash[:]) + var contentType string + if avatarDetails := contactDetails.GetAvatar(); avatarDetails != nil && !strings.HasSuffix(avatarDetails.GetContentType(), "/*") { + contentType = *avatarDetails.ContentType + } else { + contentType = http.DetectContentType(*avatar) } - } else { - // Avatar has been removed - zlog.Debug().Msgf("StoreContactDetailsAsContact: no avatar found for uuid: %v", contactDetails.GetAci()) - if existingContact.ContactAvatarHash != "" { - existingContact.ContactAvatarHash = "" + existingContact.ContactAvatar = types.ContactAvatar{ + Image: *avatar, + ContentType: contentType, + Hash: avatarHash, } } @@ -102,19 +86,19 @@ func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.Contact storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) if storeErr != nil { zlog.Err(storeErr).Msg("StoreContactDetailsAsContact: error storing contact") - return *existingContact, nil, storeErr + return existingContact, storeErr } - return *existingContact, contactAvatar, nil + return existingContact, nil } -func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID, fetchProfileAvatar bool) (*types.Contact, *types.ContactAvatar, error) { +func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID) (*types.Contact, error) { ctx := context.TODO() contactChanged := false existingContact, err := cli.Store.ContactStore.LoadContact(ctx, profileUuid) if err != nil { zlog.Err(err).Msg("fetchContactThenTryAndUpdateWithProfile: error loading contact") - return nil, nil, err + return nil, err } if existingContact == nil { zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: creating new contact for uuid: %v", profileUuid) @@ -125,14 +109,7 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID } else { zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: updating existing contact for uuid: %v", profileUuid) } - var profile *Profile - var profileAvatarImage []byte - if fetchProfileAvatar && existingContact.ContactAvatarHash == "" { - // We only care about profile avatar if there is no contact avatar - profile, profileAvatarImage, err = cli.RetrieveProfileAndAvatarByID(ctx, profileUuid) - } else { - profile, err = cli.RetrieveProfileByID(ctx, profileUuid) - } + profile, err := cli.RetrieveProfileByID(ctx, profileUuid) if err != nil { zlog.Err(err).Msgf("fetchContactThenTryAndUpdateWithProfile: error retrieving profile for uuid: %v", profileUuid) //return nil, nil, err @@ -141,40 +118,23 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID if profile != nil { if existingContact.ProfileName != profile.Name { - zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: profile name changed for uuid: %v", profileUuid) existingContact.ProfileName = profile.Name contactChanged = true } if existingContact.ProfileAbout != profile.About { - zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: profile about changed for uuid: %v", profileUuid) existingContact.ProfileAbout = profile.About contactChanged = true } if existingContact.ProfileAboutEmoji != profile.AboutEmoji { - zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: profile about emoji changed for uuid: %v", profileUuid) existingContact.ProfileAboutEmoji = profile.AboutEmoji contactChanged = true } - newProfileKey := profile.Key.Slice() - if !bytes.Equal(existingContact.ProfileKey, newProfileKey) { - zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: profile key changed for uuid: %v", profileUuid) - existingContact.ProfileKey = newProfileKey + if existingContact.ProfileAvatarPath != profile.AvatarPath { + existingContact.ProfileAvatarPath = profile.AvatarPath contactChanged = true } - } - - var profileAvatar *types.ContactAvatar - if len(profileAvatarImage) > 0 { - // Avatar has changed according to profile cache - rawHash := sha256.Sum256(profileAvatarImage) - avatarHash := hex.EncodeToString(rawHash[:]) - if existingContact.ProfileAvatarHash != avatarHash { - profileAvatar = &types.ContactAvatar{ - Image: profileAvatarImage, - ContentType: http.DetectContentType(profileAvatarImage), - Hash: avatarHash, - } - existingContact.ProfileAvatarHash = avatarHash + if existingContact.ProfileKey == nil || *existingContact.ProfileKey != profile.Key { + existingContact.ProfileKey = &profile.Key contactChanged = true } } @@ -185,7 +145,7 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID zlog.Err(storeErr).Msg("fetchContactThenTryAndUpdateWithProfile: error storing contact") } } - return existingContact, profileAvatar, nil + return existingContact, nil } func (cli *Client) UpdateContactE164(uuid uuid.UUID, e164 string) error { @@ -215,18 +175,8 @@ func (cli *Client) UpdateContactE164(uuid uuid.UUID, e164 string) error { return nil } -// ContactAvatar is only populated if there is no contact avatar, and the profile the avatar has changed -// If there is a contact avatar, it will have to have been updated when the contact is sent, we can't fetch on demand -func (cli *Client) ContactByIDWithProfileAvatar(uuid uuid.UUID) (*types.Contact, *types.ContactAvatar, error) { - // Update the profile (we can call this liberally, there's a cache backing it) - // We can just return the result of this, ContactAvatar will be nil if there's no change or if there is a contact avatar - return cli.fetchContactThenTryAndUpdateWithProfile(uuid, true) -} - func (cli *Client) ContactByID(uuid uuid.UUID) (*types.Contact, error) { - // Update the profile (we can call this liberally, there's a cache backing it) - contact, _, err := cli.fetchContactThenTryAndUpdateWithProfile(uuid, false) - return contact, err + return cli.fetchContactThenTryAndUpdateWithProfile(uuid) } func (cli *Client) ContactByE164(e164 string) (*types.Contact, error) { @@ -239,8 +189,7 @@ func (cli *Client) ContactByE164(e164 string) (*types.Contact, error) { if contact == nil { return nil, nil } - // Update profile information (we can call this liberally, there's a cache backing it) - contact, _, err = cli.fetchContactThenTryAndUpdateWithProfile(contact.UUID, false) + contact, err = cli.fetchContactThenTryAndUpdateWithProfile(contact.UUID) return contact, err } diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index a3146a1..6fa73fb 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -27,18 +27,17 @@ type SignalEvent interface { isSignalEvent() } -func (*ChatEvent) isSignalEvent() {} -func (*Receipt) isSignalEvent() {} -func (*ReadSelf) isSignalEvent() {} -func (*Call) isSignalEvent() {} -func (*GroupChange) isSignalEvent() {} -func (*ContactChange) isSignalEvent() {} +func (*ChatEvent) isSignalEvent() {} +func (*Receipt) isSignalEvent() {} +func (*ReadSelf) isSignalEvent() {} +func (*Call) isSignalEvent() {} +func (*ContactList) isSignalEvent() {} type MessageInfo struct { Sender uuid.UUID ChatID string - GroupRevision int + GroupRevision uint32 } type ChatEvent struct { @@ -61,14 +60,6 @@ type Call struct { IsRinging bool } -type GroupChange struct { - SenderID uuid.UUID - Timestamp uint64 - GroupID types.GroupIdentifier - Revision int -} - -type ContactChange struct { - types.Contact - Avatar *types.ContactAvatar +type ContactList struct { + Contacts []*types.Contact } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 9446cdd..826fdc9 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -419,45 +419,39 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier return group, nil } -func (cli *Client) fetchAndDecryptGroupAvatarImage(path string, masterKey types.SerializedGroupMasterKey) ([]byte, error) { - // Fetch avatar +func (cli *Client) DownloadGroupAvatar(ctx context.Context, group *Group) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, Username: &username, Password: &password, } - zlog.Info().Str("avatar_path", path).Msg("Fetching group avatar") - resp, err := web.SendHTTPRequest(http.MethodGet, path, opts) + resp, err := web.SendHTTPRequest(http.MethodGet, group.AvatarPath, opts) if err != nil { - zlog.Err(err).Msg("error fetching group avatar") - return nil, err + return nil, fmt.Errorf("failed to send request: %w", err) } if resp.StatusCode < 200 || resp.StatusCode >= 300 { - err := errors.New(fmt.Sprintf("%v (unsuccessful status code)", resp.Status)) - zlog.Err(err).Msg("bad status fetching group avatar") - return nil, err + return nil, fmt.Errorf("unexpected response status %d", resp.StatusCode) } encryptedAvatar, err := io.ReadAll(resp.Body) if err != nil { - zlog.Err(err).Msg("error reading group avatar") - return nil, err + return nil, fmt.Errorf("failed to read response: %w", err) } - encryptedBytes := encryptedAvatar - - // Decrypt avatar - decryptedBytes, err := decryptGroupAvatar(encryptedBytes, masterKey) - return decryptedBytes, nil + decrypted, err := decryptGroupAvatar(encryptedAvatar, group.groupMasterKey) + if err != nil { + return nil, fmt.Errorf("failed to decrypt avatar: %w", err) + } + return decrypted, nil } -func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentifier) (*Group, error) { +func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentifier, revision uint32) (*Group, error) { cli.initGroupCache() lastFetched, ok := cli.GroupCache.lastFetched[gid] if ok && time.Since(lastFetched) < 1*time.Hour { group, ok := cli.GroupCache.groups[gid] - if ok { + if ok && group.Revision >= revision { return group, nil } } @@ -470,38 +464,6 @@ func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentif return group, nil } -func (cli *Client) RetrieveGroupAndAvatarByID(ctx context.Context, gid types.GroupIdentifier) (*Group, []byte, error) { - group, err := cli.RetrieveGroupByID(ctx, gid) - if err != nil { - return nil, nil, err - } - gid = group.GroupIdentifier - - // If there is an avatarPath, and it's different from the cached one, fetch it - // (we only return the avatar if it's different from the cached one) - var avatarImage []byte - cachedAvatarPath, _ := cli.GroupCache.avatarPaths[gid] - if group.AvatarPath != "" && cachedAvatarPath != group.AvatarPath { - avatarImage, err = cli.fetchAndDecryptGroupAvatarImage(group.AvatarPath, group.groupMasterKey) - if err != nil { - zlog.Err(err).Msg("error fetching group avatarImage") - return nil, nil, err - } - } - cli.GroupCache.avatarPaths[gid] = group.AvatarPath - - return group, avatarImage, nil -} - -func (cli *Client) InvalidateGroupCache(gid types.GroupIdentifier) { - if cli.GroupCache == nil { - return - } - delete(cli.GroupCache.groups, gid) - delete(cli.GroupCache.lastFetched, gid) - // Don't delete avatarPaths, they can stay cached -} - // We should store the group master key in the group store as soon as we see it, // then use the group identifier to refer to groups. As a convenience, we return // the group identifier, which is derived from the group master key. @@ -542,7 +504,6 @@ func (cli *Client) initGroupCache() { cli.GroupCache = &GroupCache{ groups: make(map[types.GroupIdentifier]*Group), lastFetched: make(map[types.GroupIdentifier]time.Time), - avatarPaths: make(map[types.GroupIdentifier]string), activeCalls: make(map[types.GroupIdentifier]string), } } @@ -551,6 +512,5 @@ func (cli *Client) initGroupCache() { type GroupCache struct { groups map[types.GroupIdentifier]*Group lastFetched map[types.GroupIdentifier]time.Time - avatarPaths map[types.GroupIdentifier]string activeCalls map[types.GroupIdentifier]string } diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 713c402..1a28de8 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -37,16 +37,36 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) -type ProfileName struct { - GivenName string - FamilyName *string +type Capabilities struct { + SenderKey bool `json:"senderKey"` + AnnouncementGroup bool `json:"announcementGroup"` + ChangeNumber bool `json:"changeNumber"` + Stories bool `json:"stories"` + GiftBadges bool `json:"giftBadges"` + PaymentActivation bool `json:"paymentActivation"` + PNI bool `json:"pni"` + Gv1Migration bool `json:"gv1-migration"` } type ProfileResponse struct { - Name string - About string - AboutEmoji string - Avatar string + UUID uuid.UUID `json:"uuid"` + + Name []byte `json:"name"` + About []byte `json:"about"` + AboutEmoji []byte `json:"aboutEmoji"` + Avatar string `json:"avatar"` + + Capabilities Capabilities `json:"capabilities"` + + Credential []byte `json:"credential"` + IdentityKey []byte `json:"identityKey"` + UnidentifiedAccess []byte `json:"unidentifiedAccess"` + + UnrestrictedUnidentifiedAccess bool `json:"UnrestrictedUnidentifiedAccess"` + + //Badges []any `json:"badges"` + //PhoneNumberSharing []byte `json:"phoneNumberSharing"` + //PaymentAddress []byte `json:"paymentAddress"` } type Profile struct { @@ -61,7 +81,6 @@ type ProfileCache struct { profiles map[string]*Profile errors map[string]*error lastFetched map[string]time.Time - avatarPaths map[string]string } func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uuid.UUID) ([]byte, error) { @@ -70,10 +89,8 @@ func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uu zlog.Err(err).Msg("ProfileKey error") return nil, err } - serverPublicParams := serverPublicParams() - requestContext, err := libsignalgo.CreateProfileKeyCredentialRequestContext( - serverPublicParams, + serverPublicParams(), signalACI, *profileKey, ) @@ -110,7 +127,6 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) profiles: make(map[string]*Profile), errors: make(map[string]*error), lastFetched: make(map[string]time.Time), - avatarPaths: make(map[string]string), } } @@ -149,28 +165,6 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) return profile, nil } -func (cli *Client) RetrieveProfileAndAvatarByID(ctx context.Context, signalID uuid.UUID) (*Profile, []byte, error) { - profile, err := cli.RetrieveProfileByID(ctx, signalID) - if err != nil { - return nil, nil, err - } - - // If there is an avatarPath, and it's different from the cached one, fetch it - // (we only return the avatar if it's different from the cached one) - var avatarImage []byte - cachedAvatarPath, _ := cli.ProfileCache.avatarPaths[signalID.String()] - if profile.AvatarPath != "" && cachedAvatarPath != profile.AvatarPath { - avatarImage, err = cli.fetchAndDecryptAvatarImage(profile.AvatarPath, &profile.Key) - if err != nil { - zlog.Err(err).Msg("error fetching profile avatarImage") - return nil, nil, err - } - } - cli.ProfileCache.avatarPaths[signalID.String()] = profile.AvatarPath - - return profile, avatarImage, nil -} - func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*Profile, error) { profileKey, err := cli.ProfileKeyForSignalID(ctx, signalID) if err != nil { @@ -231,38 +225,31 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P return nil, err } var profileResponse ProfileResponse - var profile Profile err = json.Unmarshal(resp.Body, &profileResponse) if err != nil { zlog.Err(err).Msg("json.Unmarshal error") return nil, err } - if profileResponse.Name != "" { - base64Name, err := base64.StdEncoding.DecodeString(profileResponse.Name) - decryptedName, err := decryptString(*profileKey, base64Name) + var profile Profile + if len(profileResponse.Name) > 0 { + profile.Name, err = decryptString(profileKey, profileResponse.Name) if err != nil { zlog.Err(err).Msg("error decrypting profile name") } - profile.Name = *decryptedName - // I've seen profile names come in with a null byte instead of a space - // between first and last names, so replace any null bytes with spaces + // TODO store first and last name separately instead of removing the separator profile.Name = strings.Replace(profile.Name, "\x00", " ", -1) } - if profileResponse.About != "" { - base64About, err := base64.StdEncoding.DecodeString(profileResponse.About) - decryptedAbout, err := decryptString(*profileKey, base64About) + if len(profileResponse.About) > 0 { + profile.About, err = decryptString(profileKey, profileResponse.About) if err != nil { zlog.Err(err).Msg("error decrypting profile about") } - profile.About = *decryptedAbout } - if profileResponse.AboutEmoji != "" { - base64AboutEmoji, err := base64.StdEncoding.DecodeString(profileResponse.AboutEmoji) - decryptedAboutEmoji, err := decryptString(*profileKey, base64AboutEmoji) + if len(profileResponse.AboutEmoji) > 0 { + profile.AboutEmoji, err = decryptString(profileKey, profileResponse.AboutEmoji) if err != nil { zlog.Err(err).Msg("error decrypting profile aboutEmoji") } - profile.AboutEmoji = *decryptedAboutEmoji } profile.AvatarPath = profileResponse.Avatar profile.Key = *profileKey @@ -270,45 +257,39 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P return &profile, nil } -func (cli *Client) fetchAndDecryptAvatarImage(avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { +func (cli *Client) DownloadUserAvatar(avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ - Host: web.CDN1Hostname, // I guess don't use CDN2 for profiles? + Host: web.CDN1Hostname, Username: &username, Password: &password, } - zlog.Info().Str("avatar_path", avatarPath).Msg("Fetching profile avatar") resp, err := web.SendHTTPRequest(http.MethodGet, avatarPath, opts) if err != nil { - zlog.Err(err).Msg("error fetching profile avatar") - return nil, err + return nil, fmt.Errorf("failed to send request: %w", err) } + defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { - err := errors.New(fmt.Sprintf("%v (unsuccessful status code)", resp.Status)) - zlog.Err(err).Msg("bad status fetching profile avatar") - return nil, err + return nil, fmt.Errorf("unexpected response status %d", resp.StatusCode) } encryptedAvatar, err := io.ReadAll(resp.Body) if err != nil { - zlog.Err(err).Msg("error reading profile avatar") - return nil, err + return nil, fmt.Errorf("failed to read response body: %w", err) } - avatar, err := decryptBytes(*profileKey, encryptedAvatar) + avatar, err := decryptBytes(profileKey, encryptedAvatar) if err != nil { - zlog.Err(err).Msg("error decrypting profile avatar") - return nil, err + return nil, fmt.Errorf("failed to decrypt response: %w", err) } return avatar, nil } -func decryptBytes(key libsignalgo.ProfileKey, encryptedBytes []byte) ([]byte, error) { - if len(encryptedBytes) < NONCE_LENGTH+16+1 { +func decryptBytes(key *libsignalgo.ProfileKey, encryptedText []byte) ([]byte, error) { + if len(encryptedText) < NONCE_LENGTH+16+1 { return nil, errors.New("invalid encryptedBytes length") } - nonce := encryptedBytes[:NONCE_LENGTH] - ciphertext := encryptedBytes[NONCE_LENGTH:] - keyBytes := key[:] - padded, err := AesgcmDecrypt(keyBytes, nonce, ciphertext, []byte{}) + nonce := encryptedText[:NONCE_LENGTH] + ciphertext := encryptedText[NONCE_LENGTH:] + padded, err := AesgcmDecrypt(key[:], nonce, ciphertext, []byte{}) if err != nil { return nil, err } @@ -324,27 +305,12 @@ func decryptBytes(key libsignalgo.ProfileKey, encryptedBytes []byte) ([]byte, er return returnString, nil } -func decryptString(key libsignalgo.ProfileKey, encryptedText []byte) (*string, error) { - if len(encryptedText) < NONCE_LENGTH+16+1 { - return nil, errors.New("invalid encryptedText length") - } - nonce := encryptedText[:NONCE_LENGTH] - ciphertext := encryptedText[NONCE_LENGTH:] - keyBytes := key[:] - padded, err := AesgcmDecrypt(keyBytes, nonce, ciphertext, []byte{}) +func decryptString(key *libsignalgo.ProfileKey, encryptedText []byte) (string, error) { + data, err := decryptBytes(key, encryptedText) if err != nil { - return nil, err + return "", err } - paddedLength := len(padded) - plaintextLength := 0 - for i := paddedLength - 1; i >= 0; i-- { - if padded[i] != byte(0) { - plaintextLength = i + 1 - break - } - } - returnString := string(padded[:plaintextLength]) - return &returnString, nil + return string(data), nil } func encryptString(key libsignalgo.ProfileKey, plaintext string, paddedLength int) ([]byte, error) { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 80b3d14..7dcb028 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -586,22 +586,22 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. zlog.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") } zlog.Debug().Msgf("Contacts Sync received %v contacts", len(contacts)) + convertedContacts := make([]*types.Contact, 0, len(contacts)) for i, signalContact := range contacts { if signalContact.Aci == nil || *signalContact.Aci == "" { zlog.Info().Msgf("Signal Contact UUID is nil, skipping: %v", signalContact) continue } - contact, contactAvatar, err := cli.StoreContactDetailsAsContact(signalContact, &avatars[i]) + contact, err := cli.StoreContactDetailsAsContact(signalContact, &avatars[i]) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error") continue } - // Model each contact as an incoming contact change message - cli.handleEvent(&events.ContactChange{ - Contact: contact, - Avatar: contactAvatar, - }) + convertedContacts = append(convertedContacts, contact) } + cli.handleEvent(&events.ContactList{ + Contacts: convertedContacts, + }) } } if content.SyncMessage.Read != nil { @@ -731,7 +731,7 @@ func groupOrUserID(groupID types.GroupIdentifier, userID uuid.UUID) string { func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSender, chatRecipient uuid.UUID) bool { // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier - var groupRevision int + var groupRevision uint32 if editMessage.GetDataMessage().GetGroupV2() != nil { // Pull out the master key then store it ASAP - we should pass around GroupIdentifier groupMasterKeyBytes := editMessage.GetDataMessage().GetGroupV2().GetMasterKey() @@ -742,7 +742,7 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp zlog.Err(err).Msg("StoreMasterKey error") return false } - groupRevision = int(editMessage.GetDataMessage().GetGroupV2().GetRevision()) + groupRevision = editMessage.GetDataMessage().GetGroupV2().GetRevision() } cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ @@ -768,7 +768,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier - var groupRevision int + var groupRevision uint32 if dataMessage.GetGroupV2() != nil { // Pull out the master key then store it ASAP - we should pass around GroupIdentifier groupMasterKeyBytes := dataMessage.GetGroupV2().GetMasterKey() @@ -779,33 +779,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp zlog.Err(err).Msg("StoreMasterKey error") return false } - groupRevision = int(dataMessage.GetGroupV2().GetRevision()) - - var groupHasChanged = false - if dataMessage.GetGroupV2().GroupChange != nil { - // TODO: don't parse the change for now, just invalidate our cache - zlog.Debug().Msgf("Invalidating group %v due to change: %v", groupID, dataMessage.GetGroupV2().GroupChange) - cli.InvalidateGroupCache(groupID) - groupHasChanged = true - } else if dataMessage.GetGroupV2().GetRevision() > 0 { - // Compare revision, and if it's newer, invalidate our cache - ourGroup, err := cli.RetrieveGroupByID(ctx, groupID) - if err != nil { - zlog.Err(err).Msg("RetrieveGroupByID error") - } else if dataMessage.GetGroupV2().GetRevision() > ourGroup.Revision { - zlog.Debug().Msgf("Invalidating group %v due to new revision %v > our revision: %v", groupID, dataMessage.GetGroupV2().GetRevision(), ourGroup.Revision) - cli.InvalidateGroupCache(groupID) - groupHasChanged = true - } - } - if groupHasChanged { - cli.handleEvent(&events.GroupChange{ - SenderID: messageSender, - Timestamp: dataMessage.GetTimestamp(), - GroupID: groupID, - Revision: groupRevision, - }) - } + groupRevision = dataMessage.GetGroupV2().GetRevision() } evtInfo := events.MessageInfo{ diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 0b113cc..06cf66e 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -484,7 +484,7 @@ func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { } func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { - group, err := cli.RetrieveGroupByID(ctx, gid) + group, err := cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { return nil, err } diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go index 3b7eb73..1f46513 100644 --- a/pkg/signalmeow/store/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -24,6 +24,7 @@ import ( "github.com/google/uuid" "go.mau.fi/util/dbutil" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -47,6 +48,7 @@ const ( profile_name, profile_about, profile_about_emoji, + profile_avatar_path, profile_avatar_hash FROM signalmeow_contacts ` @@ -64,9 +66,10 @@ const ( profile_name, profile_about, profile_about_emoji, + profile_avatar_path, profile_avatar_hash ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ON CONFLICT (our_aci_uuid, aci_uuid) DO UPDATE SET e164_number = excluded.e164_number, contact_name = excluded.contact_name, @@ -75,21 +78,24 @@ const ( profile_name = excluded.profile_name, profile_about = excluded.profile_about, profile_about_emoji = excluded.profile_about_emoji, + profile_avatar_path = excluded.profile_avatar_path, profile_avatar_hash = excluded.profile_avatar_hash ` ) func scanContact(row dbutil.Scannable) (*types.Contact, error) { var contact types.Contact + var profileKey []byte err := row.Scan( &contact.UUID, &contact.E164, &contact.ContactName, - &contact.ContactAvatarHash, - &contact.ProfileKey, + &contact.ContactAvatar.Hash, + &profileKey, &contact.ProfileName, &contact.ProfileAbout, &contact.ProfileAboutEmoji, + &contact.ProfileAvatarPath, &contact.ProfileAvatarHash, ) if errors.Is(err, sql.ErrNoRows) { @@ -97,6 +103,10 @@ func scanContact(row dbutil.Scannable) (*types.Contact, error) { } else if err != nil { return nil, err } + if len(profileKey) != 0 { + profileKeyConverted := libsignalgo.ProfileKey(profileKey) + contact.ProfileKey = &profileKeyConverted + } return &contact, err } @@ -126,11 +136,12 @@ func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) erro contact.UUID, contact.E164, contact.ContactName, - contact.ContactAvatarHash, - contact.ProfileKey, + contact.ContactAvatar.Hash, + contact.ProfileKey.Slice(), contact.ProfileName, contact.ProfileAbout, contact.ProfileAboutEmoji, + contact.ProfileAvatarPath, contact.ProfileAvatarHash, ) return err diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index ed7c674..857e443 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -78,6 +78,7 @@ CREATE TABLE signalmeow_groups ( CREATE TABLE signalmeow_contacts ( our_aci_uuid TEXT NOT NULL, aci_uuid TEXT NOT NULL, + -- TODO make all fields not null e164_number TEXT, contact_name TEXT, contact_avatar_hash TEXT, @@ -85,6 +86,7 @@ CREATE TABLE signalmeow_contacts ( profile_name TEXT, profile_about TEXT, profile_about_emoji TEXT, + profile_avatar_path TEXT NOT NULL DEFAULT '', profile_avatar_hash TEXT, PRIMARY KEY (our_aci_uuid, aci_uuid), diff --git a/pkg/signalmeow/store/upgrades/06-profile-avatar-path.sql b/pkg/signalmeow/store/upgrades/06-profile-avatar-path.sql new file mode 100644 index 0000000..27fccb2 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/06-profile-avatar-path.sql @@ -0,0 +1,2 @@ +-- v6 (compatible with v5+): Save profile avatar path +ALTER TABLE signalmeow_contacts ADD COLUMN profile_avatar_path TEXT NOT NULL DEFAULT ''; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index 856a0e3..11a73fb 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -18,6 +18,8 @@ package types import ( "github.com/google/uuid" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) // The Contact struct combines information from two sources: @@ -29,11 +31,12 @@ type Contact struct { UUID uuid.UUID E164 string ContactName string - ContactAvatarHash string - ProfileKey []byte + ContactAvatar ContactAvatar + ProfileKey *libsignalgo.ProfileKey ProfileName string ProfileAbout string ProfileAboutEmoji string + ProfileAvatarPath string ProfileAvatarHash string } diff --git a/portal.go b/portal.go index c6cdbd0..587473a 100644 --- a/portal.go +++ b/portal.go @@ -18,8 +18,11 @@ package main import ( "context" + "crypto/sha256" + "encoding/hex" "errors" "fmt" + "net/http" "reflect" "strings" "sync" @@ -93,6 +96,15 @@ func (br *SignalBridge) GetAllPortalsWithMXID() []*Portal { return portals } +func (br *SignalBridge) FindPrivateChatPortalsWith(userID uuid.UUID) []*Portal { + portals, err := br.dbPortalsToPortals(br.DB.Portal.FindPrivateChatsWith(context.TODO(), userID)) + if err != nil { + br.ZLog.Err(err).Msg("Failed to get all DM portals with user") + return nil + } + return portals +} + func (br *SignalBridge) GetAllIPortals() (iportals []bridge.Portal) { portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) if err != nil { @@ -849,8 +861,21 @@ func (portal *Portal) handleSignalMessage(portalMessage portalSignalMessage) { } func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg *signalpb.DataMessage) { - // FIXME hacky - updatePuppetWithSignalContact(context.TODO(), source, sender, nil) + genericCtx := portal.log.With(). + Str("action", "handle signal data message"). + Uint64("msg_ts", msg.GetTimestamp()). + Logger().WithContext(context.TODO()) + // Always update sender info when we receive a message from them, there's caching inside the function + sender.UpdateInfo( + genericCtx, + source, + nil, + ) + // Handle earlier missed group changes here. + // If this message is a group change, don't handle it here, it's handled below. + if msg.GetGroupV2().GetGroupChange() == nil && portal.Revision < msg.GetGroupV2().GetRevision() { + portal.UpdateInfo(genericCtx, source, nil, msg.GetGroupV2().GetRevision()) + } switch { case msgconv.CanConvertSignal(msg): @@ -859,6 +884,8 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg portal.handleSignalReaction(sender, msg.Reaction, msg.GetTimestamp()) case msg.Delete != nil: portal.handleSignalDelete(sender, msg.Delete, msg.GetTimestamp()) + case msg.GetGroupV2().GetGroupChange() != nil: + portal.handleSignalGroupChange(source, sender, msg.GroupV2, msg.GetTimestamp()) case msg.StoryContext != nil, msg.GroupCallUpdate != nil: // ignore default: @@ -870,6 +897,18 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg } } +func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, groupMeta *signalpb.GroupContextV2, ts uint64) { + log := portal.log.With(). + Str("action", "handle signal group change"). + Str("sender_uuid", sender.SignalID.String()). + Uint64("change_ts", ts). + Uint32("new_revision", groupMeta.GetRevision()). + Logger() + ctx := log.WithContext(context.TODO()) + // TODO handle group changes properly + portal.UpdateInfo(ctx, source, nil, groupMeta.GetRevision()) +} + func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataMessage_Reaction, ts uint64) { log := portal.log.With(). Str("action", "handle signal reaction"). @@ -998,13 +1037,10 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet ctx := log.WithContext(context.TODO()) if portal.MXID == "" { log.Debug().Msg("Creating Matrix room from incoming message") - if err := portal.CreateMatrixRoom(ctx, source, nil); err != nil { + if err := portal.CreateMatrixRoom(ctx, source, msg.GetGroupV2().GetRevision()); err != nil { log.Error().Err(err).Msg("Failed to create portal room") return } - // FIXME hacky - ensureGroupPuppetsAreJoinedToPortal(context.TODO(), source, portal) - source.Client.SendContactSyncRequest(context.TODO()) } existingMessage, err := portal.bridge.DB.Message.GetBySignalID(ctx, sender.SignalID, msg.GetTimestamp(), 0, portal.Receiver) @@ -1365,7 +1401,7 @@ func (portal *Portal) ensureUserInvited(ctx context.Context, user *User) bool { return user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) } -func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, meta *any) error { +func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRevision uint32) error { portal.roomCreateLock.Lock() defer portal.roomCreateLock.Unlock() if portal.MXID != "" { @@ -1408,6 +1444,10 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, meta *an } var invite []id.UserID + autoJoinInvites := portal.bridge.SpecVersions.Supports(mautrix.BeeperFeatureAutojoinInvites) + if autoJoinInvites { + invite = append(invite, user.MXID) + } if portal.bridge.Config.Bridge.Encryption.Default { initialState = append(initialState, &event.Event{ @@ -1423,10 +1463,22 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, meta *an } } - // FIXME slightly hacky - user.syncPortalInfo(portal) + var dmPuppet *Puppet + var groupInfo *signalmeow.Group + if portal.IsPrivateChat() { + dmPuppet = portal.GetDMPuppet() + dmPuppet.UpdateInfo(ctx, user, nil) + portal.UpdateDMInfo(ctx, false) + } else { + groupInfo = portal.UpdateGroupInfo(ctx, user, nil, groupRevision, true) + if groupInfo == nil { + portal.log.Error().Msg("Didn't get group info after updating portal") + return errors.New("failed to get group info") + } + invite = append(invite, portal.SyncParticipants(ctx, user, groupInfo)...) + } - resp, err := intent.CreateRoom(ctx, &mautrix.ReqCreateRoom{ + req := &mautrix.ReqCreateRoom{ Visibility: "private", Name: portal.Name, Topic: portal.Topic, @@ -1435,53 +1487,305 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, meta *an IsDirect: portal.IsPrivateChat(), InitialState: initialState, CreationContent: creationContent, - }) + + BeeperAutoJoinInvites: autoJoinInvites, + } + resp, err := intent.CreateRoom(ctx, req) if err != nil { portal.log.Warn().Err(err).Msg("failed to create room") return err } - portal.NameSet = true - //portal.TopicSet = true + portal.NameSet = len(req.Name) > 0 + portal.TopicSet = len(req.Topic) > 0 portal.AvatarSet = !portal.AvatarURL.IsEmpty() portal.MXID = resp.RoomID portal.bridge.portalsLock.Lock() portal.bridge.portalsByMXID[portal.MXID] = portal portal.bridge.portalsLock.Unlock() - err = portal.Update(context.TODO()) + err = portal.Update(ctx) if err != nil { portal.log.Err(err).Msg("Failed to save created portal mxid") } portal.log.Info().Msgf("Created matrix room %s", portal.MXID) - if portal.Encrypted && portal.IsPrivateChat() { - err = portal.bridge.Bot.EnsureJoined(ctx, portal.MXID, appservice.EnsureJoinedParams{BotOverride: portal.MainIntent().Client}) - if err != nil { - portal.log.Error().Err(err).Msg("Failed to ensure bridge bot is joined to private chat portal") - } + inviteMembership := event.MembershipInvite + if autoJoinInvites { + inviteMembership = event.MembershipJoin + } + for _, userID := range invite { + portal.bridge.StateStore.SetMembership(portal.MXID, userID, inviteMembership) + } + if !autoJoinInvites { + if !portal.IsPrivateChat() { + portal.SyncParticipants(ctx, user, groupInfo) + } else if portal.Encrypted { + err = portal.bridge.Bot.EnsureJoined(ctx, portal.MXID, appservice.EnsureJoinedParams{BotOverride: portal.MainIntent().Client}) + if err != nil { + portal.log.Error().Err(err).Msg("Failed to ensure bridge bot is joined to private chat portal") + } + } + user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) } - - user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) user.syncChatDoublePuppetDetails(portal, true) go portal.addToPersonalSpace(portal.log.WithContext(context.TODO()), user) - //portal.syncParticipants(user, channel.Recipients) - if portal.IsPrivateChat() { - portal.log.Debug().Msgf("Portal is private chat, updating direct chats: %s", portal.MXID) - puppet := user.bridge.GetPuppetBySignalID(portal.Receiver) - if puppet == nil { - portal.log.Error().Msgf("Failed to find puppet for portal receiver %s", portal.Receiver) - return nil - } - - chats := map[id.UserID][]id.RoomID{puppet.MXID: {portal.MXID}} - user.UpdateDirectChats(ctx, chats) + user.UpdateDirectChats(ctx, map[id.UserID][]id.RoomID{ + dmPuppet.MXID: {portal.MXID}, + }) } return nil } +func (portal *Portal) GetDMPuppet() *Puppet { + if !portal.IsPrivateChat() { + return nil + } + return portal.bridge.GetPuppetBySignalID(portal.UserID()) +} + +const PrivateChatTopic = "Signal private chat" + +func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *signalmeow.Group, revision uint32) { + if portal.IsPrivateChat() { + portal.UpdateDMInfo(ctx, false) + return + } + groupInfo = portal.UpdateGroupInfo(ctx, source, groupInfo, revision, false) + if groupInfo != nil { + portal.SyncParticipants(ctx, source, groupInfo) + } +} + +func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { + log := zerolog.Ctx(ctx).With(). + Str("function", "UpdateDMInfo"). + Logger() + log.Trace().Msg("Updating portal info") + ctx = log.WithContext(ctx) + puppet := portal.GetDMPuppet() + + update := forceSave + if portal.shouldSetDMRoomMetadata() { + update = portal.updateName(ctx, puppet.Name) || update + update = portal.updateAvatarWithMXC(ctx, puppet.AvatarPath, puppet.AvatarHash, puppet.AvatarURL) || update + } + topic := PrivateChatTopic + if puppet.Number != "" { + topic = fmt.Sprintf("%s with %s", topic, puppet.Number) + } + update = portal.updateTopic(ctx, topic) || update + if update { + err := portal.Update(ctx) + if err != nil { + log.Err(err).Msg("Failed to save portal in database after updatin group info") + } + portal.UpdateBridgeInfo(ctx) + } +} + +func (portal *Portal) UpdateGroupInfo(ctx context.Context, source *User, info *signalmeow.Group, revision uint32, forceFetch bool) *signalmeow.Group { + logWith := zerolog.Ctx(ctx).With(). + Str("function", "UpdateGroupInfo"). + Uint32("revision", revision). + Stringer("source_user_mxid", source.MXID) + if info != nil { + logWith = logWith.Uint32("info_revision", info.Revision) + } + log := logWith.Logger() + if info == nil { + if revision <= portal.Revision && !forceFetch { + log.Debug().Msg("Not fetching group info to update portal: given revision is not newer") + return nil + } + log.Debug().Msg("Fetching group info to update portal") + var err error + info, err = source.Client.RetrieveGroupByID(ctx, portal.GroupID(), revision) + if err != nil { + log.Err(err). + Stringer("source_user_id", source.MXID). + Msg("Failed to fetch group info") + return nil + } + } + if portal.Revision > info.Revision { + log.Debug().Uint32("current_revision", portal.Revision).Msg("Not updating portal with data from older revision") + return info + } + logEvt := log.Trace() + if portal.Revision != info.Revision { + logEvt = log.Debug() + } + logEvt.Uint32("current_revision", portal.Revision).Msg("Updating portal info") + ctx = log.WithContext(ctx) + update := false + if portal.Revision < info.Revision { + portal.Revision = info.Revision + update = true + } + update = portal.updateName(ctx, info.Title) || update + update = portal.updateTopic(ctx, info.Description) || update + update = portal.updateAvatarWithInfo(ctx, source, info) || update + update = portal.updateExpirationTimer(ctx, info.DisappearingMessagesDuration) || update + if update { + err := portal.Update(ctx) + if err != nil { + log.Err(err).Msg("Failed to save portal in database after updatin group info") + } + portal.UpdateBridgeInfo(ctx) + } + return info +} + +func (portal *Portal) updateExpirationTimer(ctx context.Context, newExpirationTimer uint32) bool { + if portal.ExpirationTime == newExpirationTimer { + return false + } + portal.ExpirationTime = newExpirationTimer + if portal.MXID != "" { + msg := portal.MsgConv.ConvertDisappearingTimerChangeToMatrix(ctx, newExpirationTimer, false) + _, err := portal.sendMainIntentMessage(ctx, msg.Content) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to send notice about disappearing message timer changing") + } + } + return true +} + +func (portal *Portal) updateName(ctx context.Context, newName string) bool { + if portal.Name == newName && (portal.NameSet || portal.MXID == "") { + return false + } + portal.Name = newName + portal.NameSet = false + if portal.MXID != "" { + _, err := portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update room name") + } else { + portal.NameSet = true + } + } + return true +} + +func (portal *Portal) updateTopic(ctx context.Context, newTopic string) bool { + if portal.Topic == newTopic && (portal.TopicSet || portal.MXID == "") { + return false + } + portal.Topic = newTopic + portal.TopicSet = false + if portal.MXID != "" { + _, err := portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update room topic") + } else { + portal.TopicSet = true + } + } + return true +} + +func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, group *signalmeow.Group) bool { + // If the avatar path is different, the avatar probably changed + if portal.AvatarPath == group.AvatarPath && + // If the avatar mxc isn't set, we need to reupload it (except if the avatar is unset in Signal) + (!portal.AvatarURL.IsEmpty() || group.AvatarPath == "") && + // If the avatar isn't set in the room, we need to update the room state (except if there's no Matrix room yet) + (portal.AvatarSet || portal.MXID == "") { + return false + } + portal.AvatarPath = group.AvatarPath + portal.AvatarSet = false + portal.AvatarURL = id.ContentURI{} + portal.AvatarHash = "" + if portal.AvatarPath == "" { + // Just clear the Matrix room avatar and return + portal.updateAvatarInRoom(ctx) + return true + } + log := zerolog.Ctx(ctx) + log.Debug().Str("avatar_path", portal.AvatarPath).Msg("Downloading new group avatar from Signal") + avatarBytes, err := source.Client.DownloadGroupAvatar(ctx, group) + if err != nil { + log.Err(err).Msg("Failed to download new avatar for portal") + return true + } + hash := sha256.Sum256(avatarBytes) + newAvatarHash := hex.EncodeToString(hash[:]) + if portal.AvatarHash == newAvatarHash && (portal.AvatarSet || portal.MXID == "") { + // No need to change anything else, but save the new path to the database + return true + } + portal.AvatarHash = newAvatarHash + log.Debug().Str("avatar_hash", portal.AvatarHash).Msg("Uploading new group avatar to Matrix") + resp, err := portal.MainIntent().UploadBytes(ctx, avatarBytes, http.DetectContentType(avatarBytes)) + if err != nil { + log.Err(err).Msg("Failed to upload new avatar for portal") + } else { + portal.AvatarURL = resp.ContentURI + portal.updateAvatarInRoom(ctx) + } + return true +} + +func (portal *Portal) updateAvatarWithMXC(ctx context.Context, newAvatarPath, newAvatarHash string, newAvatarURI id.ContentURI) bool { + if portal.AvatarHash == newAvatarHash && (portal.AvatarSet || portal.MXID == "") { + return false + } + portal.AvatarPath = newAvatarPath + portal.AvatarHash = newAvatarHash + portal.AvatarURL = newAvatarURI + portal.AvatarSet = false + portal.updateAvatarInRoom(ctx) + return true +} + +func (portal *Portal) updateAvatarInRoom(ctx context.Context) { + if portal.MXID == "" || portal.AvatarSet { + return + } + zerolog.Ctx(ctx).Debug(). + Str("avatar_path", portal.AvatarPath). + Str("avatar_hash", portal.AvatarHash). + Stringer("avatar_mxc", portal.AvatarURL). + Msg("Updating avatar in Matrix room") + _, err := portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update room avatar") + } else { + portal.AvatarSet = true + } +} + +func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info *signalmeow.Group) []id.UserID { + log := zerolog.Ctx(ctx) + userIDs := make([]id.UserID, 0, len(info.Members)) + for _, member := range info.Members { + if member.UserID == source.SignalID { + continue + } + puppet := portal.bridge.GetPuppetBySignalID(member.UserID) + if puppet == nil { + log.Warn().Stringer("signal_user_id", member.UserID).Msg("Couldn't get puppet for group member") + continue + } + puppet.UpdateInfo(ctx, source, nil) + intent := puppet.IntentFor(portal) + userIDs = append(userIDs, intent.UserID) + if portal.MXID != "" { + err := intent.EnsureJoined(ctx, portal.MXID) + if err != nil { + log.Err(err).Stringer("signal_user_id", member.UserID).Msg("Failed to ensure user is joined to portal") + } + } + } + // TODO kick extra members on Matrix, handle pending and requesting participants on Signal + return userIDs +} + func (portal *Portal) getBridgeInfoStateKey() string { return fmt.Sprintf("net.maunium.signal://signal/%s", portal.ChatID) } diff --git a/provisioning.go b/provisioning.go index 805c118..11cbe0a 100644 --- a/provisioning.go +++ b/provisioning.go @@ -242,7 +242,7 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { portal := user.GetPortalByChatID(resp.ChatID.UUID) if portal.MXID == "" { - if err := portal.CreateMatrixRoom(r.Context(), user, nil); err != nil { + if err := portal.CreateMatrixRoom(r.Context(), user, 0); err != nil { log.Err(err).Msg("error looking up contact") jsonResponse(w, http.StatusInternalServerError, Error{ Success: false, diff --git a/puppet.go b/puppet.go index 0aafe2d..d824c6b 100644 --- a/puppet.go +++ b/puppet.go @@ -18,108 +18,24 @@ package main import ( "context" + "crypto/sha256" + "encoding/hex" "fmt" + "net/http" "regexp" "sync" "github.com/google/uuid" "github.com/rs/zerolog" + "maunium.net/go/mautrix" "maunium.net/go/mautrix/appservice" "maunium.net/go/mautrix/bridge" "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/database" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -type Puppet struct { - *database.Puppet - - bridge *SignalBridge - log zerolog.Logger - - MXID id.UserID - - customIntent *appservice.IntentAPI - customUser *User - - syncLock sync.Mutex -} - -var userIDRegex *regexp.Regexp - -var ( - _ bridge.Ghost = (*Puppet)(nil) - _ bridge.GhostWithProfile = (*Puppet)(nil) -) - -func (puppet *Puppet) GetMXID() id.UserID { - return puppet.MXID -} - -func (puppet *Puppet) DefaultIntent() *appservice.IntentAPI { - return puppet.bridge.AS.Intent(puppet.MXID) -} - -func (puppet *Puppet) CustomIntent() *appservice.IntentAPI { - if puppet == nil { - return nil - } - return puppet.customIntent -} - -func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI { - if puppet != nil { - if puppet.customIntent == nil || portal.UserID() == puppet.SignalID { - return puppet.DefaultIntent() - } - return puppet.customIntent - } - return nil -} - -func (puppet *Puppet) GetDisplayname() string { - return puppet.Name -} - -func (puppet *Puppet) GetAvatarURL() id.ContentURI { - return puppet.AvatarURL -} - -func (br *SignalBridge) NewPuppet(dbPuppet *database.Puppet) *Puppet { - return &Puppet{ - Puppet: dbPuppet, - bridge: br, - log: br.ZLog.With().Stringer("signal_user_id", dbPuppet.SignalID).Logger(), - - MXID: br.FormatPuppetMXID(dbPuppet.SignalID), - } -} - -func (br *SignalBridge) ParsePuppetMXID(mxid id.UserID) (uuid.UUID, bool) { - if userIDRegex == nil { - pattern := fmt.Sprintf( - "^@%s:%s$", - // The "SignalID" portion of the MXID is a (lowercase) UUID - br.Config.Bridge.FormatUsername("([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"), - br.Config.Homeserver.Domain, - ) - br.ZLog.Debug().Str("pattern", pattern).Msg("Compiling userIDRegex") - - userIDRegex = regexp.MustCompile(pattern) - } - - match := userIDRegex.FindStringSubmatch(string(mxid)) - if len(match) == 2 { - parsed, err := uuid.Parse(match[1]) - if err != nil { - return uuid.Nil, false - } - return parsed, true - } - - return uuid.Nil, false -} - func (br *SignalBridge) GetPuppetByMXID(mxid id.UserID) *Puppet { signalID, ok := br.ParsePuppetMXID(mxid) if !ok { @@ -229,3 +145,252 @@ func (br *SignalBridge) dbPuppetsToPuppets(dbPuppets []*database.Puppet) []*Pupp } return output } + +func (br *SignalBridge) NewPuppet(dbPuppet *database.Puppet) *Puppet { + return &Puppet{ + Puppet: dbPuppet, + bridge: br, + log: br.ZLog.With().Stringer("signal_user_id", dbPuppet.SignalID).Logger(), + + MXID: br.FormatPuppetMXID(dbPuppet.SignalID), + } +} + +func (br *SignalBridge) ParsePuppetMXID(mxid id.UserID) (uuid.UUID, bool) { + if userIDRegex == nil { + pattern := fmt.Sprintf( + "^@%s:%s$", + // The "SignalID" portion of the MXID is a (lowercase) UUID + br.Config.Bridge.FormatUsername("([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"), + br.Config.Homeserver.Domain, + ) + br.ZLog.Debug().Str("pattern", pattern).Msg("Compiling userIDRegex") + + userIDRegex = regexp.MustCompile(pattern) + } + + match := userIDRegex.FindStringSubmatch(string(mxid)) + if len(match) == 2 { + parsed, err := uuid.Parse(match[1]) + if err != nil { + return uuid.Nil, false + } + return parsed, true + } + + return uuid.Nil, false +} + +type Puppet struct { + *database.Puppet + + bridge *SignalBridge + log zerolog.Logger + + MXID id.UserID + + customIntent *appservice.IntentAPI + customUser *User + + syncLock sync.Mutex +} + +var userIDRegex *regexp.Regexp + +var ( + _ bridge.Ghost = (*Puppet)(nil) + _ bridge.GhostWithProfile = (*Puppet)(nil) +) + +func (puppet *Puppet) GetMXID() id.UserID { + return puppet.MXID +} + +func (puppet *Puppet) DefaultIntent() *appservice.IntentAPI { + return puppet.bridge.AS.Intent(puppet.MXID) +} + +func (puppet *Puppet) CustomIntent() *appservice.IntentAPI { + if puppet == nil { + return nil + } + return puppet.customIntent +} + +func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI { + if puppet != nil { + if puppet.customIntent == nil || portal.UserID() == puppet.SignalID { + return puppet.DefaultIntent() + } + return puppet.customIntent + } + return nil +} + +func (puppet *Puppet) GetDisplayname() string { + return puppet.Name +} + +func (puppet *Puppet) GetAvatarURL() id.ContentURI { + return puppet.AvatarURL +} + +func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, info *types.Contact) { + log := zerolog.Ctx(ctx).With(). + Str("function", "Puppet.UpdateInfo"). + Stringer("signal_user_id", puppet.SignalID). + Logger() + ctx = log.WithContext(ctx) + var err error + if info == nil { + log.Debug().Msg("Fetching contact info to update puppet") + info, err = source.Client.ContactByID(puppet.SignalID) + if err != nil { + log.Err(err).Msg("Failed to fetch contact info") + return + } + } + + log.Trace().Msg("Updating puppet info") + + update := false + if puppet.Number != info.E164 { + puppet.Number = info.E164 + update = true + } + update = puppet.updateName(ctx, info) || update + update = puppet.updateAvatar(ctx, source, info) || update + if update { + puppet.ContactInfoSet = false + puppet.UpdateContactInfo(ctx) + err = puppet.Update(ctx) + if err != nil { + log.Err(err).Msg("Failed to save puppet to database after updating") + } + go puppet.updatePortalMeta(ctx) + log.Debug().Msg("Puppet info updated") + } +} +func (puppet *Puppet) UpdateContactInfo(ctx context.Context) { + if !puppet.bridge.SpecVersions.Supports(mautrix.BeeperFeatureArbitraryProfileMeta) || puppet.ContactInfoSet { + return + } + + contactInfo := map[string]any{ + "com.beeper.bridge.identifiers": []string{ + fmt.Sprintf("tel:%s", puppet.Number), + fmt.Sprintf("signal:%s", puppet.SignalID), + }, + "com.beeper.bridge.remote_id": puppet.SignalID.String(), + "com.beeper.bridge.service": "signal", + "com.beeper.bridge.network": "signal", + } + err := puppet.DefaultIntent().BeeperUpdateProfile(ctx, contactInfo) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to store custom contact info in profile") + } else { + puppet.ContactInfoSet = true + } +} + +func (puppet *Puppet) updatePortalMeta(ctx context.Context) { + for _, portal := range puppet.bridge.FindPrivateChatPortalsWith(puppet.SignalID) { + // Get room create lock to prevent races between receiving contact info and room creation. + portal.roomCreateLock.Lock() + portal.UpdateDMInfo(ctx, false) + portal.roomCreateLock.Unlock() + } +} + +func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *types.Contact) bool { + var avatarData []byte + var avatarContentType string + log := zerolog.Ctx(ctx) + if puppet.bridge.Config.Bridge.UseContactAvatars && info.ContactAvatar.Hash != "" { + if puppet.AvatarHash == info.ContactAvatar.Hash && puppet.AvatarSet { + return false + } + avatarData = info.ContactAvatar.Image + avatarContentType = info.ContactAvatar.ContentType + if avatarData == nil { + // TODO what to do? 🤔 + return false + } + puppet.AvatarSet = false + puppet.AvatarPath = "" + } else { + if puppet.AvatarPath == info.ProfileAvatarPath && puppet.AvatarSet { + return false + } + puppet.AvatarPath = info.ProfileAvatarPath + puppet.AvatarHash = "" + puppet.AvatarSet = false + puppet.AvatarURL = id.ContentURI{} + if info.ProfileAvatarPath == "" { + err := puppet.DefaultIntent().SetAvatarURL(ctx, puppet.AvatarURL) + if err != nil { + log.Err(err).Msg("Failed to remove user avatar") + return true + } + log.Debug().Msg("Avatar removed") + puppet.AvatarSet = true + return true + } + var err error + avatarData, err = source.Client.DownloadUserAvatar(info.ProfileAvatarPath, info.ProfileKey) + if err != nil { + log.Err(err). + Str("profile_avatar_path", info.ProfileAvatarPath). + Msg("Failed to download new user avatar") + return true + } + avatarContentType = http.DetectContentType(avatarData) + } + hash := sha256.Sum256(avatarData) + newHash := hex.EncodeToString(hash[:]) + if puppet.AvatarHash == newHash && puppet.AvatarSet { + log.Debug(). + Str("avatar_hash", newHash). + Str("new_avatar_path", puppet.AvatarPath). + Msg("Avatar path changed, but hash didn't") + // Path changed, but actual avatar didn't + return true + } + puppet.AvatarHash = newHash + resp, err := puppet.DefaultIntent().UploadBytes(ctx, avatarData, avatarContentType) + if err != nil { + log.Err(err). + Str("avatar_hash", puppet.AvatarHash). + Msg("Failed to upload new user avatar") + return true + } + puppet.AvatarURL = resp.ContentURI + err = puppet.DefaultIntent().SetAvatarURL(ctx, puppet.AvatarURL) + if err != nil { + log.Err(err).Msg("Failed to update user avatar") + return true + } + log.Debug(). + Str("avatar_hash", newHash). + Stringer("avatar_mxc", resp.ContentURI). + Msg("Avatar updated successfully") + puppet.AvatarSet = true + return true +} + +func (puppet *Puppet) updateName(ctx context.Context, contact *types.Contact) bool { + // TODO set name quality + newName := puppet.bridge.Config.Bridge.FormatDisplayname(contact) + if puppet.NameSet && puppet.Name == newName { + return false + } + puppet.Name = newName + puppet.NameSet = false + err := puppet.DefaultIntent().SetDisplayName(ctx, newName) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update user displayname") + } else { + puppet.NameSet = true + } + return true +} diff --git a/user.go b/user.go index db71fde..d5f916e 100644 --- a/user.go +++ b/user.go @@ -18,8 +18,6 @@ package main import ( "context" - "crypto/sha256" - "encoding/hex" "errors" "net/http" "strings" @@ -41,7 +39,6 @@ import ( "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/types" ) var ( @@ -586,126 +583,6 @@ func (user *User) populateSignalDevice() *signalmeow.Client { return user.Client } -func updatePuppetWithSignalContact(ctx context.Context, user *User, puppet *Puppet, newContactAvatar *types.ContactAvatar) error { - log := user.log.With(). - Str("action", "update puppet with signal contact"). - Str("signal_id", puppet.SignalID.String()). - Logger() - contact, newProfileAvatar, err := user.Client.ContactByIDWithProfileAvatar(puppet.SignalID) - if err != nil { - log.Err(err).Msg("error retrieving contact") - return err - } - - name := user.bridge.Config.Bridge.FormatDisplayname(contact) - if name != puppet.Name { - log.Debug().Str("new_name", name).Msg("updating puppet name") - puppet.Name = name - puppet.NameSet = false - err = puppet.DefaultIntent().SetDisplayName(ctx, name) - if err != nil { - log.Err(err).Msg("error setting display name") - return err - } - puppet.NameSet = true - err = puppet.Update(ctx) - if err != nil { - log.Err(err).Msg("error updating puppet with new name") - return err - } - } - - preferredAvatarHash := contact.ProfileAvatarHash - newAvatar := newProfileAvatar - if user.bridge.Config.Bridge.UseContactAvatars { - if contact.ContactAvatarHash != "" { - preferredAvatarHash = contact.ContactAvatarHash - } - if newContactAvatar != nil { - newAvatar = newContactAvatar - } - } - - if preferredAvatarHash == "" && puppet.AvatarSet { - log.Debug().Msg("clearing avatar") - puppet.AvatarSet = false - puppet.AvatarURL = id.ContentURI{} - puppet.AvatarHash = "" - err = puppet.DefaultIntent().SetAvatarURL(ctx, id.ContentURI{}) - if err != nil { - log.Err(err).Msg("error clearing avatar url") - return err - } - err = puppet.Update(ctx) - if err != nil { - log.Err(err).Msg("error updating puppet while clearing avatar") - return err - } - return nil - } - - // If avatar is set, we must have a new avatar image, so update it - if newAvatar != nil { - log.Debug().Msg("uploading avatar") - avatarURL, err := puppet.DefaultIntent().UploadBytes(ctx, newAvatar.Image, newAvatar.ContentType) - if err != nil { - log.Err(err).Msg("error uploading avatar") - return err - } - puppet.AvatarURL = avatarURL.ContentURI - puppet.AvatarSet = true - puppet.AvatarHash = newAvatar.Hash - - err = puppet.DefaultIntent().SetAvatarURL(ctx, avatarURL.ContentURI) - if err != nil { - log.Err(err).Msg("error setting avatar URL") - return err - } - err = puppet.Update(ctx) - if err != nil { - log.Err(err).Msg("error updating puppet with new avatar") - return err - } - } - return nil -} - -func ensureGroupPuppetsAreJoinedToPortal(ctx context.Context, user *User, portal *Portal) error { - // Ensure our puppet is joined to the room - err := portal.MainIntent().EnsureJoined(ctx, portal.MXID) - if err != nil { - user.log.Err(err).Msg("error ensuring joined") - return err - } - - // Check if ChatID is a groupID (not a UUID), otherwise do nothing else - if portal.IsPrivateChat() { - return nil - } - user.log.Info().Msgf("Ensuring everyone is joined to room %s, groupID: %s", portal.MXID, portal.ChatID) - group, err := user.Client.RetrieveGroupByID(ctx, types.GroupIdentifier(portal.ChatID)) - if err != nil { - user.log.Err(err).Msg("error retrieving group") - return err - } - for _, member := range group.Members { - if member.UserID == user.SignalID { - continue - } - memberPuppet := portal.bridge.GetPuppetBySignalID(member.UserID) - if memberPuppet == nil { - user.log.Err(err).Msgf("no puppet found for signalID %s", member.UserID) - continue - } - _ = updatePuppetWithSignalContact(context.TODO(), user, memberPuppet, nil) - err = memberPuppet.DefaultIntent().EnsureJoined(ctx, portal.MXID) - if err != nil { - user.log.Err(err).Msg("error ensuring joined") - } - } - return nil -} - func (user *User) handleReceipt(evt *events.Receipt) { log := user.log.With(). Str("action", "handle receipt"). @@ -821,103 +698,14 @@ func (user *User) handleReadSelf(evt *events.ReadSelf) { } } -func (user *User) handleContactChange(evt *events.ContactChange) { - puppet := user.bridge.GetPuppetBySignalID(evt.UUID) - if puppet == nil { - return - } - err := updatePuppetWithSignalContact(context.TODO(), user, puppet, evt.Avatar) - if err != nil { - user.log.Err(err).Msg("error updating puppet with signal contact") - } -} - -func (user *User) syncPortalInfo(portal *Portal) { - ctx := context.TODO() - updatePortal := false - if !portal.IsPrivateChat() { - group, avatarImage, err := user.Client.RetrieveGroupAndAvatarByID(ctx, portal.GroupID()) - if err != nil { - user.log.Err(err).Msg("error retrieving group") +func (user *User) handleContactList(evt *events.ContactList) { + ctx := user.log.With().Str("action", "handle contact list").Logger().WithContext(context.TODO()) + for _, contact := range evt.Contacts { + puppet := user.bridge.GetPuppetBySignalID(contact.UUID) + if puppet == nil { return } - if portal.Revision < int(group.Revision) { - portal.Revision = int(group.Revision) - updatePortal = true - } - if portal.Name != group.Title { - portal.Name = group.Title - portal.NameSet = false - updatePortal = true - } - if portal.Topic != group.Description { - portal.Topic = group.Description - updatePortal = true - } - if portal.ExpirationTime != int(group.DisappearingMessagesDuration) { - portal.ExpirationTime = int(group.DisappearingMessagesDuration) - updatePortal = true - portal.log.Debug().Msgf("Updating expiration time to %d (group)", group.DisappearingMessagesDuration) - // TODO send message - //portal.HandleNewDisappearingMessageTime(group.DisappearingMessagesDuration) - } - // avatarImage is only not nil if there's a new avatar to set - if avatarImage != nil { - user.log.Debug().Msg("Uploading new group avatar") - avatarURL, err := portal.MainIntent().UploadBytes(ctx, avatarImage, http.DetectContentType(avatarImage)) - if err != nil { - user.log.Err(err).Msg("error uploading group avatar") - return - } - portal.AvatarURL = avatarURL.ContentURI - portal.AvatarSet = false - hash := sha256.Sum256(avatarImage) - portal.AvatarHash = hex.EncodeToString(hash[:]) - updatePortal = true - } - - if portal.MXID != "" { - // ensure everyone is invited to the group - portal.ensureUserInvited(ctx, user) - _ = ensureGroupPuppetsAreJoinedToPortal(context.TODO(), user, portal) - go portal.addToPersonalSpace(portal.log.WithContext(context.TODO()), user) - } - } else if portal.shouldSetDMRoomMetadata() { - puppet := user.bridge.GetPuppetBySignalID(portal.UserID()) - if puppet.Name != portal.Name { - portal.Name = puppet.Name - portal.NameSet = false - updatePortal = true - } - if puppet.AvatarHash != portal.AvatarHash { - portal.AvatarHash = puppet.AvatarHash - portal.AvatarURL = puppet.AvatarURL - portal.AvatarSet = false - updatePortal = true - } - } - if updatePortal { - if portal.MXID != "" { - _, err := portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) - if err != nil { - user.log.Err(err).Msg("error setting room name") - } - portal.NameSet = err == nil - _, err = portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) - if err != nil { - user.log.Err(err).Msg("error setting room topic") - } - _, err = portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) - if err != nil { - user.log.Err(err).Msg("error setting room avatar") - } - portal.AvatarSet = err == nil - } - err := portal.Update(context.TODO()) - if err != nil { - user.log.Err(err).Msg("error updating portal") - } - portal.UpdateBridgeInfo(ctx) + puppet.UpdateInfo(ctx, user, contact) } } @@ -926,9 +714,6 @@ func (user *User) eventHandler(rawEvt events.SignalEvent) { case *events.ChatEvent: portal := user.GetPortalByChatID(evt.Info.ChatID) if portal != nil { - if portal.Revision < evt.Info.GroupRevision { - user.syncPortalInfo(portal) - } portal.signalMessages <- portalSignalMessage{user: user, evt: evt} } else { user.log.Warn().Str("chat_id", evt.Info.ChatID).Msg("Couldn't get portal, dropping message") @@ -949,13 +734,8 @@ func (user *User) eventHandler(rawEvt events.SignalEvent) { content.Body = "Call ended" } portal.sendMainIntentMessage(context.TODO(), content) - case *events.ContactChange: - user.handleContactChange(evt) - case *events.GroupChange: - portal := user.GetPortalByChatID(evt.GroupID.String()) - if portal != nil { - user.syncPortalInfo(portal) - } + case *events.ContactList: + user.handleContactList(evt) default: user.log.Warn().Type("event_type", evt).Msg("Unrecognized event type from signalmeow") } From 4d1c5628c84ed76908295c409b7e3479b1a5652d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 00:34:50 +0200 Subject: [PATCH 011/718] Ignore read receipts from non-logged-in users The same change also disables implicit read receipts when sending relayed messages Fixes #415 --- portal.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/portal.go b/portal.go index 587473a..d596bb4 100644 --- a/portal.go +++ b/portal.go @@ -1271,6 +1271,9 @@ func (portal *Portal) HandleMatrixReadReceipt(brSender bridge.User, eventID id.E } func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, maxTimestamp uint64, isExplicit bool) { + if sender.IsLoggedIn() { + return + } logWith := portal.log.With(). Str("event_id", eventID.String()). Str("sender", sender.MXID.String()). From 495297944d8d1150c3331c2d254ddeb90f51b80a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 00:36:47 +0200 Subject: [PATCH 012/718] Fix inverted condition --- portal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portal.go b/portal.go index d596bb4..71630fa 100644 --- a/portal.go +++ b/portal.go @@ -1271,7 +1271,7 @@ func (portal *Portal) HandleMatrixReadReceipt(brSender bridge.User, eventID id.E } func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, maxTimestamp uint64, isExplicit bool) { - if sender.IsLoggedIn() { + if !sender.IsLoggedIn() { return } logWith := portal.log.With(). From 3f737a035e72e6bfd07813e95b249555f1c171b4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 00:38:20 +0200 Subject: [PATCH 013/718] Delete disappearing message row if portal doesn't exist --- disappearing.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/disappearing.go b/disappearing.go index 200fb5b..847511b 100644 --- a/disappearing.go +++ b/disappearing.go @@ -100,6 +100,12 @@ func (dmm *DisappearingMessagesManager) redactExpiredMessages(ctx context.Contex portal := dmm.Bridge.GetPortalByMXID(msg.RoomID) if portal == nil { log.Warn().Stringer("event_id", msg.EventID).Stringer("room_id", msg.RoomID).Msg("Failed to redact message: portal not found") + err = msg.Delete(ctx) + if err != nil { + log.Err(err). + Str("event_id", msg.EventID.String()). + Msg("Failed to delete disappearing message row in database") + } continue } _, err = portal.MainIntent().RedactEvent(ctx, msg.RoomID, msg.EventID, mautrix.ReqRedact{ From 9c5b63c13052278c1d4ee3f42a09ba71d842433c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 00:53:24 +0200 Subject: [PATCH 014/718] Update to libsignal 0.38.0 --- pkg/libsignalgo/libsignal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index d47f96a..4a69727 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit d47f96abff97d19a0b125376737655c268dd20b9 +Subproject commit 4a69727457d66f2d8cf1f253d68a2f4b7fed0176 From 5146cb3ddcfbb16aefd2355a9c60e9eb662d61eb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 00:54:15 +0200 Subject: [PATCH 015/718] Use go:embed for server public params --- pkg/signalmeow/groups.go | 4 ++-- pkg/signalmeow/misc.go | 17 +++++++---------- pkg/signalmeow/prod-server-public-params.dat | Bin 0 -> 641 bytes pkg/signalmeow/profile.go | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) create mode 100644 pkg/signalmeow/prod-server-public-params.dat diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 826fdc9..e43be6f 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -156,7 +156,7 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi // Receive the auth credential authCredential, err := libsignalgo.ReceiveAuthCredentialWithPni( - serverPublicParams(), + prodServerPublicParams, cli.Store.ACI, cli.Store.PNI, redemptionTime, @@ -175,7 +175,7 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi } randomness, err := libsignalgo.GenerateRandomness() authCredentialPresentation, err := libsignalgo.CreateAuthCredentialWithPniPresentation( - serverPublicParams(), + prodServerPublicParams, randomness, groupSecretParams, *authCredential, diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 7a073e7..af4def2 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -17,7 +17,7 @@ package signalmeow import ( - "encoding/base64" + _ "embed" "github.com/rs/zerolog" @@ -76,13 +76,10 @@ func setupFFILogging() { } } -func serverPublicParams() libsignalgo.ServerPublicParams { - serverPublicParamsBase64 := "AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P" - serverPublicParamsBytes, err := base64.StdEncoding.DecodeString(serverPublicParamsBase64) - if err != nil { - panic(err) - } - var serverPublicParams libsignalgo.ServerPublicParams - copy(serverPublicParams[:], serverPublicParamsBytes) - return serverPublicParams +//go:embed prod-server-public-params.dat +var prodServerPublicParamsSlice []byte +var prodServerPublicParams libsignalgo.ServerPublicParams + +func init() { + prodServerPublicParams = libsignalgo.ServerPublicParams(prodServerPublicParamsSlice) } diff --git a/pkg/signalmeow/prod-server-public-params.dat b/pkg/signalmeow/prod-server-public-params.dat new file mode 100644 index 0000000000000000000000000000000000000000..bffaafb69f63ec1990647e3554867add48655a69 GIT binary patch literal 641 zcmV-{0)G7f$Y19y6~KhqGRNQj;Ig^aarBVpl1Up^qsX5zxTnl_R;5WuSd6}V{#%KAm}E zFi)FBl7a=gJ+!CzUL}8?)e3RN?w=CBFaX(>Nj-v8M&B3hw&3`E;`s3+AJEq#(?qJx ztToG^-@I8sGUn}l`kd+pKF)Yv!3NCtL|5poK+%*GNZ9FrRKMUHx=TAYoQAwA3dC$6 zDgilPB7U6GrO0v4ExwJ^+lR;+*{%y%{FVtF8YrWXgsFmosnKVdwAC0%0=$y3E_m=M zXa0Oc=vm|ikCU4YHwrPA_9ktBd#`c&DHP@aSFstW7v2V4GT%2(?=IhbC^P5B01z+O z`BzxRIgcYkUW_jhEa#^%T-_b0Dae~ON8L74)xvy9Z9zqTsv%rN&N~tt9rDCo?6?S} zJj#Yfo*#cIDU87NC3uQQWN<93;>}07d&Tk??7e=ObB7J%S2WSdMpH#5N|3_VaS!0X zK{#mRO{&fh_|~R)23R;fcBvULqQnqCo36*8cAXrV?!Xo2fZ!J*;zi1}7W@jsVGlvs zI2<}2KC{0>)f>pyU7XM6G6?t;Zn?xN6V$n*tcdKt@t}5Gch!#@bXU; z`dHQ1c)gL=44w?~LzrVr6BoGcES!tN}YGw4SWVS8(o zF(&}ep^3~piR$2BvgI*)Uro`mBqfQM{xhjTUQIcynj0e+8+$e(0sq=X6hL>SCg0*H bl)6kh+)6wGso&x(C~u|pLimDO=RCJULeD$= literal 0 HcmV?d00001 diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 1a28de8..90e768d 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -90,7 +90,7 @@ func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uu return nil, err } requestContext, err := libsignalgo.CreateProfileKeyCredentialRequestContext( - serverPublicParams(), + prodServerPublicParams, signalACI, *profileKey, ) From 2444eaf39ca42bcd439ed78427b75ddf23341da1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 01:19:53 +0200 Subject: [PATCH 016/718] Fix signalmeow initial schema upgrade --- pkg/signalmeow/store/upgrades/00-latest.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 857e443..73d0270 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v5: Latest revision +-- v0 -> v6: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, From 6a1b2b1df1c95ec4d0aba39cd5396827fffe8fa2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 01:31:00 +0200 Subject: [PATCH 017/718] Include raw URI when using login command --- commands.go | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/commands.go b/commands.go index f859f9c..eca50ea 100644 --- a/commands.go +++ b/commands.go @@ -18,6 +18,7 @@ package main import ( "context" + "fmt" "strings" "github.com/google/uuid" @@ -294,7 +295,7 @@ func fnLogin(ce *WrappedCommandEvent) { // return //} - var qrEventID id.EventID + var qrEventID, msgEventID id.EventID var signalID uuid.UUID var signalPhone string @@ -312,7 +313,7 @@ func fnLogin(ce *WrappedCommandEvent) { return } if resp.State == signalmeow.StateProvisioningURLReceived { - qrEventID = ce.User.sendQR(ce, resp.ProvisioningURL, qrEventID) + qrEventID, msgEventID = ce.User.sendQR(ce, resp.ProvisioningURL, qrEventID, msgEventID) } else { ce.Reply("Unexpected state: %v", resp.State) return @@ -321,6 +322,7 @@ func fnLogin(ce *WrappedCommandEvent) { // Next, get the results of finishing registration resp = <-provChan _, _ = ce.Bot.RedactEvent(ce.Ctx, ce.RoomID, qrEventID) + _, _ = ce.Bot.RedactEvent(ce.Ctx, ce.RoomID, msgEventID) if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { if resp.Err != nil && strings.HasSuffix(resp.Err.Error(), " EOF") { ce.Reply("Logging in timed out, please try again.") @@ -369,26 +371,41 @@ func fnLogin(ce *WrappedCommandEvent) { ce.User.Connect() } -func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevEvent id.EventID) id.EventID { +func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg id.EventID) (qr, msg id.EventID) { url, ok := user.uploadQR(ce, code) if !ok { - return prevEvent + return prevQR, prevMsg } content := event.MessageEventContent{ MsgType: event.MsgImage, - Body: code, + Body: "qr.png", URL: url.CUString(), } - if len(prevEvent) != 0 { - content.SetEdit(prevEvent) + if len(prevQR) != 0 { + content.SetEdit(prevQR) } resp, err := ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) if err != nil { ce.Log.Errorln("Failed to send QR code to user:", err) - } else if len(prevEvent) == 0 { - prevEvent = resp.EventID + } else if len(prevQR) == 0 { + prevQR = resp.EventID } - return prevEvent + content = event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: fmt.Sprintf("Raw linking URI: %s", code), + Format: event.FormatHTML, + FormattedBody: fmt.Sprintf("Raw linking URI: %s", code), + } + if len(prevMsg) != 0 { + content.SetEdit(prevMsg) + } + resp, err = ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) + if err != nil { + ce.Log.Errorln("Failed to send raw code to user:", err) + } else if len(prevMsg) == 0 { + prevMsg = resp.EventID + } + return prevQR, prevMsg } func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (id.ContentURI, bool) { From 2f315f85dd36ca007f340dd4c99a4980d8150a76 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 01:42:35 +0200 Subject: [PATCH 018/718] Fix IsLoggedIn check --- user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user.go b/user.go index d5f916e..1e349b8 100644 --- a/user.go +++ b/user.go @@ -183,7 +183,7 @@ func (user *User) IsLoggedIn() bool { user.Lock() defer user.Unlock() - return user.Client.IsLoggedIn() + return user.Client != nil && user.Client.IsLoggedIn() } func (user *User) GetManagementRoomID() id.RoomID { From 6286fc9bd7316bf2e4aeaa31d10d5c1bdc1c58ec Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 01:46:01 +0200 Subject: [PATCH 019/718] Include info in QR code image event --- commands.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/commands.go b/commands.go index eca50ea..8de4e96 100644 --- a/commands.go +++ b/commands.go @@ -372,15 +372,10 @@ func fnLogin(ce *WrappedCommandEvent) { } func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg id.EventID) (qr, msg id.EventID) { - url, ok := user.uploadQR(ce, code) + content, ok := user.uploadQR(ce, code) if !ok { return prevQR, prevMsg } - content := event.MessageEventContent{ - MsgType: event.MsgImage, - Body: "qr.png", - URL: url.CUString(), - } if len(prevQR) != 0 { content.SetEdit(prevQR) } @@ -408,12 +403,13 @@ func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg i return prevQR, prevMsg } -func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (id.ContentURI, bool) { - qrCode, err := qrcode.Encode(code, qrcode.Low, 256) +func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (event.MessageEventContent, bool) { + const size = 512 + qrCode, err := qrcode.Encode(code, qrcode.Low, size) if err != nil { ce.Log.Errorln("Failed to encode QR code:", err) ce.Reply("Failed to encode QR code: %v", err) - return id.ContentURI{}, false + return event.MessageEventContent{}, false } bot := user.bridge.AS.BotClient() @@ -422,9 +418,19 @@ func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (id.ContentURI, if err != nil { ce.Log.Errorln("Failed to upload QR code:", err) ce.Reply("Failed to upload QR code: %v", err) - return id.ContentURI{}, false + return event.MessageEventContent{}, false } - return resp.ContentURI, true + return event.MessageEventContent{ + MsgType: event.MsgImage, + Info: &event.FileInfo{ + MimeType: "image/png", + Width: size, + Height: size, + Size: len(qrCode), + }, + Body: "qr.png", + URL: resp.ContentURI.CUString(), + }, true } func canDeletePortal(ctx context.Context, portal *Portal, userID id.UserID) bool { From 40ffcd0042d88ea8d911aab601452a21280a8e59 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 17:01:38 +0200 Subject: [PATCH 020/718] Move logged-in checks to event-specific handlers --- commands.go | 4 ++-- messagetracking.go | 1 + portal.go | 27 +++++++++++++-------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/commands.go b/commands.go index 8de4e96..86e1b9b 100644 --- a/commands.go +++ b/commands.go @@ -130,7 +130,7 @@ var cmdDeleteSession = &commands.FullHandler{ } func fnDeleteSession(ce *WrappedCommandEvent) { - if !ce.User.Client.IsLoggedIn() { + if !ce.User.IsLoggedIn() { ce.Reply("You're not logged in") return } @@ -150,7 +150,7 @@ var cmdPing = &commands.FullHandler{ func fnPing(ce *WrappedCommandEvent) { if ce.User.SignalID == uuid.Nil { ce.Reply("You're not logged in") - } else if !ce.User.Client.IsLoggedIn() { + } else if !ce.User.IsLoggedIn() { ce.Reply("You were logged in at some point, but are not anymore") } else if !ce.User.Client.IsConnected() { ce.Reply("You're logged into Signal, but not connected to the server") diff --git a/messagetracking.go b/messagetracking.go index 2e03f3b..bc69415 100644 --- a/messagetracking.go +++ b/messagetracking.go @@ -37,6 +37,7 @@ var ( errDifferentUser = errors.New("user is not the recipient of this private chat portal") errUserNotLoggedIn = errors.New("user is not logged in and chat has no relay bot") errRelaybotNotLoggedIn = errors.New("neither user nor relay bot of chat are logged in") + errCantRelayReactions = errors.New("user is not logged in and reactions can't be relayed") errMNoticeDisabled = errors.New("bridging m.notice messages is disabled") errUnexpectedParsedContentType = errors.New("unexpected parsed content type") diff --git a/portal.go b/portal.go index 71630fa..292305a 100644 --- a/portal.go +++ b/portal.go @@ -343,13 +343,6 @@ func (portal *Portal) messageLoop() { } func (portal *Portal) handleMatrixMessages(msg portalMatrixMessage) { - // If we have no Client, the bridge isn't logged in properly, - // so send BAD_CREDENTIALS so the user knows - if !msg.user.Client.IsLoggedIn() && !portal.HasRelaybot() { - go portal.sendMessageMetrics(context.TODO(), msg.evt, errUserNotLoggedIn, "Ignoring", nil) - msg.user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - return - } log := portal.log.With(). Str("action", "handle matrix event"). Str("event_id", msg.evt.ID.String()). @@ -434,13 +427,12 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt realSenderMXID := sender.MXID isRelay := false if !sender.IsLoggedIn() { - if !portal.HasRelaybot() { - go ms.sendMessageMetrics(evt, errUserNotLoggedIn, "Error converting", true) - return - } sender = portal.GetRelayUser() - if !sender.IsLoggedIn() { - go ms.sendMessageMetrics(evt, errRelaybotNotLoggedIn, "Error converting", true) + if sender == nil { + go ms.sendMessageMetrics(evt, errUserNotLoggedIn, "Ignoring", true) + return + } else if !sender.IsLoggedIn() { + go ms.sendMessageMetrics(evt, errRelaybotNotLoggedIn, "Ignoring", true) return } isRelay = true @@ -531,6 +523,13 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e if !sender.IsLoggedIn() { sender = portal.GetRelayUser() + if sender == nil { + portal.sendMessageStatusCheckpointFailed(ctx, evt, errUserNotLoggedIn) + return + } else if !sender.IsLoggedIn() { + portal.sendMessageStatusCheckpointFailed(ctx, evt, errRelaybotNotLoggedIn) + return + } } if dbMessage != nil { @@ -598,7 +597,7 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, evt *event.Event) { log := zerolog.Ctx(ctx) if !sender.IsLoggedIn() { - log.Error().Msg("Cannot relay reaction from non-logged-in user. Ignoring") + portal.sendMessageStatusCheckpointFailed(ctx, evt, errCantRelayReactions) return } // Find the original signal message based on eventID From 1611ae06ad9dd3a8cc2e1286d1c0aab8a3dec295 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 6 Jan 2024 17:03:06 +0200 Subject: [PATCH 021/718] Fix typo --- database/message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/message.go b/database/message.go index 8a6133b..5184bd8 100644 --- a/database/message.go +++ b/database/message.go @@ -152,7 +152,7 @@ func (mq *MessageQuery) GetManyBySignalID(ctx context.Context, sender uuid.UUID, arguments[i+varargIndex] = timestamp placeholders[i] = fmt.Sprintf("?%d", i+varargIndex+1) } - return mq.QueryMany(ctx, strings.Replace(getManyMessagesBySignalIDQuerySQLite, fmt.Sprintf("?%d", varargIndex+1), strings.Join(placeholders, ", ?"), 1), arguments...) + return mq.QueryMany(ctx, strings.Replace(getManyMessagesBySignalIDQuerySQLite, fmt.Sprintf("?%d", varargIndex+1), strings.Join(placeholders, ", "), 1), arguments...) } } From b3223a86494b508ba36b78f2c64621161fbeabf1 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Tue, 26 Dec 2023 18:30:22 -0700 Subject: [PATCH 022/718] pre-commit: ban Msgf() from zerolog Signed-off-by: Sumner Evans --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d1d5f01..064e948 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,4 +20,5 @@ repos: - repo: https://github.com/beeper/pre-commit-go rev: v0.3.0 hooks: + - id: zerolog-ban-msgf - id: zerolog-use-stringer From b872577982409216da1638e7d7686690e23d42e2 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 09:09:43 -0700 Subject: [PATCH 023/718] portal: use structured logging Signed-off-by: Sumner Evans --- portal.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/portal.go b/portal.go index 292305a..3283402 100644 --- a/portal.go +++ b/portal.go @@ -201,10 +201,15 @@ var signalFormatParams *signalfmt.FormatParams var matrixFormatParams *matrixfmt.HTMLParser func (br *SignalBridge) NewPortal(dbPortal *database.Portal) *Portal { + log := br.ZLog.With().Str("chat_id", dbPortal.ChatID).Logger() + if dbPortal.MXID != "" { + log = log.With().Stringer("room_id", dbPortal.MXID).Logger() + } + portal := &Portal{ Portal: dbPortal, bridge: br, - log: br.ZLog.With().Str("chat_id", dbPortal.ChatID).Logger(), + log: log, signalMessages: make(chan portalSignalMessage, br.Config.Bridge.PortalMessageBuffer), matrixMessages: make(chan portalMatrixMessage, br.Config.Bridge.PortalMessageBuffer), @@ -618,7 +623,7 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) if err != nil { portal.sendMessageStatusCheckpointFailed(ctx, evt, err) - portal.log.Error().Msgf("Failed to send reaction %s", evt.ID) + log.Error().Msg("Failed to send reaction") return } @@ -714,7 +719,7 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte } else if len(result.SuccessfullySentTo) < totalRecipients { log.Warn().Msg("Only sent event to some members of Signal group") } else { - log.Debug().Msgf("Sent event to all members of Signal group") + log.Debug().Msg("Sent event to all members of Signal group") } } return err @@ -1245,7 +1250,7 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { // require SenderKey sending to not be terrible if portal.IsPrivateChat() { // this is a 1:1 chat - portal.log.Debug().Msgf("Sending Typing event to Signal %s", portal.ChatID) + portal.log.Debug().Msg("Sending Typing event to Signal") ctx := context.TODO() typingMessage := signalmeow.TypingMessage(isTyping) result := user.Client.SendMessage(ctx, portal.UserID(), typingMessage) @@ -1497,6 +1502,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev portal.log.Warn().Err(err).Msg("failed to create room") return err } + portal.log = portal.log.With().Stringer("room_id", resp.RoomID).Logger() portal.NameSet = len(req.Name) > 0 portal.TopicSet = len(req.Topic) > 0 @@ -1507,9 +1513,10 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev portal.bridge.portalsLock.Unlock() err = portal.Update(ctx) if err != nil { - portal.log.Err(err).Msg("Failed to save created portal mxid") + portal.log.Err(err).Msg("Failed to save portal room ID") + return err } - portal.log.Info().Msgf("Created matrix room %s", portal.MXID) + portal.log.Info().Msg("Created matrix room for portal") inviteMembership := event.MembershipInvite if autoJoinInvites { From e874d19390c7a805142f94697cce79b2310401ff Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 09:26:52 -0700 Subject: [PATCH 024/718] signalmeow/contact: use contexts and structured logging Signed-off-by: Sumner Evans --- commands.go | 2 +- pkg/signalmeow/contact.go | 87 ++++++++++++++++++++----------------- pkg/signalmeow/receiving.go | 7 ++- provisioning.go | 12 ++--- puppet.go | 2 +- 5 files changed, 61 insertions(+), 49 deletions(-) diff --git a/commands.go b/commands.go index 86e1b9b..bc11ca9 100644 --- a/commands.go +++ b/commands.go @@ -204,7 +204,7 @@ func fnPM(ce *WrappedCommandEvent) { user := ce.User number := strings.Join(ce.Args, "") - contact, err := user.Client.ContactByE164(number) + contact, err := user.Client.ContactByE164(ce.Ctx, number) if err != nil { ce.Reply("Error looking up number in local contact list: %v", err) return diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index f45f3e0..5ec22c3 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -27,6 +27,7 @@ import ( "strings" "github.com/google/uuid" + "github.com/rs/zerolog" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -34,24 +35,27 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.ContactDetails, avatar *[]byte) (*types.Contact, error) { - ctx := context.TODO() +func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDetails *signalpb.ContactDetails, avatar *[]byte) (*types.Contact, error) { parsedUUID, err := uuid.Parse(contactDetails.GetAci()) if err != nil { return nil, err } + log := zerolog.Ctx(ctx).With(). + Str("action", "store contact details as contact"). + Str("uuid", parsedUUID.String()). + Logger() existingContact, err := cli.Store.ContactStore.LoadContact(ctx, parsedUUID) if err != nil { - zlog.Err(err).Msg("StoreContactDetailsAsContact error loading contact") + log.Err(err).Msg("error loading contact") return nil, err } if existingContact == nil { - zlog.Debug().Msgf("StoreContactDetailsAsContact: creating new contact for uuid: %v", parsedUUID) + log.Debug().Msg("creating new contact") existingContact = &types.Contact{ UUID: parsedUUID, } } else { - zlog.Debug().Msgf("StoreContactDetailsAsContact: updating existing contact for uuid: %v", parsedUUID) + log.Debug().Msg("updating existing contact") } existingContact.E164 = contactDetails.GetNumber() @@ -61,7 +65,7 @@ func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.Contact existingContact.ProfileKey = &profileKey err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, existingContact.UUID, profileKey) if err != nil { - zlog.Err(err).Msg("StoreContactDetailsAsContact error storing profile key") + log.Err(err).Msg("storing profile key") //return *existingContact, nil, err } } @@ -82,36 +86,39 @@ func (cli *Client) StoreContactDetailsAsContact(contactDetails *signalpb.Contact } } - zlog.Debug().Msgf("StoreContactDetailsAsContact: storing contact for uuid: %v", contactDetails.GetAci()) + log.Debug().Msg("storing contact") storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) if storeErr != nil { - zlog.Err(storeErr).Msg("StoreContactDetailsAsContact: error storing contact") + log.Err(storeErr).Msg("error storing contact") return existingContact, storeErr } return existingContact, nil } -func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID) (*types.Contact, error) { - ctx := context.TODO() +func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, profileUUID uuid.UUID) (*types.Contact, error) { + log := zerolog.Ctx(ctx).With(). + Str("action", "fetch contact then try and update with profile"). + Stringer("profile_uuid", profileUUID). + Logger() contactChanged := false - existingContact, err := cli.Store.ContactStore.LoadContact(ctx, profileUuid) + existingContact, err := cli.Store.ContactStore.LoadContact(ctx, profileUUID) if err != nil { - zlog.Err(err).Msg("fetchContactThenTryAndUpdateWithProfile: error loading contact") + log.Err(err).Msg("error loading contact") return nil, err } if existingContact == nil { - zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: creating new contact for uuid: %v", profileUuid) + log.Debug().Msg("creating new contact") existingContact = &types.Contact{ - UUID: profileUuid, + UUID: profileUUID, } contactChanged = true } else { - zlog.Debug().Msgf("fetchContactThenTryAndUpdateWithProfile: updating existing contact for uuid: %v", profileUuid) + log.Debug().Msg("updating existing contact") } - profile, err := cli.RetrieveProfileByID(ctx, profileUuid) + profile, err := cli.RetrieveProfileByID(ctx, profileUUID) if err != nil { - zlog.Err(err).Msgf("fetchContactThenTryAndUpdateWithProfile: error retrieving profile for uuid: %v", profileUuid) + log.Err(err).Msg("error retrieving profile") //return nil, nil, err // Don't return here, we still want to return what we have } @@ -140,56 +147,56 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(profileUuid uuid.UUID } if contactChanged { - storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) - if storeErr != nil { - zlog.Err(storeErr).Msg("fetchContactThenTryAndUpdateWithProfile: error storing contact") + err := cli.Store.ContactStore.StoreContact(ctx, *existingContact) + if err != nil { + log.Err(err).Msg("error storing contact") + return nil, err } } return existingContact, nil } -func (cli *Client) UpdateContactE164(uuid uuid.UUID, e164 string) error { - ctx := context.TODO() +func (cli *Client) UpdateContactE164(ctx context.Context, uuid uuid.UUID, e164 string) error { + log := zerolog.Ctx(ctx).With(). + Str("action", "update contact e164"). + Stringer("uuid", uuid). + Str("e164", e164). + Logger() existingContact, err := cli.Store.ContactStore.LoadContact(ctx, uuid) if err != nil { - zlog.Err(err).Msg("UpdateContactE164: error loading contact") + log.Err(err).Msg("error loading contact") return err } if existingContact == nil { - zlog.Debug().Msgf("UpdateContactE164: creating new contact for uuid: %v", uuid) + log.Debug().Msg("creating new contact") existingContact = &types.Contact{ UUID: uuid, } } else { - zlog.Debug().Msgf("UpdateContactE164: found existing contact for uuid: %v", uuid) + log.Debug().Msg("found existing contact") } - if existingContact.E164 != e164 { - zlog.Debug().Msgf("UpdateContactE164: e164 changed for uuid: %v", uuid) - existingContact.E164 = e164 - storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) - if storeErr != nil { - zlog.Err(storeErr).Msg("UpdateContactE164: error storing contact") - return storeErr - } + if existingContact.E164 == e164 { + return nil } - return nil + log.Debug().Msg("e164 changed for contact") + existingContact.E164 = e164 + return cli.Store.ContactStore.StoreContact(ctx, *existingContact) } -func (cli *Client) ContactByID(uuid uuid.UUID) (*types.Contact, error) { - return cli.fetchContactThenTryAndUpdateWithProfile(uuid) +func (cli *Client) ContactByID(ctx context.Context, uuid uuid.UUID) (*types.Contact, error) { + return cli.fetchContactThenTryAndUpdateWithProfile(ctx, uuid) } -func (cli *Client) ContactByE164(e164 string) (*types.Contact, error) { - ctx := context.TODO() +func (cli *Client) ContactByE164(ctx context.Context, e164 string) (*types.Contact, error) { contact, err := cli.Store.ContactStore.LoadContactByE164(ctx, e164) if err != nil { - zlog.Err(err).Msg("ContactByE164 error loading contact") + zerolog.Ctx(ctx).Err(err).Msg("ContactByE164 error loading contact") return nil, err } if contact == nil { return nil, nil } - contact, err = cli.fetchContactThenTryAndUpdateWithProfile(contact.UUID) + contact, err = cli.fetchContactThenTryAndUpdateWithProfile(ctx, contact.UUID) return contact, err } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 7dcb028..dfd14f5 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -312,7 +312,10 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } zlog.Trace().Msgf("SealedSender senderUUID: %v, senderDeviceID: %v", senderUUID, senderDeviceID) - cli.UpdateContactE164(senderUUID, senderE164) + err = cli.UpdateContactE164(ctx, senderUUID, senderE164) + if err != nil { + zlog.Err(err).Msg("UpdateContactE164 error") + } switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: @@ -592,7 +595,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. zlog.Info().Msgf("Signal Contact UUID is nil, skipping: %v", signalContact) continue } - contact, err := cli.StoreContactDetailsAsContact(signalContact, &avatars[i]) + contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) if err != nil { zlog.Err(err).Msg("StoreContactDetailsAsContact error") continue diff --git a/provisioning.go b/provisioning.go index 11cbe0a..bb7755f 100644 --- a/provisioning.go +++ b/provisioning.go @@ -146,14 +146,14 @@ type ResolveIdentifierResponseOtherUser struct { AvatarURL string `json:"avatar_url"` } -func (prov *ProvisioningAPI) resolveIdentifier(user *User, phoneNum string) (int, *ResolveIdentifierResponse, error) { +func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, phoneNum string) (int, *ResolveIdentifierResponse, error) { if !strings.HasPrefix(phoneNum, "+") { phoneNum = "+" + phoneNum } if user.Client == nil { - return http.StatusUnauthorized, nil, fmt.Errorf("Not currently connected to Signal") + return http.StatusUnauthorized, nil, errors.New("not currently connected to Signal") } - contact, err := user.Client.ContactByE164(phoneNum) + contact, err := user.Client.ContactByE164(ctx, phoneNum) if err != nil { return http.StatusInternalServerError, nil, fmt.Errorf("Error looking up number in local contact list: %w", err) } @@ -187,9 +187,10 @@ func (prov *ProvisioningAPI) ResolveIdentifier(w http.ResponseWriter, r *http.Re Str("user_id", user.MXID.String()). Str("phone_num", phoneNum). Logger() + ctx := log.WithContext(r.Context()) log.Debug().Msg("resolving identifier") - status, resp, err := prov.resolveIdentifier(user, phoneNum) + status, resp, err := prov.resolveIdentifier(ctx, user, phoneNum) if err != nil { errCode := "M_INTERNAL" if status == http.StatusNotFound { @@ -221,9 +222,10 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { Str("user_id", user.MXID.String()). Str("phone_num", phoneNum). Logger() + ctx := log.WithContext(r.Context()) log.Debug().Msg("starting private message") - status, resp, err := prov.resolveIdentifier(user, phoneNum) + status, resp, err := prov.resolveIdentifier(ctx, user, phoneNum) if err != nil { errCode := "M_INTERNAL" if status == http.StatusNotFound { diff --git a/puppet.go b/puppet.go index d824c6b..c2d2584 100644 --- a/puppet.go +++ b/puppet.go @@ -244,7 +244,7 @@ func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, info *types. var err error if info == nil { log.Debug().Msg("Fetching contact info to update puppet") - info, err = source.Client.ContactByID(puppet.SignalID) + info, err = source.Client.ContactByID(ctx, puppet.SignalID) if err != nil { log.Err(err).Msg("Failed to fetch contact info") return From 4828f643de817e72d7584186eb3f3cf62e65b3c5 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 10:01:15 -0700 Subject: [PATCH 025/718] signalmeow/receiving: use structured logging Signed-off-by: Sumner Evans --- pkg/signalmeow/receiving.go | 206 +++++++++++++++++++++--------------- pkg/signalmeow/sending.go | 2 +- 2 files changed, 120 insertions(+), 88 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index dfd14f5..ac92e06 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -25,6 +25,7 @@ import ( "time" "github.com/google/uuid" + "github.com/rs/zerolog" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -67,20 +68,21 @@ type SignalConnectionStatus struct { } func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnectionStatus, error) { - ctx, cancel := context.WithCancel(ctx) + log := zerolog.Ctx(ctx).With().Str("action", "start receive loops").Logger() + ctx, cancel := context.WithCancel(log.WithContext(ctx)) cli.WSCancel = cancel authChan, err := cli.ConnectAuthedWS(ctx, cli.incomingRequestHandler) if err != nil { cancel() return nil, err } - zlog.Info().Msg("Authed websocket connecting") + log.Info().Msg("Authed websocket connecting") unauthChan, err := cli.ConnectUnauthedWS(ctx) if err != nil { cancel() return nil, err } - zlog.Info().Msg("Unauthed websocket connecting") + log.Info().Msg("Unauthed websocket connecting") statusChan := make(chan SignalConnectionStatus, 10000) initialConnectChan := make(chan struct{}) @@ -94,7 +96,7 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection for { select { case <-ctx.Done(): - zlog.Info().Msg("Context done, exiting websocket status loop") + log.Info().Msg("Context done, exiting websocket status loop") return case status := <-authChan: lastAuthStatus = status @@ -104,17 +106,17 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection case web.SignalWebsocketConnectionEventConnecting: // do nothing? case web.SignalWebsocketConnectionEventConnected: - zlog.Info().Msg("Authed websocket connected") + log.Info().Msg("Authed websocket connected") case web.SignalWebsocketConnectionEventDisconnected: - zlog.Err(status.Err).Msg("Authed websocket disconnected") + log.Err(status.Err).Msg("Authed websocket disconnected") case web.SignalWebsocketConnectionEventLoggedOut: - zlog.Err(status.Err).Msg("Authed websocket logged out") + log.Err(status.Err).Msg("Authed websocket logged out") // TODO: Also make sure unauthed websocket is disconnected //StopReceiveLoops(d) case web.SignalWebsocketConnectionEventError: - zlog.Err(status.Err).Msg("Authed websocket error") + log.Err(status.Err).Msg("Authed websocket error") case web.SignalWebsocketConnectionEventCleanShutdown: - zlog.Info().Msg("Authed websocket clean shutdown") + log.Info().Msg("Authed websocket clean shutdown") } case status := <-unauthChan: lastUnauthStatus = status @@ -124,16 +126,19 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection case web.SignalWebsocketConnectionEventConnecting: // do nothing? case web.SignalWebsocketConnectionEventConnected: - zlog.Info().Msg("Unauthed websocket connected") - zlog.Info().Msgf("lastUnauthStatus: %v, lastAuthStatus: %v, currentStatus: %v", lastUnauthStatus, lastAuthStatus, currentStatus) + log.Info(). + Any("last_unauth_status", lastUnauthStatus). + Any("last_auth_status", lastAuthStatus). + Any("current_status", currentStatus). + Msg("Unauthed websocket connected") case web.SignalWebsocketConnectionEventDisconnected: - zlog.Err(status.Err).Msg("Unauthed websocket disconnected") + log.Err(status.Err).Msg("Unauthed websocket disconnected") case web.SignalWebsocketConnectionEventLoggedOut: - zlog.Err(status.Err).Msg("Unauthed websocket logged out ** THIS SHOULD BE IMPOSSIBLE **") + log.Err(status.Err).Msg("Unauthed websocket logged out ** THIS SHOULD BE IMPOSSIBLE **") case web.SignalWebsocketConnectionEventError: - zlog.Err(status.Err).Msg("Unauthed websocket error") + log.Err(status.Err).Msg("Unauthed websocket error") case web.SignalWebsocketConnectionEventCleanShutdown: - zlog.Info().Msg("Unauthed websocket clean shutdown") + log.Info().Msg("Unauthed websocket clean shutdown") } } @@ -167,7 +172,7 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection } } if statusToSend.Event != 0 && statusToSend.Event != lastSentStatus.Event { - zlog.Info().Msgf("Sending connection status: %v", statusToSend) + log.Info().Any("status_to_send", statusToSend).Msg("Sending connection status") statusChan <- statusToSend lastSentStatus = statusToSend } @@ -181,7 +186,7 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection case <-ctx.Done(): return case <-initialConnectChan: - zlog.Info().Msg("Both websockets connected, sending contacts sync request") + log.Info().Msg("Both websockets connected, sending contacts sync request") // TODO hacky cli.SendContactSyncRequest(ctx) return @@ -244,31 +249,39 @@ func (cli *Client) checkDecryptionErrorAndDisconnect(err error) { } func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { + log := zerolog.Ctx(ctx).With(). + Str("handler", "incoming request handler"). + Str("verb", *req.Verb). + Str("path", *req.Path). + Logger() + ctx = log.WithContext(ctx) if *req.Verb == http.MethodPut && *req.Path == "/api/v1/message" { return cli.incomingAPIMessageHandler(ctx, req) } else if *req.Verb == http.MethodPut && *req.Path == "/api/v1/queue/empty" { - zlog.Trace().Msgf("Received queue empty. verb: %v, path: %v", *req.Verb, *req.Path) + log.Trace().Msg("Received queue empty") } else { - zlog.Warn().Msgf("######## Don't know what I received ########## req: %v", req) + log.Warn().Any("req", req).Msg("Unknown websocket request message") } return &web.SimpleResponse{ Status: 200, }, nil } +// TODO: we should split this up into multiple functions func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { + log := zerolog.Ctx(ctx).With().Str("handler_type", "incoming API message handler").Logger() responseCode := 200 envelope := &signalpb.Envelope{} err := proto.Unmarshal(req.Body, envelope) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") return nil, err } var result *DecryptionResult switch *envelope.Type { case signalpb.Envelope_UNIDENTIFIED_SENDER: - zlog.Trace().Msgf("Received envelope type UNIDENTIFIED_SENDER, verb: %v, path: %v", *req.Verb, *req.Path) + log.Trace().Msg("Received envelope type UNIDENTIFIED_SENDER") usmc, err := libsignalgo.SealedSenderDecryptToUSMC( ctx, envelope.GetContent(), @@ -278,48 +291,54 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if err == nil { err = fmt.Errorf("usmc is nil") } - zlog.Err(err).Msg("SealedSenderDecryptToUSMC error") + log.Err(err).Msg("SealedSenderDecryptToUSMC error") return nil, err } messageType, err := usmc.GetMessageType() if err != nil { - zlog.Err(err).Msg("GetMessageType error") + log.Err(err).Msg("GetMessageType error") } senderCertificate, err := usmc.GetSenderCertificate() if err != nil { - zlog.Err(err).Msg("GetSenderCertificate error") + log.Err(err).Msg("GetSenderCertificate error") } senderUUID, err := senderCertificate.GetSenderUUID() if err != nil { - zlog.Err(err).Msg("GetSenderUUID error") + log.Err(err).Msg("GetSenderUUID error") } senderDeviceID, err := senderCertificate.GetDeviceID() if err != nil { - zlog.Err(err).Msg("GetDeviceID error") + log.Err(err).Msg("GetDeviceID error") } senderAddress, err := libsignalgo.NewUUIDAddress(senderUUID, uint(senderDeviceID)) if err != nil { - zlog.Err(err).Msg("NewAddress error") + log.Err(err).Msg("NewAddress error") } senderE164, err := senderCertificate.GetSenderE164() if err != nil { - zlog.Err(err).Msg("GetSenderE164 error") + log.Err(err).Msg("GetSenderE164 error") } usmcContents, err := usmc.GetContents() if err != nil { - zlog.Err(err).Msg("GetContents error") + log.Err(err).Msg("GetContents error") } - zlog.Trace().Msgf("SealedSender senderUUID: %v, senderDeviceID: %v", senderUUID, senderDeviceID) + log = log.With(). + Str("sender_uuid", senderUUID.String()). + Uint32("sender_device_id", senderDeviceID). + Str("sender_e164", senderE164). + Logger() + ctx = log.WithContext(ctx) + log.Trace().Msg("Received SealedSender message") err = cli.UpdateContactE164(ctx, senderUUID, senderE164) if err != nil { - zlog.Err(err).Msg("UpdateContactE164 error") + log.Err(err).Msg("UpdateContactE164 error") } switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: - zlog.Trace().Msg("SealedSender messageType is CiphertextMessageTypeSenderKey ") + log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeSenderKey") decryptedText, err := libsignalgo.GroupDecrypt( ctx, usmcContents, @@ -328,9 +347,9 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { - zlog.Warn().Msg("Duplicate message, ignoring") + log.Warn().Msg("Duplicate message, ignoring") } else { - zlog.Err(err).Msg("GroupDecrypt error") + log.Err(err).Msg("GroupDecrypt error") } } else { err = stripPadding(&decryptedText) @@ -340,7 +359,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. content := signalpb.Content{} err = proto.Unmarshal(decryptedText, &content) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") } result = &DecryptionResult{ SenderAddress: senderAddress, @@ -350,17 +369,17 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case libsignalgo.CiphertextMessageTypePreKey: - zlog.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") + log.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") result, err = cli.prekeyDecrypt(ctx, senderAddress, usmcContents) if err != nil { - zlog.Err(err).Msg("prekeyDecrypt error") + log.Err(err).Msg("prekeyDecrypt error") } case libsignalgo.CiphertextMessageTypeWhisper: - zlog.Trace().Msg("SealedSender messageType is CiphertextMessageTypeWhisper") + log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeWhisper") message, err := libsignalgo.DeserializeMessage(usmcContents) if err != nil { - zlog.Err(err).Msg("DeserializeMessage error") + log.Err(err).Msg("DeserializeMessage error") } decryptedText, err := libsignalgo.Decrypt( ctx, @@ -370,7 +389,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. cli.Store.IdentityStore, ) if err != nil { - zlog.Err(err).Msg("Sealed sender Whisper Decryption error") + log.Err(err).Msg("Sealed sender Whisper Decryption error") } else { err = stripPadding(&decryptedText) if err != nil { @@ -379,7 +398,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. content := signalpb.Content{} err = proto.Unmarshal(decryptedText, &content) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") } result = &DecryptionResult{ SenderAddress: senderAddress, @@ -389,22 +408,22 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case libsignalgo.CiphertextMessageTypePlaintext: - zlog.Debug().Msg("SealedSender messageType is CiphertextMessageTypePlaintext") + log.Debug().Msg("SealedSender messageType is CiphertextMessageTypePlaintext") // TODO: handle plaintext (usually DecryptionErrorMessage) and retries // when implementing SenderKey groups //plaintextContent, err := libsignalgo.DeserializePlaintextContent(usmcContents) //if err != nil { - // zlog.Err(err).Msg("DeserializePlaintextContent error") + // log.Err(err).Msg("DeserializePlaintextContent error") //} //body, err := plaintextContent.GetBody() //if err != nil { - // zlog.Err(err).Msg("PlaintextContent GetBody error") + // log.Err(err).Msg("PlaintextContent GetBody error") //} //content := signalpb.Content{} //err = proto.Unmarshal(body, &content) //if err != nil { - // zlog.Err(err).Msg("PlaintextContent Unmarshal error") + // log.Err(err).Msg("PlaintextContent Unmarshal error") //} //result = &DecryptionResult{ // SenderAddress: *senderAddress, @@ -417,28 +436,31 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. }, nil default: - zlog.Warn().Msg("SealedSender messageType is unknown") + log.Warn().Msg("SealedSender messageType is unknown") } // If we couldn't decrypt with specific decryption methods, try sealedSenderDecrypt if result == nil || responseCode != 200 { - zlog.Debug().Msg("Didn't decrypt with specific methods, trying sealedSenderDecrypt") + log.Debug().Msg("Didn't decrypt with specific methods, trying sealedSenderDecrypt") var err error result, err = cli.sealedSenderDecrypt(ctx, envelope) if err != nil { if strings.Contains(err.Error(), "self send of a sealed sender message") { - zlog.Debug().Msg("Message sent by us, ignoring") + log.Debug().Msg("Message sent by us, ignoring") } else { - zlog.Err(err).Msg("sealedSenderDecrypt error") + log.Err(err).Msg("sealedSenderDecrypt error") cli.checkDecryptionErrorAndDisconnect(err) } } else { - zlog.Trace().Msgf("SealedSender decrypt result - address: %v, content: %v", result.SenderAddress, result.Content) + log.Trace(). + Any("sender_address", result.SenderAddress). + Any("content", result.Content). + Msg("SealedSender decrypt result") } } case signalpb.Envelope_PREKEY_BUNDLE: - zlog.Debug().Msgf("Received envelope type PREKEY_BUNDLE, verb: %v, path: %v", *req.Verb, *req.Path) + log.Debug().Msg("Received envelope type PREKEY_BUNDLE") sender, err := libsignalgo.NewUUIDAddressFromString( *envelope.SourceServiceId, uint(*envelope.SourceDevice), @@ -448,27 +470,30 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } result, err = cli.prekeyDecrypt(ctx, sender, envelope.Content) if err != nil { - zlog.Err(err).Msg("prekeyDecrypt error") + log.Err(err).Msg("prekeyDecrypt error") cli.checkDecryptionErrorAndDisconnect(err) } else { - zlog.Trace().Msgf("prekey decrypt result - address: %v, data: %v", result.SenderAddress, result.Content) + log.Trace(). + Any("sender_address", result.SenderAddress). + Any("content", result.Content). + Msg("prekey decrypt result") } case signalpb.Envelope_PLAINTEXT_CONTENT: - zlog.Debug().Msgf("Received envelope type PLAINTEXT_CONTENT, verb: %v, path: %v", *req.Verb, *req.Path) + log.Debug().Msg("Received envelope type PLAINTEXT_CONTENT") case signalpb.Envelope_CIPHERTEXT: - zlog.Debug().Msgf("Received envelope type CIPHERTEXT, verb: %v, path: %v", *req.Verb, *req.Path) + log.Debug().Msg("Received envelope type CIPHERTEXT") message, err := libsignalgo.DeserializeMessage(envelope.Content) if err != nil { - zlog.Err(err).Msg("DeserializeMessage error") + log.Err(err).Msg("DeserializeMessage error") } senderAddress, err := libsignalgo.NewUUIDAddressFromString( *envelope.SourceServiceId, uint(*envelope.SourceDevice), ) if err != nil { - return nil, fmt.Errorf("NewAddress error: %v", err) + return nil, fmt.Errorf("NewAddress error: %w", err) } decryptedText, err := libsignalgo.Decrypt( ctx, @@ -479,9 +504,9 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { - zlog.Info().Msg("Duplicate message, ignoring") + log.Info().Msg("Duplicate message, ignoring") } else { - zlog.Err(err).Msg("Whisper Decryption error") + log.Err(err).Msg("Whisper Decryption error") } } else { err = stripPadding(&decryptedText) @@ -491,7 +516,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. content := signalpb.Content{} err = proto.Unmarshal(decryptedText, &content) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") } result = &DecryptionResult{ SenderAddress: senderAddress, @@ -500,19 +525,19 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case signalpb.Envelope_RECEIPT: - zlog.Debug().Msgf("Received envelope type RECEIPT, verb: %v, path: %v", *req.Verb, *req.Path) + log.Debug().Msg("Received envelope type RECEIPT") // TODO: handle receipt case signalpb.Envelope_KEY_EXCHANGE: - zlog.Debug().Msgf("Received envelope type KEY_EXCHANGE, verb: %v, path: %v", *req.Verb, *req.Path) + log.Debug().Msg("Received envelope type KEY_EXCHANGE") responseCode = 400 case signalpb.Envelope_UNKNOWN: - zlog.Warn().Msgf("Received envelope type UNKNOWN, verb: %v, path: %v", *req.Verb, *req.Path) + log.Warn().Msg("Received envelope type UNKNOWN") responseCode = 400 default: - zlog.Warn().Msgf("Received actual unknown envelope type, verb: %v, path: %v", *req.Verb, *req.Path) + log.Warn().Msg("Received actual unknown envelope type") responseCode = 400 } @@ -523,16 +548,20 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. name, _ := result.SenderAddress.Name() deviceId, _ := result.SenderAddress.DeviceID() - zlog.Debug().Msgf("Decrypted message from %v:%v", name, deviceId) - printMessage := fmt.Sprintf("Decrypted content fields (%v:%v)", name, deviceId) - printContentFieldString(content, printMessage) + log = log.With(). + Str("sender_name", name). + Uint("sender_device_id", deviceId). + Logger() + ctx = log.WithContext(ctx) + log.Debug().Msg("Decrypted message") + printContentFieldString(ctx, content, "Decrypted content fields") // If there's a sender key distribution message, process it if content.GetSenderKeyDistributionMessage() != nil { - zlog.Debug().Msg("content includes sender key distribution message") + log.Debug().Msg("content includes sender key distribution message") skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(content.GetSenderKeyDistributionMessage()) if err != nil { - zlog.Err(err).Msg("DeserializeSenderKeyDistributionMessage error") + log.Err(err).Msg("DeserializeSenderKeyDistributionMessage error") return nil, err } err = libsignalgo.ProcessSenderKeyDistributionMessage( @@ -542,14 +571,14 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. cli.Store.SenderKeyStore, ) if err != nil { - zlog.Err(err).Msg("ProcessSenderKeyDistributionMessage error") + log.Err(err).Msg("ProcessSenderKeyDistributionMessage error") return nil, err } } theirUUID, err := result.SenderAddress.NameUUID() if err != nil { - zlog.Err(err).Msg("Name error") + log.Err(err).Msg("Name error") return nil, err } @@ -562,12 +591,12 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if destination != nil { destinationUUID, err = uuid.Parse(*destination) if err != nil { - zlog.Err(err).Msg("Sync message destination parse error") + log.Err(err).Msg("Sync message destination parse error") return nil, err } } if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { - zlog.Warn().Msg("sync message sent destination is nil") + log.Warn().Msg("sync message sent destination is nil") } else if content.SyncMessage.Sent.Message != nil { // TODO handle expiration start ts, and maybe the sync message ts? cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, destinationUUID) @@ -576,28 +605,30 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } } if content.SyncMessage.Contacts != nil { - zlog.Debug().Msgf("Recieved sync message contacts") + log.Debug().Msg("Recieved sync message contacts") blob := content.SyncMessage.Contacts.Blob if blob != nil { contactsBytes, err := DownloadAttachment(ctx, blob) if err != nil { - zlog.Err(err).Msg("Contacts Sync DownloadAttachment error") + log.Err(err).Msg("Contacts Sync DownloadAttachment error") } // unmarshall contacts contacts, avatars, err := unmarshalContactDetailsMessages(contactsBytes) if err != nil { - zlog.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") + log.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") } - zlog.Debug().Msgf("Contacts Sync received %v contacts", len(contacts)) + log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") convertedContacts := make([]*types.Contact, 0, len(contacts)) for i, signalContact := range contacts { if signalContact.Aci == nil || *signalContact.Aci == "" { - zlog.Info().Msgf("Signal Contact UUID is nil, skipping: %v", signalContact) + log.Info(). + Any("contact", signalContact). + Msg("Signal Contact UUID is nil, skipping") continue } contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) if err != nil { - zlog.Err(err).Msg("StoreContactDetailsAsContact error") + log.Err(err).Msg("StoreContactDetailsAsContact error") continue } convertedContacts = append(convertedContacts, contact) @@ -625,7 +656,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. // TODO send delivery receipts after actually bridging instead of here err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirUUID) if err != nil { - zlog.Err(err).Msg("sendDeliveryReceipts error") + log.Err(err).Msg("sendDeliveryReceipts error") } } @@ -678,7 +709,7 @@ func printStructFields(message protoreflect.Message, parent string, builder *str message.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { fieldName := string(fd.Name()) currentField := parent + fieldName - builder.WriteString(fmt.Sprintf("%s (%s), ", currentField, fd.Kind().String())) + fmt.Fprintf(builder, "%s (%s), ", currentField, fd.Kind().String()) //builder.WriteString(fmt.Sprintf("%s (%s): %s, ", currentField, fd.Kind().String(), v.String())) // DEBUG: printing value, don't commit if fd.Kind() == protoreflect.MessageKind && !fd.IsList() && v.Message().IsValid() { builder.WriteString("{ ") @@ -706,21 +737,22 @@ func printStructFields(message protoreflect.Message, parent string, builder *str }) } -func printContentFieldString(c *signalpb.Content, message string) { +func printContentFieldString(ctx context.Context, c *signalpb.Content, message string) { + log := zerolog.Ctx(ctx) go func() { // catch panic defer func() { if r := recover(); r != nil { - zlog.Warn().Msgf("Panic in contentFieldsString: %v", r) + log.Warn().Any("recover", r).Msg("Panic in contentFieldsString") } }() - zlog.Debug().Msgf("%v: %v", message, contentFieldsString(c)) + log.Debug().Str("content_fields", contentFieldsString(c)).Msg(message) }() } func contentFieldsString(c *signalpb.Content) string { - builder := &strings.Builder{} - printStructFields(c.ProtoReflect(), "", builder) + var builder strings.Builder + printStructFields(c.ProtoReflect(), "", &builder) return builder.String() } @@ -814,7 +846,7 @@ func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps receipt := DeliveredReceiptMessageForTimestamps(deliveredTimestamps) result := cli.SendMessage(ctx, senderUUID, receipt) if !result.WasSuccessful { - zlog.Error().Msgf("Failed to send delivery receipts: %v", result) + return fmt.Errorf("failed to send delivery receipts: %v", result) } } return nil diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 06cf66e..d86462a 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -615,7 +615,7 @@ func (cli *Client) sendContent( content *signalpb.Content, retryCount int, // For ending recursive retries ) (sentUnidentified bool, err error) { - printContentFieldString(content, "Outgoing message") + printContentFieldString(ctx, content, "Outgoing message") zerolog.Ctx(ctx).Trace().Any("raw_content", content).Msg("Raw data of outgoing message") // If it's a data message, add our profile key From 76e8eb27663ff5ade19f65cfb59ca2e407bc657b Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 10:26:24 -0700 Subject: [PATCH 026/718] signalmeow/sending: use structured logging Signed-off-by: Sumner Evans --- pkg/signalmeow/sending.go | 135 +++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 45 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index d86462a..8728d65 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -132,13 +132,13 @@ func checkForErrorWithSessions(err error, addresses []*libsignalgo.Address, sess return err } if addresses == nil || sessionRecords == nil { - return fmt.Errorf("Addresses or session records are nil") + return fmt.Errorf("addresses or session records are nil") } if len(addresses) != len(sessionRecords) { - return fmt.Errorf("Mismatched number of addresses (%d) and session records (%d)", len(addresses), len(sessionRecords)) + return fmt.Errorf("mismatched number of addresses (%d) and session records (%d)", len(addresses), len(sessionRecords)) } if len(addresses) == 0 || len(sessionRecords) == 0 { - return fmt.Errorf("No addresses or session records") + return fmt.Errorf("no addresses or session records") } return nil } @@ -153,7 +153,7 @@ func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { for _, address := range addresses { deviceID, err := address.DeviceID() if err != nil { - zlog.Err(err).Msg("Error getting deviceID from address") + zerolog.Ctx(ctx).Err(err).Msg("Error getting deviceID from address") continue } if deviceID != uint(cli.Store.DeviceID) { @@ -189,7 +189,9 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.U // Don't send to this device that we are sending from if recipientUUID == cli.Store.ACI && recipientDeviceID == uint(cli.Store.DeviceID) { - zlog.Debug().Msgf("Not sending to the device I'm sending from (%v:%v)", recipientUUID, recipientDeviceID) + zerolog.Ctx(ctx).Debug(). + Uint("recipient_device_id", recipientDeviceID). + Msg("Not sending to the device I'm sending from") continue } @@ -199,6 +201,9 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.U return nil, err } paddedMessage, err := addPadding(3, []byte(serializedMessage)) // TODO: figure out how to get actual version + if err != nil { + return nil, err + } sessionRecord := sessionRecords[i] var envelopeType int @@ -208,6 +213,9 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.U } else { envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, recipientAddress, paddedMessage) } + if err != nil { + return nil, err + } destinationRegistrationID, err := sessionRecord.GetRemoteRegistrationID() if err != nil { @@ -233,6 +241,9 @@ func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddres cli.Store.SessionStore, cli.Store.IdentityStore, ) + if err != nil { + return 0, nil, err + } encryptedPayload, err = cipherTextMessage.Serialize() if err != nil { return 0, nil, err @@ -245,7 +256,7 @@ func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddres } else if cipherMessageType == libsignalgo.CiphertextMessageTypeWhisper { // 2 -> 1 envelopeType = int(signalpb.Envelope_CIPHERTEXT) } else { - return 0, nil, fmt.Errorf("Unknown message type: %v", cipherMessageType) + return 0, nil, fmt.Errorf("unknown message type: %v", cipherMessageType) } return envelopeType, encryptedPayload, nil } @@ -374,9 +385,11 @@ func syncMessageForContactRequest() *signalpb.Content { } } -func syncMessageFromReadReceiptMessage(receiptMessage *signalpb.ReceiptMessage, messageSender uuid.UUID) *signalpb.Content { +func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender uuid.UUID) *signalpb.Content { if *receiptMessage.Type != signalpb.ReceiptMessage_READ { - zlog.Warn().Msgf("syncMessageFromReadReceiptMessage called with non-read receipt message: %v", receiptMessage.Type) + zerolog.Ctx(ctx).Warn(). + Any("receipt_message_type", receiptMessage.Type). + Msg("syncMessageFromReadReceiptMessage called with non-read receipt message") return nil } read := []*signalpb.SyncMessage_Read{} @@ -394,18 +407,28 @@ func syncMessageFromReadReceiptMessage(receiptMessage *signalpb.ReceiptMessage, } func (cli *Client) SendContactSyncRequest(ctx context.Context) error { + if cli.LastContactRequestTime == nil { + cli.LastContactRequestTime = new(int64) + } currentUnixTime := time.Now().Unix() lastRequestTime := cli.LastContactRequestTime + log := zerolog.Ctx(ctx).With(). + Str("action", "send contact sync request"). + Int64("current_unix_time", currentUnixTime). + Int64("last_request_time", *lastRequestTime). + Int64("seconds_since_last_request", currentUnixTime-*lastRequestTime). + Logger() + ctx = log.WithContext(ctx) // If we've requested in the last minute, don't request again if lastRequestTime != nil && currentUnixTime-*lastRequestTime < 60 { - zlog.Warn().Msgf("Not sending contact sync request, already sent %v seconds ago", currentUnixTime-*lastRequestTime) + log.Warn().Msg("Not sending contact sync request because we already requested it in the past minute") return nil } groupRequest := syncMessageForContactRequest() _, err := cli.sendContent(ctx, cli.Store.ACI, uint64(currentUnixTime), groupRequest, 0) if err != nil { - zlog.Err(err).Msg("Failed to send contact sync request message to myself (%v)") + log.Err(err).Msg("Failed to send contact sync request message to myself") return err } cli.LastContactRequestTime = ¤tUnixTime @@ -484,6 +507,11 @@ func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { } func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { + log := zerolog.Ctx(ctx).With(). + Str("action", "send group message"). + Stringer("group_id", gid). + Logger() + ctx = log.WithContext(ctx) group, err := cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { return nil, err @@ -508,19 +536,21 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi // Don't send normal DataMessages to ourselves continue } + log := log.With().Stringer("member", member.UserID).Logger() + ctx := log.WithContext(ctx) sentUnidentified, err := cli.sendContent(ctx, member.UserID, messageTimestamp, content, 0) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ RecipientUUID: member.UserID, Error: err, }) - zlog.Err(err).Msgf("Failed to send to %v", member.UserID) + log.Err(err).Msg("Failed to send to user") } else { result.SuccessfullySentTo = append(result.SuccessfullySentTo, SuccessfulSendResult{ RecipientUUID: member.UserID, Unidentified: sentUnidentified, }) - zlog.Trace().Msgf("Successfully sent to %v", member.UserID) + log.Trace().Msg("Successfully sent to user") } } @@ -534,7 +564,7 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0) if selfSendErr != nil { - zlog.Err(selfSendErr).Msg("Failed to send sync message to myself (%v)") + log.Err(selfSendErr).Msg("Failed to send sync message to myself") } } @@ -543,7 +573,7 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } if len(result.SuccessfullySentTo) == 0 { lastError := result.FailedToSendTo[len(result.FailedToSendTo)-1].Error - return nil, fmt.Errorf("Failed to send to any group members: %v", lastError) + return nil, fmt.Errorf("failed to send to any group members: %w", lastError) } return result, nil @@ -592,12 +622,12 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, conte } else if content.GetEditMessage() != nil { syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result.SuccessfulSendResult) } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { - syncContent = syncMessageFromReadReceiptMessage(content.ReceiptMessage, recipientID) + syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, recipientID) } if syncContent != nil { _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0) if selfSendErr != nil { - zlog.Err(selfSendErr).Msg("Failed to send sync message to myself") + zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } } } @@ -615,23 +645,28 @@ func (cli *Client) sendContent( content *signalpb.Content, retryCount int, // For ending recursive retries ) (sentUnidentified bool, err error) { + log := zerolog.Ctx(ctx).With(). + Str("action", "send content"). + Stringer("recipient", recipientUUID). + Uint64("timestamp", messageTimestamp). + Logger() + ctx = log.WithContext(ctx) printContentFieldString(ctx, content, "Outgoing message") - zerolog.Ctx(ctx).Trace().Any("raw_content", content).Msg("Raw data of outgoing message") + log.Trace().Any("raw_content", content).Msg("Raw data of outgoing message") // If it's a data message, add our profile key if content.DataMessage != nil { profileKey, err := cli.ProfileKeyForSignalID(ctx, cli.Store.ACI) if err != nil { - zlog.Err(err).Msg("Error getting profile key, not adding to outgoing message") + log.Err(err).Msg("Error getting profile key, not adding to outgoing message") } else { content.DataMessage.ProfileKey = profileKey.Slice() } } if retryCount > 3 { - err := fmt.Errorf("Too many retries") - zlog.Err(err).Msgf("sendContent too many retries: %v", retryCount) - return false, err + log.Error().Int("retry_count", retryCount).Msg("sendContent too many retries") + return false, fmt.Errorf("too many retries") } useUnidentifiedSender := true @@ -641,7 +676,7 @@ func (cli *Client) sendContent( } profileKey, err := cli.ProfileKeyForSignalID(ctx, recipientUUID) if err != nil || profileKey == nil { - zlog.Err(err).Msg("Error getting profile key") + log.Err(err).Msg("Error getting profile key") useUnidentifiedSender = false // Try to self heal by requesting contact sync, though this is slow and not guaranteed to help cli.SendContactSyncRequest(ctx) @@ -650,7 +685,7 @@ func (cli *Client) sendContent( if profileKey != nil { accessKey, err = profileKey.DeriveAccessKey() if err != nil { - zlog.Err(err).Msg("Error deriving access key") + log.Err(err).Msg("Error deriving access key") useUnidentifiedSender = false } } @@ -665,7 +700,7 @@ func (cli *Client) sendContent( var messages []MyMessage messages, err = cli.buildMessagesToSend(ctx, recipientUUID, content, useUnidentifiedSender) if err != nil { - zlog.Err(err).Msg("Error building messages to send") + log.Err(err).Msg("Error building messages to send") return false, err } @@ -684,19 +719,24 @@ func (cli *Client) sendContent( var response *signalpb.WebSocketResponseMessage if useUnidentifiedSender { - zlog.Trace().Msgf("Sending message to %v over unidentified WS", recipientUUID) + log.Trace().Msg("Sending message over unidentified WS") base64AccessKey := base64.StdEncoding.EncodeToString(accessKey[:]) request.Headers = append(request.Headers, "unidentified-access-key:"+base64AccessKey) response, err = cli.UnauthedWS.SendRequest(ctx, request) } else { - zlog.Trace().Msgf("Sending message to %v over authed WS", recipientUUID) + log.Trace().Msg("Sending message over authed WS") response, err = cli.AuthedWS.SendRequest(ctx, request) } sentUnidentified = useUnidentifiedSender if err != nil { return sentUnidentified, err } - zlog.Trace().Msgf("Received a response to a message send from: %v, id: %v, code: %v", recipientUUID, *response.Id, *response.Status) + log = log.With(). + Uint64("response_id", *response.Id). + Uint32("response_status", *response.Status). + Logger() + ctx = log.WithContext(ctx) + log.Trace().Msg("Received a response to a message send") retryableStatuses := []uint32{409, 410, 428, 500, 503} @@ -724,13 +764,11 @@ func (cli *Client) sendContent( // Try to send again (**RECURSIVELY**) sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1) if err != nil { - zlog.Err(err).Msg("2nd try sendMessage error") + log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err } } else if *response.Status != 200 { - err := fmt.Errorf("Unexpected status code while sending: %v", *response.Status) - zlog.Err(err).Msg("") - return sentUnidentified, err + return sentUnidentified, fmt.Errorf("unexpected status code while sending: %d", *response.Status) } return sentUnidentified, nil @@ -738,25 +776,26 @@ func (cli *Client) sendContent( // A 409 means our device list was out of date, so we will fix it up func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { + log := zerolog.Ctx(ctx) // Decode json body var body map[string]interface{} err := json.Unmarshal(response.Body, &body) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") return err } // check for missingDevices and extraDevices if body["missingDevices"] != nil { - missingDevices := body["missingDevices"].([]interface{}) - zlog.Debug().Msgf("missing devices found in 409 response: %v", missingDevices) + missingDevices := body["missingDevices"].([]any) + log.Debug().Any("missing_devices", missingDevices).Msg("missing devices found in 409 response") // TODO: establish session with missing devices for _, missingDevice := range missingDevices { cli.FetchAndProcessPreKey(ctx, recipientUUID, int(missingDevice.(float64))) } } if body["extraDevices"] != nil { - extraDevices := body["extraDevices"].([]interface{}) - zlog.Debug().Msgf("extra devices found in 409 response: %v", extraDevices) + extraDevices := body["extraDevices"].([]any) + log.Debug().Any("extra_devices", extraDevices).Msg("extra devices found in 409 response") for _, extraDevice := range extraDevices { // Remove extra device from the sessionstore recipient, err := libsignalgo.NewUUIDAddress( @@ -764,12 +803,12 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo uint(extraDevice.(float64)), ) if err != nil { - zlog.Err(err).Msg("NewAddress error") + log.Err(err).Msg("NewAddress error") return err } err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipient) if err != nil { - zlog.Err(err).Msg("RemoveSession error") + log.Err(err).Msg("RemoveSession error") return err } } @@ -779,25 +818,30 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo // A 410 means we have a stale device, so get rid of it func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { + log := zerolog.Ctx(ctx) // Decode json body var body map[string]interface{} err := json.Unmarshal(response.Body, &body) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") return err } // check for staleDevices and make new sessions with them if body["staleDevices"] != nil { - staleDevices := body["staleDevices"].([]interface{}) - zlog.Debug().Msgf("stale devices found in 410 response: %v", staleDevices) + staleDevices := body["staleDevices"].([]any) + log.Debug().Any("stale_devices", staleDevices).Msg("stale devices found in 410 response") for _, staleDevice := range staleDevices { recipient, err := libsignalgo.NewUUIDAddress( recipientUUID, uint(staleDevice.(float64)), ) + if err != nil { + log.Err(err).Msg("error creating new UUID Address") + return err + } err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipient) if err != nil { - zlog.Err(err).Msg("RemoveSession error") + log.Err(err).Msg("RemoveSession error") return err } cli.FetchAndProcessPreKey(ctx, recipientUUID, int(staleDevice.(float64))) @@ -810,11 +854,12 @@ func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, respo // We ~~will~~ could try sending a "pushChallenge" response, but if that doesn't work we just gotta wait. // TODO: explore captcha response func (cli *Client) handle428(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { + log := zerolog.Ctx(ctx) // Decode json body var body map[string]interface{} err := json.Unmarshal(response.Body, &body) if err != nil { - zlog.Err(err).Msg("Unmarshal error") + log.Err(err).Msg("Unmarshal error") return err } @@ -829,12 +874,12 @@ func (cli *Client) handle428(ctx context.Context, recipientUUID uuid.UUID, respo if key == "Retry-After" { retryAfterSeconds, err = strconv.ParseUint(value, 10, 64) if err != nil { - zlog.Err(err).Msg("ParseUint error") + log.Err(err).Msg("ParseUint error") } } } if retryAfterSeconds > 0 { - zlog.Warn().Msgf("Got rate limited, need to wait %v seconds", retryAfterSeconds) + log.Warn().Uint64("retry_after_seconds", retryAfterSeconds).Msg("Got rate limited") } // TODO: responding to a pushChallenge this way doesn't work, server just returns 422 // Luckily challenges seem rare when sending with sealed sender From af261c55f1743c7dadedddf475b54e247d9caa32 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 10:27:16 -0700 Subject: [PATCH 027/718] messagetracking/sendMessageMetrics: use local log Signed-off-by: Sumner Evans --- messagetracking.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/messagetracking.go b/messagetracking.go index bc69415..a106ee6 100644 --- a/messagetracking.go +++ b/messagetracking.go @@ -184,15 +184,16 @@ func (portal *Portal) sendMessageMetrics(ctx context.Context, evt *event.Event, if evt.Type == event.EventRedaction { log = log.With().Stringer("redacts", evt.Redacts).Logger() } + ctx = log.WithContext(ctx) origEvtID := evt.ID if retryMeta := evt.Content.AsMessage().MessageSendRetry; retryMeta != nil { origEvtID = retryMeta.OriginalEventID } if err != nil { - logEvt := portal.log.Error() + logEvt := log.Error() if part == "Ignoring" { - logEvt = portal.log.Debug() + logEvt = log.Debug() } logEvt.Err(err).Msg("Sending message metrics for event") reason, statusCode, isCertain, sendNotice, _ := errorToStatusReason(err) @@ -203,7 +204,7 @@ func (portal *Portal) sendMessageMetrics(ctx context.Context, evt *event.Event, } portal.sendStatusEvent(ctx, origEvtID, evt.ID, err, nil) } else { - portal.log.Debug().Msg("Sending metrics for successfully handled Matrix event") + log.Debug().Msg("Sending metrics for successfully handled Matrix event") portal.sendDeliveryReceipt(ctx, evt.ID) portal.bridge.SendMessageSuccessCheckpoint(evt, status.MsgStepRemote, ms.getRetryNum()) var deliveredTo *[]id.UserID @@ -218,7 +219,7 @@ func (portal *Portal) sendMessageMetrics(ctx context.Context, evt *event.Event, } } if ms != nil { - portal.log.Debug().Object("timings", ms.timings).Msg("Timings for event") + log.Debug().Object("timings", ms.timings).Msg("Timings for event") } } From e33fa9563881f33fc1926103fed5adf068e4f30f Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 14:53:48 -0700 Subject: [PATCH 028/718] treewide: fix all ignored errors Signed-off-by: Sumner Evans --- pkg/libsignalgo/groupsecretparams.go | 13 +++++------ pkg/signalmeow/groups.go | 3 +-- pkg/signalmeow/keys.go | 9 +++++++ pkg/signalmeow/provisioning.go | 35 +++++++++++++++++++++++----- pkg/signalmeow/sending.go | 3 +++ pkg/signalmeow/store/device.go | 3 +++ portal.go | 9 ++++--- 7 files changed, 55 insertions(+), 20 deletions(-) diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index b6783c4..4861868 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -31,10 +31,13 @@ import ( type Randomness [C.SignalRANDOMNESS_LEN]byte -func GenerateRandomness() (Randomness, error) { +func GenerateRandomness() Randomness { var randomness Randomness _, err := rand.Read(randomness[:]) - return randomness, err + if err != nil { + panic(err) + } + return randomness } type GroupMasterKey [C.SignalGROUP_MASTER_KEY_LEN]byte @@ -46,11 +49,7 @@ type UUIDCiphertext [C.SignalUUID_CIPHERTEXT_LEN]byte type ProfileKeyCiphertext [C.SignalPROFILE_KEY_CIPHERTEXT_LEN]byte func GenerateGroupSecretParams() (GroupSecretParams, error) { - randomness, err := GenerateRandomness() - if err != nil { - return GroupSecretParams{}, err - } - return GenerateGroupSecretParamsWithRandomness(randomness) + return GenerateGroupSecretParamsWithRandomness(GenerateRandomness()) } func GenerateGroupSecretParamsWithRandomness(randomness Randomness) (GroupSecretParams, error) { diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index e43be6f..e2e391a 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -173,10 +173,9 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") return nil, err } - randomness, err := libsignalgo.GenerateRandomness() authCredentialPresentation, err := libsignalgo.CreateAuthCredentialWithPniPresentation( prodServerPublicParams, - randomness, + libsignalgo.GenerateRandomness(), groupSecretParams, *authCredential, ) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 4313f92..dc12075 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -95,6 +95,9 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type // Mark prekeys as registered // (kyber prekeys don't have "mark as uploaded" we just assume they always are) lastPreKeyID, err := preKeys[len(preKeys)-1].GetID() + if err != nil { + return fmt.Errorf("failed to get last prekey ID: %w", err) + } err = cli.Store.PreKeyStoreExtras.MarkPreKeysAsUploaded(ctx, uuidKind, lastPreKeyID) if err != nil { @@ -316,6 +319,9 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI } rawIdentityKey, err := addBase64PaddingAndDecode(prekeyResponse.IdentityKey) + if err != nil { + return fmt.Errorf("error decoding identity key: %w", err) + } identityKey, err := libsignalgo.DeserializeIdentityKey([]byte(rawIdentityKey)) if err != nil { zlog.Err(err).Msg("Error deserializing identity key") @@ -372,6 +378,9 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI return err } kyberPreKeySignature, err = addBase64PaddingAndDecode(d.PQPreKey.Signature) + if err != nil { + return fmt.Errorf("error decoding kyber prekey signature: %w", err) + } } rawSignature, err := addBase64PaddingAndDecode(d.SignedPreKey.Signature) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 871a136..a0436f3 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -186,10 +186,19 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt // Store identity keys? address, err := libsignalgo.NewUUIDAddress(device.ACI, uint(device.DeviceID)) + if err != nil { + c <- ProvisioningResponse{ + State: StateProvisioningError, + Err: fmt.Errorf("error creating new address: %w", err), + } + return + } _, err = device.IdentityStore.SaveIdentityKey(ctx, address, device.ACIIdentityKeyPair.GetIdentityKey()) if err != nil { - zlog.Err(err).Msg("error saving identity key") - c <- ProvisioningResponse{State: StateProvisioningError, Err: err} + c <- ProvisioningResponse{ + State: StateProvisioningError, + Err: fmt.Errorf("error saving identity key: %w", err), + } return } @@ -202,8 +211,10 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt // Store our profile key err = device.ProfileKeyStore.StoreProfileKey(ctx, data.ACI, profileKey) if err != nil { - zlog.Err(err).Msg("error storing profile key") - c <- ProvisioningResponse{State: StateProvisioningError, Err: err} + c <- ProvisioningResponse{ + State: StateProvisioningError, + Err: fmt.Errorf("error storing profile key: %w", err), + } return } @@ -214,11 +225,20 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt // TODO hacky client construction cli := &Client{Store: device} err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindACI) + if err != nil { + c <- ProvisioningResponse{ + State: StateProvisioningError, + Err: fmt.Errorf("error generating and registering ACI prekeys: %w", err), + } + return + } err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindPNI) if err != nil { - zlog.Err(err).Msg("error generating and registering prekeys") - c <- ProvisioningResponse{State: StateProvisioningError, Err: err} + c <- ProvisioningResponse{ + State: StateProvisioningError, + Err: fmt.Errorf("error generating and registering PNI prekeys: %w", err), + } return } @@ -248,6 +268,9 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph // Decode provisioning UUID provisioningUuid := &signalpb.ProvisioningUuid{} err = proto.Unmarshal(msg.Request.Body, provisioningUuid) + if err != nil { + return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) + } // Create provisioning URL bytesKey, _ := pubKey.Serialize() diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 8728d65..b696872 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -274,6 +274,9 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l cli.Store.SessionStore, cli.Store.IdentityStore, ) + if err != nil { + return 0, nil, err + } envelopeType = int(signalpb.Envelope_UNIDENTIFIED_SENDER) return envelopeType, encryptedPayload, nil diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index fcc3b39..16d3c1e 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -74,6 +74,9 @@ func (d *Device) ClearDeviceKeys(ctx context.Context) error { return nil } err := d.PreKeyStoreExtras.DeleteAllPreKeys(ctx) + if err != nil { + return err + } err = d.SessionStoreExtras.RemoveAllSessions(ctx) return err } diff --git a/portal.go b/portal.go index 3283402..ab229bb 100644 --- a/portal.go +++ b/portal.go @@ -682,13 +682,11 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte log.Debug().Msg("Sending event to Signal") // Check to see if portal.ChatID is a standard UUID (with dashes) - var err error if portal.IsPrivateChat() { // this is a 1:1 chat result := sender.Client.SendMessage(ctx, portal.UserID(), msg) if !result.WasSuccessful { - err = result.FailedSendResult.Error - log.Err(err).Msg("Error sending event to Signal") + return result.Error } } else { // this is a group chat @@ -715,14 +713,15 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte log.Debug().Msg("No successes or failures - Probably sent to myself") } else if len(result.SuccessfullySentTo) == 0 { log.Error().Msg("Failed to send event to all members of Signal group") - err = errors.New("failed to send to any members of Signal group") + return errors.New("failed to send to any members of Signal group") + } else if len(result.SuccessfullySentTo) < totalRecipients { log.Warn().Msg("Only sent event to some members of Signal group") } else { log.Debug().Msg("Sent event to all members of Signal group") } } - return err + return nil } func (portal *Portal) sendMessageStatusCheckpointSuccess(ctx context.Context, evt *event.Event) { From 0cb6ec69d16a71284f62419d6aba71b11e075a84 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 7 Jan 2024 13:10:52 +0200 Subject: [PATCH 029/718] Add proper name for notes to self room --- config/bridge.go | 3 +++ config/upgrade.go | 2 ++ example-config.yaml | 4 ++++ portal.go | 18 ++++++++++++++---- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/config/bridge.go b/config/bridge.go index b023852..521c56d 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -35,6 +35,9 @@ type BridgeConfig struct { DisplaynameTemplate string `yaml:"displayname_template"` PrivateChatPortalMeta string `yaml:"private_chat_portal_meta"` UseContactAvatars bool `yaml:"use_contact_avatars"` + NumberInTopic bool `yaml:"number_in_topic"` + + NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` PortalMessageBuffer int `yaml:"portal_message_buffer"` diff --git a/config/upgrade.go b/config/upgrade.go index 3892778..ba0daf9 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -83,6 +83,8 @@ func DoUpgrade(helper *up.Helper) { } helper.Copy(up.Str, "bridge", "private_chat_portal_meta") helper.Copy(up.Bool, "bridge", "use_contact_avatars") + helper.Copy(up.Bool, "bridge", "number_in_topic") + helper.Copy(up.Str, "bridge", "note_to_self_avatar") helper.Copy(up.Int, "bridge", "portal_message_buffer") helper.Copy(up.Bool, "bridge", "personal_filtering_spaces") helper.Copy(up.Bool, "bridge", "bridge_notices") diff --git a/example-config.yaml b/example-config.yaml index af71116..1a208a4 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -106,6 +106,10 @@ bridge: private_chat_portal_meta: default # Should avatars from the user's contact list be used? This is not safe on multi-user instances. use_contact_avatars: false + # Should the Signal user's phone number be included in the room topic in private chat portal rooms? + number_in_topic: true + # Avatar image for the Note to Self room. + note_to_self_avatar: mxc://maunium.net/REBIVrqjZwmaWpssCZpBlmlL portal_message_buffer: 128 diff --git a/portal.go b/portal.go index ab229bb..3171812 100644 --- a/portal.go +++ b/portal.go @@ -878,6 +878,9 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg // If this message is a group change, don't handle it here, it's handled below. if msg.GetGroupV2().GetGroupChange() == nil && portal.Revision < msg.GetGroupV2().GetRevision() { portal.UpdateInfo(genericCtx, source, nil, msg.GetGroupV2().GetRevision()) + } else if portal.IsPrivateChat() && portal.UserID() == portal.Receiver && portal.Name != NoteToSelfName { + // Slightly hacky way to make note to self names backfill + portal.UpdateDMInfo(genericCtx, false) } switch { @@ -1554,8 +1557,6 @@ func (portal *Portal) GetDMPuppet() *Puppet { return portal.bridge.GetPuppetBySignalID(portal.UserID()) } -const PrivateChatTopic = "Signal private chat" - func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *signalmeow.Group, revision uint32) { if portal.IsPrivateChat() { portal.UpdateDMInfo(ctx, false) @@ -1567,6 +1568,9 @@ func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *s } } +const PrivateChatTopic = "Signal private chat" +const NoteToSelfName = "Signal Note to Self" + func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { log := zerolog.Ctx(ctx).With(). Str("function", "UpdateDMInfo"). @@ -1576,12 +1580,18 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { puppet := portal.GetDMPuppet() update := forceSave - if portal.shouldSetDMRoomMetadata() { + if portal.UserID() == portal.Receiver { + noteToSelfAvatar := portal.bridge.Config.Bridge.NoteToSelfAvatar.ParseOrIgnore() + avatarHash := sha256.Sum256([]byte(noteToSelfAvatar.String())) + + update = portal.updateName(ctx, NoteToSelfName) || update + update = portal.updateAvatarWithMXC(ctx, "notetoself", hex.EncodeToString(avatarHash[:]), noteToSelfAvatar) || update + } else if portal.shouldSetDMRoomMetadata() { update = portal.updateName(ctx, puppet.Name) || update update = portal.updateAvatarWithMXC(ctx, puppet.AvatarPath, puppet.AvatarHash, puppet.AvatarURL) || update } topic := PrivateChatTopic - if puppet.Number != "" { + if portal.bridge.Config.Bridge.NumberInTopic && puppet.Number != "" { topic = fmt.Sprintf("%s with %s", topic, puppet.Number) } update = portal.updateTopic(ctx, topic) || update From b90b12f6ffbabde8f320b4cfebeed470b72dfd7e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 7 Jan 2024 13:22:33 +0200 Subject: [PATCH 030/718] Send notes to self properly --- pkg/signalmeow/sending.go | 58 +++++++++++++++++++++++++-------------- portal.go | 17 ++++++------ 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index b696872..188e060 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -582,6 +582,29 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi return result, nil } +func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool { + // If we have other devices, send Sync messages to them too + if cli.howManyOtherDevicesDoWeHave(ctx) > 0 { + var syncContent *signalpb.Content + if content.GetDataMessage() != nil { + syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result) + } else if content.GetEditMessage() != nil { + syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) + } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { + syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.RecipientUUID) + } + if syncContent != nil { + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTS, syncContent, 0) + if selfSendErr != nil { + zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") + } else { + return true + } + } + } + return false +} + func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, content *signalpb.Content) SendMessageResult { // Assemble the content to send var messageTimestamp uint64 @@ -593,6 +616,19 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, conte messageTimestamp = currentMessageTimestamp() } + isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY + if recipientID == cli.Store.ACI && !isDeliveryReceipt { + res := &SuccessfulSendResult{ + RecipientUUID: recipientID, + Unidentified: false, + } + ok := cli.sendSyncCopy(ctx, content, messageTimestamp, res) + return SendMessageResult{ + WasSuccessful: ok, + SuccessfulSendResult: res, + } + } + // Send to the recipient sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0) if err != nil { @@ -612,28 +648,8 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, conte }, } - // TODO: don't fetch every time - // (But for now this makes sure we know about all our other devices) - // ((Actually I don't think this is necessary?)) - //FetchAndProcessPreKey(ctx, device, device.Data.ACI, -1) + cli.sendSyncCopy(ctx, content, messageTimestamp, result.SuccessfulSendResult) - // If we have other devices, send Sync messages to them too - if cli.howManyOtherDevicesDoWeHave(ctx) > 0 { - var syncContent *signalpb.Content - if content.GetDataMessage() != nil { - syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result.SuccessfulSendResult) - } else if content.GetEditMessage() != nil { - syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result.SuccessfulSendResult) - } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { - syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, recipientID) - } - if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0) - if selfSendErr != nil { - zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") - } - } - } return result } diff --git a/portal.go b/portal.go index 3171812..b3d3035 100644 --- a/portal.go +++ b/portal.go @@ -267,16 +267,13 @@ func (portal *Portal) GetRelayUser() *User { return portal.relayUser } -func isUUID(s string) bool { - if _, uuidErr := uuid.Parse(s); uuidErr == nil { - return true - } - return false +func (portal *Portal) IsPrivateChat() bool { + return portal.UserID() != uuid.Nil } -func (portal *Portal) IsPrivateChat() bool { - // If ChatID is a UUID, it's a private chat, otherwise it's base64 and a group chat - return isUUID(portal.ChatID) +func (portal *Portal) IsNoteToSelf() bool { + userID := portal.UserID() + return userID != uuid.Nil && userID == portal.Receiver } func (portal *Portal) MainIntent() *appservice.IntentAPI { @@ -1264,6 +1261,10 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { } func (portal *Portal) HandleMatrixTyping(newTyping []id.UserID) { + if portal.IsNoteToSelf() { + return + } + portal.currentlyTypingLock.Lock() defer portal.currentlyTypingLock.Unlock() startedTyping, stoppedTyping := typingDiff(portal.currentlyTyping, newTyping) From 6b98c3f955d5c176392c0b2b94220650fc0db728 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 10:44:36 -0700 Subject: [PATCH 031/718] signalmeow/web: use context logger, make SendHTTPRequest use context Signed-off-by: Sumner Evans --- commands.go | 2 +- pkg/signalmeow/attachments.go | 6 +++--- pkg/signalmeow/devicename.go | 9 +++++---- pkg/signalmeow/groups.go | 4 ++-- pkg/signalmeow/keys.go | 23 +++++++++++------------ pkg/signalmeow/misc.go | 2 -- pkg/signalmeow/profile.go | 8 ++++---- pkg/signalmeow/provisioning.go | 17 ++++++++++------- pkg/signalmeow/sending.go | 4 ++-- pkg/signalmeow/web/signalwebsocket.go | 20 ++++++++++---------- pkg/signalmeow/web/web.go | 25 ++++++++++--------------- provisioning.go | 2 +- puppet.go | 2 +- 13 files changed, 60 insertions(+), 64 deletions(-) diff --git a/commands.go b/commands.go index bc11ca9..5b88031 100644 --- a/commands.go +++ b/commands.go @@ -177,7 +177,7 @@ func fnSetDeviceName(ce *WrappedCommandEvent) { } name := strings.Join(ce.Args, " ") - err := ce.User.Client.UpdateDeviceName(name) + err := ce.User.Client.UpdateDeviceName(ce.Ctx, name) if err != nil { ce.Reply("Error setting device name: %v", err) return diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index f27b79b..2095d1e 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -139,7 +139,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb attributesPath := "/v3/attachments/form/upload" username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(http.MethodGet, attributesPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, attributesPath, opts) if err != nil { log.Err(err).Msg("Error sending request fetching upload attributes") return nil, err @@ -152,7 +152,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb } // Allocate attachment on CDN - resp, err = web.SendHTTPRequest(http.MethodPost, "", &web.HTTPReqOpt{ + resp, err = web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ OverrideURL: uploadAttributes.SignedUploadLocation, ContentType: web.ContentTypeOctetStream, Headers: uploadAttributes.Headers, @@ -169,7 +169,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb } // Upload attachment to CDN - resp, err = web.SendHTTPRequest(http.MethodPut, "", &web.HTTPReqOpt{ + resp, err = web.SendHTTPRequest(ctx, http.MethodPut, "", &web.HTTPReqOpt{ OverrideURL: resp.Header.Get("Location"), Body: encryptedWithMAC, ContentType: web.ContentTypeOctetStream, diff --git a/pkg/signalmeow/devicename.go b/pkg/signalmeow/devicename.go index e253e3a..c22e94d 100644 --- a/pkg/signalmeow/devicename.go +++ b/pkg/signalmeow/devicename.go @@ -17,6 +17,7 @@ package signalmeow import ( + "context" "crypto/aes" "crypto/cipher" "crypto/hmac" @@ -43,19 +44,19 @@ func aes256CTR(key, iv, dst, source []byte) { cipher.NewCTR(block, iv).XORKeyStream(dst, source) } -func (cli *Client) UpdateDeviceName(name string) error { +func (cli *Client) UpdateDeviceName(ctx context.Context, name string) error { encryptedName, err := EncryptDeviceName(name, cli.Store.ACIIdentityKeyPair.GetPublicKey()) if err != nil { return fmt.Errorf("failed to encrypt device name: %w", err) } - err = cli.updateDeviceName(encryptedName) + err = cli.updateDeviceName(ctx, encryptedName) if err != nil { return fmt.Errorf("failed to update device name: %w", err) } return nil } -func (cli *Client) updateDeviceName(encryptedName []byte) error { +func (cli *Client) updateDeviceName(ctx context.Context, encryptedName []byte) error { reqData, err := json.Marshal(map[string]any{ "deviceName": encryptedName, }) @@ -63,7 +64,7 @@ func (cli *Client) updateDeviceName(encryptedName []byte) error { return fmt.Errorf("failed to marshal device name update request: %w", err) } username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(http.MethodPut, "/v1/accounts/name", &web.HTTPReqOpt{ + resp, err := web.SendHTTPRequest(ctx, http.MethodPut, "/v1/accounts/name", &web.HTTPReqOpt{ Body: reqData, Username: &username, Password: &password, diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index e2e391a..0f7f7fb 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -379,7 +379,7 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier ContentType: web.ContentTypeProtobuf, Host: web.StorageHostname, } - response, err := web.SendHTTPRequest(http.MethodGet, "/v1/groups", opts) + response, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/groups", opts) if err != nil { zlog.Err(err).Msg("RetrieveGroupById SendHTTPRequest error") return nil, err @@ -425,7 +425,7 @@ func (cli *Client) DownloadGroupAvatar(ctx context.Context, group *Group) ([]byt Username: &username, Password: &password, } - resp, err := web.SendHTTPRequest(http.MethodGet, group.AvatarPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, group.AvatarPath, opts) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index dc12075..e30d6ca 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -86,7 +86,7 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type preKeyUsername = cli.Store.ACI.String() } preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, cli.Store.DeviceID) - err = RegisterPreKeys(&generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) + err = RegisterPreKeys(ctx, &generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) if err != nil { zlog.Err(err).Msg("RegisterPreKeys error") return err @@ -228,7 +228,8 @@ func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) map[string]in return kyberPreKeyJson } -func RegisterPreKeys(generatedPreKeys *GeneratedPreKeys, uuidKind types.UUIDKind, username string, password string) error { +func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, uuidKind types.UUIDKind, username string, password string) error { + log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() // Convert generated prekeys to JSON preKeysJson := []map[string]interface{}{} kyberPreKeysJson := []map[string]interface{}{} @@ -252,22 +253,20 @@ func RegisterPreKeys(generatedPreKeys *GeneratedPreKeys, uuidKind types.UUIDKind keysPath := "/v2/keys?identity=" + string(uuidKind) jsonBytes, err := json.Marshal(register_json) if err != nil { - zlog.Err(err).Msg("Error marshalling register JSON") + log.Err(err).Msg("Error marshalling register JSON") return err } opts := &web.HTTPReqOpt{Body: jsonBytes, Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(http.MethodPut, keysPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodPut, keysPath, opts) if err != nil { - zlog.Err(err).Msg("Error sending request") - return err - } - // status code not 2xx - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - err := fmt.Errorf("Error registering prekeys: %v", resp.Status) - zlog.Err(err).Msg("Error registering prekeys") + log.Err(err).Msg("Error sending request") return err } defer resp.Body.Close() + // status code not 2xx + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("error registering prekeys: %v", resp.Status) + } return err } @@ -306,7 +305,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI } path := "/v2/keys/" + theirUUID.String() + deviceIDPath + "?pq=true" username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) if err != nil { zlog.Err(err).Msg("Error sending request") return err diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index af4def2..8e6894e 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -22,7 +22,6 @@ import ( "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) // Deprecated: global loggers are bad @@ -31,7 +30,6 @@ var zlog zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{}).With().Timestamp( func SetLogger(l zerolog.Logger) { zlog = l setupFFILogging() - web.SetLogger(l.With().Str("component", "signalmeow/web").Logger()) } type FFILogger struct{} diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 90e768d..503418b 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -220,7 +220,7 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P } zlog.Trace().Msg("Got profile response") if *resp.Status < 200 || *resp.Status >= 300 { - err := errors.New(fmt.Sprintf("%v (unsuccessful status code)", *resp.Status)) + err := fmt.Errorf("%v (unsuccessful status code)", *resp.Status) zlog.Err(err).Msg("profile response error") return nil, err } @@ -237,7 +237,7 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P zlog.Err(err).Msg("error decrypting profile name") } // TODO store first and last name separately instead of removing the separator - profile.Name = strings.Replace(profile.Name, "\x00", " ", -1) + profile.Name = strings.ReplaceAll(profile.Name, "\x00", " ") } if len(profileResponse.About) > 0 { profile.About, err = decryptString(profileKey, profileResponse.About) @@ -257,14 +257,14 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P return &profile, nil } -func (cli *Client) DownloadUserAvatar(avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { +func (cli *Client) DownloadUserAvatar(ctx context.Context, avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, Username: &username, Password: &password, } - resp, err := web.SendHTTPRequest(http.MethodGet, avatarPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, avatarPath, opts) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index a0436f3..6e09256 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -29,6 +29,7 @@ import ( "time" "github.com/google/uuid" + "github.com/rs/zerolog" "google.golang.org/protobuf/proto" "nhooyr.io/websocket" @@ -249,6 +250,7 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt // Returns the provisioningUrl and an error func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCipher *ProvisioningCipher) (string, error) { + log := zerolog.Ctx(ctx).With().Str("action", "start provisioning").Logger() pubKey := provisioningCipher.GetPublicKey() provisioningUrl := "" @@ -256,7 +258,7 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph msg := &signalpb.WebSocketMessage{} err := wspb.Read(ctx, ws, msg) if err != nil { - zlog.Err(err).Msg("error reading websocket message") + log.Err(err).Msg("error reading websocket message") return "", err } @@ -280,10 +282,10 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph provisioningUrl = "sgnl://linkdevice?uuid=" + uuid + "&pub_key=" + pubKey // Create and send response - response := web.CreateWSResponse(*msg.Request.Id, 200) + response := web.CreateWSResponse(ctx, *msg.Request.Id, 200) err = wspb.Write(ctx, ws, response) if err != nil { - zlog.Err(err).Msg("error writing websocket message") + log.Err(err).Msg("error writing websocket message") return "", err } } @@ -291,11 +293,12 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph } func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCipher *ProvisioningCipher) (*signalpb.ProvisionMessage, error) { + log := zerolog.Ctx(ctx).With().Str("action", "continue provisioning").Logger() envelope := &signalpb.ProvisionEnvelope{} msg := &signalpb.WebSocketMessage{} err := wspb.Read(ctx, ws, msg) if err != nil { - zlog.Err(err).Msg("error reading websocket message") + log.Err(err).Msg("error reading websocket message") return nil, err } @@ -309,15 +312,15 @@ func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningC return nil, err } - response := web.CreateWSResponse(*msg.Request.Id, 200) + response := web.CreateWSResponse(ctx, *msg.Request.Id, 200) err = wspb.Write(ctx, ws, response) if err != nil { - zlog.Err(err).Msg("error writing websocket message") + log.Err(err).Msg("error writing websocket message") return nil, err } } else { err = fmt.Errorf("invalid provisioning message, type: %v, verb: %v, path: %v", *msg.Type, *msg.Request.Verb, *msg.Request.Path) - zlog.Err(err).Msg("problem reading websocket message") + log.Err(err).Msg("problem reading websocket message") return nil, err } provisioningMessage, err := provisioningCipher.Decrypt(envelope) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 188e060..c5cd7a7 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -60,7 +60,7 @@ func (cli *Client) senderCertificate(ctx context.Context) (*libsignalgo.SenderCe username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(http.MethodGet, "/v1/certificate/delivery", opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/certificate/delivery", opts) if err != nil { return nil, err } @@ -121,7 +121,7 @@ func addPadding(version uint32, contents []byte) ([]byte, error) { err := padBlock(&buffer, messageLength) if err != nil { - return nil, errors.New(fmt.Sprintf("Invalid message padding: %v", err)) + return nil, fmt.Errorf("Invalid message padding: %w", err) } return buffer, nil } diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index c00ada6..8ef8c25 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -219,14 +219,14 @@ func (s *SignalWebsocket) connectLoop( // Unexpected status code s.statusChannel <- SignalWebsocketConnectionStatus{ Event: SignalWebsocketConnectionEventError, - Err: fmt.Errorf("Bad status opening websocket: %v", resp.Status), + Err: fmt.Errorf("bad status opening websocket: %v", resp.Status), } return // NOT RETRYING, KILLING THE CONNECTION LOOP } else { // Something is very wrong s.statusChannel <- SignalWebsocketConnectionStatus{ Event: SignalWebsocketConnectionEventError, - Err: fmt.Errorf("Unexpected error opening websocket: %v", resp.Status), + Err: fmt.Errorf("unexpected error opening websocket: %v", resp.Status), } } // Retry the connection @@ -385,10 +385,10 @@ func readLoop( return fmt.Errorf("error reading message: %w", err) } if msg.Type == nil { - return errors.New("Received message with no type") + return errors.New("received message with no type") } else if *msg.Type == signalpb.WebSocketMessage_REQUEST { if msg.Request == nil { - return errors.New("Received request message with no request") + return errors.New("received request message with no request") } log.Debug(). Uint64("request_id", *msg.Request.Id). @@ -421,9 +421,9 @@ func readLoop( Msg("Deleted response channel for ID") close(responseChannel) } else if *msg.Type == signalpb.WebSocketMessage_UNKNOWN { - return fmt.Errorf("Received message with unknown type: %v", *msg.Type) + return fmt.Errorf("received message with unknown type: %v", *msg.Type) } else { - return fmt.Errorf("Received message with actually unknown type: %v", *msg.Type) + return fmt.Errorf("received message with actually unknown type: %v", *msg.Type) } } } @@ -498,7 +498,7 @@ func writeLoop( return fmt.Errorf("error writing request message: %w", err) } } else if request.RequestMessage != nil && request.ResponseMessage != nil { - message := CreateWSResponse(*request.RequestMessage.Id, request.ResponseMessage.Status) + message := CreateWSResponse(ctx, *request.RequestMessage.Id, request.ResponseMessage.Status) log.Debug(). Uint64("request_id", *request.RequestMessage.Id). Int("response_status", request.ResponseMessage.Status). @@ -508,7 +508,7 @@ func writeLoop( return fmt.Errorf("error writing response message: %w", err) } } else { - return fmt.Errorf("Invalid request: %+v", request) + return fmt.Errorf("invalid request: %+v", request) } } } @@ -576,10 +576,10 @@ func OpenWebsocket(ctx context.Context, path string) (*websocket.Conn, *http.Res return ws, resp, err } -func CreateWSResponse(id uint64, status int) *signalpb.WebSocketMessage { +func CreateWSResponse(ctx context.Context, id uint64, status int) *signalpb.WebSocketMessage { if status != 200 && status != 400 { // TODO support more responses to Signal? Are there more? - zlog.Fatal().Int("status", status).Msg("Error creating response. Non 200/400 not supported yet.") + zerolog.Ctx(ctx).Fatal().Int("status", status).Msg("Error creating response. Non 200/400 not supported yet.") return nil } msg_type := signalpb.WebSocketMessage_RESPONSE diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index f8a1882..6e98990 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -50,13 +50,6 @@ var CDNHosts = []string{ CDN3Hostname, } -// Deprecated: global loggers should never be used -var zlog zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{}).With().Timestamp().Logger() - -func SetLogger(l zerolog.Logger) { - zlog = l -} - //go:embed signal-root.crt.der var signalRootCertBytes []byte var signalTransport = &http.Transport{ @@ -112,7 +105,7 @@ type HTTPReqOpt struct { var httpReqCounter = 0 -func SendHTTPRequest(method string, path string, opt *HTTPReqOpt) (*http.Response, error) { +func SendHTTPRequest(ctx context.Context, method string, path string, opt *HTTPReqOpt) (*http.Response, error) { // Set defaults if opt == nil { opt = &HTTPReqOpt{} @@ -127,10 +120,16 @@ func SendHTTPRequest(method string, path string, opt *HTTPReqOpt) (*http.Respons if opt.OverrideURL != "" { urlStr = opt.OverrideURL } + log := zerolog.Ctx(ctx).With(). + Str("action", "send HTTP request"). + Str("method", method). + Str("url", urlStr). + Logger() + ctx = log.WithContext(ctx) - req, err := http.NewRequest(method, urlStr, bytes.NewBuffer(opt.Body)) + req, err := http.NewRequestWithContext(ctx, method, urlStr, bytes.NewBuffer(opt.Body)) if err != nil { - zlog.Err(err).Msg("Error creating request") + log.Err(err).Msg("Error creating request") return nil, err } if opt.Headers != nil { @@ -152,11 +151,7 @@ func SendHTTPRequest(method string, path string, opt *HTTPReqOpt) (*http.Respons } httpReqCounter++ - log := zlog.With(). - Int("request_number", httpReqCounter). - Str("method", method). - Str("url", urlStr). - Logger() + log = log.With().Int("request_number", httpReqCounter).Logger() log.Trace().Msg("Sending HTTP request") resp, err := signalHTTPClient.Do(req) if err != nil { diff --git a/provisioning.go b/provisioning.go index bb7755f..6920903 100644 --- a/provisioning.go +++ b/provisioning.go @@ -341,7 +341,7 @@ func (prov *ProvisioningAPI) loginOrSendError(ctx context.Context, w http.Respon Int("existing_provisioning_handle", handle.id). Msg("user already has pending provisioning request, cancelling") prov.clearSession(ctx, user) - newSessionLoggedIn, handle, err = prov.newOrExistingSession(user) + _, handle, err = prov.newOrExistingSession(user) if err != nil { return nil, fmt.Errorf("error logging in after cancelling existing session: %w", err) } diff --git a/puppet.go b/puppet.go index c2d2584..67f3726 100644 --- a/puppet.go +++ b/puppet.go @@ -337,7 +337,7 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type return true } var err error - avatarData, err = source.Client.DownloadUserAvatar(info.ProfileAvatarPath, info.ProfileKey) + avatarData, err = source.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, info.ProfileKey) if err != nil { log.Err(err). Str("profile_avatar_path", info.ProfileAvatarPath). From 84601c56f345452bedbb9224d2b6f1d653f2f53e Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sat, 6 Jan 2024 11:37:52 -0700 Subject: [PATCH 032/718] signalmeow/misc: remove global zlog Signed-off-by: Sumner Evans --- pkg/signalmeow/groups.go | 109 +++++++++++--------------- pkg/signalmeow/keys.go | 83 +++++++------------- pkg/signalmeow/misc.go | 37 ++++----- pkg/signalmeow/profile.go | 53 +++++-------- pkg/signalmeow/provisioning.go | 43 +++++----- pkg/signalmeow/provisioning_cipher.go | 45 ++++------- pkg/signalmeow/receiving.go | 52 ++++++------ pkg/signalmeow/sending.go | 18 ++++- 8 files changed, 182 insertions(+), 258 deletions(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 0f7f7fb..d485264 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -21,7 +21,6 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -30,6 +29,7 @@ import ( "unicode" "github.com/google/uuid" + "github.com/rs/zerolog" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -80,30 +80,30 @@ type GroupAuth struct { } func (cli *Client) fetchNewGroupCreds(ctx context.Context, today time.Time) (*GroupCredentials, error) { + log := zerolog.Ctx(ctx).With(). + Str("action", "fetch new group creds"). + Logger() sevenDaysOut := today.Add(7 * 24 * time.Hour) path := fmt.Sprintf("/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d", today.Unix(), sevenDaysOut.Unix()) authRequest := web.CreateWSRequest(http.MethodGet, path, nil, nil, nil) resp, err := cli.AuthedWS.SendRequest(ctx, authRequest) if err != nil { - zlog.Err(err).Msg("SendRequest error") - return nil, err + return nil, fmt.Errorf("SendRequest error: %w", err) } if *resp.Status != 200 { - err := fmt.Errorf("bad status code: %d", *resp.Status) - zlog.Err(err).Msg("bad status code fetching group creds") - return nil, err + return nil, fmt.Errorf("bad status code fetching group creds: %d", *resp.Status) } var creds GroupCredentials err = json.Unmarshal(resp.Body, &creds) if err != nil { - zlog.Err(err).Msg("json.Unmarshal error") + log.Err(err).Msg("json.Unmarshal error") return nil, err } // make sure pni matches device pni if creds.PNI != cli.Store.PNI { err := fmt.Errorf("creds.PNI != d.PNI") - zlog.Err(err).Msg("creds.PNI != d.PNI") + log.Err(err).Msg("creds.PNI != d.PNI") return nil, err } return &creds, nil @@ -121,11 +121,13 @@ func (cli *Client) getCachedAuthorizationForToday(today time.Time) *GroupCredent return &cred } } - zlog.Info().Msg("No cached credential found for today") return nil } func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsignalgo.GroupMasterKey) (*GroupAuth, error) { + log := zerolog.Ctx(ctx).With(). + Str("action", "get authorization for today"). + Logger() // Timestamps for the start of today, and 7 days later today := time.Now().Truncate(24 * time.Hour) @@ -133,16 +135,13 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi if todayCred == nil { creds, err := cli.fetchNewGroupCreds(ctx, today) if err != nil { - zlog.Err(err).Msg("fetchNewGroupCreds error") - return nil, err + return nil, fmt.Errorf("fetchNewGroupCreds error: %w", err) } cli.GroupCredentials = creds todayCred = cli.getCachedAuthorizationForToday(today) } if todayCred == nil { - err := errors.New("Couldn't get credential for today") - zlog.Err(err).Msg("GetAuthorizationForToday error") - return nil, err + return nil, fmt.Errorf("couldn't get credential for today") } //TODO: cache cred after unmarshalling @@ -150,7 +149,7 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi credential := todayCred.Credential authCredentialResponse, err := libsignalgo.NewAuthCredentialWithPniResponse(credential) if err != nil { - zlog.Err(err).Msg("NewAuthCredentialWithPniResponse error") + log.Err(err).Msg("NewAuthCredentialWithPniResponse error") return nil, err } @@ -163,14 +162,14 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi *authCredentialResponse, ) if err != nil { - zlog.Err(err).Msg("ReceiveAuthCredentialWithPni error") + log.Err(err).Msg("ReceiveAuthCredentialWithPni error") return nil, err } // get auth presentation groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKey) if err != nil { - zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") + log.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") return nil, err } authCredentialPresentation, err := libsignalgo.CreateAuthCredentialWithPniPresentation( @@ -180,12 +179,12 @@ func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsi *authCredential, ) if err != nil { - zlog.Err(err).Msg("CreateAuthCredentialWithPniPresentation error") + log.Err(err).Msg("CreateAuthCredentialWithPniPresentation error") return nil, err } groupPublicParams, err := groupSecretParams.GetPublicParams() if err != nil { - zlog.Err(err).Msg("GetPublicParams error") + log.Err(err).Msg("GetPublicParams error") return nil, err } @@ -199,8 +198,7 @@ func masterKeyToBytes(groupMasterKey types.SerializedGroupMasterKey) libsignalgo // We are very tricksy, groupMasterKey is just base64 encoded group master key :O masterKeyBytes, err := base64.StdEncoding.DecodeString(string(groupMasterKey)) if err != nil { - //zlog.Err(err).Msg("") - zlog.Fatal().Err(err).Msg("We should always be able to decode groupMasterKey into masterKeyBytes") + panic(fmt.Errorf("we should always be able to decode groupMasterKey into masterKeyBytes: %w", err)) } return libsignalgo.GroupMasterKey(masterKeyBytes) } @@ -212,39 +210,37 @@ func masterKeyFromBytes(masterKey libsignalgo.GroupMasterKey) types.SerializedGr func groupIdentifierFromMasterKey(masterKey types.SerializedGroupMasterKey) (types.GroupIdentifier, error) { groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(masterKey)) if err != nil { - zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") - return "", err + return "", fmt.Errorf("DeriveGroupSecretParamsFromMasterKey error: %w", err) } // Get the "group identifier" that isn't just the master key groupPublicParams, err := groupSecretParams.GetPublicParams() if err != nil { - zlog.Err(err).Msg("GetPublicParams error") - return "", err + return "", fmt.Errorf("GetPublicParams error: %w", err) } groupIdentifier, err := libsignalgo.GetGroupIdentifier(*groupPublicParams) if err != nil { - zlog.Err(err).Msg("GetGroupIdentifier error") - return "", err + return "", fmt.Errorf("GetGroupIdentifier error: %w", err) } base64GroupIdentifier := base64.StdEncoding.EncodeToString(groupIdentifier[:]) gid := types.GroupIdentifier(base64GroupIdentifier) return gid, nil } -func decryptGroup(encryptedGroup *signalpb.Group, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { +func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { + log := zerolog.Ctx(ctx).With().Str("action", "decrypt group").Logger() decryptedGroup := &Group{ groupMasterKey: groupMasterKey, } groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) if err != nil { - zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") + log.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") return nil, err } gid, err := groupIdentifierFromMasterKey(groupMasterKey) if err != nil { - zlog.Err(err).Msg("groupIdentifierFromMasterKey error") + log.Err(err).Msg("groupIdentifierFromMasterKey error") return nil, err } decryptedGroup.GroupIdentifier = gid @@ -283,13 +279,13 @@ func decryptGroup(encryptedGroup *signalpb.Group, groupMasterKey types.Serialize encryptedUserID := libsignalgo.UUIDCiphertext(member.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - zlog.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(member.ProfileKey) profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) if err != nil { - zlog.Err(err).Msg("DecryptProfileKey ProfileKey error") + log.Err(err).Msg("DecryptProfileKey ProfileKey error") return nil, err } decryptedGroup.Members = append(decryptedGroup.Members, &GroupMember{ @@ -306,16 +302,14 @@ func decryptGroup(encryptedGroup *signalpb.Group, groupMasterKey types.Serialize func decryptGroupPropertyIntoBlob(groupSecretParams libsignalgo.GroupSecretParams, encryptedProperty []byte) (*signalpb.GroupAttributeBlob, error) { decryptedProperty, err := groupSecretParams.DecryptBlobWithPadding(encryptedProperty) if err != nil { - zlog.Err(err).Msg("DecryptBlobWithPadding error") - return nil, err + return nil, fmt.Errorf("error decrypting blob with padding: %w", err) } - propertyBlob := &signalpb.GroupAttributeBlob{} - err = proto.Unmarshal(decryptedProperty, propertyBlob) + var propertyBlob signalpb.GroupAttributeBlob + err = proto.Unmarshal(decryptedProperty, &propertyBlob) if err != nil { - zlog.Err(err).Msg("Unmarshal error") - return nil, err + return nil, fmt.Errorf("error unmarshalling blob: %w", err) } - return propertyBlob, nil + return &propertyBlob, nil } func cleanupStringProperty(property string) string { @@ -335,8 +329,7 @@ func cleanupStringMapping(r rune) rune { func decryptGroupAvatar(encryptedAvatar []byte, groupMasterKey types.SerializedGroupMasterKey) ([]byte, error) { groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) if err != nil { - zlog.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") - return nil, err + return nil, fmt.Errorf("error deriving group secret params from master key: %w", err) } avatarBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedAvatar) if err != nil { @@ -360,13 +353,10 @@ func groupMetadataForDataMessage(group Group) *signalpb.GroupContextV2 { func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier) (*Group, error) { groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { - zlog.Err(err).Msg("Failed to get group master key") - return nil, err + return nil, fmt.Errorf("failed to get group master key: %w", err) } if groupMasterKey == "" { - err := fmt.Errorf("No group master key found for group identifier") - zlog.Err(err).Str("gid", string(gid)).Msg("") - return nil, err + return nil, fmt.Errorf("No group master key found for group identifier %s", gid) } masterKeyBytes := masterKeyToBytes(groupMasterKey) groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) @@ -381,38 +371,31 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier } response, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/groups", opts) if err != nil { - zlog.Err(err).Msg("RetrieveGroupById SendHTTPRequest error") return nil, err } if response.StatusCode != 200 { - err := fmt.Errorf("RetrieveGroupById SendHTTPRequest bad status: %v", response.StatusCode) - zlog.Err(err).Msg("") - return nil, err + return nil, fmt.Errorf("fetchGroupByID SendHTTPRequest bad status: %d", response.StatusCode) } - encryptedGroup := &signalpb.Group{} + var encryptedGroup signalpb.Group groupBytes, err := io.ReadAll(response.Body) if err != nil { - zlog.Err(err).Msg("RetrieveGroupById ReadAll error") return nil, err } - err = proto.Unmarshal(groupBytes, encryptedGroup) + err = proto.Unmarshal(groupBytes, &encryptedGroup) if err != nil { - zlog.Err(err).Msg("RetrieveGroupById Unmarshal error") - return nil, err + return nil, fmt.Errorf("failed to unmarshal group: %w", err) } - group, err := decryptGroup(encryptedGroup, groupMasterKey) + group, err := decryptGroup(ctx, &encryptedGroup, groupMasterKey) if err != nil { - zlog.Err(err).Msg("RetrieveGroupById decryptGroup error") - return nil, err + return nil, fmt.Errorf("failed to decrypt group: %w", err) } // Store the profile keys in case they're new for _, member := range group.Members { err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) if err != nil { - zlog.Err(err).Msg("DecryptGroup StoreProfileKey error") - //return nil, err + return nil, fmt.Errorf("failed to store profile key: %w", err) } } return group, nil @@ -469,13 +452,11 @@ func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentif func (cli *Client) StoreMasterKey(ctx context.Context, groupMasterKey types.SerializedGroupMasterKey) (types.GroupIdentifier, error) { groupIdentifier, err := groupIdentifierFromMasterKey(groupMasterKey) if err != nil { - zlog.Err(err).Msg("groupIdentifierFromMasterKey error") - return "", err + return "", fmt.Errorf("groupIdentifierFromMasterKey error: %w", err) } err = cli.Store.GroupStore.StoreMasterKey(ctx, groupIdentifier, groupMasterKey) if err != nil { - zlog.Err(err).Msg("StoreMasterKey error") - return "", err + return "", fmt.Errorf("StoreMasterKey error: %w", err) } return groupIdentifier, nil } diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index e30d6ca..ceede16 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -88,8 +88,7 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, cli.Store.DeviceID) err = RegisterPreKeys(ctx, &generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) if err != nil { - zlog.Err(err).Msg("RegisterPreKeys error") - return err + return fmt.Errorf("failed to register prekeys: %w", err) } // Mark prekeys as registered @@ -112,13 +111,11 @@ func GeneratePreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind) []*li for i := startKeyId; i < startKeyId+count; i++ { privateKey, err := libsignalgo.GeneratePrivateKey() if err != nil { - zlog.Err(err).Msg("Error generating private key") - panic(err) + panic(fmt.Errorf("error generating private key: %w", err)) } preKey, err := libsignalgo.NewPreKeyRecordFromPrivateKey(uint32(i), privateKey) if err != nil { - zlog.Err(err).Msg("Error creating preKey record") - panic(err) + panic(fmt.Errorf("error creating prekey record: %w", err)) } generatedPreKeys = append(generatedPreKeys, preKey) } @@ -130,28 +127,23 @@ func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind, for i := startKeyId; i < startKeyId+count; i++ { kyberPreKeyPair, err := libsignalgo.KyberKeyPairGenerate() if err != nil { - zlog.Err(err).Msg("Error generating kyber key pair") - panic(err) + panic(fmt.Errorf("error generating kyber key pair: %w", err)) } publicKey, err := kyberPreKeyPair.GetPublicKey() if err != nil { - zlog.Err(err).Msg("Error getting kyber public key") - panic(err) + panic(fmt.Errorf("error getting kyber public key: %w", err)) } serializedPublicKey, err := publicKey.Serialize() if err != nil { - zlog.Err(err).Msg("Error serializing kyber public key") - panic(err) + panic(fmt.Errorf("error serializing kyber public key: %w", err)) } signature, err := identityKeyPair.GetPrivateKey().Sign(serializedPublicKey) if err != nil { - zlog.Err(err).Msg("Error signing kyber public key") - panic(err) + panic(fmt.Errorf("error signing kyber public key: %w", err)) } preKey, err := libsignalgo.NewKyberPreKeyRecord(uint32(i), time.Now(), kyberPreKeyPair, signature) if err != nil { - zlog.Err(err).Msg("Error creating kyber preKey record") - panic(err) + panic(fmt.Errorf("error creating kyber prekey record: %w", err)) } generatedKyberPreKeys = append(generatedKyberPreKeys, preKey) @@ -163,29 +155,24 @@ func GenerateSignedPreKey(startSignedKeyId uint32, uuidKind types.UUIDKind, iden // Generate a signed prekey privateKey, err := libsignalgo.GeneratePrivateKey() if err != nil { - zlog.Err(err).Msg("Error generating private key") - panic(err) + panic(fmt.Errorf("error generating private key: %w", err)) } timestamp := time.Now() publicKey, err := privateKey.GetPublicKey() if err != nil { - zlog.Err(err).Msg("Error getting public key") - panic(err) + panic(fmt.Errorf("error getting public key: %w", err)) } serializedPublicKey, err := publicKey.Serialize() if err != nil { - zlog.Err(err).Msg("Error serializing public key") - panic(err) + panic(fmt.Errorf("error serializing public key: %w", err)) } signature, err := identityKeyPair.GetPrivateKey().Sign(serializedPublicKey) if err != nil { - zlog.Err(err).Msg("Error signing public key") - panic(err) + panic(fmt.Errorf("error signing public key: %w", err)) } signedPreKey, err := libsignalgo.NewSignedPreKeyRecordFromPrivateKey(startSignedKeyId, timestamp, privateKey, signature) if err != nil { - zlog.Err(err).Msg("Error creating signed preKey record") - panic(err) + panic(fmt.Errorf("error creating signed prekey record: %w", err)) } return signedPreKey @@ -307,14 +294,12 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI username, password := cli.Store.BasicAuthCreds() resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) if err != nil { - zlog.Err(err).Msg("Error sending request") - return err + return fmt.Errorf("error sending request: %w", err) } var prekeyResponse prekeyResponse err = web.DecodeHTTPResponseBody(ctx, &prekeyResponse, resp) if err != nil { - zlog.Err(err).Msg("Fetching prekeys, error with response body") - return err + return fmt.Errorf("error decoding response body: %w", err) } rawIdentityKey, err := addBase64PaddingAndDecode(prekeyResponse.IdentityKey) @@ -323,13 +308,10 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI } identityKey, err := libsignalgo.DeserializeIdentityKey([]byte(rawIdentityKey)) if err != nil { - zlog.Err(err).Msg("Error deserializing identity key") - return err + return fmt.Errorf("error deserializing identity key: %w", err) } if identityKey == nil { - err := fmt.Errorf("Deserializing identity key returned nil with no error") - zlog.Err(err).Msg("") - return err + return fmt.Errorf("deserializing identity key returned nil with no error") } // Process each prekey in response (should only be one at the moment) @@ -340,25 +322,21 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI preKeyID = uint32(d.PreKey.KeyID) rawPublicKey, err := addBase64PaddingAndDecode(d.PreKey.PublicKey) if err != nil { - zlog.Err(err).Msg("Error decoding public key") - return err + return fmt.Errorf("error decoding public key: %w", err) } publicKey, err = libsignalgo.DeserializePublicKey(rawPublicKey) if err != nil { - zlog.Err(err).Msg("Error deserializing public key") - return err + return fmt.Errorf("error deserializing public key: %w", err) } } rawSignedPublicKey, err := addBase64PaddingAndDecode(d.SignedPreKey.PublicKey) if err != nil { - zlog.Err(err).Msg("Error decoding signed public key") - return err + return fmt.Errorf("error decoding signed public key: %w", err) } signedPublicKey, err := libsignalgo.DeserializePublicKey(rawSignedPublicKey) if err != nil { - zlog.Err(err).Msg("Error deserializing signed public key") - return err + return fmt.Errorf("error deserializing signed public key: %w", err) } var kyberPublicKey *libsignalgo.KyberPublicKey @@ -368,13 +346,11 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI kyberPreKeyID = uint32(d.PQPreKey.KeyID) rawKyberPublicKey, err := addBase64PaddingAndDecode(d.PQPreKey.PublicKey) if err != nil { - zlog.Err(err).Msg("Error decoding kyber public key") - return err + return fmt.Errorf("error decoding kyber public key: %w", err) } kyberPublicKey, err = libsignalgo.DeserializeKyberPublicKey(rawKyberPublicKey) if err != nil { - zlog.Err(err).Msg("Error deserializing kyber public key") - return err + return fmt.Errorf("error deserializing kyber public key: %w", err) } kyberPreKeySignature, err = addBase64PaddingAndDecode(d.PQPreKey.Signature) if err != nil { @@ -384,8 +360,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI rawSignature, err := addBase64PaddingAndDecode(d.SignedPreKey.Signature) if err != nil { - zlog.Err(err).Msg("Error decoding signature") - return err + return fmt.Errorf("error decoding signature: %w", err) } preKeyBundle, err := libsignalgo.NewPreKeyBundle( @@ -402,13 +377,11 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI identityKey, ) if err != nil { - zlog.Err(err).Msg("Error creating prekey bundle") - return err + return fmt.Errorf("error creating prekey bundle: %w", err) } address, err := libsignalgo.NewUUIDAddress(theirUUID, uint(d.DeviceID)) if err != nil { - zlog.Err(err).Msg("Error creating address") - return err + return fmt.Errorf("error creating address: %w", err) } err = libsignalgo.ProcessPreKeyBundle( ctx, @@ -417,10 +390,8 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI cli.Store.SessionStore, cli.Store.IdentityStore, ) - if err != nil { - zlog.Err(err).Msg("Error processing prekey bundle") - return err + return fmt.Errorf("error processing prekey bundle: %w", err) } } diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 8e6894e..0c305ee 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -24,31 +24,37 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -// Deprecated: global loggers are bad -var zlog zerolog.Logger = zerolog.New(zerolog.ConsoleWriter{}).With().Timestamp().Logger() +var loggingSetup = false func SetLogger(l zerolog.Logger) { - zlog = l - setupFFILogging() + if loggingSetup { + return + } + libsignalgo.InitLogger(libsignalgo.LogLevelInfo, FFILogger{ + logger: l, + }) + loggingSetup = true } -type FFILogger struct{} +type FFILogger struct { + logger zerolog.Logger +} func (FFILogger) Enabled(target string, level libsignalgo.LogLevel) bool { return true } -func (FFILogger) Log(target string, level libsignalgo.LogLevel, file string, line uint, message string) { +func (l FFILogger) Log(target string, level libsignalgo.LogLevel, file string, line uint, message string) { var evt *zerolog.Event switch level { case libsignalgo.LogLevelError: - evt = zlog.Error() + evt = l.logger.Error() case libsignalgo.LogLevelWarn: - evt = zlog.Warn() + evt = l.logger.Warn() case libsignalgo.LogLevelInfo: - evt = zlog.Info() + evt = l.logger.Info() case libsignalgo.LogLevelDebug: - evt = zlog.Debug() + evt = l.logger.Debug() case libsignalgo.LogLevelTrace: - evt = zlog.Trace() + evt = l.logger.Trace() default: panic("invalid log level from libsignal") } @@ -65,15 +71,6 @@ func (FFILogger) Flush() {} // Ensure FFILogger implements the Logger interface var _ libsignalgo.Logger = FFILogger{} -var loggingSetup = false - -func setupFFILogging() { - if !loggingSetup { - libsignalgo.InitLogger(libsignalgo.LogLevelInfo, FFILogger{}) - loggingSetup = true - } -} - //go:embed prod-server-public-params.dat var prodServerPublicParamsSlice []byte var prodServerPublicParams libsignalgo.ServerPublicParams diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 503418b..57aa7f2 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -32,6 +32,7 @@ import ( "time" "github.com/google/uuid" + "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" @@ -86,8 +87,7 @@ type ProfileCache struct { func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uuid.UUID) ([]byte, error) { profileKey, err := cli.ProfileKeyForSignalID(ctx, signalACI) if err != nil { - zlog.Err(err).Msg("ProfileKey error") - return nil, err + return nil, fmt.Errorf("error getting profile key for ACI: %w", err) } requestContext, err := libsignalgo.CreateProfileKeyCredentialRequestContext( prodServerPublicParams, @@ -95,14 +95,12 @@ func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uu *profileKey, ) if err != nil { - zlog.Err(err).Msg("CreateProfileKeyCredentialRequestContext error") - return nil, err + return nil, fmt.Errorf("error creating profile key credential request context: %w", err) } request, err := requestContext.ProfileKeyCredentialRequestContextGetRequest() if err != nil { - zlog.Err(err).Msg("CreateProfileKeyCredentialRequest error") - return nil, err + return nil, fmt.Errorf("error getting profile key credential request: %w", err) } // convert request bytes to hexidecimal representation @@ -113,8 +111,7 @@ func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uu func (cli *Client) ProfileKeyForSignalID(ctx context.Context, signalACI uuid.UUID) (*libsignalgo.ProfileKey, error) { profileKey, err := cli.Store.ProfileKeyStore.LoadProfileKey(ctx, signalACI) if err != nil { - zlog.Err(err).Msg("GetProfileKey error") - return nil, err + return nil, fmt.Errorf("error getting profile key: %w", err) } return profileKey, nil } @@ -166,39 +163,36 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) } func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*Profile, error) { + log := zerolog.Ctx(ctx) profileKey, err := cli.ProfileKeyForSignalID(ctx, signalID) if err != nil { - zlog.Err(err).Msg("ProfileKey error") - return nil, err + return nil, fmt.Errorf("error getting profile key: %w", err) } if profileKey == nil { - zlog.Err(err).Msg("profileKey is nil") + log.Warn().Msg("profileKey is nil") return nil, nil } profileKeyVersion, err := profileKey.GetProfileKeyVersion(signalID) if err != nil { - zlog.Err(err).Msg("profileKey error") - return nil, err + return nil, fmt.Errorf("error getting profile key version: %w", err) } accessKey, err := profileKey.DeriveAccessKey() if err != nil { - zlog.Err(err).Msg("DeriveAccessKey error") - return nil, err + return nil, fmt.Errorf("error deriving access key: %w", err) } base64AccessKey := base64.StdEncoding.EncodeToString(accessKey[:]) credentialRequest, err := cli.ProfileKeyCredentialRequest(ctx, signalID) if err != nil { - zlog.Err(err).Msg("ProfileKeyCredentialRequest error") - return nil, err + return nil, fmt.Errorf("error getting profile key credential request: %w", err) } path := "/v1/profile/" + signalID.String() useUnidentified := profileKeyVersion != nil && accessKey != nil if useUnidentified { - zlog.Trace(). + log.Trace(). Hex("profile_key_version", profileKeyVersion[:]). Msg("Using unidentified profile request") // Assuming we can just make the version bytes into a string @@ -215,26 +209,22 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P } resp, err := cli.UnauthedWS.SendRequest(ctx, profileRequest) if err != nil { - zlog.Err(err).Msg("SendRequest error") - return nil, err + return nil, fmt.Errorf("error sending request: %w", err) } - zlog.Trace().Msg("Got profile response") + log.Trace().Msg("Got profile response") if *resp.Status < 200 || *resp.Status >= 300 { - err := fmt.Errorf("%v (unsuccessful status code)", *resp.Status) - zlog.Err(err).Msg("profile response error") - return nil, err + return nil, fmt.Errorf("error getting profile (unsuccessful status code %d)", *resp.Status) } var profileResponse ProfileResponse err = json.Unmarshal(resp.Body, &profileResponse) if err != nil { - zlog.Err(err).Msg("json.Unmarshal error") - return nil, err + return nil, fmt.Errorf("error unmarshalling profile response: %w", err) } var profile Profile if len(profileResponse.Name) > 0 { profile.Name, err = decryptString(profileKey, profileResponse.Name) if err != nil { - zlog.Err(err).Msg("error decrypting profile name") + return nil, fmt.Errorf("error decrypting profile name: %w", err) } // TODO store first and last name separately instead of removing the separator profile.Name = strings.ReplaceAll(profile.Name, "\x00", " ") @@ -242,13 +232,13 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P if len(profileResponse.About) > 0 { profile.About, err = decryptString(profileKey, profileResponse.About) if err != nil { - zlog.Err(err).Msg("error decrypting profile about") + return nil, fmt.Errorf("error decrypting profile about: %w", err) } } if len(profileResponse.AboutEmoji) > 0 { profile.AboutEmoji, err = decryptString(profileKey, profileResponse.AboutEmoji) if err != nil { - zlog.Err(err).Msg("error decrypting profile aboutEmoji") + return nil, fmt.Errorf("error decrypting profile aboutEmoji: %w", err) } } profile.AvatarPath = profileResponse.Avatar @@ -307,10 +297,7 @@ func decryptBytes(key *libsignalgo.ProfileKey, encryptedText []byte) ([]byte, er func decryptString(key *libsignalgo.ProfileKey, encryptedText []byte) (string, error) { data, err := decryptBytes(key, encryptedText) - if err != nil { - return "", err - } - return string(data), nil + return string(data), err } func encryptString(key libsignalgo.ProfileKey, plaintext string, paddedLength int) ([]byte, error) { diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 6e09256..471526a 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -79,16 +79,17 @@ type ProvisioningResponse struct { Err error } -func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceStore, deviceName string) chan ProvisioningResponse { +func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, deviceName string) chan ProvisioningResponse { + log := zerolog.Ctx(ctx).With().Str("action", "perform provisioning").Logger() c := make(chan ProvisioningResponse) go func() { defer close(c) - ctx, cancel := context.WithTimeout(incomingCtx, 2*time.Minute) + ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() ws, resp, err := web.OpenWebsocket(ctx, web.WebsocketProvisioningPath) if err != nil { - zlog.Err(err).Any("resp", resp).Msg("error opening provisioning websocket") + log.Err(err).Any("resp", resp).Msg("error opening provisioning websocket") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } @@ -97,7 +98,7 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt provisioningUrl, err := startProvisioning(ctx, ws, provisioningCipher) if err != nil { - zlog.Err(err).Msg("startProvisioning error") + log.Err(err).Msg("startProvisioning error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } @@ -105,7 +106,7 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt provisioningMessage, err := continueProvisioning(ctx, ws, provisioningCipher) if err != nil { - zlog.Err(err).Msg("continueProvisioning error") + log.Err(err).Msg("continueProvisioning error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } @@ -145,7 +146,7 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt deviceName, ) if err != nil { - zlog.Err(err).Msg("confirmDevice error") + log.Err(err).Msg("confirmDevice error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } @@ -170,14 +171,14 @@ func PerformProvisioning(incomingCtx context.Context, deviceStore store.DeviceSt // Store the provisioning data err = deviceStore.PutDevice(ctx, data) if err != nil { - zlog.Err(err).Msg("error storing new device") + log.Err(err).Msg("error storing new device") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } device, err := deviceStore.DeviceByACI(ctx, data.ACI) if err != nil { - zlog.Err(err).Msg("error retrieving new device") + log.Err(err).Msg("error retrieving new device") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } @@ -341,6 +342,8 @@ func confirmDevice( aciIdentityKeyPair *libsignalgo.IdentityKeyPair, deviceName string, ) (*ConfirmDeviceResponse, error) { + log := zerolog.Ctx(ctx).With().Str("action", "confirm device").Logger() + ctx = log.WithContext(ctx) encryptedDeviceName, err := EncryptDeviceName(deviceName, aciIdentityKeyPair.GetPublicKey()) if err != nil { return nil, fmt.Errorf("failed to encrypt device name: %w", err) @@ -348,7 +351,7 @@ func confirmDevice( ws, resp, err := web.OpenWebsocket(ctx, web.WebsocketPath) if err != nil { - zlog.Err(err).Any("resp", resp).Msg("error opening websocket") + log.Err(err).Any("resp", resp).Msg("error opening websocket") return nil, err } defer ws.Close(websocket.StatusInternalError, "Websocket StatusInternalError") @@ -359,14 +362,14 @@ func confirmDevice( aciPQLastResortPreKeyJson := KyberPreKeyToJSON(aciPQLastResortPreKey) pniPQLastResortPreKeyJson := KyberPreKeyToJSON(pniPQLastResortPreKey) - data := map[string]interface{}{ + data := map[string]any{ "verificationCode": code, - "accountAttributes": map[string]interface{}{ + "accountAttributes": map[string]any{ "fetchesMessages": true, "name": encryptedDeviceName, "registrationId": registrationId, "pniRegistrationId": pniRegistrationId, - "capabilities": map[string]interface{}{ + "capabilities": map[string]any{ "pni": true, }, }, @@ -378,8 +381,7 @@ func confirmDevice( jsonBytes, err := json.Marshal(data) if err != nil { - zlog.Err(err).Msg("failed to marshal JSON") - return nil, err + return nil, fmt.Errorf("failed to marshal JSON: %w", err) } // Create and send request TODO: Use SignalWebsocket @@ -393,30 +395,25 @@ func confirmDevice( } err = wspb.Write(ctx, ws, message) if err != nil { - zlog.Err(err).Msg("failed on write protobuf data to websocket") - return nil, err + return nil, fmt.Errorf("failed on write protobuf data to websocket: %w", err) } receivedMsg := &signalpb.WebSocketMessage{} err = wspb.Read(ctx, ws, receivedMsg) if err != nil { - zlog.Err(err).Msg("failed to read from websocket after devices call") - return nil, err + return nil, fmt.Errorf("failed to read from websocket after devices call: %w", err) } status := int(*receivedMsg.Response.Status) if status < 200 || status >= 300 { - err := fmt.Errorf("problem with devices response - status: %d, message: %s", status, *receivedMsg.Response.Message) - zlog.Err(err).Msg("non-200 status code from devices response") - return nil, err + return nil, fmt.Errorf("non-200 status code (%d) from devices response: %s", status, *receivedMsg.Response.Message) } // unmarshal JSON response into ConfirmDeviceResponse deviceResp := ConfirmDeviceResponse{} err = json.Unmarshal(receivedMsg.Response.Body, &deviceResp) if err != nil { - zlog.Err(err).Msg("failed to unmarshal JSON") - return nil, err + return nil, fmt.Errorf("failed to unmarshal JSON: %w", err) } return &deviceResp, nil diff --git a/pkg/signalmeow/provisioning_cipher.go b/pkg/signalmeow/provisioning_cipher.go index ec39b7e..8670274 100644 --- a/pkg/signalmeow/provisioning_cipher.go +++ b/pkg/signalmeow/provisioning_cipher.go @@ -44,8 +44,7 @@ func (c *ProvisioningCipher) GetPublicKey() *libsignalgo.PublicKey { if c.keyPair == nil { keyPair, err := libsignalgo.GenerateIdentityKeyPair() if err != nil { - zlog.Err(err).Msg("") - zlog.Fatal().Msg("Unable to generate key pair") + panic(fmt.Errorf("unable to generate key pair: %w", err)) } c.keyPair = keyPair } @@ -65,52 +64,40 @@ const CIPHERTEXT_OFFSET uint = IV_OFFSET + IV_LENGTH func (c *ProvisioningCipher) Decrypt(env *signalpb.ProvisionEnvelope) (*signalpb.ProvisionMessage, error) { masterEphemeral, err := libsignalgo.DeserializePublicKey(env.GetPublicKey()) if err != nil { - zlog.Err(err).Msg("Unable to deserialize public key") - return nil, err + return nil, fmt.Errorf("unable to deserialize public key: %w", err) } if masterEphemeral == nil { - err = fmt.Errorf("No public key: %v", env) - zlog.Err(err).Msg("") - return nil, err + return nil, fmt.Errorf("no public key: %v", env) } body := env.GetBody() if body == nil { - err = fmt.Errorf("No body: %v", env) - zlog.Err(err).Msg("") - return nil, err + return nil, fmt.Errorf("no body: %v", env) } if body[0] != 1 { - err = fmt.Errorf("Invalid ProvisionMessage version: %v", body[0]) - zlog.Err(err).Msg("") - return nil, err + return nil, fmt.Errorf("invalid ProvisionMessage version: %v", body[0]) } bodyLen := uint(len(body)) iv := body[IV_OFFSET : IV_OFFSET+IV_LENGTH] mac := body[bodyLen-MAC_SIZE : bodyLen] if uint(len(mac)) != MAC_SIZE { - err = fmt.Errorf("Invalid MAC size: %v", len(mac)) - zlog.Err(err).Msg("") - return nil, err + return nil, fmt.Errorf("invalid MAC size: %d", len(mac)) } if uint(len(iv)) != IV_LENGTH { - err = fmt.Errorf("Invalid IV size: %v", len(iv)) - zlog.Err(err).Msg("") - return nil, err + return nil, fmt.Errorf("invalid IV size: %d", len(iv)) } cipherText := body[CIPHERTEXT_OFFSET : bodyLen-CIPHER_KEY_SIZE] ivAndCipherText := body[0 : bodyLen-CIPHER_KEY_SIZE] agreement, err := c.keyPair.GetPrivateKey().Agree(masterEphemeral) if err != nil { - zlog.Err(err).Msg("Unable to agree on key") - return nil, err + return nil, fmt.Errorf("unable to agree on key: %w", err) } sharedSecrets := make([]byte, 64) hkdfReader := hkdf.New(sha256.New, agreement, nil, []byte("TextSecure Provisioning Message")) if _, err := io.ReadFull(hkdfReader, sharedSecrets); err != nil { - zlog.Err(err).Msg("Unable to read from hkdfReader") + return nil, fmt.Errorf("unable to read from hkdfReader: %w", err) } parts1 := sharedSecrets[:32] @@ -120,18 +107,15 @@ func (c *ProvisioningCipher) Decrypt(env *signalpb.ProvisionEnvelope) (*signalpb verifier.Write(ivAndCipherText) ourMac := verifier.Sum(nil) if len(ourMac) != len(mac) { - err = fmt.Errorf("Invalid MAC length: ourmac:%v mac:%v", len(ourMac), len(mac)) - zlog.Err(err).Msg("") + return nil, fmt.Errorf("Invalid MAC length: ourmac:%d mac:%d", len(ourMac), len(mac)) } if !hmac.Equal(ourMac[:32], mac) { - err = fmt.Errorf("Invalid MAC: %v", ourMac) - zlog.Err(err).Msg("") + return nil, fmt.Errorf("invalid MAC: %v", ourMac) } block, err := aes.NewCipher(parts1) if err != nil { - zlog.Err(err).Msg("Unable to create cipher") - return nil, err + return nil, fmt.Errorf("unable to create cipher: %w", err) } mode := cipher.NewCBCDecrypter(block, iv) @@ -140,14 +124,13 @@ func (c *ProvisioningCipher) Decrypt(env *signalpb.ProvisionEnvelope) (*signalpb decrypted, err := UnpadPKCS7(decryptedWithPadding) if err != nil { - zlog.Err(err).Msg("Unable to unpad") + return nil, fmt.Errorf("unable to unpad: %w", err) } message := &signalpb.ProvisionMessage{} err = proto.Unmarshal(decrypted, message) if err != nil { - zlog.Err(err).Msg("Unable to unmarshal ProvisionMessage") - return nil, err + return nil, fmt.Errorf("unable to unmarshal ProvisionMessage: %w", err) } return message, nil diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index ac92e06..6068f83 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -235,15 +235,17 @@ func (cli *Client) ClearKeysAndDisconnect(ctx context.Context) error { } // If a bridge can't decrypt prekeys, it's probably because the prekeys are broken so force re-registration -func (cli *Client) checkDecryptionErrorAndDisconnect(err error) { - if err != nil { - if strings.Contains(err.Error(), "30: invalid PreKey message: decryption failed") || - strings.Contains(err.Error(), "70: invalid signed prekey identifier") { - zlog.Warn().Msg("Failed decrypting a PreKey message, probably our prekeys are broken, force re-registration") - disconnectErr := cli.ClearKeysAndDisconnect(context.TODO()) - if disconnectErr != nil { - zlog.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") - } +func (cli *Client) checkDecryptionErrorAndDisconnect(ctx context.Context, err error) { + if err == nil { + return + } + log := zerolog.Ctx(ctx).With().Str("action", "check decryption error and disconnect").Logger() + if strings.Contains(err.Error(), "30: invalid PreKey message: decryption failed") || + strings.Contains(err.Error(), "70: invalid signed prekey identifier") { + log.Warn().Msg("Failed decrypting a PreKey message, probably our prekeys are broken, force re-registration") + disconnectErr := cli.ClearKeysAndDisconnect(ctx) + if disconnectErr != nil { + log.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") } } } @@ -449,7 +451,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Debug().Msg("Message sent by us, ignoring") } else { log.Err(err).Msg("sealedSenderDecrypt error") - cli.checkDecryptionErrorAndDisconnect(err) + cli.checkDecryptionErrorAndDisconnect(ctx, err) } } else { log.Trace(). @@ -471,7 +473,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. result, err = cli.prekeyDecrypt(ctx, sender, envelope.Content) if err != nil { log.Err(err).Msg("prekeyDecrypt error") - cli.checkDecryptionErrorAndDisconnect(err) + cli.checkDecryptionErrorAndDisconnect(ctx, err) } else { log.Trace(). Any("sender_address", result.SenderAddress). @@ -544,7 +546,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. // Handle content that is now decrypted if result != nil && result.Content != nil { content := result.Content - zlog.Trace().Any("raw_data", content).Msg("Raw event data") + log.Trace().Any("raw_data", content).Msg("Raw event data") name, _ := result.SenderAddress.Name() deviceId, _ := result.SenderAddress.DeviceID() @@ -774,7 +776,7 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp var err error groupID, err = cli.StoreMasterKey(ctx, masterKey) if err != nil { - zlog.Err(err).Msg("StoreMasterKey error") + zerolog.Ctx(ctx).Err(err).Msg("StoreMasterKey error") return false } groupRevision = editMessage.GetDataMessage().GetGroupV2().GetRevision() @@ -796,7 +798,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp profileKey := libsignalgo.ProfileKey(dataMessage.ProfileKey) err := cli.Store.ProfileKeyStore.StoreProfileKey(ctx, messageSender, profileKey) if err != nil { - zlog.Err(err).Msg("StoreProfileKey error") + zerolog.Ctx(ctx).Err(err).Msg("StoreProfileKey error") return false } } @@ -811,7 +813,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp var err error groupID, err = cli.StoreMasterKey(ctx, masterKey) if err != nil { - zlog.Err(err).Msg("StoreMasterKey error") + zerolog.Ctx(ctx).Err(err).Msg("StoreMasterKey error") return false } groupRevision = dataMessage.GetGroupV2().GetRevision() @@ -863,13 +865,11 @@ func serverTrustRootKey() *libsignalgo.PublicKey { serverTrustRoot := "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" serverTrustRootBytes, err := base64.StdEncoding.DecodeString(serverTrustRoot) if err != nil { - zlog.Err(err).Msg("DecodeString error") - panic(err) + panic(fmt.Errorf("DecodeString error: %w", err)) } serverTrustRootKey, err := libsignalgo.DeserializePublicKey(serverTrustRootBytes) if err != nil { - zlog.Err(err).Msg("DeserializePublicKey error") - panic(err) + panic(fmt.Errorf("DeserializePublicKey error: %w", err)) } return serverTrustRootKey } @@ -892,30 +892,26 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E cli.Store.PreKeyStore, cli.Store.SignedPreKeyStore, ) - if err != nil { - zlog.Err(err).Msg("SealedSenderDecrypt error") - return nil, err + return nil, fmt.Errorf("SealedSenderDecrypt error: %w", err) } + msg := result.Message err = stripPadding(&msg) if err != nil { - zlog.Err(err).Msg("stripPadding error") - return nil, err + return nil, fmt.Errorf("stripPadding error: %w", err) } address, err := libsignalgo.NewUUIDAddress( result.Sender.UUID, uint(result.Sender.DeviceID), ) if err != nil { - zlog.Err(err).Msg("NewAddress error") - return nil, err + return nil, fmt.Errorf("NewAddress error: %w", err) } content := &signalpb.Content{} err = proto.Unmarshal(msg, content) if err != nil { - zlog.Err(err).Msg("Unmarshal error") - return nil, err + return nil, fmt.Errorf("Unmarshal error: %w", err) } DecryptionResult := &DecryptionResult{ SenderAddress: address, diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index c5cd7a7..b308c39 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -173,7 +173,10 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.U addresses, sessionRecords, err := cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) if err == nil && (len(addresses) == 0 || len(sessionRecords) == 0) { // No sessions, make one with prekey - cli.FetchAndProcessPreKey(ctx, recipientUUID, -1) + err = cli.FetchAndProcessPreKey(ctx, recipientUUID, -1) + if err != nil { + return nil, err + } addresses, sessionRecords, err = cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) } err = checkForErrorWithSessions(err, addresses, sessionRecords) @@ -797,6 +800,7 @@ func (cli *Client) sendContent( func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { log := zerolog.Ctx(ctx) // Decode json body + // TODO use an actual struct for this var body map[string]interface{} err := json.Unmarshal(response.Body, &body) if err != nil { @@ -809,7 +813,10 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo log.Debug().Any("missing_devices", missingDevices).Msg("missing devices found in 409 response") // TODO: establish session with missing devices for _, missingDevice := range missingDevices { - cli.FetchAndProcessPreKey(ctx, recipientUUID, int(missingDevice.(float64))) + err = cli.FetchAndProcessPreKey(ctx, recipientUUID, int(missingDevice.(float64))) + if err != nil { + return nil + } } } if body["extraDevices"] != nil { @@ -839,6 +846,7 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { log := zerolog.Ctx(ctx) // Decode json body + // TODO use an actual struct var body map[string]interface{} err := json.Unmarshal(response.Body, &body) if err != nil { @@ -863,7 +871,10 @@ func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, respo log.Err(err).Msg("RemoveSession error") return err } - cli.FetchAndProcessPreKey(ctx, recipientUUID, int(staleDevice.(float64))) + err = cli.FetchAndProcessPreKey(ctx, recipientUUID, int(staleDevice.(float64))) + if err != nil { + return err + } } } return err @@ -875,6 +886,7 @@ func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, respo func (cli *Client) handle428(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { log := zerolog.Ctx(ctx) // Decode json body + // TODO use an actual struct var body map[string]interface{} err := json.Unmarshal(response.Body, &body) if err != nil { From fee5cf2fbc684dd6b23cf2d1f08c01d1f73deedb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 7 Jan 2024 15:16:02 +0200 Subject: [PATCH 033/718] Only decode server trust root once --- go.mod | 2 +- go.sum | 4 ++-- pkg/signalmeow/receiving.go | 23 ++++++++++------------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index c53ab70..71167af 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.0 - go.mau.fi/util v0.2.2-0.20231229201527-e01ca03301e9 + go.mau.fi/util v0.2.2-0.20240107131103-852f29430a02 golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231226003508-02704c960a9b golang.org/x/net v0.19.0 diff --git a/go.sum b/go.sum index d113cff..17e51cf 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mau.fi/util v0.2.2-0.20231229201527-e01ca03301e9 h1:sYi2qn5XYnWyHjzBj04/ZeyqMMK31qPM1l2v7aWeiA0= -go.mau.fi/util v0.2.2-0.20231229201527-e01ca03301e9/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= +go.mau.fi/util v0.2.2-0.20240107131103-852f29430a02 h1:jREUBe6TF4a2HCGowTLzcvOFg44QDZ0xgoo+YJK3ugc= +go.mau.fi/util v0.2.2-0.20240107131103-852f29430a02/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 6068f83..e6908f9 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -26,6 +26,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/exerrors" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -860,18 +861,14 @@ type DecryptionResult struct { SealedSender bool } -func serverTrustRootKey() *libsignalgo.PublicKey { - // TODO: put this server's trust root in the config or DB or something - serverTrustRoot := "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" - serverTrustRootBytes, err := base64.StdEncoding.DecodeString(serverTrustRoot) - if err != nil { - panic(fmt.Errorf("DecodeString error: %w", err)) - } - serverTrustRootKey, err := libsignalgo.DeserializePublicKey(serverTrustRootBytes) - if err != nil { - panic(fmt.Errorf("DeserializePublicKey error: %w", err)) - } - return serverTrustRootKey +const prodServerTrustRootStr = "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" + +var prodServerTrustRootBytes = exerrors.Must(base64.StdEncoding.DecodeString(prodServerTrustRootStr)) +var prodServerTrustRootKey = exerrors.Must(libsignalgo.DeserializePublicKey(prodServerTrustRootBytes)) + +func init() { + // It's never going to be freed anyway + prodServerTrustRootKey.CancelFinalizer() } func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.Envelope) (*DecryptionResult, error) { @@ -885,7 +882,7 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E ctx, envelope.Content, localAddress, - serverTrustRootKey(), + prodServerTrustRootKey, timestamp, cli.Store.SessionStore, cli.Store.IdentityStore, From 959eb7eaf9eb648f97b8e85d7650ea87f2639cd1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 7 Jan 2024 22:50:38 +0200 Subject: [PATCH 034/718] Update mautrix-go --- commands.go | 2 +- custompuppet.go | 2 +- database/portal.go | 4 +-- database/upgrades/upgrades.go | 5 ++-- database/userportal.go | 4 +-- go.mod | 4 +-- go.sum | 8 +++--- main.go | 8 +++--- metrics.go | 8 +++--- pkg/signalmeow/store/contact_store.go | 12 ++++---- pkg/signalmeow/store/container.go | 12 ++++---- pkg/signalmeow/store/group_store.go | 4 +-- pkg/signalmeow/store/identity_store.go | 12 ++++---- pkg/signalmeow/store/prekey_store.go | 34 +++++++++++------------ pkg/signalmeow/store/profile_key_store.go | 6 ++-- pkg/signalmeow/store/sender_key_store.go | 4 +-- pkg/signalmeow/store/session_store.go | 10 +++---- portal.go | 9 +----- user.go | 7 +++-- 19 files changed, 75 insertions(+), 80 deletions(-) diff --git a/commands.go b/commands.go index 5b88031..f06c429 100644 --- a/commands.go +++ b/commands.go @@ -260,7 +260,7 @@ func fnSyncSpace(ce *WrappedCommandEvent) { if portal.IsPrivateChat() { continue } - if ce.Bridge.StateStore.IsInRoom(portal.MXID, ce.User.MXID) && portal.addToPersonalSpace(ctx, ce.User) { + if ce.Bridge.StateStore.IsInRoom(ctx, portal.MXID, ce.User.MXID) && portal.addToPersonalSpace(ctx, ce.User) { count++ } } diff --git a/custompuppet.go b/custompuppet.go index 31cc119..5ef7842 100644 --- a/custompuppet.go +++ b/custompuppet.go @@ -58,7 +58,7 @@ func (puppet *Puppet) ClearCustomMXID() { } func (puppet *Puppet) StartCustomMXID(reloginOnFail bool) error { - newIntent, newAccessToken, err := puppet.bridge.DoublePuppet.Setup(puppet.CustomMXID, puppet.AccessToken, reloginOnFail) + newIntent, newAccessToken, err := puppet.bridge.DoublePuppet.Setup(context.TODO(), puppet.CustomMXID, puppet.AccessToken, reloginOnFail) if err != nil { puppet.ClearCustomMXID() return err diff --git a/database/portal.go b/database/portal.go index 14e40bc..31132c6 100644 --- a/database/portal.go +++ b/database/portal.go @@ -130,11 +130,11 @@ func (pq *PortalQuery) GetAllWithMXID(ctx context.Context) ([]*Portal, error) { } func (pq *PortalQuery) FindPrivateChatsNotInSpace(ctx context.Context, receiver uuid.UUID) ([]PortalKey, error) { - rows, err := pq.GetDB().QueryContext(ctx, getChatsNotInSpaceQuery, receiver) + rows, err := pq.GetDB().Query(ctx, getChatsNotInSpaceQuery, receiver) if err != nil { return nil, err } - return dbutil.NewRowIter(rows, func(rows dbutil.Rows) (key PortalKey, err error) { + return dbutil.NewRowIter(rows, func(rows dbutil.Scannable) (key PortalKey, err error) { err = rows.Scan(&key.ChatID) key.Receiver = receiver return diff --git a/database/upgrades/upgrades.go b/database/upgrades/upgrades.go index c99efe8..895be62 100644 --- a/database/upgrades/upgrades.go +++ b/database/upgrades/upgrades.go @@ -17,6 +17,7 @@ package upgrades import ( + "context" "embed" "errors" @@ -29,10 +30,10 @@ var Table dbutil.UpgradeTable var rawUpgrades embed.FS func init() { - Table.Register(-1, 12, 0, "Unsupported version", false, func(tx dbutil.Execable, database *dbutil.Database) error { + Table.Register(-1, 12, 0, "Unsupported version", false, func(ctx context.Context, database *dbutil.Database) error { return errors.New("please upgrade to mautrix-signal v0.4.3 before upgrading to a newer version") }) - Table.Register(1, 13, 0, "Jump to version 13", false, func(tx dbutil.Execable, database *dbutil.Database) error { + Table.Register(1, 13, 0, "Jump to version 13", false, func(ctx context.Context, database *dbutil.Database) error { return nil }) Table.RegisterFS(rawUpgrades) diff --git a/database/userportal.go b/database/userportal.go index 3799f59..c1ba828 100644 --- a/database/userportal.go +++ b/database/userportal.go @@ -45,7 +45,7 @@ func (u *User) GetLastReadTS(ctx context.Context, portal PortalKey) uint64 { return cached } var ts int64 - err := u.qh.GetDB().QueryRowContext(ctx, getLastReadTSQuery, u.MXID, portal.ChatID, portal.Receiver).Scan(&ts) + err := u.qh.GetDB().QueryRow(ctx, getLastReadTSQuery, u.MXID, portal.ChatID, portal.Receiver).Scan(&ts) if err != nil && !errors.Is(err, sql.ErrNoRows) { zerolog.Ctx(ctx).Err(err). Str("user_id", u.MXID.String()). @@ -83,7 +83,7 @@ func (u *User) IsInSpace(ctx context.Context, portal PortalKey) bool { return cached } var inSpace bool - err := u.qh.GetDB().QueryRowContext(ctx, getIsInSpaceQuery, u.MXID, portal.ChatID, portal.Receiver).Scan(&inSpace) + err := u.qh.GetDB().QueryRow(ctx, getIsInSpaceQuery, u.MXID, portal.ChatID, portal.Receiver).Scan(&inSpace) if err != nil && !errors.Is(err, sql.ErrNoRows) { zerolog.Ctx(ctx).Err(err). Str("user_id", u.MXID.String()). diff --git a/go.mod b/go.mod index 71167af..33de9f3 100644 --- a/go.mod +++ b/go.mod @@ -14,13 +14,13 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.0 - go.mau.fi/util v0.2.2-0.20240107131103-852f29430a02 + go.mau.fi/util v0.2.2-0.20240107143939-48dfc4dc3894 golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231226003508-02704c960a9b golang.org/x/net v0.19.0 google.golang.org/protobuf v1.32.0 maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.16.3-0.20240104125737-88631708a41b + maunium.net/go/mautrix v0.16.3-0.20240107204502-25bc36bc7ae7 nhooyr.io/websocket v1.8.10 ) diff --git a/go.sum b/go.sum index 17e51cf..ab06e6a 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mau.fi/util v0.2.2-0.20240107131103-852f29430a02 h1:jREUBe6TF4a2HCGowTLzcvOFg44QDZ0xgoo+YJK3ugc= -go.mau.fi/util v0.2.2-0.20240107131103-852f29430a02/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= +go.mau.fi/util v0.2.2-0.20240107143939-48dfc4dc3894 h1:CuR5LDSxBQLETorfwJ9vRtySeLHjMvJ7//lnCMw7Dy8= +go.mau.fi/util v0.2.2-0.20240107143939-48dfc4dc3894/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= @@ -92,7 +92,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.16.3-0.20240104125737-88631708a41b h1:WWCD0vaAztVrrTRWcTXeOHq9U7HRcP2a1hs+0+guPPg= -maunium.net/go/mautrix v0.16.3-0.20240104125737-88631708a41b/go.mod h1:lI43hRW+/92FCqHLD5bINSPqsWrviZ5MpLl7J3hjvW4= +maunium.net/go/mautrix v0.16.3-0.20240107204502-25bc36bc7ae7 h1:Yo1S3mSazHoT/MHNheRMuRPH74rU6/ZyVaJqTEsmaN0= +maunium.net/go/mautrix v0.16.3-0.20240107204502-25bc36bc7ae7/go.mod h1:eRQu5ED1ODsP+xq1K9l1AOD+O9FMkAhodd/RVc3Bkqg= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index e864633..2044fb1 100644 --- a/main.go +++ b/main.go @@ -172,7 +172,7 @@ func (br *SignalBridge) logLostPortals(ctx context.Context) { func (br *SignalBridge) Start() { go br.logLostPortals(context.TODO()) - err := br.MeowStore.Upgrade() + err := br.MeowStore.Upgrade(context.TODO()) if err != nil { br.Log.Fatalln("Failed to upgrade signalmeow database: %v", err) os.Exit(15) @@ -298,9 +298,9 @@ func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomI log.Err(err).Msg("Failed to enable e2be") } } - br.AS.StateStore.SetMembership(roomID, inviter.MXID, event.MembershipJoin) - br.AS.StateStore.SetMembership(roomID, puppet.MXID, event.MembershipJoin) - br.AS.StateStore.SetMembership(roomID, br.Bot.UserID, event.MembershipJoin) + br.AS.StateStore.SetMembership(ctx, roomID, inviter.MXID, event.MembershipJoin) + br.AS.StateStore.SetMembership(ctx, roomID, puppet.MXID, event.MembershipJoin) + br.AS.StateStore.SetMembership(ctx, roomID, br.Bot.UserID, event.MembershipJoin) portal.Encrypted = true } portal.UpdateDMInfo(ctx, true) diff --git a/metrics.go b/metrics.go index da18836..d8b5ace 100644 --- a/metrics.go +++ b/metrics.go @@ -229,7 +229,7 @@ func (mh *MetricsHandler) TrackConnectionState(signalID string, connected bool) func (mh *MetricsHandler) updateStats() { start := time.Now() var puppetCount int - err := mh.db.QueryRowContext(mh.ctx, "SELECT COUNT(*) FROM puppet").Scan(&puppetCount) + err := mh.db.QueryRow(mh.ctx, "SELECT COUNT(*) FROM puppet").Scan(&puppetCount) if err != nil { mh.log.Warnln("Failed to scan number of puppets:", err) } else { @@ -237,7 +237,7 @@ func (mh *MetricsHandler) updateStats() { } var userCount int - err = mh.db.QueryRowContext(mh.ctx, `SELECT COUNT(*) FROM "user"`).Scan(&userCount) + err = mh.db.QueryRow(mh.ctx, `SELECT COUNT(*) FROM "user"`).Scan(&userCount) if err != nil { mh.log.Warnln("Failed to scan number of users:", err) } else { @@ -245,7 +245,7 @@ func (mh *MetricsHandler) updateStats() { } var messageCount int - err = mh.db.QueryRowContext(mh.ctx, "SELECT COUNT(*) FROM message").Scan(&messageCount) + err = mh.db.QueryRow(mh.ctx, "SELECT COUNT(*) FROM message").Scan(&messageCount) if err != nil { mh.log.Warnln("Failed to scan number of messages:", err) } else { @@ -255,7 +255,7 @@ func (mh *MetricsHandler) updateStats() { var encryptedGroupCount, encryptedPrivateCount, unencryptedGroupCount, unencryptedPrivateCount int // TODO Use a more precise way to check if a chat_id is a UUID. // It should also be compatible with both SQLite & Postgres. - err = mh.db.QueryRowContext(mh.ctx, ` + err = mh.db.QueryRow(mh.ctx, ` SELECT COUNT(CASE WHEN chat_id NOT LIKE '%-%-%-%-%' AND encrypted THEN 1 END) AS encrypted_group_portals, COUNT(CASE WHEN chat_id LIKE '%-%-%-%-%' AND encrypted THEN 1 END) AS encrypted_private_portals, diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go index 1f46513..5718577 100644 --- a/pkg/signalmeow/store/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -111,25 +111,23 @@ func scanContact(row dbutil.Scannable) (*types.Contact, error) { } func (s *SQLStore) LoadContact(ctx context.Context, theirUUID uuid.UUID) (*types.Contact, error) { - return scanContact(s.db.Conn(ctx).QueryRowContext(ctx, getContactByUUIDQuery, s.ACI, theirUUID)) + return scanContact(s.db.QueryRow(ctx, getContactByUUIDQuery, s.ACI, theirUUID)) } func (s *SQLStore) LoadContactByE164(ctx context.Context, e164 string) (*types.Contact, error) { - return scanContact(s.db.Conn(ctx).QueryRowContext(ctx, getContactByPhoneQuery, s.ACI, e164)) + return scanContact(s.db.QueryRow(ctx, getContactByPhoneQuery, s.ACI, e164)) } func (s *SQLStore) AllContacts(ctx context.Context) ([]*types.Contact, error) { - rows, err := s.db.Conn(ctx).QueryContext(ctx, getAllContactsOfUserQuery, s.ACI) + rows, err := s.db.Query(ctx, getAllContactsOfUserQuery, s.ACI) if err != nil { return nil, err } - return dbutil.NewRowIter(rows, func(rows dbutil.Rows) (*types.Contact, error) { - return scanContact(rows) - }).AsList() + return dbutil.NewRowIter(rows, scanContact).AsList() } func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) error { - _, err := s.db.Conn(ctx).ExecContext( + _, err := s.db.Exec( ctx, upsertContactQuery, s.ACI, diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 1ef0fd5..a173597 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -40,8 +40,8 @@ FROM signalmeow_device const getDeviceQuery = getAllDevicesQuery + " WHERE aci_uuid=$1" -func (c *StoreContainer) Upgrade() error { - return c.db.Upgrade() +func (c *StoreContainer) Upgrade(ctx context.Context) error { + return c.db.Upgrade(ctx) } func (c *StoreContainer) scanDevice(row dbutil.Scannable) (*Device, error) { @@ -85,7 +85,7 @@ func (c *StoreContainer) scanDevice(row dbutil.Scannable) (*Device, error) { // GetAllDevices finds all the devices in the database. func (c *StoreContainer) GetAllDevices(ctx context.Context) ([]*Device, error) { - rows, err := c.db.Conn(ctx).QueryContext(ctx, getAllDevicesQuery) + rows, err := c.db.Query(ctx, getAllDevicesQuery) if err != nil { return nil, fmt.Errorf("failed to query sessions: %w", err) } @@ -104,7 +104,7 @@ func (c *StoreContainer) GetAllDevices(ctx context.Context) ([]*Device, error) { // GetDevice finds the device with the specified ACI UUID in the database. // If the device is not found, nil is returned instead. func (c *StoreContainer) DeviceByACI(ctx context.Context, aci uuid.UUID) (*Device, error) { - sess, err := c.scanDevice(c.db.Conn(ctx).QueryRowContext(ctx, getDeviceQuery, aci)) + sess, err := c.scanDevice(c.db.QueryRow(ctx, getDeviceQuery, aci)) if errors.Is(err, sql.ErrNoRows) { return nil, nil } @@ -150,7 +150,7 @@ func (c *StoreContainer) PutDevice(ctx context.Context, device *DeviceData) erro zerolog.Ctx(ctx).Err(err).Msg("failed to serialize pni identity key pair") return err } - _, err = c.db.Conn(ctx).ExecContext(ctx, insertDeviceQuery, + _, err = c.db.Exec(ctx, insertDeviceQuery, device.ACI, aciIdentityKeyPair, device.RegistrationID, device.PNI, pniIdentityKeyPair, device.PNIRegistrationID, device.DeviceID, device.Number, device.Password, @@ -166,6 +166,6 @@ func (c *StoreContainer) DeleteDevice(ctx context.Context, device *DeviceData) e if device.ACI == uuid.Nil { return ErrDeviceIDMustBeSet } - _, err := c.db.Conn(ctx).ExecContext(ctx, deleteDeviceQuery, device.ACI) + _, err := c.db.Exec(ctx, deleteDeviceQuery, device.ACI) return err } diff --git a/pkg/signalmeow/store/group_store.go b/pkg/signalmeow/store/group_store.go index b584296..5ee356e 100644 --- a/pkg/signalmeow/store/group_store.go +++ b/pkg/signalmeow/store/group_store.go @@ -61,7 +61,7 @@ func scanGroup(row dbutil.Scannable) (*dbGroup, error) { } func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (types.SerializedGroupMasterKey, error) { - g, err := scanGroup(s.db.Conn(ctx).QueryRowContext(ctx, getGroupByIDQuery, s.ACI, groupID)) + g, err := scanGroup(s.db.QueryRow(ctx, getGroupByIDQuery, s.ACI, groupID)) if g == nil { return "", err } else { @@ -70,6 +70,6 @@ func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID typ } func (s *SQLStore) StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key types.SerializedGroupMasterKey) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, upsertGroupMasterKeyQuery, s.ACI, groupID, key) + _, err := s.db.Exec(ctx, upsertGroupMasterKeyQuery, s.ACI, groupID, key) return err } diff --git a/pkg/signalmeow/store/identity_store.go b/pkg/signalmeow/store/identity_store.go index f017681..14276a1 100644 --- a/pkg/signalmeow/store/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -71,12 +71,12 @@ func scanIdentityKey(row dbutil.Scannable) (*libsignalgo.IdentityKey, error) { } func (s *SQLStore) GetIdentityKeyPair(ctx context.Context) (*libsignalgo.IdentityKeyPair, error) { - return scanIdentityKeyPair(s.db.Conn(ctx).QueryRowContext(ctx, getIdentityKeyPairQuery, s.ACI)) + return scanIdentityKeyPair(s.db.QueryRow(ctx, getIdentityKeyPairQuery, s.ACI)) } func (s *SQLStore) GetLocalRegistrationID(ctx context.Context) (uint32, error) { var regID sql.NullInt64 - err := s.db.Conn(ctx).QueryRowContext(ctx, getRegistrationLocalIDQuery, s.ACI).Scan(®ID) + err := s.db.QueryRow(ctx, getRegistrationLocalIDQuery, s.ACI).Scan(®ID) if err != nil { return 0, fmt.Errorf("failed to get local registration ID: %w", err) } @@ -97,7 +97,7 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add if err != nil { return false, fmt.Errorf("failed to get device ID: %w", err) } - oldKey, err := scanIdentityKey(s.db.Conn(ctx).QueryRowContext(ctx, getIdentityKeyQuery, s.ACI, theirUUID, deviceID)) + oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirUUID, deviceID)) if err != nil { return false, fmt.Errorf("failed to get old identity key: %w", err) } @@ -110,7 +110,7 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add // We are replacing the old key if the old key exists, and it is not equal to the new key replacing = !equal } - _, err = s.db.Conn(ctx).ExecContext(ctx, insertIdentityKeyQuery, s.ACI, theirUUID, deviceID, serialized, trustLevel) + _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.ACI, theirUUID, deviceID, serialized, trustLevel) if err != nil { return replacing, fmt.Errorf("failed to insert new identity key: %w", err) } @@ -128,7 +128,7 @@ func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.A return false, fmt.Errorf("failed to get device ID: %w", err) } var trustLevel string - err = s.db.Conn(ctx).QueryRowContext(ctx, getIdentityKeyTrustLevelQuery, s.ACI, theirUUID, deviceID).Scan(&trustLevel) + err = s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.ACI, theirUUID, deviceID).Scan(&trustLevel) if errors.Is(err, sql.ErrNoRows) { // If no rows, they are a new identity, so trust by default return true, nil @@ -148,7 +148,7 @@ func (s *SQLStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Addr if err != nil { return nil, fmt.Errorf("failed to get device ID: %w", err) } - key, err := scanIdentityKey(s.db.Conn(ctx).QueryRowContext(ctx, getIdentityKeyQuery, s.ACI, theirUUID, deviceID)) + key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirUUID, deviceID)) if err != nil { return nil, fmt.Errorf("failed to get identity key from database: %w", err) } diff --git a/pkg/signalmeow/store/prekey_store.go b/pkg/signalmeow/store/prekey_store.go index 5f4f572..5b4ee7b 100644 --- a/pkg/signalmeow/store/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -108,7 +108,7 @@ const ( func (s *SQLStore) KyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) { var record []byte var isLastResort bool - err := s.db.Conn(ctx).QueryRowContext(ctx, getKyberPreKeyQuery, s.ACI, preKeyID, uuidKind).Scan(&record, &isLastResort) + err := s.db.QueryRow(ctx, getKyberPreKeyQuery, s.ACI, preKeyID, uuidKind).Scan(&record, &isLastResort) if errors.Is(err, sql.ErrNoRows) { return nil, nil } @@ -127,18 +127,18 @@ func (s *SQLStore) SaveKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, if err != nil { return fmt.Errorf("failed to serialize kyber prekey record: %w", err) } - _, err = s.db.Conn(ctx).ExecContext(ctx, insertKyberPreKeyQuery, s.ACI, id, uuidKind, serialized, lastResort) + _, err = s.db.Exec(ctx, insertKyberPreKeyQuery, s.ACI, id, uuidKind, serialized, lastResort) return err } func (s *SQLStore) DeleteKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, deleteKyberPreKeyQuery, s.ACI, preKeyID, uuidKind) + _, err := s.db.Exec(ctx, deleteKyberPreKeyQuery, s.ACI, preKeyID, uuidKind) return err } func (s *SQLStore) GetNextKyberPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { var lastKeyID sql.NullInt64 - err := s.db.Conn(ctx).QueryRowContext(ctx, getLastKyberPreKeyIDQuery, s.ACI, uuidKind).Scan(&lastKeyID) + err := s.db.QueryRow(ctx, getLastKyberPreKeyIDQuery, s.ACI, uuidKind).Scan(&lastKeyID) if err != nil { return 0, fmt.Errorf("failed to query next kyber prekey ID: %w", err) } @@ -147,7 +147,7 @@ func (s *SQLStore) GetNextKyberPreKeyID(ctx context.Context, uuidKind types.UUID func (s *SQLStore) IsKyberPreKeyLastResort(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (bool, error) { var isLastResort bool - err := s.db.Conn(ctx).QueryRowContext(ctx, isLastResortQuery, s.ACI, preKeyID, uuidKind).Scan(&isLastResort) + err := s.db.QueryRow(ctx, isLastResortQuery, s.ACI, preKeyID, uuidKind).Scan(&isLastResort) if err != nil { return false, err } @@ -189,11 +189,11 @@ func scanSignedPreKey(row dbutil.Scannable) (*libsignalgo.SignedPreKeyRecord, er } func (s *SQLStore) PreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) { - return scanPreKey(s.db.Conn(ctx).QueryRowContext(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, false)) + return scanPreKey(s.db.QueryRow(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, false)) } func (s *SQLStore) SignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) { - return scanSignedPreKey(s.db.Conn(ctx).QueryRowContext(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, true)) + return scanSignedPreKey(s.db.QueryRow(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, true)) } func (s *SQLStore) SavePreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error { @@ -205,7 +205,7 @@ func (s *SQLStore) SavePreKey(ctx context.Context, uuidKind types.UUIDKind, preK if err != nil { return fmt.Errorf("failed to serialize prekey: %w", err) } - _, err = s.db.Conn(ctx).ExecContext(ctx, insertPreKeyQuery, s.ACI, id, uuidKind, false, serialized, markUploaded) + _, err = s.db.Exec(ctx, insertPreKeyQuery, s.ACI, id, uuidKind, false, serialized, markUploaded) return err } @@ -218,23 +218,23 @@ func (s *SQLStore) SaveSignedPreKey(ctx context.Context, uuidKind types.UUIDKind if err != nil { return fmt.Errorf("failed to serialize signed prekey: %w", err) } - _, err = s.db.Conn(ctx).ExecContext(ctx, insertPreKeyQuery, s.ACI, id, uuidKind, true, serialized, markUploaded) + _, err = s.db.Exec(ctx, insertPreKeyQuery, s.ACI, id, uuidKind, true, serialized, markUploaded) return err } func (s *SQLStore) DeletePreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, false) + _, err := s.db.Exec(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, false) return err } func (s *SQLStore) DeleteSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, true) + _, err := s.db.Exec(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, true) return err } func (s *SQLStore) GetNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { var lastKeyID sql.NullInt64 - err := s.db.Conn(ctx).QueryRowContext(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, false).Scan(&lastKeyID) + err := s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, false).Scan(&lastKeyID) if err != nil { return 0, fmt.Errorf("failed to query next prekey ID: %w", err) } @@ -243,7 +243,7 @@ func (s *SQLStore) GetNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) func (s *SQLStore) GetSignedNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { var lastKeyID sql.NullInt64 - err := s.db.Conn(ctx).QueryRowContext(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, true).Scan(&lastKeyID) + err := s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, true).Scan(&lastKeyID) if err != nil { return 0, fmt.Errorf("failed to query next signed prekey ID: %w", err) } @@ -251,22 +251,22 @@ func (s *SQLStore) GetSignedNextPreKeyID(ctx context.Context, uuidKind types.UUI } func (s *SQLStore) MarkPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, false, upToID) + _, err := s.db.Exec(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, false, upToID) return err } func (s *SQLStore) MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, true, upToID) + _, err := s.db.Exec(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, true, upToID) return err } func (s *SQLStore) DeleteAllPreKeys(ctx context.Context) error { return s.db.DoTxn(ctx, nil, func(ctx context.Context) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, "DELETE FROM signalmeow_pre_keys WHERE aci_uuid=$1", s.ACI) + _, err := s.db.Exec(ctx, "DELETE FROM signalmeow_pre_keys WHERE aci_uuid=$1", s.ACI) if err != nil { return err } - _, err = s.db.Conn(ctx).ExecContext(ctx, "DELETE FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1", s.ACI) + _, err = s.db.Exec(ctx, "DELETE FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1", s.ACI) return err }) } diff --git a/pkg/signalmeow/store/profile_key_store.go b/pkg/signalmeow/store/profile_key_store.go index ba80ebe..c384f4f 100644 --- a/pkg/signalmeow/store/profile_key_store.go +++ b/pkg/signalmeow/store/profile_key_store.go @@ -55,14 +55,14 @@ func scanProfileKey(row dbutil.Scannable) (*libsignalgo.ProfileKey, error) { } func (s *SQLStore) LoadProfileKey(ctx context.Context, theirACI uuid.UUID) (*libsignalgo.ProfileKey, error) { - return scanProfileKey(s.db.Conn(ctx).QueryRowContext(ctx, loadProfileKeyQuery, s.ACI, theirACI)) + return scanProfileKey(s.db.QueryRow(ctx, loadProfileKeyQuery, s.ACI, theirACI)) } func (s *SQLStore) MyProfileKey(ctx context.Context) (*libsignalgo.ProfileKey, error) { - return scanProfileKey(s.db.Conn(ctx).QueryRowContext(ctx, loadProfileKeyQuery, s.ACI, s.ACI)) + return scanProfileKey(s.db.QueryRow(ctx, loadProfileKeyQuery, s.ACI, s.ACI)) } func (s *SQLStore) StoreProfileKey(ctx context.Context, theirACI uuid.UUID, key libsignalgo.ProfileKey) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, storeProfileKeyQuery, s.ACI, theirACI, key.Slice()) + _, err := s.db.Exec(ctx, storeProfileKeyQuery, s.ACI, theirACI, key.Slice()) return err } diff --git a/pkg/signalmeow/store/sender_key_store.go b/pkg/signalmeow/store/sender_key_store.go index 9bfa5c2..e9ffea2 100644 --- a/pkg/signalmeow/store/sender_key_store.go +++ b/pkg/signalmeow/store/sender_key_store.go @@ -55,7 +55,7 @@ func (s *SQLStore) LoadSenderKey(ctx context.Context, sender *libsignalgo.Addres if err != nil { return nil, fmt.Errorf("failed to get sender device ID: %w", err) } - return scanSenderKey(s.db.Conn(ctx).QueryRowContext(ctx, loadSenderKeyQuery, s.ACI, senderUUID, deviceID, distributionID)) + return scanSenderKey(s.db.QueryRow(ctx, loadSenderKeyQuery, s.ACI, senderUUID, deviceID, distributionID)) } func (s *SQLStore) StoreSenderKey(ctx context.Context, sender *libsignalgo.Address, distributionID uuid.UUID, record *libsignalgo.SenderKeyRecord) error { @@ -71,6 +71,6 @@ func (s *SQLStore) StoreSenderKey(ctx context.Context, sender *libsignalgo.Addre if err != nil { return fmt.Errorf("failed to serialize sender key: %w", err) } - _, err = s.db.Conn(ctx).ExecContext(ctx, storeSenderKeyQuery, s.ACI, senderUUID, deviceID, distributionID, serialized) + _, err = s.db.Exec(ctx, storeSenderKeyQuery, s.ACI, senderUUID, deviceID, distributionID, serialized) return err } diff --git a/pkg/signalmeow/store/session_store.go b/pkg/signalmeow/store/session_store.go index ca66926..5c190da 100644 --- a/pkg/signalmeow/store/session_store.go +++ b/pkg/signalmeow/store/session_store.go @@ -69,12 +69,12 @@ func (s *SQLStore) RemoveSession(ctx context.Context, address *libsignalgo.Addre if err != nil { return fmt.Errorf("failed to get their device ID: %w", err) } - _, err = s.db.Conn(ctx).ExecContext(ctx, removeSessionQuery, s.ACI, theirUUID, deviceID) + _, err = s.db.Exec(ctx, removeSessionQuery, s.ACI, theirUUID, deviceID) return err } func (s *SQLStore) AllSessionsForUUID(ctx context.Context, theirUUID uuid.UUID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) { - rows, err := s.db.Conn(ctx).QueryContext(ctx, allSessionsQuery, s.ACI, theirUUID) + rows, err := s.db.Query(ctx, allSessionsQuery, s.ACI, theirUUID) if err != nil { return nil, nil, err } @@ -105,7 +105,7 @@ func (s *SQLStore) LoadSession(ctx context.Context, address *libsignalgo.Address if err != nil { return nil, fmt.Errorf("failed to get their device ID: %w", err) } - _, record, err := scanRecord(s.db.Conn(ctx).QueryRowContext(ctx, loadSessionQuery, s.ACI, theirUUID, deviceID)) + _, record, err := scanRecord(s.db.QueryRow(ctx, loadSessionQuery, s.ACI, theirUUID, deviceID)) return record, err } @@ -122,11 +122,11 @@ func (s *SQLStore) StoreSession(ctx context.Context, address *libsignalgo.Addres if err != nil { return fmt.Errorf("failed to serialize session record: %w", err) } - _, err = s.db.Conn(ctx).ExecContext(ctx, storeSessionQuery, s.ACI, theirUUID, deviceID, serialized) + _, err = s.db.Exec(ctx, storeSessionQuery, s.ACI, theirUUID, deviceID, serialized) return err } func (s *SQLStore) RemoveAllSessions(ctx context.Context) error { - _, err := s.db.Conn(ctx).ExecContext(ctx, "DELETE FROM signalmeow_sessions WHERE our_aci_uuid=$1", s.ACI) + _, err := s.db.Exec(ctx, "DELETE FROM signalmeow_sessions WHERE our_aci_uuid=$1", s.ACI) return err } diff --git a/portal.go b/portal.go index b3d3035..8b016b2 100644 --- a/portal.go +++ b/portal.go @@ -1371,7 +1371,7 @@ func (portal *Portal) encrypt(ctx context.Context, intent *appservice.IntentAPI, // TODO maybe the locking should be inside mautrix-go? portal.encryptLock.Lock() defer portal.encryptLock.Unlock() - err := portal.bridge.Crypto.Encrypt(portal.MXID, eventType, content) + err := portal.bridge.Crypto.Encrypt(ctx, portal.MXID, eventType, content) if err != nil { return eventType, fmt.Errorf("failed to encrypt event: %w", err) } @@ -1521,13 +1521,6 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev } portal.log.Info().Msg("Created matrix room for portal") - inviteMembership := event.MembershipInvite - if autoJoinInvites { - inviteMembership = event.MembershipJoin - } - for _, userID := range invite { - portal.bridge.StateStore.SetMembership(portal.MXID, userID, inviteMembership) - } if !autoJoinInvites { if !portal.IsPrivateChat() { portal.SyncParticipants(ctx, user, groupInfo) diff --git a/user.go b/user.go index 1e349b8..cad7a16 100644 --- a/user.go +++ b/user.go @@ -229,7 +229,7 @@ func (user *User) GetIGhost() bridge.Ghost { func (user *User) ensureInvited(ctx context.Context, intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) (ok bool) { log := user.log.With().Str("action", "ensure_invited").Stringer("room_id", roomID).Logger() - if user.bridge.StateStore.GetMembership(roomID, user.MXID) == event.MembershipJoin { + if user.bridge.StateStore.IsMembership(ctx, roomID, user.MXID, event.MembershipJoin) { ok = true return } @@ -247,7 +247,10 @@ func (user *User) ensureInvited(ctx context.Context, intent *appservice.IntentAP _, err := intent.InviteUser(ctx, roomID, &mautrix.ReqInviteUser{UserID: user.MXID}, extraContent) var httpErr mautrix.HTTPError if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") { - user.bridge.StateStore.SetMembership(roomID, user.MXID, event.MembershipJoin) + err = user.bridge.StateStore.SetMembership(ctx, roomID, user.MXID, event.MembershipJoin) + if err != nil { + log.Warn().Err(err).Msg("Failed to update membership in state store") + } ok = true return } else if err != nil { From 26c69f8e8772e8d72f1c85019105cbf9d311c4fa Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 8 Jan 2024 09:34:42 -0700 Subject: [PATCH 035/718] staticcheck: fix S1005: unnecessary assignment to the blank identifier Signed-off-by: Sumner Evans --- provisioning.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/provisioning.go b/provisioning.go index 6920903..679d825 100644 --- a/provisioning.go +++ b/provisioning.go @@ -180,7 +180,7 @@ func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, func (prov *ProvisioningAPI) ResolveIdentifier(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) - phoneNum, _ := mux.Vars(r)["phonenum"] + phoneNum := mux.Vars(r)["phonenum"] log := prov.log.With(). Str("action", "resolve_identifier"). @@ -215,7 +215,7 @@ func (prov *ProvisioningAPI) ResolveIdentifier(w http.ResponseWriter, r *http.Re func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) - phoneNum, _ := mux.Vars(r)["phonenum"] + phoneNum := mux.Vars(r)["phonenum"] log := prov.log.With(). Str("action", "start_pm"). From 1fbdaa3028cb877a228590fa9194f2d0a413be94 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sun, 7 Jan 2024 13:49:10 -0700 Subject: [PATCH 036/718] staticcheck: fix S1021: merge variable declaration with assignment on next line Signed-off-by: Sumner Evans --- portal.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/portal.go b/portal.go index 8b016b2..ac1e4dc 100644 --- a/portal.go +++ b/portal.go @@ -305,8 +305,7 @@ func (portal *Portal) getBridgeInfo() (string, CustomBridgeInfoContent) { AvatarURL: portal.AvatarURL.CUString(), }, } - var bridgeInfoStateKey string - bridgeInfoStateKey = fmt.Sprintf("fi.mau.signal://signal/%s", portal.ChatID) + bridgeInfoStateKey := fmt.Sprintf("fi.mau.signal://signal/%s", portal.ChatID) bridgeInfo.Channel.ExternalURL = fmt.Sprintf("https://signal.me/#p/%s", portal.ChatID) var roomType string if portal.IsPrivateChat() { From c456d6ed03d2f343c67e55c80c596c04cbfb87ba Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sun, 7 Jan 2024 13:52:07 -0700 Subject: [PATCH 037/718] staticcheck: fix S1012,S1024: use time.Until and time.Since Signed-off-by: Sumner Evans --- disappearing.go | 2 +- metrics.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/disappearing.go b/disappearing.go index 847511b..ede68f0 100644 --- a/disappearing.go +++ b/disappearing.go @@ -75,7 +75,7 @@ func (dmm *DisappearingMessagesManager) StartDisappearingLoop(ctx context.Contex log.Err(err).Msg("Failed to get next disappearing message") continue } else if nextMsg != nil { - duration = nextMsg.ExpireAt.Sub(time.Now()) + duration = time.Until(nextMsg.ExpireAt) } select { diff --git a/metrics.go b/metrics.go index d8b5ace..783a6ad 100644 --- a/metrics.go +++ b/metrics.go @@ -146,7 +146,7 @@ func (mh *MetricsHandler) TrackMatrixEvent(eventType event.Type) func() { } start := time.Now() return func() { - duration := time.Now().Sub(start) + duration := time.Since(start) mh.matrixEventHandling. With(prometheus.Labels{"event_type": eventType.Type}). Observe(duration.Seconds()) @@ -160,11 +160,11 @@ func (mh *MetricsHandler) TrackSignalMessage(timestamp time.Time, messageType st start := time.Now() return func() { - duration := time.Now().Sub(start) + duration := time.Since(start) mh.signalMessageHandling. With(prometheus.Labels{"message_type": messageType}). Observe(duration.Seconds()) - mh.signalMessageAge.Observe(time.Now().Sub(timestamp).Seconds()) + mh.signalMessageAge.Observe(time.Since(timestamp).Seconds()) } } @@ -271,7 +271,7 @@ func (mh *MetricsHandler) updateStats() { mh.unencryptedGroupCount.Set(float64(unencryptedGroupCount)) mh.unencryptedPrivateCount.Set(float64(encryptedPrivateCount)) } - mh.countCollection.Observe(time.Now().Sub(start).Seconds()) + mh.countCollection.Observe(time.Since(start).Seconds()) } func (mh *MetricsHandler) startUpdatingStats() { From a082ca14ffd2e87445a86ed70b62ed3b3dadcbc9 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 8 Jan 2024 09:40:24 -0700 Subject: [PATCH 038/718] staticcheck: fix SA5011: possible nil pointer dereference Signed-off-by: Sumner Evans --- pkg/signalmeow/sending.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index b308c39..9e432dd 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -417,16 +417,15 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { cli.LastContactRequestTime = new(int64) } currentUnixTime := time.Now().Unix() - lastRequestTime := cli.LastContactRequestTime log := zerolog.Ctx(ctx).With(). Str("action", "send contact sync request"). Int64("current_unix_time", currentUnixTime). - Int64("last_request_time", *lastRequestTime). - Int64("seconds_since_last_request", currentUnixTime-*lastRequestTime). + Int64("last_request_time", *cli.LastContactRequestTime). + Int64("seconds_since_last_request", currentUnixTime-*cli.LastContactRequestTime). Logger() ctx = log.WithContext(ctx) // If we've requested in the last minute, don't request again - if lastRequestTime != nil && currentUnixTime-*lastRequestTime < 60 { + if cli.LastContactRequestTime != nil && currentUnixTime-*cli.LastContactRequestTime < 60 { log.Warn().Msg("Not sending contact sync request because we already requested it in the past minute") return nil } From 4aaea04d411716b46cb896a0e07c8b7438ce6ed9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Jan 2024 13:14:37 +0200 Subject: [PATCH 039/718] Clean up linking code --- commands.go | 24 ++++----- pkg/signalmeow/provisioning.go | 95 +++++++++++++--------------------- user.go | 9 +++- 3 files changed, 54 insertions(+), 74 deletions(-) diff --git a/commands.go b/commands.go index f06c429..ebe9584 100644 --- a/commands.go +++ b/commands.go @@ -286,14 +286,14 @@ var cmdLogin = &commands.FullHandler{ } func fnLogin(ce *WrappedCommandEvent) { - //if ce.User.Session != nil { - // if ce.User.IsConnected() { - // ce.Reply("You're already logged in") - // } else { - // ce.Reply("You're already logged in. Perhaps you wanted to `reconnect`?") - // } - // return - //} + if ce.User.IsLoggedIn() { + if ce.User.Client.IsConnected() { + ce.Reply("You're already logged in") + } else { + ce.Reply("You're already logged in, but not connected 🤔") + } + return + } var qrEventID, msgEventID id.EventID var signalID uuid.UUID @@ -334,8 +334,6 @@ func fnLogin(ce *WrappedCommandEvent) { if resp.State == signalmeow.StateProvisioningDataReceived { signalID = resp.ProvisioningData.ACI signalPhone = resp.ProvisioningData.Number - ce.Reply("Successfully logged in!") - ce.Reply("ACI: %v, Phone Number: %v", resp.ProvisioningData.ACI, resp.ProvisioningData.Number) } else { ce.Reply("Unexpected state: %v", resp.State) return @@ -346,10 +344,7 @@ func fnLogin(ce *WrappedCommandEvent) { if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { ce.Reply("Error with prekeys: %v", resp.Err) return - } - if resp.State == signalmeow.StateProvisioningPreKeysRegistered { - ce.Reply("Successfully generated, registered and stored prekeys! 🎉") - } else { + } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { ce.Reply("Unexpected state: %v", resp.State) return } @@ -369,6 +364,7 @@ func fnLogin(ce *WrappedCommandEvent) { // Connect to Signal ce.User.Connect() + ce.Reply("Successfully logged in as %s (UUID: %s)", ce.User.SignalUsername, ce.User.SignalID) } func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg id.EventID) (qr, msg id.EventID) { diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 471526a..5f959d6 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -18,11 +18,9 @@ package signalmeow import ( "context" - crand "crypto/rand" "encoding/base64" "encoding/json" "fmt" - "math/big" mrand "math/rand" "net/http" "net/url" @@ -30,6 +28,8 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/exerrors" + "go.mau.fi/util/random" "google.golang.org/protobuf/proto" "nhooyr.io/websocket" @@ -96,13 +96,13 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev defer ws.Close(websocket.StatusInternalError, "Websocket StatusInternalError") provisioningCipher := NewProvisioningCipher() - provisioningUrl, err := startProvisioning(ctx, ws, provisioningCipher) + provisioningURL, err := startProvisioning(ctx, ws, provisioningCipher) if err != nil { log.Err(err).Msg("startProvisioning error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} return } - c <- ProvisioningResponse{State: StateProvisioningURLReceived, ProvisioningURL: provisioningUrl, Err: err} + c <- ProvisioningResponse{State: StateProvisioningURLReceived, ProvisioningURL: provisioningURL, Err: err} provisioningMessage, err := continueProvisioning(ctx, ws, provisioningCipher) if err != nil { @@ -112,16 +112,16 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev } ws.Close(websocket.StatusNormalClosure, "") - aciPublicKey, _ := libsignalgo.DeserializePublicKey(provisioningMessage.GetAciIdentityKeyPublic()) - aciPrivateKey, _ := libsignalgo.DeserializePrivateKey(provisioningMessage.GetAciIdentityKeyPrivate()) - aciIdentityKeyPair, _ := libsignalgo.NewIdentityKeyPair(aciPublicKey, aciPrivateKey) - pniPublicKey, _ := libsignalgo.DeserializePublicKey(provisioningMessage.GetPniIdentityKeyPublic()) - pniPrivateKey, _ := libsignalgo.DeserializePrivateKey(provisioningMessage.GetPniIdentityKeyPrivate()) - pniIdentityKeyPair, _ := libsignalgo.NewIdentityKeyPair(pniPublicKey, pniPrivateKey) + aciPublicKey := exerrors.Must(libsignalgo.DeserializePublicKey(provisioningMessage.GetAciIdentityKeyPublic())) + aciPrivateKey := exerrors.Must(libsignalgo.DeserializePrivateKey(provisioningMessage.GetAciIdentityKeyPrivate())) + aciIdentityKeyPair := exerrors.Must(libsignalgo.NewIdentityKeyPair(aciPublicKey, aciPrivateKey)) + pniPublicKey := exerrors.Must(libsignalgo.DeserializePublicKey(provisioningMessage.GetPniIdentityKeyPublic())) + pniPrivateKey := exerrors.Must(libsignalgo.DeserializePrivateKey(provisioningMessage.GetPniIdentityKeyPrivate())) + pniIdentityKeyPair := exerrors.Must(libsignalgo.NewIdentityKeyPair(pniPublicKey, pniPrivateKey)) profileKey := libsignalgo.ProfileKey(provisioningMessage.GetProfileKey()) username := *provisioningMessage.Number - password, _ := generateRandomPassword(22) + password := random.String(22) code := provisioningMessage.ProvisioningCode registrationId := mrand.Intn(16383) + 1 pniRegistrationId := mrand.Intn(16383) + 1 @@ -235,7 +235,6 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev return } err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindPNI) - if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, @@ -254,8 +253,6 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph log := zerolog.Ctx(ctx).With().Str("action", "start provisioning").Logger() pubKey := provisioningCipher.GetPublicKey() - provisioningUrl := "" - msg := &signalpb.WebSocketMessage{} err := wspb.Read(ctx, ws, msg) if err != nil { @@ -264,33 +261,33 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph } // Ensure the message is a request and has a valid verb and path - if *msg.Type == signalpb.WebSocketMessage_REQUEST && - *msg.Request.Verb == http.MethodPut && - *msg.Request.Path == "/v1/address" { - - // Decode provisioning UUID - provisioningUuid := &signalpb.ProvisioningUuid{} - err = proto.Unmarshal(msg.Request.Body, provisioningUuid) - if err != nil { - return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) - } - - // Create provisioning URL - bytesKey, _ := pubKey.Serialize() - base64Key := base64.StdEncoding.EncodeToString(bytesKey) - uuid := url.QueryEscape(*provisioningUuid.Uuid) - pubKey := url.QueryEscape(base64Key) - provisioningUrl = "sgnl://linkdevice?uuid=" + uuid + "&pub_key=" + pubKey - - // Create and send response - response := web.CreateWSResponse(ctx, *msg.Request.Id, 200) - err = wspb.Write(ctx, ws, response) - if err != nil { - log.Err(err).Msg("error writing websocket message") - return "", err - } + if msg.GetType() != signalpb.WebSocketMessage_REQUEST || msg.GetRequest().GetVerb() != http.MethodPut || msg.GetRequest().GetPath() != "/v1/address" { + return "", fmt.Errorf("unexpected websocket message: %v", msg) } - return provisioningUrl, nil + + var provisioningBody signalpb.ProvisioningUuid + err = proto.Unmarshal(msg.GetRequest().GetBody(), &provisioningBody) + if err != nil { + return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) + } + + provisioningURL := (&url.URL{ + Scheme: "sgnl", + Host: "linkdevice", + RawQuery: url.Values{ + "uuid": []string{provisioningBody.GetUuid()}, + "pub_key": []string{base64.StdEncoding.EncodeToString(exerrors.Must(pubKey.Serialize()))}, + }.Encode(), + }).String() + + // Create and send response + response := web.CreateWSResponse(ctx, msg.GetRequest().GetId(), 200) + err = wspb.Write(ctx, ws, response) + if err != nil { + log.Err(err).Msg("error writing websocket message") + return "", err + } + return provisioningURL, nil } func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCipher *ProvisioningCipher) (*signalpb.ProvisionMessage, error) { @@ -418,21 +415,3 @@ func confirmDevice( return &deviceResp, nil } - -func generateRandomPassword(length int) (string, error) { - if length < 1 { - return "", fmt.Errorf("password length must be at least 1") - } - - const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var password []byte - for i := 0; i < length; i++ { - index, err := crand.Int(crand.Reader, big.NewInt(int64(len(charset)))) - if err != nil { - return "", fmt.Errorf("error generating random index: %v", err) - } - password = append(password, charset[index.Int64()]) - } - - return string(password), nil -} diff --git a/user.go b/user.go index cad7a16..69ff3e3 100644 --- a/user.go +++ b/user.go @@ -485,6 +485,9 @@ func (user *User) startupTryConnect(retryCount int) { user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: err.Error()}) } user.clearKeysAndDisconnect() + if managementRoom := user.GetManagementRoomID(); managementRoom != "" { + _, _ = user.bridge.Bot.SendText(ctx, managementRoom, "You've been logged out of Signal") + } case signalmeow.SignalConnectionEventError: user.log.Debug().Msg("Sending UnknownError BridgeState") @@ -565,9 +568,11 @@ func (user *User) populateSignalDevice() *signalmeow.Client { if user.SignalID == uuid.Nil { return nil - } else if user.Client != nil { - return user.Client } + // TODO clear client on logout properly so that populating can skip creating if it already exists + /*else if user.Client != nil { + return user.Client + }*/ device, err := user.bridge.MeowStore.DeviceByACI(context.TODO(), user.SignalID) if err != nil { From 44084885733a31e992994c2475ffc2b0c1f18fb1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Jan 2024 15:33:09 +0200 Subject: [PATCH 040/718] Retry without sealed sender if send fails with 401 (#419) --- pkg/signalmeow/sending.go | 52 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 9e432dd..33cd93f 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -431,7 +431,7 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { } groupRequest := syncMessageForContactRequest() - _, err := cli.sendContent(ctx, cli.Store.ACI, uint64(currentUnixTime), groupRequest, 0) + _, err := cli.sendContent(ctx, cli.Store.ACI, uint64(currentUnixTime), groupRequest, 0, true) if err != nil { log.Err(err).Msg("Failed to send contact sync request message to myself") return err @@ -543,7 +543,7 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } log := log.With().Stringer("member", member.UserID).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, member.UserID, messageTimestamp, content, 0) + sentUnidentified, err := cli.sendContent(ctx, member.UserID, messageTimestamp, content, 0, true) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ RecipientUUID: member.UserID, @@ -567,7 +567,7 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } else if content.GetEditMessage() != nil { syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) } - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0, true) if selfSendErr != nil { log.Err(selfSendErr).Msg("Failed to send sync message to myself") } @@ -596,7 +596,7 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.RecipientUUID) } if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTS, syncContent, 0) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTS, syncContent, 0, true) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } else { @@ -632,7 +632,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, conte } // Send to the recipient - sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0) + sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0, true) if err != nil { return SendMessageResult{ WasSuccessful: false, @@ -664,7 +664,8 @@ func (cli *Client) sendContent( recipientUUID uuid.UUID, messageTimestamp uint64, content *signalpb.Content, - retryCount int, // For ending recursive retries + retryCount int, + useUnidentifiedSender bool, ) (sentUnidentified bool, err error) { log := zerolog.Ctx(ctx).With(). Str("action", "send content"). @@ -690,34 +691,24 @@ func (cli *Client) sendContent( return false, fmt.Errorf("too many retries") } - useUnidentifiedSender := true // Don't use unauthed websocket to send a payload to my own other devices if recipientUUID == cli.Store.ACI { useUnidentifiedSender = false } - profileKey, err := cli.ProfileKeyForSignalID(ctx, recipientUUID) - if err != nil || profileKey == nil { - log.Err(err).Msg("Error getting profile key") - useUnidentifiedSender = false - // Try to self heal by requesting contact sync, though this is slow and not guaranteed to help - cli.SendContactSyncRequest(ctx) - } var accessKey *libsignalgo.AccessKey - if profileKey != nil { - accessKey, err = profileKey.DeriveAccessKey() + if useUnidentifiedSender { + profileKey, err := cli.ProfileKeyForSignalID(ctx, recipientUUID) if err != nil { + return false, fmt.Errorf("failed to get profile key: %w", err) + } else if profileKey == nil { + log.Warn().Msg("Profile key not found") + useUnidentifiedSender = false + } else if accessKey, err = profileKey.DeriveAccessKey(); err != nil { log.Err(err).Msg("Error deriving access key") useUnidentifiedSender = false } } - // TODO: JUST FOR DEBUGGING - //if content.DataMessage != nil { - // if *content.DataMessage.Body == "UNSEAL" { - // useUnidentifiedSender = false - // } - //} - // Encrypt messages var messages []MyMessage messages, err = cli.buildMessagesToSend(ctx, recipientUUID, content, useUnidentifiedSender) if err != nil { @@ -757,6 +748,11 @@ func (cli *Client) sendContent( Uint32("response_status", *response.Status). Logger() ctx = log.WithContext(ctx) + if json.Valid(response.GetBody()) { + log.Debug().RawJSON("response_body", response.GetBody()).Msg("DEBUG: message send response data") + } else { + log.Debug().Bytes("response_body", response.GetBody()).Msg("DEBUG: message send response data") + } log.Trace().Msg("Received a response to a message send") retryableStatuses := []uint32{409, 410, 428, 500, 503} @@ -783,7 +779,15 @@ func (cli *Client) sendContent( return false, err } // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1) + sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1, sentUnidentified) + if err != nil { + log.Err(err).Msg("2nd try sendMessage error") + return sentUnidentified, err + } + } else if *response.Status == 401 && useUnidentifiedSender { + log.Debug().Msg("Retrying send without sealed sender") + // Try to send again (**RECURSIVELY**) + sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1, false) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err From 121c81a7831ab77690f75a0ea0a7a05a4bb7adc1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Jan 2024 16:20:49 +0200 Subject: [PATCH 041/718] Update changelog [skip ci] --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b51415..b2ff61f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,12 @@ * Rewrote bridge in Go. * The bridge doesn't use signald anymore. * All users will have to re-link the bridge. - * Primary device mode is no longer supported. + * Primary device mode is no longer supported, signal-cli is recommended if + you don't want to use the official Signal mobile apps. + * Some old features are not yet supported (e.g. membership action bridging, + join rules and getting group invite links). * Renamed main branch from `master` to `main`. +* Added support for edits and message formatting. # v0.4.3 (2023-05-17) From d9a8f7bedce3bf78a50c5fdc2097033ce7c32174 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Mon, 8 Jan 2024 14:30:41 -0500 Subject: [PATCH 042/718] Generate and register more prekeys if we're running low --- pkg/signalmeow/keys.go | 168 ++++++++++++++++++++++++++++++------ pkg/signalmeow/receiving.go | 3 + 2 files changed, 147 insertions(+), 24 deletions(-) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index ceede16..3d365ce 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -21,6 +21,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "math/rand" "net/http" "strings" "time" @@ -40,6 +41,24 @@ type GeneratedPreKeys struct { } func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { + preKeys, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) + if err != nil { + return fmt.Errorf("failed to generate and save next prekey batch: %w", err) + } + kyberPreKeys, err := cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) + if err != nil { + return fmt.Errorf("failed to generate and save next kyber prekey batch: %w", err) + } + + err = cli.RegisterPreKeyBatches(ctx, preKeys, kyberPreKeys, uuidKind) + if err != nil { + return fmt.Errorf("failed to register prekey batches: %w", err) + } + + return err +} + +func (cli *Client) RegisterPreKeyBatches(ctx context.Context, preKeys []*libsignalgo.PreKeyRecord, kyberPreKeys []*libsignalgo.KyberPreKeyRecord, uuidKind types.UUIDKind) error { var identityKeyPair *libsignalgo.IdentityKeyPair if uuidKind == types.UUIDKindPNI { identityKeyPair = cli.Store.PNIIdentityKeyPair @@ -47,31 +66,11 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type identityKeyPair = cli.Store.ACIIdentityKeyPair } - nextPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextPreKeyID(ctx, uuidKind) - if err != nil { - return fmt.Errorf("failed to get next prekey ID: %w", err) - } - nextKyberPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextKyberPreKeyID(ctx, uuidKind) - if err != nil { - return fmt.Errorf("failed to get next kyber prekey ID: %w", err) - } - preKeys := GeneratePreKeys(nextPreKeyID, 100, uuidKind) - kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, 100, uuidKind, identityKeyPair) - - for _, preKey := range preKeys { - err = cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) - if err != nil { - return fmt.Errorf("failed to save prekey: %w", err) - } - } - for _, kyberPreKey := range kyberPreKeys { - err = cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) - if err != nil { - return fmt.Errorf("failed to save kyber prekey: %w", err) - } + // We need to have some keys to upload + if len(preKeys) == 0 && len(kyberPreKeys) == 0 { + return fmt.Errorf("no prekeys to upload") } - // Register prekeys identityKey, err := identityKeyPair.GetPublicKey().Serialize() if err != nil { return fmt.Errorf("failed to serialize identity key: %w", err) @@ -98,7 +97,6 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type return fmt.Errorf("failed to get last prekey ID: %w", err) } err = cli.Store.PreKeyStoreExtras.MarkPreKeysAsUploaded(ctx, uuidKind, lastPreKeyID) - if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to mark prekeys as uploaded") } @@ -106,6 +104,42 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type return err } +func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.PreKeyRecord, error) { + nextPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextPreKeyID(ctx, uuidKind) + if err != nil { + return nil, fmt.Errorf("failed to get next prekey ID: %w", err) + } + preKeys := GeneratePreKeys(nextPreKeyID, 100, uuidKind) + for _, preKey := range preKeys { + err = cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) + if err != nil { + return nil, fmt.Errorf("failed to save prekey: %w", err) + } + } + return preKeys, nil +} + +func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.KyberPreKeyRecord, error) { + var identityKeyPair *libsignalgo.IdentityKeyPair + if uuidKind == types.UUIDKindPNI { + identityKeyPair = cli.Store.PNIIdentityKeyPair + } else { + identityKeyPair = cli.Store.ACIIdentityKeyPair + } + nextKyberPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextKyberPreKeyID(ctx, uuidKind) + if err != nil { + return nil, fmt.Errorf("failed to get next kyber prekey ID: %w", err) + } + kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, 100, uuidKind, identityKeyPair) + for _, kyberPreKey := range kyberPreKeys { + err = cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) + if err != nil { + return nil, fmt.Errorf("failed to save kyber prekey: %w", err) + } + } + return kyberPreKeys, nil +} + func GeneratePreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind) []*libsignalgo.PreKeyRecord { generatedPreKeys := []*libsignalgo.PreKeyRecord{} for i := startKeyId; i < startKeyId+count; i++ { @@ -262,6 +296,11 @@ type prekeyResponse struct { Devices []prekeyDevice `json:"devices"` } +type preKeyCountResponse struct { + Count int `json:"count"` + PQCount int `json:"pqCount"` +} + type prekeyDevice struct { DeviceID int `json:"deviceId"` RegistrationID int `json:"registrationId"` @@ -397,3 +436,84 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI return err } + +func (cli *Client) GetMyKeyCounts(ctx context.Context, uuidKind types.UUIDKind) (int, int, error) { + log := zerolog.Ctx(ctx).With().Str("action", "get my key counts").Logger() + username, password := cli.Store.BasicAuthCreds() + path := "/v2/keys?identity=" + string(uuidKind) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) + if err != nil { + log.Err(err).Msg("Error sending request") + return 0, 0, err + } + var preKeyCountResponse preKeyCountResponse + err = web.DecodeHTTPResponseBody(ctx, &preKeyCountResponse, resp) + if err != nil { + log.Err(err).Msg("Fetching prekey counts, error with response body") + return 0, 0, err + } + return preKeyCountResponse.Count, preKeyCountResponse.PQCount, err +} + +func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { + log := zerolog.Ctx(ctx).With().Str("action", "check and upload new prekeys").Logger() + // Check if we need to upload prekeys + preKeyCount, kyberPreKeyCount, err := cli.GetMyKeyCounts(ctx, uuidKind) + if err != nil { + log.Err(err).Msg("Error getting prekey counts") + return err + } + log.Debug().Int("preKeyCount", preKeyCount).Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Checking prekey counts") + + var preKeys []*libsignalgo.PreKeyRecord + var kyberPreKeys []*libsignalgo.KyberPreKeyRecord + if preKeyCount < 10 { + log.Info().Int("preKeyCount", preKeyCount).Msg("Generating and uploading new prekeys") + preKeys, err = cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) + if err != nil { + log.Err(err).Msg("Error generating and saving next prekey batch") + return err + } + } + if kyberPreKeyCount < 10 { + log.Info().Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Generating and uploading new kyber prekeys") + kyberPreKeys, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) + if err != nil { + log.Err(err).Msg("Error generating and saving next kyber prekey batch") + return err + } + } + cli.RegisterPreKeyBatches(ctx, preKeys, kyberPreKeys, uuidKind) + return err +} + +func (cli *Client) StartKeyCheckLoop(ctx context.Context, uuidKind types.UUIDKind) { + log := zerolog.Ctx(ctx).With().Str("action", "start key check loop").Logger() + go func() { + // Do the initial check within an hour of starting the loop + window_start := 0 + window_size := 60 + for { + random_minutes_in_window := rand.Intn(window_size) + window_start + check_time := time.Duration(random_minutes_in_window) * time.Minute + log.Debug().Int("check_time", int(check_time.Minutes())).Msg("Waiting to check for new prekeys") + + select { + case <-ctx.Done(): + return + case <-time.After(check_time): + err := cli.CheckAndUploadNewPreKeys(ctx, uuidKind) + if err != nil { + log.Err(err).Msg("Error checking and uploading new prekeys") + // Retry within half an hour + window_start = 5 + window_size = 25 + continue + } + // After a successful check, check again in 36 to 60 hours + window_start = 36 * 60 + window_size = 24 * 60 + } + } + }() +} diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index e6908f9..2ee008b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -195,6 +195,9 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection } }() + // Start loop to check for and upload more prekeys + cli.StartKeyCheckLoop(ctx, types.UUIDKindACI) + return statusChan, nil } From f24c94b011c5938fdf80f00982c87396fad45a3d Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Tue, 9 Jan 2024 12:03:56 -0500 Subject: [PATCH 043/718] Upload all unused prekeys every time, and change delay logic --- pkg/signalmeow/keys.go | 50 +++++++++++++++++++++------- pkg/signalmeow/store/prekey_store.go | 33 ++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 3d365ce..235b32c 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -34,6 +34,8 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) +const PREKEY_BATCH_SIZE = 100 + type GeneratedPreKeys struct { PreKeys []*libsignalgo.PreKeyRecord KyberPreKeys []*libsignalgo.KyberPreKeyRecord @@ -41,16 +43,17 @@ type GeneratedPreKeys struct { } func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { - preKeys, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) + _, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) if err != nil { return fmt.Errorf("failed to generate and save next prekey batch: %w", err) } - kyberPreKeys, err := cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) + _, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) if err != nil { return fmt.Errorf("failed to generate and save next kyber prekey batch: %w", err) } - err = cli.RegisterPreKeyBatches(ctx, preKeys, kyberPreKeys, uuidKind) + // We need to upload all currently valid prekeys, not just the ones we just generated + err = cli.RegisterAllPreKeys(ctx, uuidKind) if err != nil { return fmt.Errorf("failed to register prekey batches: %w", err) } @@ -58,7 +61,7 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type return err } -func (cli *Client) RegisterPreKeyBatches(ctx context.Context, preKeys []*libsignalgo.PreKeyRecord, kyberPreKeys []*libsignalgo.KyberPreKeyRecord, uuidKind types.UUIDKind) error { +func (cli *Client) RegisterAllPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { var identityKeyPair *libsignalgo.IdentityKeyPair if uuidKind == types.UUIDKindPNI { identityKeyPair = cli.Store.PNIIdentityKeyPair @@ -66,6 +69,16 @@ func (cli *Client) RegisterPreKeyBatches(ctx context.Context, preKeys []*libsign identityKeyPair = cli.Store.ACIIdentityKeyPair } + // Get all prekeys and kyber prekeys from the database + preKeys, err := cli.Store.PreKeyStoreExtras.AllPreKeys(ctx, uuidKind) + if err != nil { + return fmt.Errorf("failed to get all prekeys: %w", err) + } + kyberPreKeys, err := cli.Store.PreKeyStoreExtras.AllNormalKyberPreKeys(ctx, uuidKind) + if err != nil { + return fmt.Errorf("failed to get all kyber prekeys: %w", err) + } + // We need to have some keys to upload if len(preKeys) == 0 && len(kyberPreKeys) == 0 { return fmt.Errorf("no prekeys to upload") @@ -75,6 +88,7 @@ func (cli *Client) RegisterPreKeyBatches(ctx context.Context, preKeys []*libsign if err != nil { return fmt.Errorf("failed to serialize identity key: %w", err) } + generatedPreKeys := GeneratedPreKeys{ PreKeys: preKeys, KyberPreKeys: kyberPreKeys, @@ -85,6 +99,8 @@ func (cli *Client) RegisterPreKeyBatches(ctx context.Context, preKeys []*libsign preKeyUsername = cli.Store.ACI.String() } preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, cli.Store.DeviceID) + log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() + log.Debug().Int("num_prekeys", len(preKeys)).Int("num_kyber_prekeys", len(kyberPreKeys)).Interface("generated_prekeys", generatedPreKeys).Msg("Registering prekeys") err = RegisterPreKeys(ctx, &generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) if err != nil { return fmt.Errorf("failed to register prekeys: %w", err) @@ -92,6 +108,8 @@ func (cli *Client) RegisterPreKeyBatches(ctx context.Context, preKeys []*libsign // Mark prekeys as registered // (kyber prekeys don't have "mark as uploaded" we just assume they always are) + // TODO: we don't need to mark prekeys as uploaded, since we just upload all unused prekeys each time. + // So we can drop this column and remove these methods lastPreKeyID, err := preKeys[len(preKeys)-1].GetID() if err != nil { return fmt.Errorf("failed to get last prekey ID: %w", err) @@ -109,7 +127,7 @@ func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, uuidKind if err != nil { return nil, fmt.Errorf("failed to get next prekey ID: %w", err) } - preKeys := GeneratePreKeys(nextPreKeyID, 100, uuidKind) + preKeys := GeneratePreKeys(nextPreKeyID, PREKEY_BATCH_SIZE, uuidKind) for _, preKey := range preKeys { err = cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) if err != nil { @@ -130,7 +148,7 @@ func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, uuid if err != nil { return nil, fmt.Errorf("failed to get next kyber prekey ID: %w", err) } - kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, 100, uuidKind, identityKeyPair) + kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, PREKEY_BATCH_SIZE, uuidKind, identityKeyPair) for _, kyberPreKey := range kyberPreKeys { err = cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) if err != nil { @@ -468,7 +486,7 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types. var preKeys []*libsignalgo.PreKeyRecord var kyberPreKeys []*libsignalgo.KyberPreKeyRecord if preKeyCount < 10 { - log.Info().Int("preKeyCount", preKeyCount).Msg("Generating and uploading new prekeys") + log.Info().Int("preKeyCount", preKeyCount).Msg("Generating and saving new prekeys") preKeys, err = cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) if err != nil { log.Err(err).Msg("Error generating and saving next prekey batch") @@ -476,15 +494,23 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types. } } if kyberPreKeyCount < 10 { - log.Info().Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Generating and uploading new kyber prekeys") + log.Info().Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Generating and saving new kyber prekeys") kyberPreKeys, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) if err != nil { log.Err(err).Msg("Error generating and saving next kyber prekey batch") return err } } - cli.RegisterPreKeyBatches(ctx, preKeys, kyberPreKeys, uuidKind) - return err + if len(preKeys) == 0 && len(kyberPreKeys) == 0 { + log.Debug().Msg("No new prekeys to upload") + return nil + } + err = cli.RegisterAllPreKeys(ctx, uuidKind) + if err != nil { + log.Err(err).Msg("Error registering prekey batches") + return err + } + return nil } func (cli *Client) StartKeyCheckLoop(ctx context.Context, uuidKind types.UUIDKind) { @@ -492,11 +518,11 @@ func (cli *Client) StartKeyCheckLoop(ctx context.Context, uuidKind types.UUIDKin go func() { // Do the initial check within an hour of starting the loop window_start := 0 - window_size := 60 + window_size := 1 for { random_minutes_in_window := rand.Intn(window_size) + window_start check_time := time.Duration(random_minutes_in_window) * time.Minute - log.Debug().Int("check_time", int(check_time.Minutes())).Msg("Waiting to check for new prekeys") + log.Debug().Dur("check_time", check_time).Msg("Waiting to check for new prekeys") select { case <-ctx.Done(): diff --git a/pkg/signalmeow/store/prekey_store.go b/pkg/signalmeow/store/prekey_store.go index 5b4ee7b..4963491 100644 --- a/pkg/signalmeow/store/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -51,6 +51,8 @@ type PreKeyStoreExtras interface { MarkPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error IsKyberPreKeyLastResort(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (bool, error) + AllPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.PreKeyRecord, error) + AllNormalKyberPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.KyberPreKeyRecord, error) DeleteAllPreKeys(ctx context.Context) error } @@ -270,3 +272,34 @@ func (s *SQLStore) DeleteAllPreKeys(ctx context.Context) error { return err }) } + +func (s *SQLStore) AllPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.PreKeyRecord, error) { + queryString := "SELECT key_id, key_pair FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_signed=$3" + rows, err := s.db.Query(ctx, queryString, s.ACI, uuidKind, false) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + if err != nil { + return nil, err + } + return dbutil.NewRowIter(rows, scanPreKey).AsList() +} + +func (s *SQLStore) AllNormalKyberPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.KyberPreKeyRecord, error) { + queryString := "SELECT key_id, key_pair FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_last_resort=false" + rows, err := s.db.Query(ctx, queryString, s.ACI, uuidKind) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } else if err != nil { + return nil, err + } + return dbutil.NewRowIter(rows, func(row dbutil.Scannable) (*libsignalgo.KyberPreKeyRecord, error) { + var id uint + var record []byte + err := row.Scan(&id, &record) + if err != nil { + return nil, err + } + return libsignalgo.DeserializeKyberPreKeyRecord(record) + }).AsList() +} From 4602d8b91f50bcb0ada9f500a7fd55be9ed35a43 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Tue, 9 Jan 2024 13:51:09 -0500 Subject: [PATCH 044/718] Fix a long log --- pkg/signalmeow/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 235b32c..48a70a9 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -100,7 +100,7 @@ func (cli *Client) RegisterAllPreKeys(ctx context.Context, uuidKind types.UUIDKi } preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, cli.Store.DeviceID) log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() - log.Debug().Int("num_prekeys", len(preKeys)).Int("num_kyber_prekeys", len(kyberPreKeys)).Interface("generated_prekeys", generatedPreKeys).Msg("Registering prekeys") + log.Debug().Int("num_prekeys", len(preKeys)).Int("num_kyber_prekeys", len(kyberPreKeys)).Msg("Registering prekeys") err = RegisterPreKeys(ctx, &generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) if err != nil { return fmt.Errorf("failed to register prekeys: %w", err) From de8c8d97c23dc1982686a698162b45f1f112155b Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Wed, 10 Jan 2024 12:17:05 -0500 Subject: [PATCH 045/718] Fix BAD_CREDENTIALS / UNCONFIGURED race --- user.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/user.go b/user.go index 69ff3e3..f3a8971 100644 --- a/user.go +++ b/user.go @@ -518,7 +518,6 @@ func (br *SignalBridge) StartUsers() { br.ZLog.Debug().Msg("Starting users") usersWithToken := br.GetAllLoggedInUsers() - numUsersStarting := 0 for _, u := range usersWithToken { device := u.populateSignalDevice() if device == nil || !device.IsLoggedIn() { @@ -527,9 +526,8 @@ func (br *SignalBridge) StartUsers() { continue } go u.Connect() - numUsersStarting++ } - if numUsersStarting == 0 { + if len(usersWithToken) == 0 { br.SendGlobalBridgeState(status.BridgeState{StateEvent: status.StateUnconfigured}.Fill(nil)) } From e631a350aaaea54f939118ce3c9788f6245e1cf9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 14:17:51 +0200 Subject: [PATCH 046/718] Update to libsignal 0.39.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 4a69727..d0879d7 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 4a69727457d66f2d8cf1f253d68a2f4b7fed0176 +Subproject commit d0879d7150c12301385bc357a2daaa69269d464c diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 5fea70d..8d1b16f 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -168,12 +168,17 @@ typedef enum { SignalErrorCodeUsernameCannotBeEmpty = 120, SignalErrorCodeUsernameCannotStartWithDigit = 121, SignalErrorCodeUsernameMissingSeparator = 122, - SignalErrorCodeUsernameBadDiscriminator = 123, - SignalErrorCodeUsernameBadCharacter = 124, + SignalErrorCodeUsernameBadDiscriminatorCharacter = 123, + SignalErrorCodeUsernameBadNicknameCharacter = 124, SignalErrorCodeUsernameTooShort = 125, SignalErrorCodeUsernameTooLong = 126, SignalErrorCodeUsernameLinkInvalidEntropyDataLength = 127, SignalErrorCodeUsernameLinkInvalid = 128, + SignalErrorCodeUsernameDiscriminatorCannotBeEmpty = 140, + SignalErrorCodeUsernameDiscriminatorCannotBeZero = 141, + SignalErrorCodeUsernameDiscriminatorCannotBeSingleDigit = 142, + SignalErrorCodeUsernameDiscriminatorCannotHaveLeadingZeros = 143, + SignalErrorCodeUsernameDiscriminatorTooLarge = 144, SignalErrorCodeIoError = 130, SignalErrorCodeInvalidMediaInput = 131, SignalErrorCodeUnsupportedMediaInput = 132, @@ -1239,6 +1244,8 @@ SignalFfiError *signal_username_verify(SignalBorrowedBuffer proof, SignalBorrowe SignalFfiError *signal_username_candidates_from(const char **out, const char *nickname, uint32_t min_len, uint32_t max_len); +SignalFfiError *signal_username_hash_from_parts(uint8_t (*out)[32], const char *nickname, const char *discriminator, uint32_t min_len, uint32_t max_len); + SignalFfiError *signal_username_link_create(SignalOwnedBuffer *out, const char *username, SignalBorrowedBuffer entropy); SignalFfiError *signal_username_link_decrypt_username(const char **out, SignalBorrowedBuffer entropy, SignalBorrowedBuffer encrypted_username); From ba5728c69c5894284bbac7ecc946695c4dfa610f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 14:20:08 +0200 Subject: [PATCH 047/718] Update protobufs and add ContactDiscovery schema --- .../protobuf/ContactDiscovery.pb.go | 317 +++ .../protobuf/ContactDiscovery.proto | 53 + pkg/signalmeow/protobuf/DeviceName.pb.go | 5 +- pkg/signalmeow/protobuf/Groups.pb.go | 5 +- pkg/signalmeow/protobuf/Provisioning.pb.go | 5 +- pkg/signalmeow/protobuf/SignalService.pb.go | 2153 ++++++++--------- pkg/signalmeow/protobuf/SignalService.proto | 17 +- .../protobuf/StickerResources.pb.go | 5 +- .../protobuf/UnidentifiedDelivery.pb.go | 5 +- .../protobuf/WebSocketResources.pb.go | 5 +- pkg/signalmeow/protobuf/update-protos.sh | 5 +- 11 files changed, 1436 insertions(+), 1139 deletions(-) create mode 100644 pkg/signalmeow/protobuf/ContactDiscovery.pb.go create mode 100644 pkg/signalmeow/protobuf/ContactDiscovery.proto diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go new file mode 100644 index 0000000..282d9a8 --- /dev/null +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -0,0 +1,317 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.21.12 +// source: ContactDiscovery.proto + +// Copyright 2021 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" +) + +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 CDSClientRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Each ACI/UAK pair is a 32-byte buffer, containing the 16-byte ACI followed + // by its 16-byte UAK. + AciUakPairs []byte `protobuf:"bytes,1,opt,name=aci_uak_pairs,json=aciUakPairs" json:"aci_uak_pairs,omitempty"` + // Each E164 is an 8-byte big-endian number, as 8 bytes. + PrevE164S []byte `protobuf:"bytes,2,opt,name=prev_e164s,json=prevE164s" json:"prev_e164s,omitempty"` + NewE164S []byte `protobuf:"bytes,3,opt,name=new_e164s,json=newE164s" json:"new_e164s,omitempty"` + DiscardE164S []byte `protobuf:"bytes,4,opt,name=discard_e164s,json=discardE164s" json:"discard_e164s,omitempty"` + // If true, the client has more pairs or e164s to send. If false or unset, + // this is the client's last request, and processing should commence. + HasMore *bool `protobuf:"varint,5,opt,name=has_more,json=hasMore" json:"has_more,omitempty"` + // If set, a token which allows rate limiting to discount the e164s in + // the request's prev_e164s, only counting new_e164s. If not set, then + // rate limiting considers both prev_e164s' and new_e164s' size. + Token []byte `protobuf:"bytes,6,opt,name=token" json:"token,omitempty"` + // After receiving a new token from the server, send back a message just + // containing a token_ack. + TokenAck *bool `protobuf:"varint,7,opt,name=token_ack,json=tokenAck" json:"token_ack,omitempty"` + // Request that, if the server allows, both ACI and PNI be returned even + // if the aci_uak_pairs don't match. + ReturnAcisWithoutUaks *bool `protobuf:"varint,8,opt,name=return_acis_without_uaks,json=returnAcisWithoutUaks" json:"return_acis_without_uaks,omitempty"` +} + +func (x *CDSClientRequest) Reset() { + *x = CDSClientRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_ContactDiscovery_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CDSClientRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CDSClientRequest) ProtoMessage() {} + +func (x *CDSClientRequest) ProtoReflect() protoreflect.Message { + mi := &file_ContactDiscovery_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CDSClientRequest.ProtoReflect.Descriptor instead. +func (*CDSClientRequest) Descriptor() ([]byte, []int) { + return file_ContactDiscovery_proto_rawDescGZIP(), []int{0} +} + +func (x *CDSClientRequest) GetAciUakPairs() []byte { + if x != nil { + return x.AciUakPairs + } + return nil +} + +func (x *CDSClientRequest) GetPrevE164S() []byte { + if x != nil { + return x.PrevE164S + } + return nil +} + +func (x *CDSClientRequest) GetNewE164S() []byte { + if x != nil { + return x.NewE164S + } + return nil +} + +func (x *CDSClientRequest) GetDiscardE164S() []byte { + if x != nil { + return x.DiscardE164S + } + return nil +} + +func (x *CDSClientRequest) GetHasMore() bool { + if x != nil && x.HasMore != nil { + return *x.HasMore + } + return false +} + +func (x *CDSClientRequest) GetToken() []byte { + if x != nil { + return x.Token + } + return nil +} + +func (x *CDSClientRequest) GetTokenAck() bool { + if x != nil && x.TokenAck != nil { + return *x.TokenAck + } + return false +} + +func (x *CDSClientRequest) GetReturnAcisWithoutUaks() bool { + if x != nil && x.ReturnAcisWithoutUaks != nil { + return *x.ReturnAcisWithoutUaks + } + return false +} + +type CDSClientResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Each triple is an 8-byte e164, a 16-byte PNI, and a 16-byte ACI. + // If the e164 was not found, PNI and ACI are all zeros. If the PNI + // was found but the ACI was not, the PNI will be non-zero and the ACI + // will be all zeros. ACI will be returned if one of the returned + // PNIs has an ACI/UAK pair that matches. + // + // Should the request be successful (IE: a successful status returned), + // |e164_pni_aci_triple| will always equal |e164| of the request, + // so the entire marshalled size of the response will be (2+32)*|e164|, + // where the additional 2 bytes are the id/type/length additions of the + // protobuf marshaling added to each byte array. This avoids any data + // leakage based on the size of the encrypted output. + E164PniAciTriples []byte `protobuf:"bytes,1,opt,name=e164_pni_aci_triples,json=e164PniAciTriples" json:"e164_pni_aci_triples,omitempty"` + // A token which allows subsequent calls' rate limiting to discount the + // e164s sent up in this request, only counting those in the next + // request's new_e164s. + Token []byte `protobuf:"bytes,3,opt,name=token" json:"token,omitempty"` +} + +func (x *CDSClientResponse) Reset() { + *x = CDSClientResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_ContactDiscovery_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CDSClientResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CDSClientResponse) ProtoMessage() {} + +func (x *CDSClientResponse) ProtoReflect() protoreflect.Message { + mi := &file_ContactDiscovery_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CDSClientResponse.ProtoReflect.Descriptor instead. +func (*CDSClientResponse) Descriptor() ([]byte, []int) { + return file_ContactDiscovery_proto_rawDescGZIP(), []int{1} +} + +func (x *CDSClientResponse) GetE164PniAciTriples() []byte { + if x != nil { + return x.E164PniAciTriples + } + return nil +} + +func (x *CDSClientResponse) GetToken() []byte { + if x != nil { + return x.Token + } + return nil +} + +var File_ContactDiscovery_proto protoreflect.FileDescriptor + +var file_ContactDiscovery_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x9e, 0x02, 0x0a, 0x10, 0x43, 0x44, 0x53, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0d, + 0x61, 0x63, 0x69, 0x5f, 0x75, 0x61, 0x6b, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x61, 0x63, 0x69, 0x55, 0x61, 0x6b, 0x50, 0x61, 0x69, 0x72, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x72, 0x65, 0x76, 0x45, 0x31, 0x36, 0x34, 0x73, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x73, 0x12, 0x23, 0x0a, 0x0d, + 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x73, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x45, 0x31, 0x36, 0x34, + 0x73, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x5f, 0x6d, 0x6f, 0x72, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x61, 0x73, 0x4d, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x63, 0x6b, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x63, 0x6b, 0x12, + 0x37, 0x0a, 0x18, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x61, 0x63, 0x69, 0x73, 0x5f, 0x77, + 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x5f, 0x75, 0x61, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x15, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x41, 0x63, 0x69, 0x73, 0x57, 0x69, 0x74, + 0x68, 0x6f, 0x75, 0x74, 0x55, 0x61, 0x6b, 0x73, 0x22, 0x5a, 0x0a, 0x11, 0x43, 0x44, 0x53, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, + 0x14, 0x65, 0x31, 0x36, 0x34, 0x5f, 0x70, 0x6e, 0x69, 0x5f, 0x61, 0x63, 0x69, 0x5f, 0x74, 0x72, + 0x69, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x65, 0x31, 0x36, + 0x34, 0x50, 0x6e, 0x69, 0x41, 0x63, 0x69, 0x54, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, +} + +var ( + file_ContactDiscovery_proto_rawDescOnce sync.Once + file_ContactDiscovery_proto_rawDescData = file_ContactDiscovery_proto_rawDesc +) + +func file_ContactDiscovery_proto_rawDescGZIP() []byte { + file_ContactDiscovery_proto_rawDescOnce.Do(func() { + file_ContactDiscovery_proto_rawDescData = protoimpl.X.CompressGZIP(file_ContactDiscovery_proto_rawDescData) + }) + return file_ContactDiscovery_proto_rawDescData +} + +var file_ContactDiscovery_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_ContactDiscovery_proto_goTypes = []interface{}{ + (*CDSClientRequest)(nil), // 0: signalservice.CDSClientRequest + (*CDSClientResponse)(nil), // 1: signalservice.CDSClientResponse +} +var file_ContactDiscovery_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] 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_ContactDiscovery_proto_init() } +func file_ContactDiscovery_proto_init() { + if File_ContactDiscovery_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_ContactDiscovery_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CDSClientRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ContactDiscovery_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CDSClientResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ContactDiscovery_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_ContactDiscovery_proto_goTypes, + DependencyIndexes: file_ContactDiscovery_proto_depIdxs, + MessageInfos: file_ContactDiscovery_proto_msgTypes, + }.Build() + File_ContactDiscovery_proto = out.File + file_ContactDiscovery_proto_rawDesc = nil + file_ContactDiscovery_proto_goTypes = nil + file_ContactDiscovery_proto_depIdxs = nil +} diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.proto b/pkg/signalmeow/protobuf/ContactDiscovery.proto new file mode 100644 index 0000000..d1f5e04 --- /dev/null +++ b/pkg/signalmeow/protobuf/ContactDiscovery.proto @@ -0,0 +1,53 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +package signalservice; + +message CDSClientRequest { + // Each ACI/UAK pair is a 32-byte buffer, containing the 16-byte ACI followed + // by its 16-byte UAK. + optional bytes aci_uak_pairs = 1; + + // Each E164 is an 8-byte big-endian number, as 8 bytes. + optional bytes prev_e164s = 2; + optional bytes new_e164s = 3; + optional bytes discard_e164s = 4; + + // If true, the client has more pairs or e164s to send. If false or unset, + // this is the client's last request, and processing should commence. + optional bool has_more = 5; + + // If set, a token which allows rate limiting to discount the e164s in + // the request's prev_e164s, only counting new_e164s. If not set, then + // rate limiting considers both prev_e164s' and new_e164s' size. + optional bytes token = 6; + + // After receiving a new token from the server, send back a message just + // containing a token_ack. + optional bool token_ack = 7; + + // Request that, if the server allows, both ACI and PNI be returned even + // if the aci_uak_pairs don't match. + optional bool return_acis_without_uaks = 8; +} + +message CDSClientResponse { + // Each triple is an 8-byte e164, a 16-byte PNI, and a 16-byte ACI. + // If the e164 was not found, PNI and ACI are all zeros. If the PNI + // was found but the ACI was not, the PNI will be non-zero and the ACI + // will be all zeros. ACI will be returned if one of the returned + // PNIs has an ACI/UAK pair that matches. + // + // Should the request be successful (IE: a successful status returned), + // |e164_pni_aci_triple| will always equal |e164| of the request, + // so the entire marshalled size of the response will be (2+32)*|e164|, + // where the additional 2 bytes are the id/type/length additions of the + // protobuf marshaling added to each byte array. This avoids any data + // leakage based on the size of the encrypted output. + optional bytes e164_pni_aci_triples = 1; + + // A token which allows subsequent calls' rate limiting to discount the + // e164s sent up in this request, only counting those in the next + // request's new_e164s. + optional bytes token = 3; +} diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index d3d00d4..657dcf5 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -10,11 +10,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 31a4c38..a49ea9f 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -12,11 +12,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index e57beec..446162e 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -12,11 +12,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index 08b6722..c27e635 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -12,11 +12,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( @@ -1897,7 +1896,6 @@ type CallMessage struct { Offer *CallMessage_Offer `protobuf:"bytes,1,opt,name=offer" json:"offer,omitempty"` Answer *CallMessage_Answer `protobuf:"bytes,2,opt,name=answer" json:"answer,omitempty"` IceUpdate []*CallMessage_IceUpdate `protobuf:"bytes,3,rep,name=iceUpdate" json:"iceUpdate,omitempty"` - LegacyHangup *CallMessage_Hangup `protobuf:"bytes,4,opt,name=legacyHangup" json:"legacyHangup,omitempty"` Busy *CallMessage_Busy `protobuf:"bytes,5,opt,name=busy" json:"busy,omitempty"` Hangup *CallMessage_Hangup `protobuf:"bytes,7,opt,name=hangup" json:"hangup,omitempty"` DestinationDeviceId *uint32 `protobuf:"varint,9,opt,name=destinationDeviceId" json:"destinationDeviceId,omitempty"` @@ -1957,13 +1955,6 @@ func (x *CallMessage) GetIceUpdate() []*CallMessage_IceUpdate { return nil } -func (x *CallMessage) GetLegacyHangup() *CallMessage_Hangup { - if x != nil { - return x.LegacyHangup - } - return nil -} - func (x *CallMessage) GetBusy() *CallMessage_Busy { if x != nil { return x.Busy @@ -3883,9 +3874,7 @@ type CallMessage_Offer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - // Legacy/deprecated; replaced by 'opaque' - Sdp *string `protobuf:"bytes,2,opt,name=sdp" json:"sdp,omitempty"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` Type *CallMessage_Offer_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.CallMessage_Offer_Type" json:"type,omitempty"` Opaque []byte `protobuf:"bytes,4,opt,name=opaque" json:"opaque,omitempty"` } @@ -3929,13 +3918,6 @@ func (x *CallMessage_Offer) GetId() uint64 { return 0 } -func (x *CallMessage_Offer) GetSdp() string { - if x != nil && x.Sdp != nil { - return *x.Sdp - } - return "" -} - func (x *CallMessage_Offer) GetType() CallMessage_Offer_Type { if x != nil && x.Type != nil { return *x.Type @@ -3955,9 +3937,7 @@ type CallMessage_Answer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - // Legacy/deprecated; replaced by 'opaque' - Sdp *string `protobuf:"bytes,2,opt,name=sdp" json:"sdp,omitempty"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` Opaque []byte `protobuf:"bytes,3,opt,name=opaque" json:"opaque,omitempty"` } @@ -4000,13 +3980,6 @@ func (x *CallMessage_Answer) GetId() uint64 { return 0 } -func (x *CallMessage_Answer) GetSdp() string { - if x != nil && x.Sdp != nil { - return *x.Sdp - } - return "" -} - func (x *CallMessage_Answer) GetOpaque() []byte { if x != nil { return x.Opaque @@ -4019,13 +3992,7 @@ type CallMessage_IceUpdate struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - // Legacy/deprecated; remove when old clients are gone. - Mid *string `protobuf:"bytes,2,opt,name=mid" json:"mid,omitempty"` - // Legacy/deprecated; remove when old clients are gone. - Line *uint32 `protobuf:"varint,3,opt,name=line" json:"line,omitempty"` - // Legacy/deprecated; replaced by 'opaque' - Sdp *string `protobuf:"bytes,4,opt,name=sdp" json:"sdp,omitempty"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` Opaque []byte `protobuf:"bytes,5,opt,name=opaque" json:"opaque,omitempty"` } @@ -4068,27 +4035,6 @@ func (x *CallMessage_IceUpdate) GetId() uint64 { return 0 } -func (x *CallMessage_IceUpdate) GetMid() string { - if x != nil && x.Mid != nil { - return *x.Mid - } - return "" -} - -func (x *CallMessage_IceUpdate) GetLine() uint32 { - if x != nil && x.Line != nil { - return *x.Line - } - return 0 -} - -func (x *CallMessage_IceUpdate) GetSdp() string { - if x != nil && x.Sdp != nil { - return *x.Sdp - } - return "" -} - func (x *CallMessage_IceUpdate) GetOpaque() []byte { if x != nil { return x.Opaque @@ -7363,7 +7309,7 @@ var file_SignalService_proto_rawDesc = []byte{ 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x65, 0x64, - 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf1, 0x09, 0x0a, 0x0b, 0x43, 0x61, + 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf2, 0x08, 0x0a, 0x0b, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, @@ -7376,967 +7322,959 @@ var file_SignalService_proto_rawDesc = []byte{ 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x49, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x09, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x45, 0x0a, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x52, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, - 0x79, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x12, 0x33, 0x0a, 0x04, 0x62, 0x75, 0x73, 0x79, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x42, 0x75, 0x73, 0x79, 0x52, 0x04, 0x62, 0x75, 0x73, 0x79, 0x12, 0x39, 0x0a, 0x06, - 0x68, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, - 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x52, - 0x06, 0x68, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x6f, 0x70, 0x61, - 0x71, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x52, 0x06, 0x6f, 0x70, - 0x61, 0x71, 0x75, 0x65, 0x1a, 0xb6, 0x01, 0x0a, 0x05, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, - 0x12, 0x39, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, + 0x12, 0x33, 0x0a, 0x04, 0x62, 0x75, 0x73, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, - 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x66, 0x66, 0x65, 0x72, - 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, - 0x70, 0x61, 0x71, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x70, 0x61, - 0x71, 0x75, 0x65, 0x22, 0x38, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x4f, - 0x46, 0x46, 0x45, 0x52, 0x5f, 0x41, 0x55, 0x44, 0x49, 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, - 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x5f, 0x56, 0x49, 0x44, 0x45, 0x4f, - 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x22, 0x04, 0x08, 0x02, 0x10, 0x02, 0x1a, 0x42, 0x0a, - 0x06, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x70, 0x61, - 0x71, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, - 0x65, 0x1a, 0x6b, 0x0a, 0x09, 0x49, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x6d, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x69, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, - 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x1a, 0x16, - 0x0a, 0x04, 0x42, 0x75, 0x73, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x1a, 0xe2, 0x01, 0x0a, 0x06, 0x48, 0x61, 0x6e, 0x67, 0x75, - 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x26, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x67, - 0x75, 0x70, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, - 0x41, 0x4c, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x41, - 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x48, 0x41, 0x4e, - 0x47, 0x55, 0x50, 0x5f, 0x44, 0x45, 0x43, 0x4c, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0f, - 0x0a, 0x0b, 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x42, 0x55, 0x53, 0x59, 0x10, 0x03, 0x12, - 0x1a, 0x0a, 0x16, 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x4e, 0x45, 0x45, 0x44, 0x5f, 0x50, - 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x1a, 0x93, 0x01, 0x0a, 0x06, - 0x4f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x07, 0x75, 0x72, - 0x67, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x2e, 0x55, - 0x72, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x07, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x22, - 0x30, 0x0a, 0x07, 0x55, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x52, - 0x4f, 0x50, 0x50, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x41, 0x4e, - 0x44, 0x4c, 0x45, 0x5f, 0x49, 0x4d, 0x4d, 0x45, 0x44, 0x49, 0x41, 0x54, 0x45, 0x4c, 0x59, 0x10, - 0x01, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xfe, 0x01, - 0x0a, 0x09, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0a, 0x6d, 0x65, 0x6e, - 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x0a, 0x6d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x69, 0x12, 0x36, 0x0a, 0x05, 0x73, - 0x74, 0x79, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, - 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x05, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x22, 0x56, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x08, 0x0a, 0x04, - 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4c, 0x44, 0x10, 0x01, - 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x54, 0x41, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, - 0x53, 0x50, 0x4f, 0x49, 0x4c, 0x45, 0x52, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x52, - 0x49, 0x4b, 0x45, 0x54, 0x48, 0x52, 0x4f, 0x55, 0x47, 0x48, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, - 0x4d, 0x4f, 0x4e, 0x4f, 0x53, 0x50, 0x41, 0x43, 0x45, 0x10, 0x05, 0x42, 0x11, 0x0a, 0x0f, 0x61, - 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xba, - 0x22, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, - 0x64, 0x79, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, - 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, - 0x32, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x12, - 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x05, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x3c, 0x0a, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x30, 0x0a, 0x07, 0x70, - 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x65, - 0x76, 0x69, 0x65, 0x77, 0x52, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x3c, 0x0a, - 0x07, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, - 0x65, 0x72, 0x52, 0x07, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x17, 0x72, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x56, 0x69, 0x65, 0x77, 0x4f, - 0x6e, 0x63, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x56, 0x69, 0x65, - 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, - 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x0f, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x0f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x14, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x4b, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x42, 0x75, 0x73, 0x79, 0x52, + 0x04, 0x62, 0x75, 0x73, 0x79, 0x12, 0x39, 0x0a, 0x06, 0x68, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x52, 0x06, 0x68, 0x61, 0x6e, 0x67, 0x75, 0x70, + 0x12, 0x30, 0x0a, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x64, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, + 0x70, 0x61, 0x71, 0x75, 0x65, 0x52, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x1a, 0xaa, 0x01, + 0x0a, 0x05, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x2e, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x22, 0x38, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x5f, 0x41, 0x55, 0x44, 0x49, + 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x46, 0x46, 0x45, + 0x52, 0x5f, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x22, 0x04, + 0x08, 0x02, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0x36, 0x0a, 0x06, 0x41, 0x6e, + 0x73, 0x77, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x02, + 0x10, 0x03, 0x1a, 0x45, 0x0a, 0x09, 0x49, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x6f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, + 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0x16, 0x0a, 0x04, 0x42, 0x75, 0x73, + 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, + 0x64, 0x1a, 0xe2, 0x01, 0x0a, 0x06, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3a, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x70, 0x2e, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, + 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, + 0x13, 0x0a, 0x0f, 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, + 0x45, 0x44, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x48, 0x41, 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x44, + 0x45, 0x43, 0x4c, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x48, 0x41, 0x4e, + 0x47, 0x55, 0x50, 0x5f, 0x42, 0x55, 0x53, 0x59, 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x41, + 0x4e, 0x47, 0x55, 0x50, 0x5f, 0x4e, 0x45, 0x45, 0x44, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, + 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x1a, 0x93, 0x01, 0x0a, 0x06, 0x4f, 0x70, 0x61, 0x71, 0x75, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x43, 0x0a, 0x07, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x4f, 0x70, 0x61, 0x71, 0x75, 0x65, 0x2e, 0x55, 0x72, 0x67, 0x65, 0x6e, 0x63, + 0x79, 0x52, 0x07, 0x75, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x30, 0x0a, 0x07, 0x55, 0x72, + 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x52, 0x4f, 0x50, 0x50, 0x41, 0x42, + 0x4c, 0x45, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x48, 0x41, 0x4e, 0x44, 0x4c, 0x45, 0x5f, 0x49, + 0x4d, 0x4d, 0x45, 0x44, 0x49, 0x41, 0x54, 0x45, 0x4c, 0x59, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x04, + 0x10, 0x05, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xfe, + 0x01, 0x0a, 0x09, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0a, 0x6d, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0a, 0x6d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x69, 0x12, 0x36, 0x0a, 0x05, + 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x05, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x22, 0x56, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x08, 0x0a, + 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4c, 0x44, 0x10, + 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x54, 0x41, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x12, 0x0b, 0x0a, + 0x07, 0x53, 0x50, 0x4f, 0x49, 0x4c, 0x45, 0x52, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, + 0x52, 0x49, 0x4b, 0x45, 0x54, 0x48, 0x52, 0x4f, 0x55, 0x47, 0x48, 0x10, 0x04, 0x12, 0x0d, 0x0a, + 0x09, 0x4d, 0x4f, 0x4e, 0x4f, 0x53, 0x50, 0x41, 0x43, 0x45, 0x10, 0x05, 0x42, 0x11, 0x0a, 0x0f, + 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0xba, 0x22, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, + 0x6f, 0x64, 0x79, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, + 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x61, + 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x56, 0x32, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, + 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x42, 0x0a, 0x09, - 0x67, 0x69, 0x66, 0x74, 0x42, 0x61, 0x64, 0x67, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x69, 0x66, 0x74, - 0x42, 0x61, 0x64, 0x67, 0x65, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x42, 0x61, 0x64, 0x67, 0x65, - 0x1a, 0xd0, 0x03, 0x0a, 0x05, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x53, 0x0a, 0x0b, - 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x31, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x64, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, - 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0x90, 0x01, 0x0a, 0x10, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x74, 0x68, 0x75, - 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, - 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x09, - 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x22, 0x22, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0e, 0x0a, - 0x0a, 0x47, 0x49, 0x46, 0x54, 0x5f, 0x42, 0x41, 0x44, 0x47, 0x45, 0x10, 0x01, 0x4a, 0x04, 0x08, - 0x02, 0x10, 0x03, 0x1a, 0xbf, 0x0a, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, - 0x3b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, - 0x74, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x06, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, - 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x3e, - 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, - 0x74, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x4a, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x65, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x05, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x3c, + 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x63, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x06, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x41, - 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x22, 0x0a, - 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x1a, 0xb6, 0x01, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, - 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, - 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, - 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, - 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, - 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, - 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x69, - 0x64, 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0xaa, 0x01, 0x0a, 0x05, 0x50, - 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x41, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x61, 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x30, 0x0a, 0x07, + 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x72, + 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x3c, + 0x0a, 0x07, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, + 0x6b, 0x65, 0x72, 0x52, 0x07, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x17, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x56, 0x69, 0x65, 0x77, + 0x4f, 0x6e, 0x63, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x56, 0x69, + 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x50, 0x68, 0x6f, - 0x6e, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x48, - 0x4f, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, - 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, - 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x04, 0x1a, 0xaa, 0x01, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, - 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x41, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, + 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x0f, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x2e, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, - 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, 0x45, - 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x08, - 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, - 0x4f, 0x4d, 0x10, 0x04, 0x1a, 0xcc, 0x02, 0x0a, 0x0d, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x49, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x65, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x70, 0x6f, 0x62, 0x6f, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x70, 0x6f, 0x62, 0x6f, 0x78, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, - 0x72, 0x68, 0x6f, 0x6f, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x69, - 0x67, 0x68, 0x62, 0x6f, 0x72, 0x68, 0x6f, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x74, - 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, - 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x74, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x74, 0x63, 0x6f, 0x64, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x26, 0x0a, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, - 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, 0x4f, - 0x4d, 0x10, 0x03, 0x1a, 0x60, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x38, 0x0a, - 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x0f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x14, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x4b, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, + 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x42, 0x0a, + 0x09, 0x67, 0x69, 0x66, 0x74, 0x42, 0x61, 0x64, 0x67, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x69, 0x66, + 0x74, 0x42, 0x61, 0x64, 0x67, 0x65, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x42, 0x61, 0x64, 0x67, + 0x65, 0x1a, 0xd0, 0x03, 0x0a, 0x05, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x53, 0x0a, + 0x0b, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x51, + 0x75, 0x6f, 0x74, 0x65, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x64, 0x41, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x52, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0x90, 0x01, 0x0a, 0x10, 0x51, 0x75, 0x6f, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x74, 0x68, + 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, - 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, - 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, - 0x6b, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, - 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x49, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x34, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x6f, 0x6a, 0x69, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x1a, 0x9a, 0x01, - 0x0a, 0x08, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, - 0x6f, 0x6a, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x6f, 0x6a, 0x69, - 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, - 0x63, 0x69, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x1a, 0x3a, 0x0a, 0x06, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, - 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x1a, 0x27, 0x0a, 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x61, - 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x61, 0x49, 0x64, 0x1a, - 0x52, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x12, 0x24, 0x0a, - 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x1a, 0x9a, 0x05, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x55, 0x0a, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, - 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x63, 0x74, - 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x92, 0x01, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x56, 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x0a, - 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x1a, 0x26, 0x0a, 0x0a, 0x4d, 0x6f, - 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x69, 0x63, 0x6f, - 0x4d, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x70, 0x69, 0x63, 0x6f, 0x4d, - 0x6f, 0x62, 0x42, 0x08, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xbf, 0x01, 0x0a, - 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, - 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, - 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x1a, - 0x26, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x18, 0x0a, - 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x06, 0x08, 0xeb, 0x07, 0x10, 0xec, 0x07, 0x1a, 0x78, - 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, - 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x22, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, - 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x43, 0x54, - 0x49, 0x56, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, - 0x4a, 0x06, 0x08, 0xea, 0x07, 0x10, 0xeb, 0x07, 0x4a, 0x06, 0x08, 0xeb, 0x07, 0x10, 0xec, 0x07, - 0x1a, 0x51, 0x0a, 0x09, 0x47, 0x69, 0x66, 0x74, 0x42, 0x61, 0x64, 0x67, 0x65, 0x12, 0x44, 0x0a, - 0x1d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x4d, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x0f, 0x0a, 0x0b, - 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1b, 0x0a, - 0x17, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, - 0x52, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, - 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, - 0x10, 0x04, 0x22, 0xb0, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, - 0x4c, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, - 0x49, 0x4d, 0x45, 0x52, 0x53, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x56, 0x49, 0x45, 0x57, 0x5f, - 0x4f, 0x4e, 0x43, 0x45, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x4f, - 0x4e, 0x43, 0x45, 0x5f, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x52, - 0x45, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x44, - 0x4e, 0x5f, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x41, 0x43, - 0x48, 0x4d, 0x45, 0x4e, 0x54, 0x53, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x45, 0x4e, 0x54, - 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, - 0x54, 0x53, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x55, 0x52, 0x52, 0x45, 0x4e, 0x54, 0x10, - 0x07, 0x1a, 0x02, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x27, 0x0a, 0x0b, 0x4e, - 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, - 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, - 0x64, 0x69, 0x6e, 0x67, 0x22, 0x92, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x2a, 0x0a, - 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, - 0x59, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, - 0x06, 0x56, 0x49, 0x45, 0x57, 0x45, 0x44, 0x10, 0x02, 0x22, 0xa8, 0x01, 0x0a, 0x0d, 0x54, 0x79, - 0x70, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3b, 0x0a, 0x06, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x69, 0x6e, 0x67, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x22, 0x22, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, - 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, - 0x45, 0x44, 0x10, 0x01, 0x22, 0xe6, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x56, 0x32, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x4a, 0x0a, 0x0e, 0x66, 0x69, - 0x6c, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x41, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0e, 0x74, 0x65, 0x78, 0x74, 0x41, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, - 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x0e, 0x74, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, - 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x61, - 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x42, - 0x0c, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x9f, 0x01, - 0x0a, 0x07, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x12, 0x36, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x64, - 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x22, - 0xd1, 0x04, 0x0a, 0x0e, 0x54, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x41, 0x0a, 0x09, 0x74, 0x65, 0x78, 0x74, 0x53, 0x74, - 0x79, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x41, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, 0x09, - 0x74, 0x65, 0x78, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x65, 0x78, - 0x74, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x74, 0x65, 0x78, 0x74, 0x46, 0x6f, 0x72, 0x65, - 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x13, 0x74, - 0x65, 0x78, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, - 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x74, 0x65, 0x78, 0x74, 0x42, 0x61, - 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x30, 0x0a, - 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, - 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, - 0x44, 0x0a, 0x08, 0x67, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x47, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x08, 0x67, 0x72, 0x61, - 0x64, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x1a, 0x92, 0x01, - 0x0a, 0x08, 0x47, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, - 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x65, 0x6e, - 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x06, 0x63, 0x6f, - 0x6c, 0x6f, 0x72, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x02, 0x52, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x47, 0x55, - 0x4c, 0x41, 0x52, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4c, 0x44, 0x10, 0x02, 0x12, - 0x09, 0x0a, 0x05, 0x53, 0x45, 0x52, 0x49, 0x46, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x43, - 0x52, 0x49, 0x50, 0x54, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x44, 0x45, 0x4e, - 0x53, 0x45, 0x44, 0x10, 0x05, 0x42, 0x0c, 0x0a, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, - 0x75, 0x6e, 0x64, 0x22, 0xe5, 0x01, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, - 0x63, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x69, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x20, 0x0a, 0x0b, 0x6e, 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6e, 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, - 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xb3, 0x29, 0x0a, 0x0b, - 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x73, - 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x74, - 0x12, 0x3f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, - 0x73, 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x33, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x04, - 0x72, 0x65, 0x61, 0x64, 0x12, 0x3c, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, - 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, - 0x67, 0x12, 0x63, 0x0a, 0x14, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, - 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x14, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x4f, 0x6e, - 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, - 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, - 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, - 0x70, 0x65, 0x6e, 0x12, 0x48, 0x0a, 0x0b, 0x66, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x52, 0x0b, 0x66, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, - 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x04, 0x6b, 0x65, - 0x79, 0x73, 0x12, 0x69, 0x0a, 0x16, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0e, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x16, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, - 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x76, 0x69, 0x65, 0x77, 0x65, 0x64, 0x18, 0x10, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x52, 0x06, 0x76, 0x69, 0x65, 0x77, 0x65, 0x64, 0x12, 0x54, - 0x0a, 0x0f, 0x70, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x0f, 0x70, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x63, - 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x51, 0x0a, 0x0e, 0x63, 0x61, 0x6c, 0x6c, - 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, - 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x63, 0x61, 0x6c, - 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x63, - 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, - 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x61, 0x6c, 0x6c, - 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x07, 0x0a, 0x04, 0x53, 0x65, 0x6e, - 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x12, 0x32, 0x0a, 0x14, 0x64, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x34, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x22, 0x22, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0e, + 0x0a, 0x0a, 0x47, 0x49, 0x46, 0x54, 0x5f, 0x42, 0x41, 0x44, 0x47, 0x45, 0x10, 0x01, 0x4a, 0x04, + 0x08, 0x02, 0x10, 0x03, 0x1a, 0xbf, 0x0a, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, + 0x12, 0x3b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x6a, 0x0a, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x11, 0x69, - 0x73, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x11, 0x69, - 0x73, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x6d, 0x0a, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, - 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x3c, 0x0a, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x7a, - 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, 0x14, - 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa9, 0x01, 0x0a, 0x15, 0x53, - 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, - 0x69, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x73, - 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, - 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x1a, 0x63, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, - 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x3e, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, + 0x4a, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x30, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x06, 0x61, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, + 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x22, + 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0xb6, 0x01, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x67, + 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x6d, + 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, + 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x69, 0x64, + 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, + 0x69, 0x64, 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0xaa, 0x01, 0x0a, 0x05, + 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x41, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x50, 0x68, + 0x6f, 0x6e, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, + 0x48, 0x4f, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, + 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, + 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x04, 0x1a, 0xaa, 0x01, 0x0a, 0x05, 0x45, 0x6d, 0x61, + 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x41, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, + 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x4f, 0x42, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x12, + 0x08, 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, + 0x54, 0x4f, 0x4d, 0x10, 0x04, 0x1a, 0xcc, 0x02, 0x0a, 0x0d, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x6c, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x49, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x6c, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, + 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x70, 0x6f, 0x62, 0x6f, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x70, 0x6f, 0x62, 0x6f, 0x78, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x65, 0x69, 0x67, 0x68, 0x62, + 0x6f, 0x72, 0x68, 0x6f, 0x6f, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, + 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x68, 0x6f, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, + 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x74, 0x79, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x74, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x74, 0x63, 0x6f, + 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x26, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x08, + 0x0a, 0x04, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, + 0x4f, 0x4d, 0x10, 0x03, 0x1a, 0x60, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x38, + 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, + 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, + 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x63, + 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x49, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x52, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, - 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x53, 0x0a, 0x07, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x69, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, - 0x61, 0x63, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, - 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, - 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, - 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4e, - 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, - 0x4b, 0x45, 0x59, 0x53, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4e, 0x49, 0x5f, 0x49, 0x44, - 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0x06, 0x1a, 0x48, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, - 0x10, 0x02, 0x1a, 0x4a, 0x0a, 0x06, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, - 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x83, - 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x70, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x75, 0x6e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, - 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, - 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, - 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x4a, 0x04, - 0x08, 0x04, 0x10, 0x05, 0x1a, 0xb3, 0x01, 0x0a, 0x14, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, - 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x12, - 0x48, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, - 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1f, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x0a, - 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x01, 0x1a, 0x50, 0x0a, 0x0c, 0x56, 0x69, - 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa5, 0x01, 0x0a, - 0x0b, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x55, 0x0a, - 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x50, 0x52, 0x4f, 0x46, - 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, - 0x5f, 0x4d, 0x41, 0x4e, 0x49, 0x46, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x53, - 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x10, 0x03, 0x1a, 0x46, 0x0a, 0x04, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26, 0x0a, 0x0e, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x1a, 0xf0, 0x01, 0x0a, - 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, - 0x64, 0x41, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, - 0x61, 0x64, 0x41, 0x63, 0x69, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, - 0x4a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4c, 0x0a, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, - 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x4c, 0x4f, 0x43, - 0x4b, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, - 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, - 0x8e, 0x04, 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, - 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, - 0x69, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, - 0x1a, 0xcc, 0x02, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, - 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, - 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, - 0x62, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, - 0x62, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x6c, - 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, 0x65, 0x64, 0x67, 0x65, - 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x2a, 0x0a, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, - 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x73, - 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x42, - 0x0f, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x1a, 0xd7, 0x01, 0x0a, 0x0f, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x22, - 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, - 0x65, 0x79, 0x12, 0x34, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, 0x74, - 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, 0x62, - 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, 0x04, 0x0a, 0x09, 0x43, - 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x76, - 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3d, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, - 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x4c, 0x0a, - 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x05, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x59, 0x0a, - 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x55, 0x44, 0x49, 0x4f, - 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x49, 0x44, 0x45, 0x4f, - 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x47, 0x52, 0x4f, 0x55, 0x50, - 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x44, 0x5f, 0x48, 0x4f, - 0x43, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x04, 0x22, 0x3e, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, - 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x55, - 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x43, 0x54, - 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, - 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, - 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, - 0x03, 0x1a, 0x4e, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, - 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, - 0x79, 0x1a, 0x81, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, - 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x22, 0x11, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, - 0x45, 0x41, 0x52, 0x10, 0x00, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x11, 0x10, - 0x12, 0x22, 0xdd, 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x12, - 0x18, 0x0a, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x00, 0x52, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, - 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, - 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x12, - 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, - 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x77, - 0x69, 0x64, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, - 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x28, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x64, 0x6e, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x64, - 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, - 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, - 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x4c, 0x45, 0x53, - 0x53, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x04, 0x22, 0x04, 0x08, 0x03, - 0x10, 0x03, 0x42, 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x10, 0x10, - 0x11, 0x22, 0xf0, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, - 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x06, - 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, - 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x06, - 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x04, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, - 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x55, 0x49, 0x54, - 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, 0x4e, - 0x46, 0x4f, 0x10, 0x04, 0x22, 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, - 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, - 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x20, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, 0x0a, - 0x03, 0x61, 0x63, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, - 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, - 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, - 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xe8, - 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, - 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, - 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, - 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, - 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x20, 0x0a, - 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, - 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, - 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, - 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, - 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, - 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, - 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5f, 0x0a, 0x11, - 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x6f, 0x62, 0x69, - 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x4b, 0x0a, - 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, - 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x13, 0x50, 0x6e, 0x69, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x70, - 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x6f, 0x6a, + 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x1a, 0x9a, + 0x01, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x6d, 0x6f, 0x6a, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x6f, 0x6a, + 0x69, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x41, 0x63, 0x69, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x1a, 0x3a, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x1a, 0x27, 0x0a, 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x43, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, + 0x61, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x61, 0x49, 0x64, + 0x1a, 0x52, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x12, 0x24, + 0x0a, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x1a, 0x9a, 0x05, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x55, 0x0a, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x75, 0x73, - 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x92, 0x01, 0x0a, 0x06, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x56, 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, + 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x1a, 0x26, 0x0a, 0x0a, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x69, 0x63, + 0x6f, 0x4d, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x70, 0x69, 0x63, 0x6f, + 0x4d, 0x6f, 0x62, 0x42, 0x08, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0xbf, 0x01, + 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, + 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x48, 0x00, + 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, + 0x1a, 0x26, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x06, 0x08, 0xeb, 0x07, 0x10, 0xec, 0x07, 0x1a, + 0x78, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x22, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, + 0x07, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x49, 0x74, 0x65, + 0x6d, 0x4a, 0x06, 0x08, 0xea, 0x07, 0x10, 0xeb, 0x07, 0x4a, 0x06, 0x08, 0xeb, 0x07, 0x10, 0xec, + 0x07, 0x1a, 0x51, 0x0a, 0x09, 0x47, 0x69, 0x66, 0x74, 0x42, 0x61, 0x64, 0x67, 0x65, 0x12, 0x44, + 0x0a, 0x1d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x43, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4d, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x0f, 0x0a, + 0x0b, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1b, + 0x0a, 0x17, 0x45, 0x58, 0x50, 0x49, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, + 0x45, 0x52, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x50, + 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, + 0x45, 0x10, 0x04, 0x22, 0xb0, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x49, 0x54, 0x49, + 0x41, 0x4c, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, + 0x54, 0x49, 0x4d, 0x45, 0x52, 0x53, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x56, 0x49, 0x45, 0x57, + 0x5f, 0x4f, 0x4e, 0x43, 0x45, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x56, 0x49, 0x45, 0x57, 0x5f, + 0x4f, 0x4e, 0x43, 0x45, 0x5f, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, + 0x52, 0x45, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x43, + 0x44, 0x4e, 0x5f, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x5f, 0x41, 0x54, 0x54, 0x41, + 0x43, 0x48, 0x4d, 0x45, 0x4e, 0x54, 0x53, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x45, 0x4e, + 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x59, 0x4d, 0x45, + 0x4e, 0x54, 0x53, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x55, 0x52, 0x52, 0x45, 0x4e, 0x54, + 0x10, 0x07, 0x1a, 0x02, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x27, 0x0a, 0x0b, + 0x4e, 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x92, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x2a, + 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, + 0x52, 0x59, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x56, 0x49, 0x45, 0x57, 0x45, 0x44, 0x10, 0x02, 0x22, 0xa8, 0x01, 0x0a, 0x0d, 0x54, + 0x79, 0x70, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3b, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x69, 0x6e, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x22, 0x22, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x53, + 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x50, + 0x50, 0x45, 0x44, 0x10, 0x01, 0x22, 0xe6, 0x02, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x56, 0x32, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x4a, 0x0a, 0x0e, 0x66, + 0x69, 0x6c, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x41, 0x74, 0x74, + 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0e, 0x74, 0x65, 0x78, 0x74, 0x41, + 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x54, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x0e, 0x74, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, + 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, + 0x42, 0x0c, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x9f, + 0x01, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, + 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, + 0x22, 0xd1, 0x04, 0x0a, 0x0e, 0x54, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x41, 0x0a, 0x09, 0x74, 0x65, 0x78, 0x74, 0x53, + 0x74, 0x79, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x41, + 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x52, + 0x09, 0x74, 0x65, 0x78, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x65, + 0x78, 0x74, 0x46, 0x6f, 0x72, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x74, 0x65, 0x78, 0x74, 0x46, 0x6f, 0x72, + 0x65, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x13, + 0x74, 0x65, 0x78, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, + 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x74, 0x65, 0x78, 0x74, 0x42, + 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x30, + 0x0a, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, + 0x12, 0x44, 0x0a, 0x08, 0x67, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x2e, 0x47, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x08, 0x67, 0x72, + 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x1a, 0x92, + 0x01, 0x0a, 0x08, 0x47, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x65, + 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x65, + 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6e, 0x67, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x06, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x02, 0x52, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, + 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x47, + 0x55, 0x4c, 0x41, 0x52, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4c, 0x44, 0x10, 0x02, + 0x12, 0x09, 0x0a, 0x05, 0x53, 0x45, 0x52, 0x49, 0x46, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x53, + 0x43, 0x52, 0x49, 0x50, 0x54, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x44, 0x45, + 0x4e, 0x53, 0x45, 0x44, 0x10, 0x05, 0x42, 0x0c, 0x0a, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, + 0x6f, 0x75, 0x6e, 0x64, 0x22, 0xe5, 0x01, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x41, 0x63, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x69, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6e, 0x75, 0x6c, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xb3, 0x29, 0x0a, + 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x04, + 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x73, 0x65, 0x6e, + 0x74, 0x12, 0x3f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x73, 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x33, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, + 0x04, 0x72, 0x65, 0x61, 0x64, 0x12, 0x3c, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, + 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x4e, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, + 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x63, 0x0a, 0x14, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, + 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x14, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x4f, + 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, + 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, + 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, + 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x48, 0x0a, 0x0b, 0x66, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x52, 0x0b, 0x66, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x33, + 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x04, 0x6b, + 0x65, 0x79, 0x73, 0x12, 0x69, 0x0a, 0x16, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x16, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, + 0x0a, 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x0f, 0x6f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x76, 0x69, 0x65, 0x77, 0x65, 0x64, 0x18, 0x10, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x52, 0x06, 0x76, 0x69, 0x65, 0x77, 0x65, 0x64, 0x12, + 0x54, 0x0a, 0x0f, 0x70, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x52, 0x0f, 0x70, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x09, + 0x63, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x51, 0x0a, 0x0e, 0x63, 0x61, 0x6c, + 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, + 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0e, 0x63, 0x61, + 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x4b, 0x0a, 0x0c, + 0x63, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, + 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x61, 0x6c, + 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x07, 0x0a, 0x04, 0x53, 0x65, + 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x45, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x12, 0x32, 0x0a, 0x14, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x34, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x6a, 0x0a, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x11, + 0x69, 0x73, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x11, + 0x69, 0x73, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x6d, 0x0a, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, + 0x7a, 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, + 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, + 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa9, 0x01, 0x0a, 0x15, + 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, + 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, + 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x1a, 0x63, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x52, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x0a, 0x08, 0x63, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x53, 0x0a, 0x07, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x69, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x04, 0x61, 0x63, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, + 0x73, 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, + 0x07, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, + 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x08, 0x0a, + 0x04, 0x4b, 0x45, 0x59, 0x53, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4e, 0x49, 0x5f, 0x49, + 0x44, 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0x06, 0x1a, 0x48, 0x0a, 0x04, 0x52, 0x65, 0x61, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, + 0x01, 0x10, 0x02, 0x1a, 0x4a, 0x0a, 0x06, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, + 0x83, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, + 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x75, + 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, + 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, + 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, + 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x6c, + 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x4a, + 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xb3, 0x01, 0x0a, 0x14, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, + 0x12, 0x48, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, + 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1f, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, + 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x01, 0x1a, 0x50, 0x0a, 0x0c, 0x56, + 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa5, 0x01, + 0x0a, 0x0b, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x55, + 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x50, 0x52, 0x4f, + 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, + 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x49, 0x46, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, + 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x10, 0x03, 0x1a, 0x46, 0x0a, 0x04, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26, 0x0a, + 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x1a, 0xf0, 0x01, + 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x41, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x68, 0x72, + 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, + 0x12, 0x4a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4c, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, + 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x4c, 0x4f, + 0x43, 0x4b, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x41, 0x4e, + 0x44, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, + 0x1a, 0x8e, 0x04, 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, + 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, + 0x6e, 0x1a, 0xcc, 0x02, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, + 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, + 0x6f, 0x62, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, + 0x6f, 0x62, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x32, 0x0a, 0x14, + 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, 0x65, 0x64, 0x67, + 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c, 0x65, 0x64, 0x67, + 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, + 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, + 0x42, 0x0f, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x1a, 0xd7, 0x01, 0x0a, 0x0f, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, + 0x22, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, + 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, + 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, + 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, 0x04, 0x0a, 0x09, + 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, + 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x4c, + 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, + 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x05, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x59, + 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x55, 0x44, 0x49, + 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x49, 0x44, 0x45, + 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x47, 0x52, 0x4f, 0x55, + 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x44, 0x5f, 0x48, + 0x4f, 0x43, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x04, 0x22, 0x3e, 0x0a, 0x09, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, + 0x08, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, + 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x43, + 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, + 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, + 0x50, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, + 0x10, 0x03, 0x1a, 0x4e, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, + 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, + 0x65, 0x79, 0x1a, 0x81, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, + 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x22, 0x11, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x43, + 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x11, + 0x10, 0x12, 0x22, 0xdd, 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x64, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, + 0x12, 0x18, 0x0a, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, + 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x72, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, + 0x12, 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, + 0x61, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, + 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x64, + 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, + 0x64, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, + 0x73, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, + 0x47, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x4c, 0x45, + 0x53, 0x53, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x04, 0x22, 0x04, 0x08, + 0x03, 0x10, 0x03, 0x42, 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x10, + 0x10, 0x11, 0x22, 0xf0, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, + 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, + 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, + 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, + 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, + 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x55, 0x49, + 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, + 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, + 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, + 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, + 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, + 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, + 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, + 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, + 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, + 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, + 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5f, 0x0a, + 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, + 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x4b, + 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x13, 0x50, 0x6e, + 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, + 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x75, + 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, } var ( @@ -8469,104 +8407,103 @@ var file_SignalService_proto_depIdxs = []int32{ 48, // 10: signalservice.CallMessage.offer:type_name -> signalservice.CallMessage.Offer 49, // 11: signalservice.CallMessage.answer:type_name -> signalservice.CallMessage.Answer 50, // 12: signalservice.CallMessage.iceUpdate:type_name -> signalservice.CallMessage.IceUpdate - 52, // 13: signalservice.CallMessage.legacyHangup:type_name -> signalservice.CallMessage.Hangup - 51, // 14: signalservice.CallMessage.busy:type_name -> signalservice.CallMessage.Busy - 52, // 15: signalservice.CallMessage.hangup:type_name -> signalservice.CallMessage.Hangup - 53, // 16: signalservice.CallMessage.opaque:type_name -> signalservice.CallMessage.Opaque - 4, // 17: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style - 39, // 18: signalservice.DataMessage.attachments:type_name -> signalservice.AttachmentPointer - 41, // 19: signalservice.DataMessage.groupV2:type_name -> signalservice.GroupContextV2 - 54, // 20: signalservice.DataMessage.quote:type_name -> signalservice.DataMessage.Quote - 55, // 21: signalservice.DataMessage.contact:type_name -> signalservice.DataMessage.Contact - 35, // 22: signalservice.DataMessage.preview:type_name -> signalservice.Preview - 56, // 23: signalservice.DataMessage.sticker:type_name -> signalservice.DataMessage.Sticker - 57, // 24: signalservice.DataMessage.reaction:type_name -> signalservice.DataMessage.Reaction - 58, // 25: signalservice.DataMessage.delete:type_name -> signalservice.DataMessage.Delete - 29, // 26: signalservice.DataMessage.bodyRanges:type_name -> signalservice.BodyRange - 59, // 27: signalservice.DataMessage.groupCallUpdate:type_name -> signalservice.DataMessage.GroupCallUpdate - 61, // 28: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment - 60, // 29: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext - 62, // 30: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge - 12, // 31: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type - 13, // 32: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action - 41, // 33: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 - 39, // 34: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer - 36, // 35: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment - 29, // 36: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange - 39, // 37: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer - 14, // 38: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style - 35, // 39: signalservice.TextAttachment.preview:type_name -> signalservice.Preview - 74, // 40: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient - 15, // 41: signalservice.Verified.state:type_name -> signalservice.Verified.State - 75, // 42: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent - 76, // 43: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts - 78, // 44: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request - 79, // 45: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read - 77, // 46: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked - 37, // 47: signalservice.SyncMessage.verified:type_name -> signalservice.Verified - 81, // 48: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration - 82, // 49: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation - 83, // 50: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen - 84, // 51: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest - 85, // 52: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys - 86, // 53: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse - 87, // 54: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment - 80, // 55: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed - 88, // 56: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber - 89, // 57: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent - 90, // 58: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate - 91, // 59: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 25, // 60: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type - 95, // 61: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member - 39, // 62: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer - 96, // 63: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 37, // 64: signalservice.ContactDetails.verified:type_name -> signalservice.Verified - 98, // 65: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member - 97, // 66: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar - 99, // 67: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress - 30, // 68: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 1, // 69: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 70: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 71: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 63, // 72: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 29, // 73: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 74: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 64, // 75: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 65, // 76: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 66, // 77: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 67, // 78: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 68, // 79: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 39, // 80: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 70, // 81: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 71, // 82: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 39, // 83: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 84: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 85: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 86: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 39, // 87: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 72, // 88: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 73, // 89: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 11, // 90: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 30, // 91: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 92, // 92: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 34, // 93: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 93, // 94: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 47, // 95: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 39, // 96: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 16, // 97: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 17, // 98: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 18, // 99: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 19, // 100: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 94, // 101: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 20, // 102: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 21, // 103: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 22, // 104: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 23, // 105: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 106, // [106:106] is the sub-list for method output_type - 106, // [106:106] is the sub-list for method input_type - 106, // [106:106] is the sub-list for extension type_name - 106, // [106:106] is the sub-list for extension extendee - 0, // [0:106] is the sub-list for field type_name + 51, // 13: signalservice.CallMessage.busy:type_name -> signalservice.CallMessage.Busy + 52, // 14: signalservice.CallMessage.hangup:type_name -> signalservice.CallMessage.Hangup + 53, // 15: signalservice.CallMessage.opaque:type_name -> signalservice.CallMessage.Opaque + 4, // 16: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style + 39, // 17: signalservice.DataMessage.attachments:type_name -> signalservice.AttachmentPointer + 41, // 18: signalservice.DataMessage.groupV2:type_name -> signalservice.GroupContextV2 + 54, // 19: signalservice.DataMessage.quote:type_name -> signalservice.DataMessage.Quote + 55, // 20: signalservice.DataMessage.contact:type_name -> signalservice.DataMessage.Contact + 35, // 21: signalservice.DataMessage.preview:type_name -> signalservice.Preview + 56, // 22: signalservice.DataMessage.sticker:type_name -> signalservice.DataMessage.Sticker + 57, // 23: signalservice.DataMessage.reaction:type_name -> signalservice.DataMessage.Reaction + 58, // 24: signalservice.DataMessage.delete:type_name -> signalservice.DataMessage.Delete + 29, // 25: signalservice.DataMessage.bodyRanges:type_name -> signalservice.BodyRange + 59, // 26: signalservice.DataMessage.groupCallUpdate:type_name -> signalservice.DataMessage.GroupCallUpdate + 61, // 27: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment + 60, // 28: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext + 62, // 29: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge + 12, // 30: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type + 13, // 31: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action + 41, // 32: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 + 39, // 33: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer + 36, // 34: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment + 29, // 35: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange + 39, // 36: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer + 14, // 37: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style + 35, // 38: signalservice.TextAttachment.preview:type_name -> signalservice.Preview + 74, // 39: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient + 15, // 40: signalservice.Verified.state:type_name -> signalservice.Verified.State + 75, // 41: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent + 76, // 42: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts + 78, // 43: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request + 79, // 44: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read + 77, // 45: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked + 37, // 46: signalservice.SyncMessage.verified:type_name -> signalservice.Verified + 81, // 47: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration + 82, // 48: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation + 83, // 49: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen + 84, // 50: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest + 85, // 51: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys + 86, // 52: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse + 87, // 53: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment + 80, // 54: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed + 88, // 55: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber + 89, // 56: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent + 90, // 57: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate + 91, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent + 25, // 59: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type + 95, // 60: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member + 39, // 61: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer + 96, // 62: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 37, // 63: signalservice.ContactDetails.verified:type_name -> signalservice.Verified + 98, // 64: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member + 97, // 65: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar + 99, // 66: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress + 30, // 67: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 1, // 68: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 69: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 70: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 63, // 71: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 29, // 72: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 73: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 64, // 74: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 65, // 75: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 66, // 76: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 67, // 77: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 68, // 78: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 39, // 79: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 70, // 80: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 71, // 81: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 39, // 82: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 83: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 84: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 85: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 39, // 86: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 72, // 87: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 73, // 88: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 11, // 89: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 30, // 90: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 92, // 91: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 34, // 92: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 93, // 93: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 47, // 94: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 39, // 95: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 16, // 96: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 17, // 97: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 18, // 98: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 19, // 99: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 94, // 100: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 20, // 101: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 21, // 102: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 22, // 103: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 23, // 104: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 105, // [105:105] is the sub-list for method output_type + 105, // [105:105] is the sub-list for method input_type + 105, // [105:105] is the sub-list for extension type_name + 105, // [105:105] is the sub-list for extension extendee + 0, // [0:105] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 3fccc00..866343f 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -63,27 +63,22 @@ message CallMessage { } optional uint64 id = 1; - // Legacy/deprecated; replaced by 'opaque' - optional string sdp = 2; + reserved /* sdp */ 2; optional Type type = 3; optional bytes opaque = 4; } message Answer { optional uint64 id = 1; - // Legacy/deprecated; replaced by 'opaque' - optional string sdp = 2; + reserved /* sdp */ 2; optional bytes opaque = 3; } message IceUpdate { optional uint64 id = 1; - // Legacy/deprecated; remove when old clients are gone. - optional string mid = 2; - // Legacy/deprecated; remove when old clients are gone. - optional uint32 line = 3; - // Legacy/deprecated; replaced by 'opaque' - optional string sdp = 4; + reserved /* mid */ 2; + reserved /* line */ 3; + reserved /* sdp */ 4; optional bytes opaque = 5; } @@ -118,7 +113,7 @@ message CallMessage { optional Offer offer = 1; optional Answer answer = 2; repeated IceUpdate iceUpdate = 3; - optional Hangup legacyHangup = 4; + reserved /* legacyHangup */ 4; optional Busy busy = 5; reserved /* profileKey */ 6; optional Hangup hangup = 7; diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index cf4726f..34f48be 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -12,11 +12,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index fc97a14..9f95088 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -10,11 +10,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index 0e2134c..c3aed6d 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -12,11 +12,10 @@ package signalpb import ( - reflect "reflect" - sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index c24bc3a..66314fc 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-e17b07bb12110c0ebeae193cb6fad35d33b57d40} -DESKTOP_GIT_REVISION=${1:-c6c072319993fefd9fcfab55ca77dc75263bc875} +ANDROID_GIT_REVISION=${1:-c725a2fabb76f88d555c9f8b3c4f1cbdde4d4593} +DESKTOP_GIT_REVISION=${1:-060c58be527396918fa3753ace4f9f38d7c67876} update_proto() { case "$1" in @@ -28,3 +28,4 @@ update_proto Signal-Android WebSocketResources.proto update_proto Signal-Desktop DeviceName.proto update_proto Signal-Desktop UnidentifiedDelivery.proto +update_proto Signal-Desktop ContactDiscovery.proto From 4d1cfed402a4e8179c96099fb9e0bbf4a9b4f119 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 14:21:31 +0200 Subject: [PATCH 048/718] Don't hardcode tel: address in beeper identifier list --- puppet.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/puppet.go b/puppet.go index 67f3726..020d1e8 100644 --- a/puppet.go +++ b/puppet.go @@ -276,14 +276,17 @@ func (puppet *Puppet) UpdateContactInfo(ctx context.Context) { return } + identifiers := []string{ + fmt.Sprintf("signal:%s", puppet.SignalID), + } + if puppet.Number != "" { + identifiers = append(identifiers, fmt.Sprintf("tel:%s", puppet.Number)) + } contactInfo := map[string]any{ - "com.beeper.bridge.identifiers": []string{ - fmt.Sprintf("tel:%s", puppet.Number), - fmt.Sprintf("signal:%s", puppet.SignalID), - }, - "com.beeper.bridge.remote_id": puppet.SignalID.String(), - "com.beeper.bridge.service": "signal", - "com.beeper.bridge.network": "signal", + "com.beeper.bridge.identifiers": identifiers, + "com.beeper.bridge.remote_id": puppet.SignalID.String(), + "com.beeper.bridge.service": "signal", + "com.beeper.bridge.network": "signal", } err := puppet.DefaultIntent().BeeperUpdateProfile(ctx, contactInfo) if err != nil { From f596eb75cc823740733d199f42c68325fe675e23 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 14:21:53 +0200 Subject: [PATCH 049/718] Only update phone number if it's available --- puppet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puppet.go b/puppet.go index 020d1e8..7e09f6e 100644 --- a/puppet.go +++ b/puppet.go @@ -254,7 +254,7 @@ func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, info *types. log.Trace().Msg("Updating puppet info") update := false - if puppet.Number != info.E164 { + if info.E164 != "" && puppet.Number != info.E164 { puppet.Number = info.E164 update = true } From b9f29abfcf3e7521ea16751421a735130eccf63a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 16:20:49 +0200 Subject: [PATCH 050/718] Add CDSI client --- pkg/libsignalgo/sgxclient.go | 98 +++++++++ pkg/signalmeow/client.go | 4 + pkg/signalmeow/contactdiscovery.go | 301 ++++++++++++++++++++++++++ pkg/signalmeow/web/signalwebsocket.go | 2 +- pkg/signalmeow/web/web.go | 6 +- 5 files changed, 407 insertions(+), 4 deletions(-) create mode 100644 pkg/libsignalgo/sgxclient.go create mode 100644 pkg/signalmeow/contactdiscovery.go diff --git a/pkg/libsignalgo/sgxclient.go b/pkg/libsignalgo/sgxclient.go new file mode 100644 index 0000000..c85f058 --- /dev/null +++ b/pkg/libsignalgo/sgxclient.go @@ -0,0 +1,98 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#cgo LDFLAGS: -lsignal_ffi -ldl -lm +#include "./libsignal-ffi.h" +*/ +import "C" +import ( + "runtime" + "time" +) + +type SGXClientState struct { + nc noCopy + ptr *C.SignalSgxClientState +} + +func wrapSGXClientState(ptr *C.SignalSgxClientState) *SGXClientState { + cdsClientState := &SGXClientState{ptr: ptr} + runtime.SetFinalizer(cdsClientState, (*SGXClientState).Destroy) + return cdsClientState +} + +func NewCDS2ClientState(mrenclave, attestationMessage []byte, currentTime time.Time) (*SGXClientState, error) { + var cds *C.SignalSgxClientState + signalFfiError := C.signal_cds2_client_state_new( + &cds, + BytesToBuffer(mrenclave), + BytesToBuffer(attestationMessage), + C.uint64_t(currentTime.UnixMilli()), + ) + runtime.KeepAlive(mrenclave) + runtime.KeepAlive(attestationMessage) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return wrapSGXClientState(cds), nil +} + +func (cds *SGXClientState) Destroy() error { + runtime.SetFinalizer(cds, nil) + return wrapError(C.signal_sgx_client_state_destroy(cds.ptr)) +} + +func (cds *SGXClientState) InitialRequest() ([]byte, error) { + var resp C.SignalOwnedBuffer + signalFfiError := C.signal_sgx_client_state_initial_request(&resp, cds.ptr) + runtime.KeepAlive(cds) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(resp), nil +} + +func (cds *SGXClientState) CompleteHandshake(handshakeReceived []byte) error { + signalFfiError := C.signal_sgx_client_state_complete_handshake(cds.ptr, BytesToBuffer(handshakeReceived)) + runtime.KeepAlive(cds) + runtime.KeepAlive(handshakeReceived) + return wrapError(signalFfiError) +} + +func (cds *SGXClientState) EstablishedSend(plaintext []byte) ([]byte, error) { + var resp C.SignalOwnedBuffer + signalFfiError := C.signal_sgx_client_state_established_send(&resp, cds.ptr, BytesToBuffer(plaintext)) + runtime.KeepAlive(cds) + runtime.KeepAlive(plaintext) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(resp), nil +} + +func (cds *SGXClientState) EstablishedReceive(ciphertext []byte) ([]byte, error) { + var resp C.SignalOwnedBuffer + signalFfiError := C.signal_sgx_client_state_established_recv(&resp, cds.ptr, BytesToBuffer(ciphertext)) + runtime.KeepAlive(cds) + runtime.KeepAlive(ciphertext) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(resp), nil +} diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 6dab83f..d7df48d 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -47,6 +47,10 @@ type Client struct { WSCancel context.CancelFunc EventHandler func(events.SignalEvent) + + cdAuthLock sync.Mutex + cdAuth *contactDiscoveryAuth + cdToken []byte } func (cli *Client) handleEvent(evt events.SignalEvent) { diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go new file mode 100644 index 0000000..eb9a443 --- /dev/null +++ b/pkg/signalmeow/contactdiscovery.go @@ -0,0 +1,301 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "net/http" + "net/url" + "path" + "strconv" + "strings" + "sync" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "github.com/tidwall/gjson" + "go.mau.fi/util/exerrors" + "google.golang.org/protobuf/proto" + "nhooyr.io/websocket" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +const ProdContactDiscoveryServer = "cdsi.signal.org" +const ProdContactDiscoveryMrenclave = "0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57" +const ContactDiscoveryAuthTTL = 23 * time.Hour + +const rateLimitCloseCode = websocket.StatusCode(4008) + +var prodContactDiscoveryMrenclaveBytes = exerrors.Must(hex.DecodeString(ProdContactDiscoveryMrenclave)) + +type ContactDiscoveryRateLimitError struct { + RetryAfter time.Duration +} + +func (cdrle ContactDiscoveryRateLimitError) Error() string { + return fmt.Sprintf("contact discovery rate limited for %s", cdrle.RetryAfter) +} + +type ContactDiscoveryClient struct { + CDS *libsignalgo.SGXClientState + WS *websocket.Conn + + Token []byte + Response ContactDiscoveryResponse + stateLock sync.Mutex +} + +type ContactDiscoveryResponse map[string]CDSResponseEntry + +type CDSResponseEntry struct { + ACI uuid.UUID + PNI uuid.UUID +} + +func (cli *Client) LookupPhone(ctx context.Context, e164s ...string) (ContactDiscoveryResponse, error) { + if len(e164s) == 0 { + return nil, nil + } + requestData := make([]byte, len(e164s)*8) + for i, e164 := range e164s { + e164Int, err := strconv.ParseInt(strings.TrimPrefix(e164, "+"), 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid E164 number %s: %w", e164, err) + } + binary.BigEndian.PutUint64(requestData[i*8:(i+1)*8], uint64(e164Int)) + } + ctx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() + resp, token, err := cli.doContactDiscovery(ctx, &signalpb.CDSClientRequest{ + Token: cli.cdToken, + NewE164S: requestData, + }) + if token != nil { + cli.cdToken = token + } + return resp, err +} + +func (cli *Client) doContactDiscovery(ctx context.Context, req *signalpb.CDSClientRequest) (ContactDiscoveryResponse, []byte, error) { + creds, err := cli.getContactDiscoveryAuth(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to fetch contact discovery auth: %w", err) + } + log := zerolog.Ctx(ctx).With(). + Str("websocket_type", "contact"). + Str("username", creds.Username). + Logger() + log.Trace().Any("creds", creds).Msg("Got contact discovery credentials") + ctx = log.WithContext(ctx) + addr := (&url.URL{ + Scheme: "wss", + Host: ProdContactDiscoveryServer, + User: url.UserPassword(creds.Username, creds.Password), + Path: path.Join("v1", ProdContactDiscoveryMrenclave, "discovery"), + }).String() + log.Trace().Msg("Connecting to contact discovery websocket") + ws, _, err := websocket.Dial(ctx, addr, &websocket.DialOptions{ + HTTPClient: web.SignalHTTPClient, + }) + if err != nil { + var closeErr websocket.CloseError + if errors.As(err, &closeErr) && closeErr.Code == rateLimitCloseCode { + retryAfter := gjson.Get(closeErr.Reason, "retry_after") + if retryAfter.Type == gjson.Number { + retryAfterDuration := time.Duration(retryAfter.Int()) * time.Second + return nil, nil, ContactDiscoveryRateLimitError{RetryAfter: retryAfterDuration} + } + } + return nil, nil, fmt.Errorf("failed to open contact discovery websocket: %w", err) + } + ws.SetReadLimit(1 << 20) // Increase read limit to 1MB from default of 32KB + defer func() { + _ = ws.CloseNow() + }() + cdc := &ContactDiscoveryClient{ + WS: ws, + } + log.Trace().Msg("Doing contact discovery websocket handshake") + err = cdc.Handshake(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to handshake with contact discovery server: %w", err) + } + log.Trace().Msg("Contact discovery websocket connected") + err = cdc.SendRequest(ctx, req) + if err != nil { + return nil, nil, fmt.Errorf("failed to send contact discovery request: %w", err) + } + log.Trace().Any("request", req).Msg("Contact discovery request sent") + err = cdc.ReadResponse(ctx) + if err != nil { + return nil, nil, err + } + log.Trace().Any("response", cdc.Response).Msg("Contact discovery response received") + err = cdc.WS.Close(3000, "Normal") + if err != nil { + log.Trace().Err(err).Msg("Error closing contact discovery websocket cleanly") + } + return cdc.Response, cdc.Token, nil +} + +func (cdc *ContactDiscoveryClient) Handshake(ctx context.Context) error { + msgType, attestationMsg, err := cdc.WS.Read(ctx) + if err != nil { + return fmt.Errorf("failed to read attestation message: %w", err) + } else if msgType != websocket.MessageBinary { + return fmt.Errorf("expected binary message, got %s", msgType.String()) + } + cdsClient, err := libsignalgo.NewCDS2ClientState(prodContactDiscoveryMrenclaveBytes, attestationMsg, time.Now()) + if err != nil { + return fmt.Errorf("failed to initialize CDS2 client state: %w", err) + } + initReq, err := cdsClient.InitialRequest() + if err != nil { + return fmt.Errorf("failed to generate initial request: %w", err) + } + err = cdc.WS.Write(ctx, websocket.MessageBinary, initReq) + if err != nil { + return fmt.Errorf("failed to write initial request: %w", err) + } + msgType, handshakeFinishMsg, err := cdc.WS.Read(ctx) + if err != nil { + return fmt.Errorf("failed to read handshake finish message: %w", err) + } else if msgType != websocket.MessageBinary { + return fmt.Errorf("expected binary message, got %s", msgType.String()) + } + err = cdsClient.CompleteHandshake(handshakeFinishMsg) + if err != nil { + return fmt.Errorf("failed to complete handshake: %w", err) + } + cdc.CDS = cdsClient + return nil +} + +func (cdc *ContactDiscoveryClient) SendRequest(ctx context.Context, req *signalpb.CDSClientRequest) error { + plaintext, err := proto.Marshal(req) + if err != nil { + return fmt.Errorf("failed to marshal request: %w", err) + } + ciphertext, err := cdc.CDS.EstablishedSend(plaintext) + if err != nil { + return fmt.Errorf("failed to encrypt request: %w", err) + } + err = cdc.WS.Write(ctx, websocket.MessageBinary, ciphertext) + if err != nil { + return fmt.Errorf("failed to write request: %w", err) + } + return nil +} + +func (cdc *ContactDiscoveryClient) ReadResponse(ctx context.Context) error { + for cdc.Response == nil { + msgType, msg, err := cdc.WS.Read(ctx) + if err != nil { + return fmt.Errorf("failed to read contact discovery message: %w", err) + } else if msgType != websocket.MessageBinary { + return fmt.Errorf("unexpected contact discovery message type: %w", err) + } + err = cdc.handleResponse(ctx, msg) + if err != nil { + return fmt.Errorf("failed to handle contact discovery message: %w", err) + } + } + return nil +} + +func (cdc *ContactDiscoveryClient) handleResponse(ctx context.Context, msg []byte) error { + decrypted, err := cdc.CDS.EstablishedReceive(msg) + if err != nil { + return fmt.Errorf("failed to decrypt message: %w", err) + } + var cdsClientResp signalpb.CDSClientResponse + err = proto.Unmarshal(decrypted, &cdsClientResp) + if err != nil { + return fmt.Errorf("failed to unmarshal message: %w", err) + } + if cdsClientResp.Token != nil { + cdc.Token = cdsClientResp.Token + err = cdc.SendRequest(ctx, &signalpb.CDSClientRequest{ + TokenAck: proto.Bool(true), + }) + if err != nil { + return fmt.Errorf("failed to send token ack request: %w", err) + } + } + if cdsClientResp.E164PniAciTriples != nil { + const tripleSize = 8 + 16 + 16 + triples := cdsClientResp.E164PniAciTriples + pairCount := len(triples) / tripleSize + if pairCount*tripleSize != len(triples) { + return fmt.Errorf("invalid response size %d (not divisible by 40)", len(triples)) + } + resp := make(ContactDiscoveryResponse, pairCount) + for i := 0; i < pairCount; i++ { + data := triples[i*tripleSize : (i+1)*tripleSize] + e164 := binary.BigEndian.Uint64(data[:8]) + pni := uuid.UUID(data[8:24]) + aci := uuid.UUID(data[24:40]) + resp[fmt.Sprintf("+%d", e164)] = CDSResponseEntry{PNI: pni, ACI: aci} + } + cdc.Response = resp + } + return nil +} + +type contactDiscoveryAuth struct { + Username string `json:"username"` + Password string `json:"password"` + CreatedAt time.Time `json:"-"` +} + +func (cda *contactDiscoveryAuth) Expired() bool { + return cda == nil || cda.CreatedAt.IsZero() || time.Since(cda.CreatedAt) > ContactDiscoveryAuthTTL +} + +func (cli *Client) getContactDiscoveryAuth(ctx context.Context) (*contactDiscoveryAuth, error) { + cli.cdAuthLock.Lock() + defer cli.cdAuthLock.Unlock() + if cli.cdAuth.Expired() { + username, password := cli.Store.BasicAuthCreds() + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v2/directory/auth", &web.HTTPReqOpt{ + Username: &username, + Password: &password, + }) + if err != nil { + return nil, err + } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { + return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + + var auth contactDiscoveryAuth + auth.CreatedAt = time.Now() + err = web.DecodeHTTPResponseBody(ctx, &auth, resp) + if err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + cli.cdAuth = &auth + } + return cli.cdAuth, nil +} diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 8ef8c25..64963cd 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -566,7 +566,7 @@ func (s *SignalWebsocket) sendRequestInternal( func OpenWebsocket(ctx context.Context, path string) (*websocket.Conn, *http.Response, error) { opt := &websocket.DialOptions{ - HTTPClient: signalHTTPClient, + HTTPClient: SignalHTTPClient, } urlStr := "wss://" + APIHostname + path ws, resp, err := websocket.Dial(ctx, urlStr, opt) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index 6e98990..c05f736 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -58,7 +58,7 @@ var signalTransport = &http.Transport{ RootCAs: x509.NewCertPool(), }, } -var signalHTTPClient = &http.Client{ +var SignalHTTPClient = &http.Client{ Transport: signalTransport, } @@ -153,7 +153,7 @@ func SendHTTPRequest(ctx context.Context, method string, path string, opt *HTTPR httpReqCounter++ log = log.With().Int("request_number", httpReqCounter).Logger() log.Trace().Msg("Sending HTTP request") - resp, err := signalHTTPClient.Do(req) + resp, err := SignalHTTPClient.Do(req) if err != nil { log.Err(err).Msg("Error sending request") return nil, err @@ -233,7 +233,7 @@ func GetAttachment(ctx context.Context, path string, cdnNumber uint32, opt *HTTP Logger() log.Debug().Msg("Sending Attachment HTTP request") - resp, err := signalHTTPClient.Do(req) + resp, err := SignalHTTPClient.Do(req) if err != nil { return nil, err } From f2684ef1f323e10b6ecf4ae738b8c1708e5a8d3f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 16:33:44 +0200 Subject: [PATCH 051/718] Add test command for CDSI --- commands.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/commands.go b/commands.go index ebe9584..834042a 100644 --- a/commands.go +++ b/commands.go @@ -60,6 +60,7 @@ func (br *SignalBridge) RegisterCommands() { cmdDeletePortal, cmdDeleteAllPortals, cmdCleanupLostPortals, + cmdTestCDSI, ) } @@ -75,6 +76,23 @@ func wrapCommand(handler func(*WrappedCommandEvent)) func(*commands.Event) { } } +// TODO remove this +var cmdTestCDSI = &commands.FullHandler{ + Func: wrapCommand(func(ce *WrappedCommandEvent) { + resp, err := ce.User.Client.LookupPhone(ce.Ctx, ce.Args...) + if err != nil { + ce.Reply("It broke 😿 %v", err) + } else { + var out strings.Builder + for phone, result := range resp { + _, _ = fmt.Fprintf(&out, "%s: %+v\n", phone, result) + } + ce.Reply(strings.TrimSpace(out.String())) + } + }), + Name: "cdsi-test-lookup", +} + var cmdSetRelay = &commands.FullHandler{ Func: wrapCommand(fnSetRelay), Name: "set-relay", From 7b8bcdd9e8d9a05b734566edfd95ee29ff538e36 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 17:05:43 +0200 Subject: [PATCH 052/718] Hook up CDSI to pm command and provisioning API --- commands.go | 121 ++++++++++++++++++-------- pkg/signalmeow/contactdiscovery.go | 23 ++--- pkg/signalmeow/store/contact_store.go | 26 ++++++ provisioning.go | 35 +++++--- 4 files changed, 146 insertions(+), 59 deletions(-) diff --git a/commands.go b/commands.go index 834042a..91a4d7d 100644 --- a/commands.go +++ b/commands.go @@ -19,6 +19,7 @@ package main import ( "context" "fmt" + "strconv" "strings" "github.com/google/uuid" @@ -53,6 +54,7 @@ func (br *SignalBridge) RegisterCommands() { cmdLogin, cmdSetDeviceName, cmdPM, + cmdResolvePhone, cmdSyncSpace, cmdDeleteSession, cmdSetRelay, @@ -60,7 +62,6 @@ func (br *SignalBridge) RegisterCommands() { cmdDeletePortal, cmdDeleteAllPortals, cmdCleanupLostPortals, - cmdTestCDSI, ) } @@ -76,23 +77,6 @@ func wrapCommand(handler func(*WrappedCommandEvent)) func(*commands.Event) { } } -// TODO remove this -var cmdTestCDSI = &commands.FullHandler{ - Func: wrapCommand(func(ce *WrappedCommandEvent) { - resp, err := ce.User.Client.LookupPhone(ce.Ctx, ce.Args...) - if err != nil { - ce.Reply("It broke 😿 %v", err) - } else { - var out strings.Builder - for phone, result := range resp { - _, _ = fmt.Fprintf(&out, "%s: %+v\n", phone, result) - } - ce.Reply(strings.TrimSpace(out.String())) - } - }), - Name: "cdsi-test-lookup", -} - var cmdSetRelay = &commands.FullHandler{ Func: wrapCommand(fnSetRelay), Name: "set-relay", @@ -214,40 +198,105 @@ var cmdPM = &commands.FullHandler{ RequiresLogin: true, } +var numberCleaner = strings.NewReplacer("-", "", " ", "", "(", "", ")", "", "+", "") + func fnPM(ce *WrappedCommandEvent) { if len(ce.Args) == 0 { ce.Reply("**Usage:** `pm `") return } + number, err := strconv.ParseUint(numberCleaner.Replace(strings.Join(ce.Args, "")), 10, 64) + if err != nil { + ce.Reply("Failed to parse number") + return + } user := ce.User - number := strings.Join(ce.Args, "") - contact, err := user.Client.ContactByE164(ce.Ctx, number) - if err != nil { + var targetUUID uuid.UUID + + if contact, err := user.Client.ContactByE164(ce.Ctx, fmt.Sprintf("+%d", number)); err != nil { ce.Reply("Error looking up number in local contact list: %v", err) return - } - if contact == nil { - ce.Reply("The bridge does not have the Signal ID for the number %s", number) + } else if contact != nil { + targetUUID = contact.UUID + } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { + ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") + ce.Reply("Error looking up number on server: %v", err) return + } else if resp[number].ACI == uuid.Nil { + if resp[number].PNI == uuid.Nil { + ce.Reply("+%d doesn't seem to be on Signal", number) + } else { + ce.Reply("Server only returned PNI (%s) for +%d, but the bridge doesn't know what to do with it", resp[number].PNI, number) + } + return + } else { + targetUUID = resp[number].ACI + err = user.Client.Store.ContactStore.UpdatePhone(ce.Ctx, targetUUID, fmt.Sprintf("+%d", number)) + if err != nil { + ce.ZLog.Warn().Err(err).Msg("Failed to update phone number in user's contact store") + } } + ce.ZLog.Debug(). + Uint64("e164", number). + Stringer("uuid", targetUUID). + Msg("Found DM target user") - portal := user.GetPortalByChatID(contact.UUID.String()) + portal := user.GetPortalByChatID(targetUUID.String()) if portal == nil { - ce.Reply("Error creating portal to %s", number) - ce.Log.Errorln("Error creating portal to", number) - return + ce.Reply("Couldn't get portal with %s/+%d", targetUUID, number) + } else if portal.MXID != "" { + ce.Reply("You already have a portal with +%d at [%s](%s)", number, portal.MXID, portal.MXID.URI(portal.bridge.Config.Homeserver.Domain).MatrixToURL()) + } else if err = portal.CreateMatrixRoom(ce.Ctx, user, 0); err != nil { + ce.ZLog.Err(err).Msg("Failed to create portal room") + ce.Reply("Error creating Matrix room for portal to +%d", number) + } else { + ce.Reply("Created portal room [%s](%s) with +%d and invited you to it.", portal.MXID, portal.MXID.URI(portal.bridge.Config.Homeserver.Domain).MatrixToURL(), number) } - if portal.MXID != "" { - ce.Reply("You already have a portal to %s at %s", number, portal.MXID) - return +} + +var cmdResolvePhone = &commands.FullHandler{ + Func: wrapCommand(fnResolvePhone), + Name: "resolve-phone", + Help: commands.HelpMeta{ + Section: HelpSectionCreatingPortals, + Description: "Look up phone numbers on the Signal servers.", + Args: "", + }, + RequiresLogin: true, +} + +func fnResolvePhone(ce *WrappedCommandEvent) { + numbers := make([]uint64, len(ce.Args)) + for i, arg := range ce.Args { + var err error + numbers[i], err = strconv.ParseUint(numberCleaner.Replace(arg), 10, 64) + if err != nil { + ce.Reply("Failed to parse number %s: %v", arg, err) + return + } } - if err := portal.CreateMatrixRoom(ce.Ctx, user, 0); err != nil { - ce.Reply("Error creating Matrix room for portal to %s", number) - ce.Log.Errorln("Error creating Matrix room for portal to %s: %s", number, err) - return + resp, err := ce.User.Client.LookupPhone(ce.Ctx, numbers...) + if err != nil { + ce.Reply("Failed to look up: %v", err) + } else { + var out strings.Builder + for _, phone := range numbers { + result, found := resp[phone] + if found { + _, _ = fmt.Fprintf(&out, "+%d: %s / %s\n", phone, result.ACI, result.PNI) + if result.ACI != uuid.Nil { + err = ce.User.Client.Store.ContactStore.UpdatePhone(ce.Ctx, result.ACI, fmt.Sprintf("+%d", phone)) + if err != nil { + ce.ZLog.Warn().Err(err).Msg("Failed to update phone number in user's contact store") + } + } + } else { + _, _ = fmt.Fprintf(&out, "+%d: not found\n", phone) + } + } + ce.Reply(strings.TrimSpace(out.String())) } - ce.Reply("Created portal room with and invited you to it.") } var cmdSyncSpace = &commands.FullHandler{ diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index eb9a443..759e87b 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -25,8 +25,6 @@ import ( "net/http" "net/url" "path" - "strconv" - "strings" "sync" "time" @@ -67,30 +65,30 @@ type ContactDiscoveryClient struct { stateLock sync.Mutex } -type ContactDiscoveryResponse map[string]CDSResponseEntry +type ContactDiscoveryResponse map[uint64]CDSResponseEntry type CDSResponseEntry struct { ACI uuid.UUID PNI uuid.UUID } -func (cli *Client) LookupPhone(ctx context.Context, e164s ...string) (ContactDiscoveryResponse, error) { +func (cli *Client) LookupPhone(ctx context.Context, e164s ...uint64) (ContactDiscoveryResponse, error) { if len(e164s) == 0 { return nil, nil } requestData := make([]byte, len(e164s)*8) for i, e164 := range e164s { - e164Int, err := strconv.ParseInt(strings.TrimPrefix(e164, "+"), 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid E164 number %s: %w", e164, err) - } - binary.BigEndian.PutUint64(requestData[i*8:(i+1)*8], uint64(e164Int)) + binary.BigEndian.PutUint64(requestData[i*8:(i+1)*8], e164) } ctx, cancel := context.WithTimeout(ctx, 20*time.Second) defer cancel() resp, token, err := cli.doContactDiscovery(ctx, &signalpb.CDSClientRequest{ - Token: cli.cdToken, + // TODO figure out if tokens are useful + // (it's meant for old_e164s) + //Token: cli.cdToken, NewE164S: requestData, + + ReturnAcisWithoutUaks: proto.Bool(true), }) if token != nil { cli.cdToken = token @@ -257,7 +255,10 @@ func (cdc *ContactDiscoveryClient) handleResponse(ctx context.Context, msg []byt e164 := binary.BigEndian.Uint64(data[:8]) pni := uuid.UUID(data[8:24]) aci := uuid.UUID(data[24:40]) - resp[fmt.Sprintf("+%d", e164)] = CDSResponseEntry{PNI: pni, ACI: aci} + // If some entries were not found, the server will return all zeros + if e164 != 0 { + resp[e164] = CDSResponseEntry{PNI: pni, ACI: aci} + } } cdc.Response = resp } diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go index 5718577..2d7247f 100644 --- a/pkg/signalmeow/store/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -33,6 +33,7 @@ type ContactStore interface { LoadContactByE164(ctx context.Context, e164 string) (*types.Contact, error) StoreContact(ctx context.Context, contact types.Contact) error AllContacts(ctx context.Context) ([]*types.Contact, error) + UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error } var _ ContactStore = (*SQLStore)(nil) @@ -81,6 +82,24 @@ const ( profile_avatar_path = excluded.profile_avatar_path, profile_avatar_hash = excluded.profile_avatar_hash ` + upsertContactPhoneQuery = ` + INSERT INTO signalmeow_contacts ( + our_aci_uuid, + aci_uuid, + e164_number, + contact_name, + contact_avatar_hash, + profile_key, + profile_name, + profile_about, + profile_about_emoji, + profile_avatar_path, + profile_avatar_hash + ) + VALUES ($1, $2, $3, '', '', NULL, '', '', '', '', '') + ON CONFLICT (our_aci_uuid, aci_uuid) DO UPDATE + SET e164_number = excluded.e164_number + ` ) func scanContact(row dbutil.Scannable) (*types.Contact, error) { @@ -144,3 +163,10 @@ func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) erro ) return err } + +func (s *SQLStore) UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error { + _, err := s.db.Exec( + ctx, upsertContactPhoneQuery, s.ACI, theirUUID, newE164, + ) + return err +} diff --git a/provisioning.go b/provisioning.go index 679d825..dbee734 100644 --- a/provisioning.go +++ b/provisioning.go @@ -146,29 +146,40 @@ type ResolveIdentifierResponseOtherUser struct { AvatarURL string `json:"avatar_url"` } -func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, phoneNum string) (int, *ResolveIdentifierResponse, error) { - if !strings.HasPrefix(phoneNum, "+") { - phoneNum = "+" + phoneNum - } +func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, inputPhone string) (int, *ResolveIdentifierResponse, error) { if user.Client == nil { return http.StatusUnauthorized, nil, errors.New("not currently connected to Signal") } - contact, err := user.Client.ContactByE164(ctx, phoneNum) + e164Number, err := strconv.ParseUint(numberCleaner.Replace(inputPhone), 10, 64) if err != nil { - return http.StatusInternalServerError, nil, fmt.Errorf("Error looking up number in local contact list: %w", err) + return http.StatusBadRequest, nil, fmt.Errorf("error parsing phone number: %w", err) } - if contact == nil { - return http.StatusNotFound, nil, fmt.Errorf("The bridge does not have the Signal ID for the number %s", phoneNum) + e164String := fmt.Sprintf("+%d", e164Number) + var targetUUID uuid.UUID + if contact, err := user.Client.ContactByE164(ctx, e164String); err != nil { + return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number in local contact list: %w", err) + } else if contact != nil { + targetUUID = contact.UUID + } else if resp, err := user.Client.LookupPhone(ctx, e164Number); err != nil { + return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number on server: %w", err) + } else if resp[e164Number].ACI != uuid.Nil { + targetUUID = resp[e164Number].ACI + err = user.Client.Store.ContactStore.UpdatePhone(ctx, targetUUID, e164String) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to update phone number in user's contact store") + } + } else { + return http.StatusNotFound, nil, errors.New("user not found on Signal") } - portal := user.GetPortalByChatID(contact.UUID.String()) - puppet := prov.bridge.GetPuppetBySignalID(contact.UUID) + portal := user.GetPortalByChatID(targetUUID.String()) + puppet := prov.bridge.GetPuppetBySignalID(targetUUID) return http.StatusOK, &ResolveIdentifierResponse{ RoomID: portal.MXID, ChatID: ResolveIdentifierResponseChatID{ - UUID: contact.UUID.String(), - Number: phoneNum, + UUID: targetUUID.String(), + Number: e164String, }, OtherUser: ResolveIdentifierResponseOtherUser{ MXID: puppet.MXID.String(), From cc5177bc15706215f59a561952390e2f62bb0832 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 17:16:52 +0200 Subject: [PATCH 053/718] Use ensureInvited in pm command Fixes #232 Fixes #40 --- commands.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/commands.go b/commands.go index 91a4d7d..1e06361 100644 --- a/commands.go +++ b/commands.go @@ -245,9 +245,19 @@ func fnPM(ce *WrappedCommandEvent) { portal := user.GetPortalByChatID(targetUUID.String()) if portal == nil { ce.Reply("Couldn't get portal with %s/+%d", targetUUID, number) + return } else if portal.MXID != "" { - ce.Reply("You already have a portal with +%d at [%s](%s)", number, portal.MXID, portal.MXID.URI(portal.bridge.Config.Homeserver.Domain).MatrixToURL()) - } else if err = portal.CreateMatrixRoom(ce.Ctx, user, 0); err != nil { + ok := portal.ensureUserInvited(ce.Ctx, ce.User) + if ok { + ce.Reply("You already have a portal with +%d at [%s](%s)", number, portal.MXID, portal.MXID.URI(portal.bridge.Config.Homeserver.Domain).MatrixToURL()) + return + } + ce.ZLog.Warn().Stringer("existing_room_id", portal.MXID).Msg("Ensuring user is invited to existing room failed, creating new room") + portal.Cleanup(ce.Ctx, false) + portal.MXID = "" + } + + if err = portal.CreateMatrixRoom(ce.Ctx, user, 0); err != nil { ce.ZLog.Err(err).Msg("Failed to create portal room") ce.Reply("Error creating Matrix room for portal to +%d", number) } else { From 91b0e7e48271afadadfd985fa025befbba279feb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 18:21:09 +0200 Subject: [PATCH 054/718] Add support for incoming contact messages --- ROADMAP.md | 2 +- go.mod | 1 + go.sum | 2 + msgconv/from-signal.go | 160 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 156 insertions(+), 9 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index c55bcc2..3899a4a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -39,7 +39,7 @@ * [x] Files * [x] Gifs * [x] Stickers - * [ ] Contacts + * [x] Contacts * [ ] Payment messages * [x] Message edits * [x] Message reactions diff --git a/go.mod b/go.mod index 33de9f3..6ca4726 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/go.sum b/go.sum index ab06e6a..c110c5c 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV 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-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA= +github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index 03955ae..e73ea0f 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -17,12 +17,15 @@ package msgconv import ( + "bytes" "context" + "encoding/base64" "fmt" "net/http" "strings" "time" + "github.com/emersion/go-vcard" "github.com/rs/zerolog" "go.mau.fi/util/exfmt" "go.mau.fi/util/exmime" @@ -211,16 +214,157 @@ func (mc *MessageConverter) convertGiftBadgeToMatrix(ctx context.Context, giftBa } } +func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact *signalpb.DataMessage_Contact) vcard.Card { + card := make(vcard.Card) + card.SetValue(vcard.FieldVersion, "4.0") + name := contact.GetName() + if name.GetFamilyName() != "" || name.GetGivenName() != "" { + card.SetName(&vcard.Name{ + FamilyName: name.GetFamilyName(), + GivenName: name.GetGivenName(), + AdditionalName: name.GetMiddleName(), + HonorificPrefix: name.GetPrefix(), + HonorificSuffix: name.GetSuffix(), + }) + } + if name.GetDisplayName() != "" { + card.SetValue(vcard.FieldFormattedName, name.GetDisplayName()) + } + if contact.GetOrganization() != "" { + card.SetValue(vcard.FieldOrganization, contact.GetOrganization()) + } + for _, addr := range contact.GetAddress() { + field := vcard.Field{ + Value: strings.Join([]string{ + addr.GetPobox(), + "", // extended address, + addr.GetStreet(), + addr.GetCity(), + addr.GetRegion(), + addr.GetPostcode(), + addr.GetCountry(), + // TODO put neighborhood somewhere? + }, ";"), + Params: make(vcard.Params), + } + if addr.GetLabel() != "" { + field.Params.Set("LABEL", addr.GetLabel()) + } + field.Params.Set(vcard.ParamType, strings.ToLower(addr.GetType().String())) + card.Add(vcard.FieldAddress, &field) + } + for _, email := range contact.GetEmail() { + field := vcard.Field{ + Value: email.GetValue(), + Params: make(vcard.Params), + } + field.Params.Set(vcard.ParamType, strings.ToLower(email.GetType().String())) + if email.GetLabel() != "" { + field.Params.Set("LABEL", email.GetLabel()) + } + card.Add(vcard.FieldEmail, &field) + } + for _, phone := range contact.GetNumber() { + field := vcard.Field{ + Value: phone.GetValue(), + Params: make(vcard.Params), + } + field.Params.Set(vcard.ParamType, strings.ToLower(phone.GetType().String())) + if phone.GetLabel() != "" { + field.Params.Set("LABEL", phone.GetLabel()) + } + card.Add(vcard.FieldTelephone, &field) + } + if contact.GetAvatar().GetAvatar() != nil { + avatarData, err := signalmeow.DownloadAttachment(ctx, contact.GetAvatar().GetAvatar()) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to download contact avatar") + } else { + mimeType := contact.GetAvatar().GetAvatar().GetContentType() + if mimeType == "" { + mimeType = http.DetectContentType(avatarData) + } + card.SetValue(vcard.FieldPhoto, fmt.Sprintf("data:%s;base64,%s", mimeType, base64.StdEncoding.EncodeToString(avatarData))) + } + } + return card +} + func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact *signalpb.DataMessage_Contact) *ConvertedMessagePart { + card := mc.convertContactToVCard(ctx, contact) + contact.Avatar = nil + extraData := map[string]any{ + "fi.mau.signal.contact": contact, + } + var buf bytes.Buffer + err := vcard.NewEncoder(&buf).Encode(card) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to encode vCard") + return &ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: "Failed to encode vCard", + }, + Extra: extraData, + } + } + data := buf.Bytes() + var file *event.EncryptedFileInfo + uploadMime := "text/vcard" + uploadFileName := "contact.vcf" + if mc.GetData(ctx).Encrypted { + file = &event.EncryptedFileInfo{ + EncryptedFile: *attachment.NewEncryptedFile(), + URL: "", + } + file.EncryptInPlace(data) + uploadMime = "application/octet-stream" + uploadFileName = "" + } + mxc, err := mc.UploadMatrixMedia(ctx, data, uploadFileName, uploadMime) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to upload vCard") + return &ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: "Failed to upload vCard", + }, + Extra: extraData, + } + } + displayName := contact.GetName().GetDisplayName() + if displayName == "" { + displayName = contact.GetName().GetGivenName() + if contact.GetName().GetFamilyName() != "" { + if displayName != "" { + displayName += " " + } + displayName += contact.GetName().GetFamilyName() + } + } + if displayName == "" { + displayName = "contact" + } + content := &event.MessageEventContent{ + MsgType: event.MsgFile, + Body: displayName + ".vcf", + Info: &event.FileInfo{ + MimeType: "text/vcf", + Size: len(data), + }, + } + if file != nil { + file.URL = mxc + content.File = file + } else { + content.URL = mxc + } return &ConvertedMessagePart{ - Type: event.EventMessage, - Content: &event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: "Contact messages are not yet supported", - }, - Extra: map[string]any{ - "fi.mau.signal.contact": contact, - }, + Type: event.EventMessage, + Content: content, + Extra: extraData, } } From fca8ff8eaba94811c09b6fc632c16bc2f63a4069 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jan 2024 19:03:26 +0200 Subject: [PATCH 055/718] Update dependencies --- go.mod | 14 +++++++------- go.sum | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 6ca4726..d5c5ff6 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/beeper/libserv v0.0.0-20231231163024-8eba5b0c509d + github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 github.com/google/uuid v1.5.0 github.com/gorilla/mux v1.8.0 github.com/lib/pq v1.10.9 @@ -14,13 +15,13 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.0 - go.mau.fi/util v0.2.2-0.20240107143939-48dfc4dc3894 - golang.org/x/crypto v0.17.0 - golang.org/x/exp v0.0.0-20231226003508-02704c960a9b - golang.org/x/net v0.19.0 + go.mau.fi/util v0.2.2-0.20240112154312-b89d6e13ae53 + golang.org/x/crypto v0.18.0 + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 + golang.org/x/net v0.20.0 google.golang.org/protobuf v1.32.0 maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.16.3-0.20240107204502-25bc36bc7ae7 + maunium.net/go/mautrix v0.16.3-0.20240113170152-d7c1cf6b64bf nhooyr.io/websocket v1.8.10 ) @@ -29,7 +30,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -45,7 +45,7 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.6.0 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index c110c5c..2a946e7 100644 --- a/go.sum +++ b/go.sum @@ -67,21 +67,21 @@ 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.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mau.fi/util v0.2.2-0.20240107143939-48dfc4dc3894 h1:CuR5LDSxBQLETorfwJ9vRtySeLHjMvJ7//lnCMw7Dy8= -go.mau.fi/util v0.2.2-0.20240107143939-48dfc4dc3894/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= +go.mau.fi/util v0.2.2-0.20240112154312-b89d6e13ae53 h1:1RbC2484wnz5paT/254/Hj+2HOKb+2cqpxaUbsV08jc= +go.mau.fi/util v0.2.2-0.20240112154312-b89d6e13ae53/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= -golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -94,7 +94,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.16.3-0.20240107204502-25bc36bc7ae7 h1:Yo1S3mSazHoT/MHNheRMuRPH74rU6/ZyVaJqTEsmaN0= -maunium.net/go/mautrix v0.16.3-0.20240107204502-25bc36bc7ae7/go.mod h1:eRQu5ED1ODsP+xq1K9l1AOD+O9FMkAhodd/RVc3Bkqg= +maunium.net/go/mautrix v0.16.3-0.20240113170152-d7c1cf6b64bf h1:cBh0R4zJSozUJNANqHkzGXwfEI/50BBbEGZKsc6fK5E= +maunium.net/go/mautrix v0.16.3-0.20240113170152-d7c1cf6b64bf/go.mod h1:UorXdZp+X+OFw3h6OVJHVj4NNpUCYxz111WdlEBF7H4= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From c0ce824b6a60cbfe94a514aa799ac39d9b39d20e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jan 2024 13:20:04 +0200 Subject: [PATCH 056/718] Save libsignal version in go file --- pkg/libsignalgo/update-ffi.sh | 7 +++++++ pkg/libsignalgo/version.go | 5 +++++ 2 files changed, 12 insertions(+) create mode 100644 pkg/libsignalgo/version.go diff --git a/pkg/libsignalgo/update-ffi.sh b/pkg/libsignalgo/update-ffi.sh index f0e617a..7561b61 100755 --- a/pkg/libsignalgo/update-ffi.sh +++ b/pkg/libsignalgo/update-ffi.sh @@ -12,12 +12,19 @@ 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 + # Store the current working directory ORIGINAL_DIR="$(pwd)" # Navigate to libsignal directory cd "$LIBSIGNAL_DIRECTORY" +echo "const Version = \"$(git describe --tags --always)\"" >> ../version.go + # Build libsignal cargo build -p libsignal-ffi --release diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go new file mode 100644 index 0000000..8a4885f --- /dev/null +++ b/pkg/libsignalgo/version.go @@ -0,0 +1,5 @@ +// Generated by update-ffi.sh; DO NOT EDIT. + +package libsignalgo + +const Version = "v0.39.1" From ea0dfaa61af3d24229fbd64eb6339f95b36d70ba Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jan 2024 13:31:17 +0200 Subject: [PATCH 057/718] Set user agents in signal requests --- pkg/signalmeow/contactdiscovery.go | 5 +---- pkg/signalmeow/web/signalwebsocket.go | 10 ++++++++-- pkg/signalmeow/web/web.go | 17 ++++++++++------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index 759e87b..a5cc2c4 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -114,9 +114,7 @@ func (cli *Client) doContactDiscovery(ctx context.Context, req *signalpb.CDSClie Path: path.Join("v1", ProdContactDiscoveryMrenclave, "discovery"), }).String() log.Trace().Msg("Connecting to contact discovery websocket") - ws, _, err := websocket.Dial(ctx, addr, &websocket.DialOptions{ - HTTPClient: web.SignalHTTPClient, - }) + ws, _, err := web.OpenWebsocketURL(ctx, addr) if err != nil { var closeErr websocket.CloseError if errors.As(err, &closeErr) && closeErr.Code == rateLimitCloseCode { @@ -128,7 +126,6 @@ func (cli *Client) doContactDiscovery(ctx context.Context, req *signalpb.CDSClie } return nil, nil, fmt.Errorf("failed to open contact discovery websocket: %w", err) } - ws.SetReadLimit(1 << 20) // Increase read limit to 1MB from default of 32KB defer func() { _ = ws.CloseNow() }() diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 64963cd..c827657 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -565,11 +565,17 @@ func (s *SignalWebsocket) sendRequestInternal( } func OpenWebsocket(ctx context.Context, path string) (*websocket.Conn, *http.Response, error) { + return OpenWebsocketURL(ctx, "wss://"+APIHostname+path) +} + +func OpenWebsocketURL(ctx context.Context, url string) (*websocket.Conn, *http.Response, error) { opt := &websocket.DialOptions{ HTTPClient: SignalHTTPClient, + HTTPHeader: make(http.Header, 2), } - urlStr := "wss://" + APIHostname + path - ws, resp, err := websocket.Dial(ctx, urlStr, opt) + opt.HTTPHeader.Set("User-Agent", UserAgent) + opt.HTTPHeader.Set("X-Signal-Agent", SignalAgent) + ws, resp, err := websocket.Dial(ctx, url, opt) if ws != nil { ws.SetReadLimit(1 << 20) // Increase read limit to 1MB from default of 32KB } diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index c05f736..e72570a 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -28,13 +28,20 @@ import ( "net/http" "net/url" "os" + "runtime" + "strings" "github.com/rs/zerolog" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) const proxyUrlStr = "" // Set this to proxy requests const caCertPath = "" // Set this to trust a self-signed cert (ie. for mitmproxy) +var UserAgent = "signalmeow/0.1.0 libsignal/" + libsignalgo.Version + " go/" + strings.TrimPrefix(runtime.Version(), "go") +var SignalAgent = "MAU" + const ( APIHostname = "chat.signal.org" StorageHostname = "storage.signal.org" @@ -143,9 +150,8 @@ func SendHTTPRequest(ctx context.Context, method string, path string, opt *HTTPR req.Header.Set("Content-Type", string(ContentTypeJSON)) } req.Header.Set("Content-Length", fmt.Sprintf("%d", len(opt.Body))) - // TODO: figure out what user agent to use - //req.Header.Set("User-Agent", "SignalBridge/0.1") - //req.Header.Set("X-Signal-Agent", "SignalBridge/0.1") + req.Header.Set("User-Agent", UserAgent) + req.Header.Set("X-Signal-Agent", SignalAgent) if opt.Username != nil && opt.Password != nil { req.SetBasicAuth(*opt.Username, *opt.Password) } @@ -185,7 +191,6 @@ func DecodeHTTPResponseBody(ctx context.Context, out any, resp *http.Response) e return nil } -// Download an attachment from the CDN func GetAttachment(ctx context.Context, path string, cdnNumber uint32, opt *HTTPReqOpt) (*http.Response, error) { log := zerolog.Ctx(ctx).With(). Str("action", "get_attachment"). @@ -225,6 +230,7 @@ func GetAttachment(ctx context.Context, path string, cdnNumber uint32, opt *HTTP //const SERVICE_REFLECTOR_HOST = "europe-west1-signal-cdn-reflector.cloudfunctions.net" //req.Header.Add("Host", SERVICE_REFLECTOR_HOST) req.Header.Add("Content-Type", "application/octet-stream") + req.Header.Set("User-Agent", UserAgent) httpReqCounter++ log = log.With(). @@ -241,6 +247,3 @@ func GetAttachment(ctx context.Context, path string, cdnNumber uint32, opt *HTTP return resp, err } - -// Upload an attachment to the CDN -//func PutAttachment( From 57b87faee72a4181cfa9fd00fab63e5a6fedbb62 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jan 2024 20:36:15 +0200 Subject: [PATCH 058/718] Add storage service protobuf schema --- pkg/signalmeow/protobuf/StorageService.pb.go | 2566 ++++++++++++++++++ pkg/signalmeow/protobuf/StorageService.proto | 221 ++ pkg/signalmeow/protobuf/update-protos.sh | 2 + 3 files changed, 2789 insertions(+) create mode 100644 pkg/signalmeow/protobuf/StorageService.pb.go create mode 100644 pkg/signalmeow/protobuf/StorageService.proto diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go new file mode 100644 index 0000000..1476794 --- /dev/null +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -0,0 +1,2566 @@ +//* +// Copyright (C) 2019 Open Whisper Systems +// +// Licensed according to the LICENSE file in this repository. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.21.12 +// source: StorageService.proto + +package signalpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +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 OptionalBool int32 + +const ( + OptionalBool_UNSET OptionalBool = 0 + OptionalBool_ENABLED OptionalBool = 1 + OptionalBool_DISABLED OptionalBool = 2 +) + +// Enum value maps for OptionalBool. +var ( + OptionalBool_name = map[int32]string{ + 0: "UNSET", + 1: "ENABLED", + 2: "DISABLED", + } + OptionalBool_value = map[string]int32{ + "UNSET": 0, + "ENABLED": 1, + "DISABLED": 2, + } +) + +func (x OptionalBool) Enum() *OptionalBool { + p := new(OptionalBool) + *p = x + return p +} + +func (x OptionalBool) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (OptionalBool) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[0].Descriptor() +} + +func (OptionalBool) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[0] +} + +func (x OptionalBool) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use OptionalBool.Descriptor instead. +func (OptionalBool) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{0} +} + +type ManifestRecord_Identifier_Type int32 + +const ( + ManifestRecord_Identifier_UNKNOWN ManifestRecord_Identifier_Type = 0 + ManifestRecord_Identifier_CONTACT ManifestRecord_Identifier_Type = 1 + ManifestRecord_Identifier_GROUPV1 ManifestRecord_Identifier_Type = 2 + ManifestRecord_Identifier_GROUPV2 ManifestRecord_Identifier_Type = 3 + ManifestRecord_Identifier_ACCOUNT ManifestRecord_Identifier_Type = 4 + ManifestRecord_Identifier_STORY_DISTRIBUTION_LIST ManifestRecord_Identifier_Type = 5 +) + +// Enum value maps for ManifestRecord_Identifier_Type. +var ( + ManifestRecord_Identifier_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "CONTACT", + 2: "GROUPV1", + 3: "GROUPV2", + 4: "ACCOUNT", + 5: "STORY_DISTRIBUTION_LIST", + } + ManifestRecord_Identifier_Type_value = map[string]int32{ + "UNKNOWN": 0, + "CONTACT": 1, + "GROUPV1": 2, + "GROUPV2": 3, + "ACCOUNT": 4, + "STORY_DISTRIBUTION_LIST": 5, + } +) + +func (x ManifestRecord_Identifier_Type) Enum() *ManifestRecord_Identifier_Type { + p := new(ManifestRecord_Identifier_Type) + *p = x + return p +} + +func (x ManifestRecord_Identifier_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ManifestRecord_Identifier_Type) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[1].Descriptor() +} + +func (ManifestRecord_Identifier_Type) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[1] +} + +func (x ManifestRecord_Identifier_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ManifestRecord_Identifier_Type.Descriptor instead. +func (ManifestRecord_Identifier_Type) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{5, 0, 0} +} + +type ContactRecord_IdentityState int32 + +const ( + ContactRecord_DEFAULT ContactRecord_IdentityState = 0 + ContactRecord_VERIFIED ContactRecord_IdentityState = 1 + ContactRecord_UNVERIFIED ContactRecord_IdentityState = 2 +) + +// Enum value maps for ContactRecord_IdentityState. +var ( + ContactRecord_IdentityState_name = map[int32]string{ + 0: "DEFAULT", + 1: "VERIFIED", + 2: "UNVERIFIED", + } + ContactRecord_IdentityState_value = map[string]int32{ + "DEFAULT": 0, + "VERIFIED": 1, + "UNVERIFIED": 2, + } +) + +func (x ContactRecord_IdentityState) Enum() *ContactRecord_IdentityState { + p := new(ContactRecord_IdentityState) + *p = x + return p +} + +func (x ContactRecord_IdentityState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContactRecord_IdentityState) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[2].Descriptor() +} + +func (ContactRecord_IdentityState) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[2] +} + +func (x ContactRecord_IdentityState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ContactRecord_IdentityState.Descriptor instead. +func (ContactRecord_IdentityState) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{7, 0} +} + +type GroupV2Record_StorySendMode int32 + +const ( + GroupV2Record_DEFAULT GroupV2Record_StorySendMode = 0 + GroupV2Record_DISABLED GroupV2Record_StorySendMode = 1 + GroupV2Record_ENABLED GroupV2Record_StorySendMode = 2 +) + +// Enum value maps for GroupV2Record_StorySendMode. +var ( + GroupV2Record_StorySendMode_name = map[int32]string{ + 0: "DEFAULT", + 1: "DISABLED", + 2: "ENABLED", + } + GroupV2Record_StorySendMode_value = map[string]int32{ + "DEFAULT": 0, + "DISABLED": 1, + "ENABLED": 2, + } +) + +func (x GroupV2Record_StorySendMode) Enum() *GroupV2Record_StorySendMode { + p := new(GroupV2Record_StorySendMode) + *p = x + return p +} + +func (x GroupV2Record_StorySendMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GroupV2Record_StorySendMode) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[3].Descriptor() +} + +func (GroupV2Record_StorySendMode) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[3] +} + +func (x GroupV2Record_StorySendMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GroupV2Record_StorySendMode.Descriptor instead. +func (GroupV2Record_StorySendMode) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{9, 0} +} + +type AccountRecord_PhoneNumberSharingMode int32 + +const ( + AccountRecord_UNKNOWN AccountRecord_PhoneNumberSharingMode = 0 + AccountRecord_EVERYBODY AccountRecord_PhoneNumberSharingMode = 1 + AccountRecord_NOBODY AccountRecord_PhoneNumberSharingMode = 2 +) + +// Enum value maps for AccountRecord_PhoneNumberSharingMode. +var ( + AccountRecord_PhoneNumberSharingMode_name = map[int32]string{ + 0: "UNKNOWN", + 1: "EVERYBODY", + 2: "NOBODY", + } + AccountRecord_PhoneNumberSharingMode_value = map[string]int32{ + "UNKNOWN": 0, + "EVERYBODY": 1, + "NOBODY": 2, + } +) + +func (x AccountRecord_PhoneNumberSharingMode) Enum() *AccountRecord_PhoneNumberSharingMode { + p := new(AccountRecord_PhoneNumberSharingMode) + *p = x + return p +} + +func (x AccountRecord_PhoneNumberSharingMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountRecord_PhoneNumberSharingMode) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[4].Descriptor() +} + +func (AccountRecord_PhoneNumberSharingMode) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[4] +} + +func (x AccountRecord_PhoneNumberSharingMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountRecord_PhoneNumberSharingMode.Descriptor instead. +func (AccountRecord_PhoneNumberSharingMode) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 0} +} + +type AccountRecord_UsernameLink_Color int32 + +const ( + AccountRecord_UsernameLink_UNKNOWN AccountRecord_UsernameLink_Color = 0 + AccountRecord_UsernameLink_BLUE AccountRecord_UsernameLink_Color = 1 + AccountRecord_UsernameLink_WHITE AccountRecord_UsernameLink_Color = 2 + AccountRecord_UsernameLink_GREY AccountRecord_UsernameLink_Color = 3 + AccountRecord_UsernameLink_OLIVE AccountRecord_UsernameLink_Color = 4 + AccountRecord_UsernameLink_GREEN AccountRecord_UsernameLink_Color = 5 + AccountRecord_UsernameLink_ORANGE AccountRecord_UsernameLink_Color = 6 + AccountRecord_UsernameLink_PINK AccountRecord_UsernameLink_Color = 7 + AccountRecord_UsernameLink_PURPLE AccountRecord_UsernameLink_Color = 8 +) + +// Enum value maps for AccountRecord_UsernameLink_Color. +var ( + AccountRecord_UsernameLink_Color_name = map[int32]string{ + 0: "UNKNOWN", + 1: "BLUE", + 2: "WHITE", + 3: "GREY", + 4: "OLIVE", + 5: "GREEN", + 6: "ORANGE", + 7: "PINK", + 8: "PURPLE", + } + AccountRecord_UsernameLink_Color_value = map[string]int32{ + "UNKNOWN": 0, + "BLUE": 1, + "WHITE": 2, + "GREY": 3, + "OLIVE": 4, + "GREEN": 5, + "ORANGE": 6, + "PINK": 7, + "PURPLE": 8, + } +) + +func (x AccountRecord_UsernameLink_Color) Enum() *AccountRecord_UsernameLink_Color { + p := new(AccountRecord_UsernameLink_Color) + *p = x + return p +} + +func (x AccountRecord_UsernameLink_Color) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountRecord_UsernameLink_Color) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[5].Descriptor() +} + +func (AccountRecord_UsernameLink_Color) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[5] +} + +func (x AccountRecord_UsernameLink_Color) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountRecord_UsernameLink_Color.Descriptor instead. +func (AccountRecord_UsernameLink_Color) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 1, 0} +} + +type StorageManifest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *StorageManifest) Reset() { + *x = StorageManifest{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StorageManifest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageManifest) ProtoMessage() {} + +func (x *StorageManifest) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageManifest.ProtoReflect.Descriptor instead. +func (*StorageManifest) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{0} +} + +func (x *StorageManifest) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *StorageManifest) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +type StorageItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *StorageItem) Reset() { + *x = StorageItem{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StorageItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageItem) ProtoMessage() {} + +func (x *StorageItem) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageItem.ProtoReflect.Descriptor instead. +func (*StorageItem) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{1} +} + +func (x *StorageItem) GetKey() []byte { + if x != nil { + return x.Key + } + return nil +} + +func (x *StorageItem) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +type StorageItems struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*StorageItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *StorageItems) Reset() { + *x = StorageItems{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StorageItems) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageItems) ProtoMessage() {} + +func (x *StorageItems) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageItems.ProtoReflect.Descriptor instead. +func (*StorageItems) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{2} +} + +func (x *StorageItems) GetItems() []*StorageItem { + if x != nil { + return x.Items + } + return nil +} + +type ReadOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ReadKey [][]byte `protobuf:"bytes,1,rep,name=readKey,proto3" json:"readKey,omitempty"` +} + +func (x *ReadOperation) Reset() { + *x = ReadOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadOperation) ProtoMessage() {} + +func (x *ReadOperation) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadOperation.ProtoReflect.Descriptor instead. +func (*ReadOperation) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{3} +} + +func (x *ReadOperation) GetReadKey() [][]byte { + if x != nil { + return x.ReadKey + } + return nil +} + +type WriteOperation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Manifest *StorageManifest `protobuf:"bytes,1,opt,name=manifest,proto3" json:"manifest,omitempty"` + InsertItem []*StorageItem `protobuf:"bytes,2,rep,name=insertItem,proto3" json:"insertItem,omitempty"` + DeleteKey [][]byte `protobuf:"bytes,3,rep,name=deleteKey,proto3" json:"deleteKey,omitempty"` + ClearAll bool `protobuf:"varint,4,opt,name=clearAll,proto3" json:"clearAll,omitempty"` +} + +func (x *WriteOperation) Reset() { + *x = WriteOperation{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WriteOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteOperation) ProtoMessage() {} + +func (x *WriteOperation) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteOperation.ProtoReflect.Descriptor instead. +func (*WriteOperation) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{4} +} + +func (x *WriteOperation) GetManifest() *StorageManifest { + if x != nil { + return x.Manifest + } + return nil +} + +func (x *WriteOperation) GetInsertItem() []*StorageItem { + if x != nil { + return x.InsertItem + } + return nil +} + +func (x *WriteOperation) GetDeleteKey() [][]byte { + if x != nil { + return x.DeleteKey + } + return nil +} + +func (x *WriteOperation) GetClearAll() bool { + if x != nil { + return x.ClearAll + } + return false +} + +type ManifestRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + SourceDevice uint32 `protobuf:"varint,3,opt,name=sourceDevice,proto3" json:"sourceDevice,omitempty"` + Identifiers []*ManifestRecord_Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` // Next ID: 4 +} + +func (x *ManifestRecord) Reset() { + *x = ManifestRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ManifestRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManifestRecord) ProtoMessage() {} + +func (x *ManifestRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ManifestRecord.ProtoReflect.Descriptor instead. +func (*ManifestRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{5} +} + +func (x *ManifestRecord) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *ManifestRecord) GetSourceDevice() uint32 { + if x != nil { + return x.SourceDevice + } + return 0 +} + +func (x *ManifestRecord) GetIdentifiers() []*ManifestRecord_Identifier { + if x != nil { + return x.Identifiers + } + return nil +} + +type StorageRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Record: + // + // *StorageRecord_Contact + // *StorageRecord_GroupV1 + // *StorageRecord_GroupV2 + // *StorageRecord_Account + // *StorageRecord_StoryDistributionList + Record isStorageRecord_Record `protobuf_oneof:"record"` +} + +func (x *StorageRecord) Reset() { + *x = StorageRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StorageRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageRecord) ProtoMessage() {} + +func (x *StorageRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageRecord.ProtoReflect.Descriptor instead. +func (*StorageRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{6} +} + +func (m *StorageRecord) GetRecord() isStorageRecord_Record { + if m != nil { + return m.Record + } + return nil +} + +func (x *StorageRecord) GetContact() *ContactRecord { + if x, ok := x.GetRecord().(*StorageRecord_Contact); ok { + return x.Contact + } + return nil +} + +func (x *StorageRecord) GetGroupV1() *GroupV1Record { + if x, ok := x.GetRecord().(*StorageRecord_GroupV1); ok { + return x.GroupV1 + } + return nil +} + +func (x *StorageRecord) GetGroupV2() *GroupV2Record { + if x, ok := x.GetRecord().(*StorageRecord_GroupV2); ok { + return x.GroupV2 + } + return nil +} + +func (x *StorageRecord) GetAccount() *AccountRecord { + if x, ok := x.GetRecord().(*StorageRecord_Account); ok { + return x.Account + } + return nil +} + +func (x *StorageRecord) GetStoryDistributionList() *StoryDistributionListRecord { + if x, ok := x.GetRecord().(*StorageRecord_StoryDistributionList); ok { + return x.StoryDistributionList + } + return nil +} + +type isStorageRecord_Record interface { + isStorageRecord_Record() +} + +type StorageRecord_Contact struct { + Contact *ContactRecord `protobuf:"bytes,1,opt,name=contact,proto3,oneof"` +} + +type StorageRecord_GroupV1 struct { + GroupV1 *GroupV1Record `protobuf:"bytes,2,opt,name=groupV1,proto3,oneof"` +} + +type StorageRecord_GroupV2 struct { + GroupV2 *GroupV2Record `protobuf:"bytes,3,opt,name=groupV2,proto3,oneof"` +} + +type StorageRecord_Account struct { + Account *AccountRecord `protobuf:"bytes,4,opt,name=account,proto3,oneof"` +} + +type StorageRecord_StoryDistributionList struct { + StoryDistributionList *StoryDistributionListRecord `protobuf:"bytes,5,opt,name=storyDistributionList,proto3,oneof"` +} + +func (*StorageRecord_Contact) isStorageRecord_Record() {} + +func (*StorageRecord_GroupV1) isStorageRecord_Record() {} + +func (*StorageRecord_GroupV2) isStorageRecord_Record() {} + +func (*StorageRecord_Account) isStorageRecord_Record() {} + +func (*StorageRecord_StoryDistributionList) isStorageRecord_Record() {} + +type ContactRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Aci string `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` + E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` + Pni string `protobuf:"bytes,15,opt,name=pni,proto3" json:"pni,omitempty"` + ProfileKey []byte `protobuf:"bytes,3,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + IdentityKey []byte `protobuf:"bytes,4,opt,name=identityKey,proto3" json:"identityKey,omitempty"` + IdentityState ContactRecord_IdentityState `protobuf:"varint,5,opt,name=identityState,proto3,enum=signalservice.ContactRecord_IdentityState" json:"identityState,omitempty"` + GivenName string `protobuf:"bytes,6,opt,name=givenName,proto3" json:"givenName,omitempty"` + FamilyName string `protobuf:"bytes,7,opt,name=familyName,proto3" json:"familyName,omitempty"` + Username string `protobuf:"bytes,8,opt,name=username,proto3" json:"username,omitempty"` + Blocked bool `protobuf:"varint,9,opt,name=blocked,proto3" json:"blocked,omitempty"` + Whitelisted bool `protobuf:"varint,10,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` + Archived bool `protobuf:"varint,11,opt,name=archived,proto3" json:"archived,omitempty"` + MarkedUnread bool `protobuf:"varint,12,opt,name=markedUnread,proto3" json:"markedUnread,omitempty"` + MutedUntilTimestamp uint64 `protobuf:"varint,13,opt,name=mutedUntilTimestamp,proto3" json:"mutedUntilTimestamp,omitempty"` + HideStory bool `protobuf:"varint,14,opt,name=hideStory,proto3" json:"hideStory,omitempty"` + UnregisteredAtTimestamp uint64 `protobuf:"varint,16,opt,name=unregisteredAtTimestamp,proto3" json:"unregisteredAtTimestamp,omitempty"` + SystemGivenName string `protobuf:"bytes,17,opt,name=systemGivenName,proto3" json:"systemGivenName,omitempty"` + SystemFamilyName string `protobuf:"bytes,18,opt,name=systemFamilyName,proto3" json:"systemFamilyName,omitempty"` + SystemNickname string `protobuf:"bytes,19,opt,name=systemNickname,proto3" json:"systemNickname,omitempty"` + Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` // NEXT ID: 21 +} + +func (x *ContactRecord) Reset() { + *x = ContactRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContactRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactRecord) ProtoMessage() {} + +func (x *ContactRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContactRecord.ProtoReflect.Descriptor instead. +func (*ContactRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{7} +} + +func (x *ContactRecord) GetAci() string { + if x != nil { + return x.Aci + } + return "" +} + +func (x *ContactRecord) GetE164() string { + if x != nil { + return x.E164 + } + return "" +} + +func (x *ContactRecord) GetPni() string { + if x != nil { + return x.Pni + } + return "" +} + +func (x *ContactRecord) GetProfileKey() []byte { + if x != nil { + return x.ProfileKey + } + return nil +} + +func (x *ContactRecord) GetIdentityKey() []byte { + if x != nil { + return x.IdentityKey + } + return nil +} + +func (x *ContactRecord) GetIdentityState() ContactRecord_IdentityState { + if x != nil { + return x.IdentityState + } + return ContactRecord_DEFAULT +} + +func (x *ContactRecord) GetGivenName() string { + if x != nil { + return x.GivenName + } + return "" +} + +func (x *ContactRecord) GetFamilyName() string { + if x != nil { + return x.FamilyName + } + return "" +} + +func (x *ContactRecord) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *ContactRecord) GetBlocked() bool { + if x != nil { + return x.Blocked + } + return false +} + +func (x *ContactRecord) GetWhitelisted() bool { + if x != nil { + return x.Whitelisted + } + return false +} + +func (x *ContactRecord) GetArchived() bool { + if x != nil { + return x.Archived + } + return false +} + +func (x *ContactRecord) GetMarkedUnread() bool { + if x != nil { + return x.MarkedUnread + } + return false +} + +func (x *ContactRecord) GetMutedUntilTimestamp() uint64 { + if x != nil { + return x.MutedUntilTimestamp + } + return 0 +} + +func (x *ContactRecord) GetHideStory() bool { + if x != nil { + return x.HideStory + } + return false +} + +func (x *ContactRecord) GetUnregisteredAtTimestamp() uint64 { + if x != nil { + return x.UnregisteredAtTimestamp + } + return 0 +} + +func (x *ContactRecord) GetSystemGivenName() string { + if x != nil { + return x.SystemGivenName + } + return "" +} + +func (x *ContactRecord) GetSystemFamilyName() string { + if x != nil { + return x.SystemFamilyName + } + return "" +} + +func (x *ContactRecord) GetSystemNickname() string { + if x != nil { + return x.SystemNickname + } + return "" +} + +func (x *ContactRecord) GetHidden() bool { + if x != nil { + return x.Hidden + } + return false +} + +type GroupV1Record struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Blocked bool `protobuf:"varint,2,opt,name=blocked,proto3" json:"blocked,omitempty"` + Whitelisted bool `protobuf:"varint,3,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` + Archived bool `protobuf:"varint,4,opt,name=archived,proto3" json:"archived,omitempty"` + MarkedUnread bool `protobuf:"varint,5,opt,name=markedUnread,proto3" json:"markedUnread,omitempty"` + MutedUntilTimestamp uint64 `protobuf:"varint,6,opt,name=mutedUntilTimestamp,proto3" json:"mutedUntilTimestamp,omitempty"` +} + +func (x *GroupV1Record) Reset() { + *x = GroupV1Record{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupV1Record) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupV1Record) ProtoMessage() {} + +func (x *GroupV1Record) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupV1Record.ProtoReflect.Descriptor instead. +func (*GroupV1Record) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{8} +} + +func (x *GroupV1Record) GetId() []byte { + if x != nil { + return x.Id + } + return nil +} + +func (x *GroupV1Record) GetBlocked() bool { + if x != nil { + return x.Blocked + } + return false +} + +func (x *GroupV1Record) GetWhitelisted() bool { + if x != nil { + return x.Whitelisted + } + return false +} + +func (x *GroupV1Record) GetArchived() bool { + if x != nil { + return x.Archived + } + return false +} + +func (x *GroupV1Record) GetMarkedUnread() bool { + if x != nil { + return x.MarkedUnread + } + return false +} + +func (x *GroupV1Record) GetMutedUntilTimestamp() uint64 { + if x != nil { + return x.MutedUntilTimestamp + } + return 0 +} + +type GroupV2Record struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MasterKey []byte `protobuf:"bytes,1,opt,name=masterKey,proto3" json:"masterKey,omitempty"` + Blocked bool `protobuf:"varint,2,opt,name=blocked,proto3" json:"blocked,omitempty"` + Whitelisted bool `protobuf:"varint,3,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` + Archived bool `protobuf:"varint,4,opt,name=archived,proto3" json:"archived,omitempty"` + MarkedUnread bool `protobuf:"varint,5,opt,name=markedUnread,proto3" json:"markedUnread,omitempty"` + MutedUntilTimestamp uint64 `protobuf:"varint,6,opt,name=mutedUntilTimestamp,proto3" json:"mutedUntilTimestamp,omitempty"` + DontNotifyForMentionsIfMuted bool `protobuf:"varint,7,opt,name=dontNotifyForMentionsIfMuted,proto3" json:"dontNotifyForMentionsIfMuted,omitempty"` + HideStory bool `protobuf:"varint,8,opt,name=hideStory,proto3" json:"hideStory,omitempty"` + StorySendMode GroupV2Record_StorySendMode `protobuf:"varint,10,opt,name=storySendMode,proto3,enum=signalservice.GroupV2Record_StorySendMode" json:"storySendMode,omitempty"` +} + +func (x *GroupV2Record) Reset() { + *x = GroupV2Record{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupV2Record) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupV2Record) ProtoMessage() {} + +func (x *GroupV2Record) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupV2Record.ProtoReflect.Descriptor instead. +func (*GroupV2Record) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{9} +} + +func (x *GroupV2Record) GetMasterKey() []byte { + if x != nil { + return x.MasterKey + } + return nil +} + +func (x *GroupV2Record) GetBlocked() bool { + if x != nil { + return x.Blocked + } + return false +} + +func (x *GroupV2Record) GetWhitelisted() bool { + if x != nil { + return x.Whitelisted + } + return false +} + +func (x *GroupV2Record) GetArchived() bool { + if x != nil { + return x.Archived + } + return false +} + +func (x *GroupV2Record) GetMarkedUnread() bool { + if x != nil { + return x.MarkedUnread + } + return false +} + +func (x *GroupV2Record) GetMutedUntilTimestamp() uint64 { + if x != nil { + return x.MutedUntilTimestamp + } + return 0 +} + +func (x *GroupV2Record) GetDontNotifyForMentionsIfMuted() bool { + if x != nil { + return x.DontNotifyForMentionsIfMuted + } + return false +} + +func (x *GroupV2Record) GetHideStory() bool { + if x != nil { + return x.HideStory + } + return false +} + +func (x *GroupV2Record) GetStorySendMode() GroupV2Record_StorySendMode { + if x != nil { + return x.StorySendMode + } + return GroupV2Record_DEFAULT +} + +type Payments struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + Entropy []byte `protobuf:"bytes,2,opt,name=entropy,proto3" json:"entropy,omitempty"` +} + +func (x *Payments) Reset() { + *x = Payments{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Payments) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Payments) ProtoMessage() {} + +func (x *Payments) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Payments.ProtoReflect.Descriptor instead. +func (*Payments) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{10} +} + +func (x *Payments) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *Payments) GetEntropy() []byte { + if x != nil { + return x.Entropy + } + return nil +} + +type AccountRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + GivenName string `protobuf:"bytes,2,opt,name=givenName,proto3" json:"givenName,omitempty"` + FamilyName string `protobuf:"bytes,3,opt,name=familyName,proto3" json:"familyName,omitempty"` + AvatarUrlPath string `protobuf:"bytes,4,opt,name=avatarUrlPath,proto3" json:"avatarUrlPath,omitempty"` + NoteToSelfArchived bool `protobuf:"varint,5,opt,name=noteToSelfArchived,proto3" json:"noteToSelfArchived,omitempty"` + ReadReceipts bool `protobuf:"varint,6,opt,name=readReceipts,proto3" json:"readReceipts,omitempty"` + SealedSenderIndicators bool `protobuf:"varint,7,opt,name=sealedSenderIndicators,proto3" json:"sealedSenderIndicators,omitempty"` + TypingIndicators bool `protobuf:"varint,8,opt,name=typingIndicators,proto3" json:"typingIndicators,omitempty"` + NoteToSelfMarkedUnread bool `protobuf:"varint,10,opt,name=noteToSelfMarkedUnread,proto3" json:"noteToSelfMarkedUnread,omitempty"` + LinkPreviews bool `protobuf:"varint,11,opt,name=linkPreviews,proto3" json:"linkPreviews,omitempty"` + PhoneNumberSharingMode AccountRecord_PhoneNumberSharingMode `protobuf:"varint,12,opt,name=phoneNumberSharingMode,proto3,enum=signalservice.AccountRecord_PhoneNumberSharingMode" json:"phoneNumberSharingMode,omitempty"` + UnlistedPhoneNumber bool `protobuf:"varint,13,opt,name=unlistedPhoneNumber,proto3" json:"unlistedPhoneNumber,omitempty"` + PinnedConversations []*AccountRecord_PinnedConversation `protobuf:"bytes,14,rep,name=pinnedConversations,proto3" json:"pinnedConversations,omitempty"` + PreferContactAvatars bool `protobuf:"varint,15,opt,name=preferContactAvatars,proto3" json:"preferContactAvatars,omitempty"` + Payments *Payments `protobuf:"bytes,16,opt,name=payments,proto3" json:"payments,omitempty"` + UniversalExpireTimer uint32 `protobuf:"varint,17,opt,name=universalExpireTimer,proto3" json:"universalExpireTimer,omitempty"` + PrimarySendsSms bool `protobuf:"varint,18,opt,name=primarySendsSms,proto3" json:"primarySendsSms,omitempty"` + E164 string `protobuf:"bytes,19,opt,name=e164,proto3" json:"e164,omitempty"` + PreferredReactionEmoji []string `protobuf:"bytes,20,rep,name=preferredReactionEmoji,proto3" json:"preferredReactionEmoji,omitempty"` + SubscriberId []byte `protobuf:"bytes,21,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` + SubscriberCurrencyCode string `protobuf:"bytes,22,opt,name=subscriberCurrencyCode,proto3" json:"subscriberCurrencyCode,omitempty"` + DisplayBadgesOnProfile bool `protobuf:"varint,23,opt,name=displayBadgesOnProfile,proto3" json:"displayBadgesOnProfile,omitempty"` + SubscriptionManuallyCancelled bool `protobuf:"varint,24,opt,name=subscriptionManuallyCancelled,proto3" json:"subscriptionManuallyCancelled,omitempty"` + KeepMutedChatsArchived bool `protobuf:"varint,25,opt,name=keepMutedChatsArchived,proto3" json:"keepMutedChatsArchived,omitempty"` + HasSetMyStoriesPrivacy bool `protobuf:"varint,26,opt,name=hasSetMyStoriesPrivacy,proto3" json:"hasSetMyStoriesPrivacy,omitempty"` + HasViewedOnboardingStory bool `protobuf:"varint,27,opt,name=hasViewedOnboardingStory,proto3" json:"hasViewedOnboardingStory,omitempty"` + StoriesDisabled bool `protobuf:"varint,29,opt,name=storiesDisabled,proto3" json:"storiesDisabled,omitempty"` + StoryViewReceiptsEnabled OptionalBool `protobuf:"varint,30,opt,name=storyViewReceiptsEnabled,proto3,enum=signalservice.OptionalBool" json:"storyViewReceiptsEnabled,omitempty"` + HasSeenGroupStoryEducationSheet bool `protobuf:"varint,32,opt,name=hasSeenGroupStoryEducationSheet,proto3" json:"hasSeenGroupStoryEducationSheet,omitempty"` + Username string `protobuf:"bytes,33,opt,name=username,proto3" json:"username,omitempty"` + HasCompletedUsernameOnboarding bool `protobuf:"varint,34,opt,name=hasCompletedUsernameOnboarding,proto3" json:"hasCompletedUsernameOnboarding,omitempty"` + UsernameLink *AccountRecord_UsernameLink `protobuf:"bytes,35,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` +} + +func (x *AccountRecord) Reset() { + *x = AccountRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccountRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord) ProtoMessage() {} + +func (x *AccountRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AccountRecord.ProtoReflect.Descriptor instead. +func (*AccountRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11} +} + +func (x *AccountRecord) GetProfileKey() []byte { + if x != nil { + return x.ProfileKey + } + return nil +} + +func (x *AccountRecord) GetGivenName() string { + if x != nil { + return x.GivenName + } + return "" +} + +func (x *AccountRecord) GetFamilyName() string { + if x != nil { + return x.FamilyName + } + return "" +} + +func (x *AccountRecord) GetAvatarUrlPath() string { + if x != nil { + return x.AvatarUrlPath + } + return "" +} + +func (x *AccountRecord) GetNoteToSelfArchived() bool { + if x != nil { + return x.NoteToSelfArchived + } + return false +} + +func (x *AccountRecord) GetReadReceipts() bool { + if x != nil { + return x.ReadReceipts + } + return false +} + +func (x *AccountRecord) GetSealedSenderIndicators() bool { + if x != nil { + return x.SealedSenderIndicators + } + return false +} + +func (x *AccountRecord) GetTypingIndicators() bool { + if x != nil { + return x.TypingIndicators + } + return false +} + +func (x *AccountRecord) GetNoteToSelfMarkedUnread() bool { + if x != nil { + return x.NoteToSelfMarkedUnread + } + return false +} + +func (x *AccountRecord) GetLinkPreviews() bool { + if x != nil { + return x.LinkPreviews + } + return false +} + +func (x *AccountRecord) GetPhoneNumberSharingMode() AccountRecord_PhoneNumberSharingMode { + if x != nil { + return x.PhoneNumberSharingMode + } + return AccountRecord_UNKNOWN +} + +func (x *AccountRecord) GetUnlistedPhoneNumber() bool { + if x != nil { + return x.UnlistedPhoneNumber + } + return false +} + +func (x *AccountRecord) GetPinnedConversations() []*AccountRecord_PinnedConversation { + if x != nil { + return x.PinnedConversations + } + return nil +} + +func (x *AccountRecord) GetPreferContactAvatars() bool { + if x != nil { + return x.PreferContactAvatars + } + return false +} + +func (x *AccountRecord) GetPayments() *Payments { + if x != nil { + return x.Payments + } + return nil +} + +func (x *AccountRecord) GetUniversalExpireTimer() uint32 { + if x != nil { + return x.UniversalExpireTimer + } + return 0 +} + +func (x *AccountRecord) GetPrimarySendsSms() bool { + if x != nil { + return x.PrimarySendsSms + } + return false +} + +func (x *AccountRecord) GetE164() string { + if x != nil { + return x.E164 + } + return "" +} + +func (x *AccountRecord) GetPreferredReactionEmoji() []string { + if x != nil { + return x.PreferredReactionEmoji + } + return nil +} + +func (x *AccountRecord) GetSubscriberId() []byte { + if x != nil { + return x.SubscriberId + } + return nil +} + +func (x *AccountRecord) GetSubscriberCurrencyCode() string { + if x != nil { + return x.SubscriberCurrencyCode + } + return "" +} + +func (x *AccountRecord) GetDisplayBadgesOnProfile() bool { + if x != nil { + return x.DisplayBadgesOnProfile + } + return false +} + +func (x *AccountRecord) GetSubscriptionManuallyCancelled() bool { + if x != nil { + return x.SubscriptionManuallyCancelled + } + return false +} + +func (x *AccountRecord) GetKeepMutedChatsArchived() bool { + if x != nil { + return x.KeepMutedChatsArchived + } + return false +} + +func (x *AccountRecord) GetHasSetMyStoriesPrivacy() bool { + if x != nil { + return x.HasSetMyStoriesPrivacy + } + return false +} + +func (x *AccountRecord) GetHasViewedOnboardingStory() bool { + if x != nil { + return x.HasViewedOnboardingStory + } + return false +} + +func (x *AccountRecord) GetStoriesDisabled() bool { + if x != nil { + return x.StoriesDisabled + } + return false +} + +func (x *AccountRecord) GetStoryViewReceiptsEnabled() OptionalBool { + if x != nil { + return x.StoryViewReceiptsEnabled + } + return OptionalBool_UNSET +} + +func (x *AccountRecord) GetHasSeenGroupStoryEducationSheet() bool { + if x != nil { + return x.HasSeenGroupStoryEducationSheet + } + return false +} + +func (x *AccountRecord) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *AccountRecord) GetHasCompletedUsernameOnboarding() bool { + if x != nil { + return x.HasCompletedUsernameOnboarding + } + return false +} + +func (x *AccountRecord) GetUsernameLink() *AccountRecord_UsernameLink { + if x != nil { + return x.UsernameLink + } + return nil +} + +type StoryDistributionListRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + RecipientServiceIds []string `protobuf:"bytes,3,rep,name=recipientServiceIds,proto3" json:"recipientServiceIds,omitempty"` + DeletedAtTimestamp uint64 `protobuf:"varint,4,opt,name=deletedAtTimestamp,proto3" json:"deletedAtTimestamp,omitempty"` + AllowsReplies bool `protobuf:"varint,5,opt,name=allowsReplies,proto3" json:"allowsReplies,omitempty"` + IsBlockList bool `protobuf:"varint,6,opt,name=isBlockList,proto3" json:"isBlockList,omitempty"` +} + +func (x *StoryDistributionListRecord) Reset() { + *x = StoryDistributionListRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StoryDistributionListRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoryDistributionListRecord) ProtoMessage() {} + +func (x *StoryDistributionListRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoryDistributionListRecord.ProtoReflect.Descriptor instead. +func (*StoryDistributionListRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{12} +} + +func (x *StoryDistributionListRecord) GetIdentifier() []byte { + if x != nil { + return x.Identifier + } + return nil +} + +func (x *StoryDistributionListRecord) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StoryDistributionListRecord) GetRecipientServiceIds() []string { + if x != nil { + return x.RecipientServiceIds + } + return nil +} + +func (x *StoryDistributionListRecord) GetDeletedAtTimestamp() uint64 { + if x != nil { + return x.DeletedAtTimestamp + } + return 0 +} + +func (x *StoryDistributionListRecord) GetAllowsReplies() bool { + if x != nil { + return x.AllowsReplies + } + return false +} + +func (x *StoryDistributionListRecord) GetIsBlockList() bool { + if x != nil { + return x.IsBlockList + } + return false +} + +type ManifestRecord_Identifier struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Raw []byte `protobuf:"bytes,1,opt,name=raw,proto3" json:"raw,omitempty"` + Type ManifestRecord_Identifier_Type `protobuf:"varint,2,opt,name=type,proto3,enum=signalservice.ManifestRecord_Identifier_Type" json:"type,omitempty"` +} + +func (x *ManifestRecord_Identifier) Reset() { + *x = ManifestRecord_Identifier{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ManifestRecord_Identifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManifestRecord_Identifier) ProtoMessage() {} + +func (x *ManifestRecord_Identifier) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ManifestRecord_Identifier.ProtoReflect.Descriptor instead. +func (*ManifestRecord_Identifier) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *ManifestRecord_Identifier) GetRaw() []byte { + if x != nil { + return x.Raw + } + return nil +} + +func (x *ManifestRecord_Identifier) GetType() ManifestRecord_Identifier_Type { + if x != nil { + return x.Type + } + return ManifestRecord_Identifier_UNKNOWN +} + +type AccountRecord_PinnedConversation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Identifier: + // + // *AccountRecord_PinnedConversation_Contact_ + // *AccountRecord_PinnedConversation_LegacyGroupId + // *AccountRecord_PinnedConversation_GroupMasterKey + Identifier isAccountRecord_PinnedConversation_Identifier `protobuf_oneof:"identifier"` +} + +func (x *AccountRecord_PinnedConversation) Reset() { + *x = AccountRecord_PinnedConversation{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccountRecord_PinnedConversation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord_PinnedConversation) ProtoMessage() {} + +func (x *AccountRecord_PinnedConversation) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AccountRecord_PinnedConversation.ProtoReflect.Descriptor instead. +func (*AccountRecord_PinnedConversation) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 0} +} + +func (m *AccountRecord_PinnedConversation) GetIdentifier() isAccountRecord_PinnedConversation_Identifier { + if m != nil { + return m.Identifier + } + return nil +} + +func (x *AccountRecord_PinnedConversation) GetContact() *AccountRecord_PinnedConversation_Contact { + if x, ok := x.GetIdentifier().(*AccountRecord_PinnedConversation_Contact_); ok { + return x.Contact + } + return nil +} + +func (x *AccountRecord_PinnedConversation) GetLegacyGroupId() []byte { + if x, ok := x.GetIdentifier().(*AccountRecord_PinnedConversation_LegacyGroupId); ok { + return x.LegacyGroupId + } + return nil +} + +func (x *AccountRecord_PinnedConversation) GetGroupMasterKey() []byte { + if x, ok := x.GetIdentifier().(*AccountRecord_PinnedConversation_GroupMasterKey); ok { + return x.GroupMasterKey + } + return nil +} + +type isAccountRecord_PinnedConversation_Identifier interface { + isAccountRecord_PinnedConversation_Identifier() +} + +type AccountRecord_PinnedConversation_Contact_ struct { + Contact *AccountRecord_PinnedConversation_Contact `protobuf:"bytes,1,opt,name=contact,proto3,oneof"` +} + +type AccountRecord_PinnedConversation_LegacyGroupId struct { + LegacyGroupId []byte `protobuf:"bytes,3,opt,name=legacyGroupId,proto3,oneof"` +} + +type AccountRecord_PinnedConversation_GroupMasterKey struct { + GroupMasterKey []byte `protobuf:"bytes,4,opt,name=groupMasterKey,proto3,oneof"` +} + +func (*AccountRecord_PinnedConversation_Contact_) isAccountRecord_PinnedConversation_Identifier() {} + +func (*AccountRecord_PinnedConversation_LegacyGroupId) isAccountRecord_PinnedConversation_Identifier() { +} + +func (*AccountRecord_PinnedConversation_GroupMasterKey) isAccountRecord_PinnedConversation_Identifier() { +} + +type AccountRecord_UsernameLink struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entropy []byte `protobuf:"bytes,1,opt,name=entropy,proto3" json:"entropy,omitempty"` // 32 bytes of entropy used for encryption + ServerId []byte `protobuf:"bytes,2,opt,name=serverId,proto3" json:"serverId,omitempty"` // 16 bytes of encoded UUID provided by the server + Color AccountRecord_UsernameLink_Color `protobuf:"varint,3,opt,name=color,proto3,enum=signalservice.AccountRecord_UsernameLink_Color" json:"color,omitempty"` +} + +func (x *AccountRecord_UsernameLink) Reset() { + *x = AccountRecord_UsernameLink{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccountRecord_UsernameLink) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord_UsernameLink) ProtoMessage() {} + +func (x *AccountRecord_UsernameLink) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AccountRecord_UsernameLink.ProtoReflect.Descriptor instead. +func (*AccountRecord_UsernameLink) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 1} +} + +func (x *AccountRecord_UsernameLink) GetEntropy() []byte { + if x != nil { + return x.Entropy + } + return nil +} + +func (x *AccountRecord_UsernameLink) GetServerId() []byte { + if x != nil { + return x.ServerId + } + return nil +} + +func (x *AccountRecord_UsernameLink) GetColor() AccountRecord_UsernameLink_Color { + if x != nil { + return x.Color + } + return AccountRecord_UsernameLink_UNKNOWN +} + +type AccountRecord_PinnedConversation_Contact struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` + E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` +} + +func (x *AccountRecord_PinnedConversation_Contact) Reset() { + *x = AccountRecord_PinnedConversation_Contact{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccountRecord_PinnedConversation_Contact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} + +func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AccountRecord_PinnedConversation_Contact.ProtoReflect.Descriptor instead. +func (*AccountRecord_PinnedConversation_Contact) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 0, 0} +} + +func (x *AccountRecord_PinnedConversation_Contact) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *AccountRecord_PinnedConversation_Contact) GetE164() string { + if x != nil { + return x.E164 + } + return "" +} + +var File_StorageService_proto protoreflect.FileDescriptor + +var file_StorageService_proto_rawDesc = []byte{ + 0x0a, 0x14, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x41, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x35, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x40, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, + 0x30, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x22, 0x29, 0x0a, 0x0d, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xc2, 0x01, 0x0a, + 0x0e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x3a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x69, + 0x6e, 0x73, 0x65, 0x72, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0a, 0x69, 0x6e, 0x73, + 0x65, 0x72, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x41, 0x6c, + 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x41, 0x6c, + 0x6c, 0x22, 0xe4, 0x02, 0x0a, 0x0e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, + 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x1a, 0xc7, + 0x01, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x10, 0x0a, + 0x03, 0x72, 0x61, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, + 0x41, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x61, + 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x64, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4e, 0x54, 0x41, + 0x43, 0x54, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x56, 0x31, 0x10, + 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x56, 0x32, 0x10, 0x03, 0x12, 0x0b, + 0x0a, 0x07, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x53, + 0x54, 0x4f, 0x52, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x05, 0x22, 0xe5, 0x02, 0x0a, 0x0d, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x38, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x12, 0x38, + 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, + 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x62, 0x0a, 0x15, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, + 0x15, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x22, 0x8d, 0x06, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, + 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x50, 0x0a, 0x0d, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, + 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, + 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, + 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, + 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, + 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, + 0x6f, 0x72, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, + 0x74, 0x6f, 0x72, 0x79, 0x12, 0x38, 0x0a, 0x17, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, + 0x0a, 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x47, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x47, + 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x69, + 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, 0x69, + 0x64, 0x64, 0x65, 0x6e, 0x22, 0x3a, 0x0a, 0x0d, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, + 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, + 0x22, 0xcd, 0x01, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, + 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, + 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, + 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, + 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, + 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x22, 0xce, 0x03, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, + 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, + 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, + 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, + 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, + 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, + 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, + 0x0a, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, + 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, + 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, + 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, + 0x6f, 0x64, 0x65, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, + 0x64, 0x65, 0x22, 0x37, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, + 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, + 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, 0x10, + 0x0a, 0x22, 0x3e, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, + 0x70, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, + 0x79, 0x22, 0x9a, 0x12, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x50, 0x61, + 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x55, 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, + 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, + 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x73, + 0x65, 0x61, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, 0x65, 0x61, + 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, + 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, + 0x36, 0x0a, 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, + 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, + 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, + 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, + 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, 0x6b, 0x0a, 0x16, 0x70, + 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, + 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, + 0x52, 0x16, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, + 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x75, 0x6e, 0x6c, 0x69, + 0x73, 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x50, + 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x61, 0x0a, 0x13, 0x70, 0x69, + 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, + 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, + 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x73, 0x12, 0x33, 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x08, 0x70, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x45, + 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, 0x73, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, + 0x73, 0x53, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x13, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x36, 0x0a, 0x16, 0x70, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, + 0x6a, 0x69, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, + 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, 0x64, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x72, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x16, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x36, 0x0a, 0x16, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, + 0x79, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x6b, 0x65, + 0x65, 0x70, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, + 0x69, 0x76, 0x65, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x6b, 0x65, 0x65, 0x70, + 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, + 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, + 0x6f, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x18, 0x1a, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, + 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x12, 0x3a, 0x0a, 0x18, 0x68, 0x61, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x68, 0x61, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, + 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x12, 0x57, 0x0a, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, + 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1e, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x52, + 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, + 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x1f, 0x68, 0x61, 0x73, + 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, + 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, 0x18, 0x20, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, + 0x65, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x46, 0x0a, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, + 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x1a, 0x86, 0x02, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x6e, 0x65, + 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, + 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x65, 0x67, + 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0e, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x4b, 0x65, 0x79, 0x1a, 0x3b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, + 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, + 0xf8, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, + 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, + 0x2e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0x6b, 0x0a, + 0x05, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x57, 0x48, 0x49, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x45, 0x59, + 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x4c, 0x49, 0x56, 0x45, 0x10, 0x04, 0x12, 0x09, 0x0a, + 0x05, 0x47, 0x52, 0x45, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x52, 0x41, 0x4e, + 0x47, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x4b, 0x10, 0x07, 0x12, 0x0a, + 0x0a, 0x06, 0x50, 0x55, 0x52, 0x50, 0x4c, 0x45, 0x10, 0x08, 0x22, 0x40, 0x0a, 0x16, 0x50, 0x68, + 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x01, + 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, + 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1f, 0x10, 0x20, 0x22, 0xfb, + 0x01, 0x0a, 0x1b, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, + 0x70, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x34, 0x0a, 0x0c, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x09, 0x0a, 0x05, + 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, + 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, + 0x10, 0x02, 0x42, 0x3c, 0x0a, 0x38, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x50, 0x01, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_StorageService_proto_rawDescOnce sync.Once + file_StorageService_proto_rawDescData = file_StorageService_proto_rawDesc +) + +func file_StorageService_proto_rawDescGZIP() []byte { + file_StorageService_proto_rawDescOnce.Do(func() { + file_StorageService_proto_rawDescData = protoimpl.X.CompressGZIP(file_StorageService_proto_rawDescData) + }) + return file_StorageService_proto_rawDescData +} + +var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 6) +var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_StorageService_proto_goTypes = []interface{}{ + (OptionalBool)(0), // 0: signalservice.OptionalBool + (ManifestRecord_Identifier_Type)(0), // 1: signalservice.ManifestRecord.Identifier.Type + (ContactRecord_IdentityState)(0), // 2: signalservice.ContactRecord.IdentityState + (GroupV2Record_StorySendMode)(0), // 3: signalservice.GroupV2Record.StorySendMode + (AccountRecord_PhoneNumberSharingMode)(0), // 4: signalservice.AccountRecord.PhoneNumberSharingMode + (AccountRecord_UsernameLink_Color)(0), // 5: signalservice.AccountRecord.UsernameLink.Color + (*StorageManifest)(nil), // 6: signalservice.StorageManifest + (*StorageItem)(nil), // 7: signalservice.StorageItem + (*StorageItems)(nil), // 8: signalservice.StorageItems + (*ReadOperation)(nil), // 9: signalservice.ReadOperation + (*WriteOperation)(nil), // 10: signalservice.WriteOperation + (*ManifestRecord)(nil), // 11: signalservice.ManifestRecord + (*StorageRecord)(nil), // 12: signalservice.StorageRecord + (*ContactRecord)(nil), // 13: signalservice.ContactRecord + (*GroupV1Record)(nil), // 14: signalservice.GroupV1Record + (*GroupV2Record)(nil), // 15: signalservice.GroupV2Record + (*Payments)(nil), // 16: signalservice.Payments + (*AccountRecord)(nil), // 17: signalservice.AccountRecord + (*StoryDistributionListRecord)(nil), // 18: signalservice.StoryDistributionListRecord + (*ManifestRecord_Identifier)(nil), // 19: signalservice.ManifestRecord.Identifier + (*AccountRecord_PinnedConversation)(nil), // 20: signalservice.AccountRecord.PinnedConversation + (*AccountRecord_UsernameLink)(nil), // 21: signalservice.AccountRecord.UsernameLink + (*AccountRecord_PinnedConversation_Contact)(nil), // 22: signalservice.AccountRecord.PinnedConversation.Contact +} +var file_StorageService_proto_depIdxs = []int32{ + 7, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem + 6, // 1: signalservice.WriteOperation.manifest:type_name -> signalservice.StorageManifest + 7, // 2: signalservice.WriteOperation.insertItem:type_name -> signalservice.StorageItem + 19, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier + 13, // 4: signalservice.StorageRecord.contact:type_name -> signalservice.ContactRecord + 14, // 5: signalservice.StorageRecord.groupV1:type_name -> signalservice.GroupV1Record + 15, // 6: signalservice.StorageRecord.groupV2:type_name -> signalservice.GroupV2Record + 17, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord + 18, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord + 2, // 9: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState + 3, // 10: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode + 4, // 11: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode + 20, // 12: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation + 16, // 13: signalservice.AccountRecord.payments:type_name -> signalservice.Payments + 0, // 14: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool + 21, // 15: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink + 1, // 16: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type + 22, // 17: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact + 5, // 18: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color + 19, // [19:19] is the sub-list for method output_type + 19, // [19:19] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name +} + +func init() { file_StorageService_proto_init() } +func file_StorageService_proto_init() { + if File_StorageService_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_StorageService_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StorageManifest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StorageItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StorageItems); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WriteOperation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ManifestRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StorageRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContactRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupV1Record); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupV2Record); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Payments); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccountRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StoryDistributionListRecord); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ManifestRecord_Identifier); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccountRecord_PinnedConversation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccountRecord_UsernameLink); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccountRecord_PinnedConversation_Contact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_StorageService_proto_msgTypes[6].OneofWrappers = []interface{}{ + (*StorageRecord_Contact)(nil), + (*StorageRecord_GroupV1)(nil), + (*StorageRecord_GroupV2)(nil), + (*StorageRecord_Account)(nil), + (*StorageRecord_StoryDistributionList)(nil), + } + file_StorageService_proto_msgTypes[14].OneofWrappers = []interface{}{ + (*AccountRecord_PinnedConversation_Contact_)(nil), + (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), + (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_StorageService_proto_rawDesc, + NumEnums: 6, + NumMessages: 17, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_StorageService_proto_goTypes, + DependencyIndexes: file_StorageService_proto_depIdxs, + EnumInfos: file_StorageService_proto_enumTypes, + MessageInfos: file_StorageService_proto_msgTypes, + }.Build() + File_StorageService_proto = out.File + file_StorageService_proto_rawDesc = nil + file_StorageService_proto_goTypes = nil + file_StorageService_proto_depIdxs = nil +} diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto new file mode 100644 index 0000000..c8873ff --- /dev/null +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -0,0 +1,221 @@ +/** + * Copyright (C) 2019 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto3"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.storage.protos"; +option java_multiple_files = true; + +enum OptionalBool { + UNSET = 0; + ENABLED = 1; + DISABLED = 2; +} + +message StorageManifest { + uint64 version = 1; + bytes value = 2; +} + +message StorageItem { + bytes key = 1; + bytes value = 2; +} + +message StorageItems { + repeated StorageItem items = 1; +} + +message ReadOperation { + repeated bytes readKey = 1; +} + +message WriteOperation { + StorageManifest manifest = 1; + repeated StorageItem insertItem = 2; + repeated bytes deleteKey = 3; + bool clearAll = 4; +} + +message ManifestRecord { + message Identifier { + enum Type { + UNKNOWN = 0; + CONTACT = 1; + GROUPV1 = 2; + GROUPV2 = 3; + ACCOUNT = 4; + STORY_DISTRIBUTION_LIST = 5; + } + + bytes raw = 1; + Type type = 2; + } + + uint64 version = 1; + uint32 sourceDevice = 3; + repeated Identifier identifiers = 2; + // Next ID: 4 +} + +message StorageRecord { + oneof record { + ContactRecord contact = 1; + GroupV1Record groupV1 = 2; + GroupV2Record groupV2 = 3; + AccountRecord account = 4; + StoryDistributionListRecord storyDistributionList = 5; + } +} + +message ContactRecord { + enum IdentityState { + DEFAULT = 0; + VERIFIED = 1; + UNVERIFIED = 2; + } + + string aci = 1; + string e164 = 2; + string pni = 15; + bytes profileKey = 3; + bytes identityKey = 4; + IdentityState identityState = 5; + string givenName = 6; + string familyName = 7; + string username = 8; + bool blocked = 9; + bool whitelisted = 10; + bool archived = 11; + bool markedUnread = 12; + uint64 mutedUntilTimestamp = 13; + bool hideStory = 14; + uint64 unregisteredAtTimestamp = 16; + string systemGivenName = 17; + string systemFamilyName = 18; + string systemNickname = 19; + bool hidden = 20; + // NEXT ID: 21 +} + +message GroupV1Record { + bytes id = 1; + bool blocked = 2; + bool whitelisted = 3; + bool archived = 4; + bool markedUnread = 5; + uint64 mutedUntilTimestamp = 6; +} + +message GroupV2Record { + enum StorySendMode { + DEFAULT = 0; + DISABLED = 1; + ENABLED = 2; + } + + bytes masterKey = 1; + bool blocked = 2; + bool whitelisted = 3; + bool archived = 4; + bool markedUnread = 5; + uint64 mutedUntilTimestamp = 6; + bool dontNotifyForMentionsIfMuted = 7; + bool hideStory = 8; + reserved /* storySendEnabled */ 9; + StorySendMode storySendMode = 10; +} + +message Payments { + bool enabled = 1; + bytes entropy = 2; +} + +message AccountRecord { + + enum PhoneNumberSharingMode { + UNKNOWN = 0; + EVERYBODY = 1; + NOBODY = 2; + } + + message PinnedConversation { + message Contact { + string serviceId = 1; + string e164 = 2; + } + + oneof identifier { + Contact contact = 1; + bytes legacyGroupId = 3; + bytes groupMasterKey = 4; + } + } + + message UsernameLink { + enum Color { + UNKNOWN = 0; + BLUE = 1; + WHITE = 2; + GREY = 3; + OLIVE = 4; + GREEN = 5; + ORANGE = 6; + PINK = 7; + PURPLE = 8; + } + + bytes entropy = 1; // 32 bytes of entropy used for encryption + bytes serverId = 2; // 16 bytes of encoded UUID provided by the server + Color color = 3; + } + + bytes profileKey = 1; + string givenName = 2; + string familyName = 3; + string avatarUrlPath = 4; + bool noteToSelfArchived = 5; + bool readReceipts = 6; + bool sealedSenderIndicators = 7; + bool typingIndicators = 8; + reserved /* proxiedLinkPreviews */ 9; + bool noteToSelfMarkedUnread = 10; + bool linkPreviews = 11; + PhoneNumberSharingMode phoneNumberSharingMode = 12; + bool unlistedPhoneNumber = 13; + repeated PinnedConversation pinnedConversations = 14; + bool preferContactAvatars = 15; + Payments payments = 16; + uint32 universalExpireTimer = 17; + bool primarySendsSms = 18; + string e164 = 19; + repeated string preferredReactionEmoji = 20; + bytes subscriberId = 21; + string subscriberCurrencyCode = 22; + bool displayBadgesOnProfile = 23; + bool subscriptionManuallyCancelled = 24; + bool keepMutedChatsArchived = 25; + bool hasSetMyStoriesPrivacy = 26; + bool hasViewedOnboardingStory = 27; + reserved /* storiesDisabled */ 28; + bool storiesDisabled = 29; + OptionalBool storyViewReceiptsEnabled = 30; + reserved /* hasReadOnboardingStory */ 31; + bool hasSeenGroupStoryEducationSheet = 32; + string username = 33; + bool hasCompletedUsernameOnboarding = 34; + UsernameLink usernameLink = 35; +} + +message StoryDistributionListRecord { + bytes identifier = 1; + string name = 2; + repeated string recipientServiceIds = 3; + uint64 deletedAtTimestamp = 4; + bool allowsReplies = 5; + bool isBlockList = 6; +} diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 66314fc..76bb6ae 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -25,7 +25,9 @@ update_proto Signal-Android Provisioning.proto update_proto Signal-Android SignalService.proto update_proto Signal-Android StickerResources.proto update_proto Signal-Android WebSocketResources.proto +update_proto Signal-Android StorageService.proto update_proto Signal-Desktop DeviceName.proto update_proto Signal-Desktop UnidentifiedDelivery.proto +# Android has CDSI.proto too, but the types have more generic names (since android uses a different package name) update_proto Signal-Desktop ContactDiscovery.proto From d482bca04137457c0355f02f730b934069074088 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jan 2024 22:22:14 +0200 Subject: [PATCH 059/718] Add method to fetch records from storage service --- pkg/signalmeow/client.go | 8 +- pkg/signalmeow/contactdiscovery.go | 39 +---- pkg/signalmeow/profile.go | 8 +- pkg/signalmeow/serviceauth.go | 79 ++++++++++ pkg/signalmeow/storageservice.go | 228 +++++++++++++++++++++++++++++ 5 files changed, 317 insertions(+), 45 deletions(-) create mode 100644 pkg/signalmeow/serviceauth.go create mode 100644 pkg/signalmeow/storageservice.go diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index d7df48d..de1a8cd 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -48,9 +48,11 @@ type Client struct { EventHandler func(events.SignalEvent) - cdAuthLock sync.Mutex - cdAuth *contactDiscoveryAuth - cdToken []byte + storageAuthLock sync.Mutex + storageAuth *basicExpiringCredentials + cdAuthLock sync.Mutex + cdAuth *basicExpiringCredentials + cdToken []byte } func (cli *Client) handleEvent(evt events.SignalEvent) { diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index a5cc2c4..5d5bce2 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -22,7 +22,6 @@ import ( "encoding/hex" "errors" "fmt" - "net/http" "net/url" "path" "sync" @@ -97,7 +96,7 @@ func (cli *Client) LookupPhone(ctx context.Context, e164s ...uint64) (ContactDis } func (cli *Client) doContactDiscovery(ctx context.Context, req *signalpb.CDSClientRequest) (ContactDiscoveryResponse, []byte, error) { - creds, err := cli.getContactDiscoveryAuth(ctx) + creds, err := cli.getContactDiscoveryCredentials(ctx) if err != nil { return nil, nil, fmt.Errorf("failed to fetch contact discovery auth: %w", err) } @@ -261,39 +260,3 @@ func (cdc *ContactDiscoveryClient) handleResponse(ctx context.Context, msg []byt } return nil } - -type contactDiscoveryAuth struct { - Username string `json:"username"` - Password string `json:"password"` - CreatedAt time.Time `json:"-"` -} - -func (cda *contactDiscoveryAuth) Expired() bool { - return cda == nil || cda.CreatedAt.IsZero() || time.Since(cda.CreatedAt) > ContactDiscoveryAuthTTL -} - -func (cli *Client) getContactDiscoveryAuth(ctx context.Context) (*contactDiscoveryAuth, error) { - cli.cdAuthLock.Lock() - defer cli.cdAuthLock.Unlock() - if cli.cdAuth.Expired() { - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v2/directory/auth", &web.HTTPReqOpt{ - Username: &username, - Password: &password, - }) - if err != nil { - return nil, err - } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { - return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) - } - - var auth contactDiscoveryAuth - auth.CreatedAt = time.Now() - err = web.DecodeHTTPResponseBody(ctx, &auth, resp) - if err != nil { - return nil, fmt.Errorf("failed to decode response: %w", err) - } - cli.cdAuth = &auth - } - return cli.cdAuth, nil -} diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 57aa7f2..69cb240 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -266,20 +266,20 @@ func (cli *Client) DownloadUserAvatar(ctx context.Context, avatarPath string, pr if err != nil { return nil, fmt.Errorf("failed to read response body: %w", err) } - avatar, err := decryptBytes(profileKey, encryptedAvatar) + avatar, err := decryptBytes(profileKey[:], encryptedAvatar) if err != nil { return nil, fmt.Errorf("failed to decrypt response: %w", err) } return avatar, nil } -func decryptBytes(key *libsignalgo.ProfileKey, encryptedText []byte) ([]byte, error) { +func decryptBytes(key []byte, encryptedText []byte) ([]byte, error) { if len(encryptedText) < NONCE_LENGTH+16+1 { return nil, errors.New("invalid encryptedBytes length") } nonce := encryptedText[:NONCE_LENGTH] ciphertext := encryptedText[NONCE_LENGTH:] - padded, err := AesgcmDecrypt(key[:], nonce, ciphertext, []byte{}) + padded, err := AesgcmDecrypt(key, nonce, ciphertext, []byte{}) if err != nil { return nil, err } @@ -296,7 +296,7 @@ func decryptBytes(key *libsignalgo.ProfileKey, encryptedText []byte) ([]byte, er } func decryptString(key *libsignalgo.ProfileKey, encryptedText []byte) (string, error) { - data, err := decryptBytes(key, encryptedText) + data, err := decryptBytes(key[:], encryptedText) return string(data), err } diff --git a/pkg/signalmeow/serviceauth.go b/pkg/signalmeow/serviceauth.go new file mode 100644 index 0000000..b945f30 --- /dev/null +++ b/pkg/signalmeow/serviceauth.go @@ -0,0 +1,79 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "fmt" + "net/http" + "sync" + "time" + + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +type basicExpiringCredentials struct { + Username string `json:"username"` + Password string `json:"password"` + CreatedAt time.Time `json:"-"` +} + +func (bec *basicExpiringCredentials) Expired() bool { + return bec == nil || bec.CreatedAt.IsZero() || time.Since(bec.CreatedAt) > ContactDiscoveryAuthTTL +} + +func (cli *Client) getContactDiscoveryCredentials(ctx context.Context) (*basicExpiringCredentials, error) { + return cli.getCredentialsWithCache(ctx, &cli.cdAuth, &cli.cdAuthLock, "/v2/directory/auth") +} + +func (cli *Client) getStorageCredentials(ctx context.Context) (*basicExpiringCredentials, error) { + return cli.getCredentialsWithCache(ctx, &cli.storageAuth, &cli.storageAuthLock, "/v1/storage/auth") +} + +func (cli *Client) getCredentialsWithCache(ctx context.Context, cache **basicExpiringCredentials, lock *sync.Mutex, path string) (*basicExpiringCredentials, error) { + lock.Lock() + defer lock.Unlock() + if (*cache).Expired() { + newCreds, err := cli.getCredentialsFromServer(ctx, path) + if err != nil { + return nil, err + } + *cache = newCreds + } + return *cache, nil +} + +func (cli *Client) getCredentialsFromServer(ctx context.Context, path string) (*basicExpiringCredentials, error) { + username, password := cli.Store.BasicAuthCreds() + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{ + Username: &username, + Password: &password, + }) + if err != nil { + return nil, err + } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { + return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + + var auth basicExpiringCredentials + auth.CreatedAt = time.Now() + err = web.DecodeHTTPResponseBody(ctx, &auth, resp) + if err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + return &auth, nil +} diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go new file mode 100644 index 0000000..9e2e93c --- /dev/null +++ b/pkg/signalmeow/storageservice.go @@ -0,0 +1,228 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "fmt" + "io" + "net/http" + + "go.mau.fi/util/exerrors" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" + "google.golang.org/protobuf/proto" + + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +type StorageUpdate struct { + Version uint64 + NewRecords []*DecryptedStorageRecord + RemovedRecords []string + MissingRecords []string +} + +func (cli *Client) FetchStorage(ctx context.Context, masterKey []byte, currentVersion uint64, existingKeys []string) (*StorageUpdate, error) { + storageKey := deriveStorageServiceKey(masterKey) + manifest, err := cli.fetchStorageManifest(ctx, storageKey, currentVersion) + if err != nil { + return nil, err + } else if manifest == nil { + return nil, nil + } + removedKeys := make([]string, 0) + newKeys := manifestRecordToMap(manifest.GetIdentifiers()) + slices.Sort(existingKeys) + existingKeys = slices.Compact(existingKeys) + for _, key := range existingKeys { + _, isStillThere := newKeys[key] + if isStillThere { + delete(newKeys, key) + } else { + removedKeys = append(removedKeys, key) + } + delete(newKeys, key) + } + newRecords, missingKeys, err := cli.fetchStorageRecords(ctx, storageKey, newKeys) + if err != nil { + return nil, err + } + return &StorageUpdate{ + Version: manifest.GetVersion(), + NewRecords: newRecords, + RemovedRecords: removedKeys, + MissingRecords: missingKeys, + }, nil +} + +func manifestRecordToMap(manifest []*signalpb.ManifestRecord_Identifier) map[string]signalpb.ManifestRecord_Identifier_Type { + manifestMap := make(map[string]signalpb.ManifestRecord_Identifier_Type, len(manifest)) + for _, item := range manifest { + manifestMap[base64.StdEncoding.EncodeToString(item.GetRaw())] = item.GetType() + } + return manifestMap +} + +func deriveStorageServiceKey(masterKey []byte) []byte { + h := hmac.New(sha256.New, masterKey) + h.Write([]byte("Storage Service Encryption")) + return h.Sum(nil) +} + +func deriveStorageManifestKey(storageKey []byte, version uint64) []byte { + h := hmac.New(sha256.New, storageKey) + exerrors.Must(fmt.Fprintf(h, "Manifest_%d", version)) + return h.Sum(nil) +} + +func deriveStorageItemKey(storageKey []byte, itemID string) []byte { + h := hmac.New(sha256.New, storageKey) + exerrors.Must(fmt.Fprintf(h, "Item_%s", itemID)) + return h.Sum(nil) +} + +// MaxReadStorageRecords is the maximum number of storage records to fetch at once +// from https://github.com/signalapp/Signal-Desktop/blob/v6.44.0/ts/services/storageConstants.ts +const MaxReadStorageRecords = 2500 + +type DecryptedStorageRecord struct { + ItemType signalpb.ManifestRecord_Identifier_Type + StorageID string + StorageRecord *signalpb.StorageRecord +} + +func (cli *Client) fetchStorageManifest(ctx context.Context, storageKey []byte, greaterThanVersion uint64) (*signalpb.ManifestRecord, error) { + storageCreds, err := cli.getStorageCredentials(ctx) + if err != nil { + return nil, fmt.Errorf("failed to fetch credentials: %w", err) + } + path := "/v1/storage/manifest" + if greaterThanVersion > 0 { + path += fmt.Sprintf("/version/%d", greaterThanVersion) + } + var encryptedManifest signalpb.StorageManifest + var manifestRecord signalpb.ManifestRecord + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{ + Username: &storageCreds.Username, + Password: &storageCreds.Password, + ContentType: web.ContentTypeProtobuf, + Host: web.StorageHostname, + }) + if err != nil { + return nil, fmt.Errorf("failed to fetch storage manifest: %w", err) + } else if resp.StatusCode == http.StatusNoContent { + // Already up to date + return nil, nil + } else if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code %d fetching storage manifest", resp.StatusCode) + } else if body, err := io.ReadAll(resp.Body); err != nil { + return nil, fmt.Errorf("failed to read storage manifest response: %w", err) + } else if err = proto.Unmarshal(body, &encryptedManifest); err != nil { + return nil, fmt.Errorf("failed to unmarshal encrypted storage manifest: %w", err) + } else if decryptedManifestBytes, err := decryptBytes(deriveStorageManifestKey(storageKey, encryptedManifest.GetVersion()), encryptedManifest.GetValue()); err != nil { + return nil, fmt.Errorf("failed to decrypt storage manifest: %w", err) + } else if err = proto.Unmarshal(decryptedManifestBytes, &manifestRecord); err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted manifest record: %w", err) + } else { + return &manifestRecord, nil + } +} + +func (cli *Client) fetchStorageRecords(ctx context.Context, storageKey []byte, inputRecords map[string]signalpb.ManifestRecord_Identifier_Type) ([]*DecryptedStorageRecord, []string, error) { + recordKeys := make([][]byte, 0, len(inputRecords)) + for key := range inputRecords { + decoded, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return nil, nil, fmt.Errorf("failed to decode storage key %s: %w", key, err) + } + recordKeys = append(recordKeys, decoded) + } + items := make([]*signalpb.StorageItem, 0, len(inputRecords)) + for i := 0; i < len(recordKeys); i += MaxReadStorageRecords { + end := i + MaxReadStorageRecords + if len(recordKeys) < end { + end = len(recordKeys) + } + keyChunk := recordKeys[i:end] + itemChunk, err := cli.fetchStorageItemsChunk(ctx, keyChunk) + if err != nil { + return nil, nil, err + } + items = append(items, itemChunk...) + } + records := make([]*DecryptedStorageRecord, len(items)) + for i, encryptedItem := range items { + base64Key := base64.StdEncoding.EncodeToString(encryptedItem.GetKey()) + itemKey := deriveStorageItemKey(storageKey, base64Key) + decryptedItemBytes, err := decryptBytes(itemKey, encryptedItem.GetValue()) + if err != nil { + return nil, nil, fmt.Errorf("failed to decrypt storage item #%d (%s): %w", i+1, base64Key, err) + } + var decryptedItem signalpb.StorageRecord + err = proto.Unmarshal(decryptedItemBytes, &decryptedItem) + if err != nil { + return nil, nil, fmt.Errorf("failed to unmarshal decrypted storage item #%d (%s): %w", i+1, base64Key, err) + } + itemType, ok := inputRecords[base64Key] + if !ok { + return nil, nil, fmt.Errorf("received unexpected storage item at index #%d: %s", i+1, base64Key) + } + delete(inputRecords, base64Key) + records[i] = &DecryptedStorageRecord{ + ItemType: itemType, + StorageID: base64Key, + StorageRecord: &decryptedItem, + } + } + missingKeys := maps.Keys(inputRecords) + return records, missingKeys, nil +} + +func (cli *Client) fetchStorageItemsChunk(ctx context.Context, recordKeys [][]byte) ([]*signalpb.StorageItem, error) { + storageCreds, err := cli.getStorageCredentials(ctx) + if err != nil { + return nil, fmt.Errorf("failed to fetch credentials: %w", err) + } + body, err := proto.Marshal(&signalpb.ReadOperation{ReadKey: recordKeys}) + if err != nil { + return nil, fmt.Errorf("failed to marshal read operation: %w", err) + } + var storageItems signalpb.StorageItems + resp, err := web.SendHTTPRequest(ctx, http.MethodPut, "/v1/storage/read", &web.HTTPReqOpt{ + Username: &storageCreds.Username, + Password: &storageCreds.Password, + Body: body, + ContentType: web.ContentTypeProtobuf, + Host: web.StorageHostname, + }) + if err != nil { + return nil, fmt.Errorf("failed to fetch storage records: %w", err) + } else if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code %d fetching storage records", resp.StatusCode) + } else if body, err := io.ReadAll(resp.Body); err != nil { + return nil, fmt.Errorf("failed to read storage manifest response: %w", err) + } else if err = proto.Unmarshal(body, &storageItems); err != nil { + return nil, fmt.Errorf("failed to unmarshal encrypted storage manifest: %w", err) + } else { + return storageItems.GetItems(), nil + } +} From b054aa9dd2368e4e61c10c01f9c1391351c28e4c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Jan 2024 00:07:21 +0200 Subject: [PATCH 060/718] Update dependencies --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d5c5ff6..a810ac3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module go.mau.fi/mautrix-signal go 1.20 require ( - github.com/beeper/libserv v0.0.0-20231231163024-8eba5b0c509d + github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 github.com/google/uuid v1.5.0 github.com/gorilla/mux v1.8.0 @@ -15,13 +15,13 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.0 - go.mau.fi/util v0.2.2-0.20240112154312-b89d6e13ae53 + go.mau.fi/util v0.3.0 golang.org/x/crypto v0.18.0 golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 golang.org/x/net v0.20.0 google.golang.org/protobuf v1.32.0 maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.16.3-0.20240113170152-d7c1cf6b64bf + maunium.net/go/mautrix v0.17.0 nhooyr.io/websocket v1.8.10 ) diff --git a/go.sum b/go.sum index 2a946e7..e9ba207 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ github.com/DATA-DOG/go-sqlmock v1.5.1 h1:FK6RCIUSfmbnI/imIICmboyQBkOckutaa6R5YYlLZyo= -github.com/beeper/libserv v0.0.0-20231231163024-8eba5b0c509d h1:CSrg1zpAEMXK3VIUx5deRT6YMMX3Kd8jDkiUmB1uoWw= -github.com/beeper/libserv v0.0.0-20231231163024-8eba5b0c509d/go.mod h1:b9FFm9y4mEm36G8ytVmS1vkNzJa0KepmcdVY+qf7qRU= +github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c h1:WqjRVgUO039eiISCjsZC4F9onOEV93DJAk6v33rsZzY= +github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c/go.mod h1:b9FFm9y4mEm36G8ytVmS1vkNzJa0KepmcdVY+qf7qRU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mau.fi/util v0.2.2-0.20240112154312-b89d6e13ae53 h1:1RbC2484wnz5paT/254/Hj+2HOKb+2cqpxaUbsV08jc= -go.mau.fi/util v0.2.2-0.20240112154312-b89d6e13ae53/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= +go.mau.fi/util v0.3.0 h1:Lt3lbRXP6ZBqTINK0EieRWor3zEwwwrDT14Z5N8RUCs= +go.mau.fi/util v0.3.0/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= @@ -94,7 +94,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.16.3-0.20240113170152-d7c1cf6b64bf h1:cBh0R4zJSozUJNANqHkzGXwfEI/50BBbEGZKsc6fK5E= -maunium.net/go/mautrix v0.16.3-0.20240113170152-d7c1cf6b64bf/go.mod h1:UorXdZp+X+OFw3h6OVJHVj4NNpUCYxz111WdlEBF7H4= +maunium.net/go/mautrix v0.17.0 h1:scc1qlUbzPn+wc+3eAPquyD+3gZwwy/hBANBm+iGKK8= +maunium.net/go/mautrix v0.17.0/go.mod h1:j+puTEQCEydlVxhJ/dQP5chfa26TdvBO7X6F3Ataav8= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 972b289887bc3b881cf7d1f60fe14676df9298cf Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Tue, 16 Jan 2024 19:45:37 -0500 Subject: [PATCH 061/718] Add temporary debugging logs --- portal.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/portal.go b/portal.go index ac1e4dc..54deb1d 100644 --- a/portal.go +++ b/portal.go @@ -428,7 +428,49 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt realSenderMXID := sender.MXID isRelay := false if !sender.IsLoggedIn() { + + // TODO: *** temporary debugging logs *** + if sender != nil { + if sender.Client != nil { + if sender.Client.Store != nil { + log.Warn(). + Str("ACI", sender.Client.Store.ACI.String()[:5]). + Int("device_id", sender.Client.Store.DeviceID). + Str("password", sender.Client.Store.Password[:2]). + Msg("Sender debugging") + } else { + log.Warn().Msg("Sender debugging (no store)") + } + } else { + log.Warn().Msg("Sender debugging (no client)") + } + } else { + log.Warn().Msg("Sender debugging (no sender)") + } + // *** end of temporary debugging logs *** + sender = portal.GetRelayUser() + + // TODO: *** temporary debugging logs *** + if sender != nil { + if sender.Client != nil { + if sender.Client.Store != nil { + log.Warn(). + Str("ACI", sender.Client.Store.ACI.String()[:5]). + Int("device_id", sender.Client.Store.DeviceID). + Str("password", sender.Client.Store.Password[:2]). + Msg("Sender debugging post-portal") + } else { + log.Warn().Msg("Sender debugging post-portal (no store)") + } + } else { + log.Warn().Msg("Sender debugging post-portal (no client)") + } + } else { + log.Warn().Msg("Sender debugging post-portal (no sender)") + } + // *** end of temporary debugging logs *** + if sender == nil { go ms.sendMessageMetrics(evt, errUserNotLoggedIn, "Ignoring", true) return From a546300b77ab362ac70ad31c511aa9d3ecf31aa4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 18 Jan 2024 22:50:49 +0200 Subject: [PATCH 062/718] Update usersBySignalID when logging in Also partially clear any previous users if they have the same UUID --- commands.go | 11 ++--------- custompuppet.go | 2 +- provisioning.go | 7 +------ user.go | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/commands.go b/commands.go index 1e06361..9d93ded 100644 --- a/commands.go +++ b/commands.go @@ -426,18 +426,11 @@ func fnLogin(ce *WrappedCommandEvent) { return } - // Update user with SignalID - if signalID != uuid.Nil { - ce.User.SignalID = signalID - ce.User.SignalUsername = signalPhone - } else { + if signalID == uuid.Nil { ce.Reply("Problem logging in - No SignalID received") return } - err = ce.User.Update(ce.Ctx) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to save user to database") - } + ce.User.saveSignalID(ce.Ctx, signalID, signalPhone) // Connect to Signal ce.User.Connect() diff --git a/custompuppet.go b/custompuppet.go index 5ef7842..cde3059 100644 --- a/custompuppet.go +++ b/custompuppet.go @@ -81,7 +81,7 @@ func (user *User) tryAutomaticDoublePuppeting() { } user.log.Debug().Msg("Checking if double puppeting needs to be enabled") puppet := user.bridge.GetPuppetBySignalID(user.SignalID) - if len(puppet.CustomMXID) > 0 { + if puppet.CustomMXID == user.MXID { user.log.Debug().Msg("User already has double-puppeting enabled") // Custom puppet already enabled return diff --git a/provisioning.go b/provisioning.go index dbee734..7256512 100644 --- a/provisioning.go +++ b/provisioning.go @@ -524,12 +524,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ // Update user with SignalID if resp.ProvisioningData.ACI != uuid.Nil { - user.SignalID = resp.ProvisioningData.ACI - user.SignalUsername = resp.ProvisioningData.Number - err = user.Update(r.Context()) - if err != nil { - prov.log.Err(err).Msg("Failed to save user after login") - } + user.saveSignalID(ctx, resp.ProvisioningData.ACI, resp.ProvisioningData.Number) } return case <-time.After(45 * time.Second): diff --git a/user.go b/user.go index f3a8971..b6cdcca 100644 --- a/user.go +++ b/user.go @@ -76,7 +76,10 @@ func (br *SignalBridge) maybeGetUserByMXID(userID id.UserID, userIDPtr *id.UserI func (br *SignalBridge) GetUserBySignalID(id uuid.UUID) *User { br.usersLock.Lock() defer br.usersLock.Unlock() + return br.unlockedGetUserBySignalID(id) +} +func (br *SignalBridge) unlockedGetUserBySignalID(id uuid.UUID) *User { user, ok := br.usersBySignalID[id] if !ok { dbUser, err := br.DB.User.GetBySignalID(context.TODO(), id) @@ -556,6 +559,39 @@ func (user *User) Connect() { user.startupTryConnect(0) } +func (user *User) saveSignalID(ctx context.Context, id uuid.UUID, number string) { + user.bridge.usersLock.Lock() + defer user.bridge.usersLock.Unlock() + if user.SignalID == id && user.SignalUsername == number { + return + } + if user.SignalID != id { + existingUser := user.bridge.unlockedGetUserBySignalID(id) + if existingUser != nil { + // TODO this doesn't clear the signal store properly + // the store also only has the uuid as primary key, even though it should have uuid + device id + zerolog.Ctx(ctx).Warn(). + Stringer("previous_user", existingUser.MXID). + Stringer("signal_uuid", id). + Msg("Another user is already logged in with same UUID, logging out previous user") + _ = existingUser.Disconnect() + existingUser.SignalID = uuid.Nil + existingUser.SignalUsername = "" + err := existingUser.Update(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to clear previous user's signal UUID") + } + } + } + user.SignalID = id + user.SignalUsername = number + user.bridge.usersBySignalID[id] = user + err := user.Update(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save user's signal UUID") + } +} + func (user *User) populateSignalDevice() *signalmeow.Client { user.Lock() defer user.Unlock() From d22676650f7eeee36ec553efe9f154822d89f50a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 18 Jan 2024 22:52:15 +0200 Subject: [PATCH 063/718] Revert "Add temporary debugging logs" This reverts commit 972b289887bc3b881cf7d1f60fe14676df9298cf. --- portal.go | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/portal.go b/portal.go index 54deb1d..ac1e4dc 100644 --- a/portal.go +++ b/portal.go @@ -428,49 +428,7 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt realSenderMXID := sender.MXID isRelay := false if !sender.IsLoggedIn() { - - // TODO: *** temporary debugging logs *** - if sender != nil { - if sender.Client != nil { - if sender.Client.Store != nil { - log.Warn(). - Str("ACI", sender.Client.Store.ACI.String()[:5]). - Int("device_id", sender.Client.Store.DeviceID). - Str("password", sender.Client.Store.Password[:2]). - Msg("Sender debugging") - } else { - log.Warn().Msg("Sender debugging (no store)") - } - } else { - log.Warn().Msg("Sender debugging (no client)") - } - } else { - log.Warn().Msg("Sender debugging (no sender)") - } - // *** end of temporary debugging logs *** - sender = portal.GetRelayUser() - - // TODO: *** temporary debugging logs *** - if sender != nil { - if sender.Client != nil { - if sender.Client.Store != nil { - log.Warn(). - Str("ACI", sender.Client.Store.ACI.String()[:5]). - Int("device_id", sender.Client.Store.DeviceID). - Str("password", sender.Client.Store.Password[:2]). - Msg("Sender debugging post-portal") - } else { - log.Warn().Msg("Sender debugging post-portal (no store)") - } - } else { - log.Warn().Msg("Sender debugging post-portal (no client)") - } - } else { - log.Warn().Msg("Sender debugging post-portal (no sender)") - } - // *** end of temporary debugging logs *** - if sender == nil { go ms.sendMessageMetrics(evt, errUserNotLoggedIn, "Ignoring", true) return From 6d53efde3331a54722f675801871642f14fa8a19 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 18 Jan 2024 23:12:39 +0200 Subject: [PATCH 064/718] Handle edge case in portal table upgrade --- database/upgrades/16-refactor-postgres.sql | 2 +- database/upgrades/17-refactor-sqlite.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/upgrades/16-refactor-postgres.sql b/database/upgrades/16-refactor-postgres.sql index 776aa8d..331a6ae 100644 --- a/database/upgrades/16-refactor-postgres.sql +++ b/database/upgrades/16-refactor-postgres.sql @@ -50,7 +50,7 @@ ALTER TABLE portal ADD CONSTRAINT portal_mxid_unique UNIQUE(mxid); -- Delete any portals that aren't associated with logged-in users. DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE uuid IS NOT NULL); -- Change receiver to uuid instead of phone number, also add nil uuid for groups. -UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver LIMIT 1) WHERE receiver<>''; +UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver AND uuid IS NOT NULL LIMIT 1) WHERE receiver<>''; UPDATE portal SET receiver='00000000-0000-0000-0000-000000000000' WHERE receiver=''; -- Drop the foreign keys again to allow changing types (the ON UPDATE CASCADEs are needed for the above step) ALTER TABLE message DROP CONSTRAINT message_portal_fkey; diff --git a/database/upgrades/17-refactor-sqlite.sql b/database/upgrades/17-refactor-sqlite.sql index ca55dee..c1edd5b 100644 --- a/database/upgrades/17-refactor-sqlite.sql +++ b/database/upgrades/17-refactor-sqlite.sql @@ -91,7 +91,7 @@ CREATE TABLE lost_portals ( ); INSERT INTO lost_portals SELECT mxid, chat_id, receiver FROM portal WHERE mxid<>''; DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE uuid<>''); -UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver LIMIT 1) WHERE receiver<>''; +UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver AND uuid<>'' LIMIT 1) WHERE receiver<>''; UPDATE portal SET receiver='00000000-0000-0000-0000-000000000000' WHERE receiver=''; DELETE FROM portal WHERE chat_id NOT LIKE '________-____-____-____-____________' AND LENGTH(chat_id) <> 44; DELETE FROM lost_portals WHERE mxid IN (SELECT mxid FROM portal WHERE mxid<>''); From d9844f9afd603e821ffbb11c808a2bb685a77a24 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 19 Jan 2024 17:43:25 +0200 Subject: [PATCH 065/718] Check if table exists to avoid spurious error. Fixes #426 --- main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main.go b/main.go index 2044fb1..3b3354a 100644 --- a/main.go +++ b/main.go @@ -152,6 +152,12 @@ func (br *SignalBridge) Init() { } func (br *SignalBridge) logLostPortals(ctx context.Context) { + exists, err := br.DB.TableExists(ctx, "lost_portals") + if err != nil { + br.ZLog.Err(err).Msg("Failed to check if lost_portals table exists") + } else if !exists { + return + } lostPortals, err := br.DB.LostPortal.GetAll(ctx) if err != nil { br.ZLog.Err(err).Msg("Failed to get lost portals") From 931e25b4538efbb532ba1d0367663a91bb56cb47 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 22 Jan 2024 01:22:13 +0200 Subject: [PATCH 066/718] Update to libsignal 0.39.2 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 2 +- pkg/libsignalgo/version.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index d0879d7..5436160 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit d0879d7150c12301385bc357a2daaa69269d464c +Subproject commit 5436160313d4fa43ea225918138866d05f2da6f7 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 8d1b16f..9cac926 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1259,7 +1259,7 @@ SignalFfiError *signal_mp4_sanitizer_sanitize(SignalSanitizedMetadata **out, con #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_webp_sanitizer_sanitize(bool *out, const SignalSyncInputStream *input, uint64_t len); +SignalFfiError *signal_webp_sanitizer_sanitize(bool *out, const SignalSyncInputStream *input); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 8a4885f..ba75e00 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.39.1" +const Version = "v0.39.2" From 60263e7529d986151aabbfb642f90c845797ffec Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 24 Jan 2024 14:36:27 +0200 Subject: [PATCH 067/718] Fix avatar change deduplication based on hash --- portal.go | 11 +++++++---- puppet.go | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/portal.go b/portal.go index ac1e4dc..b2d46f0 100644 --- a/portal.go +++ b/portal.go @@ -1708,11 +1708,11 @@ func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, gr (portal.AvatarSet || portal.MXID == "") { return false } - portal.AvatarPath = group.AvatarPath - portal.AvatarSet = false - portal.AvatarURL = id.ContentURI{} - portal.AvatarHash = "" if portal.AvatarPath == "" { + portal.AvatarPath = "" + portal.AvatarSet = false + portal.AvatarURL = id.ContentURI{} + portal.AvatarHash = "" // Just clear the Matrix room avatar and return portal.updateAvatarInRoom(ctx) return true @@ -1730,6 +1730,9 @@ func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, gr // No need to change anything else, but save the new path to the database return true } + portal.AvatarPath = group.AvatarPath + portal.AvatarSet = false + portal.AvatarURL = id.ContentURI{} portal.AvatarHash = newAvatarHash log.Debug().Str("avatar_hash", portal.AvatarHash).Msg("Uploading new group avatar to Matrix") resp, err := portal.MainIntent().UploadBytes(ctx, avatarBytes, http.DetectContentType(avatarBytes)) diff --git a/puppet.go b/puppet.go index 7e09f6e..67418fd 100644 --- a/puppet.go +++ b/puppet.go @@ -325,11 +325,11 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type if puppet.AvatarPath == info.ProfileAvatarPath && puppet.AvatarSet { return false } - puppet.AvatarPath = info.ProfileAvatarPath - puppet.AvatarHash = "" - puppet.AvatarSet = false - puppet.AvatarURL = id.ContentURI{} if info.ProfileAvatarPath == "" { + puppet.AvatarURL = id.ContentURI{} + puppet.AvatarPath = "" + puppet.AvatarHash = "" + puppet.AvatarSet = false err := puppet.DefaultIntent().SetAvatarURL(ctx, puppet.AvatarURL) if err != nil { log.Err(err).Msg("Failed to remove user avatar") @@ -359,7 +359,10 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type // Path changed, but actual avatar didn't return true } + puppet.AvatarPath = info.ProfileAvatarPath puppet.AvatarHash = newHash + puppet.AvatarSet = false + puppet.AvatarURL = id.ContentURI{} resp, err := puppet.DefaultIntent().UploadBytes(ctx, avatarData, avatarContentType) if err != nil { log.Err(err). From 666ccf11fba059baabbe98f870d1014340a0ad91 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 25 Jan 2024 23:41:53 +0200 Subject: [PATCH 068/718] Ignore duplicate reactions from Signal (ref #431) --- portal.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/portal.go b/portal.go index b2d46f0..2636675 100644 --- a/portal.go +++ b/portal.go @@ -937,6 +937,9 @@ func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataM if err != nil { log.Err(err).Msg("Failed to get existing reaction from database") return + } else if existingReaction.Emoji == react.GetEmoji() { + log.Debug().Msg("Ignoring duplicate reaction") + return } intent := sender.IntentFor(portal) if existingReaction != nil { From bc03cee3e142d0607937231f9966c29ba095e04f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 25 Jan 2024 23:42:08 +0200 Subject: [PATCH 069/718] Delete reaction with bridge bot if ghost fails. Closes #431 --- portal.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/portal.go b/portal.go index 2636675..79ca90c 100644 --- a/portal.go +++ b/portal.go @@ -946,6 +946,12 @@ func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataM _, err = intent.RedactEvent(ctx, portal.MXID, existingReaction.MXID, mautrix.ReqRedact{ TxnID: "mxsg_unreact_" + existingReaction.MXID.String(), }) + if errors.Is(err, mautrix.MForbidden) { + log.Debug().Err(err).Msg("Failed to redact reaction with ghost, retrying with main intent") + _, err = portal.MainIntent().RedactEvent(ctx, portal.MXID, existingReaction.MXID, mautrix.ReqRedact{ + TxnID: "mxsg_unreact_" + existingReaction.MXID.String(), + }) + } if err != nil { log.Err(err).Msg("Failed to redact reaction") } From e938532440a0e90de0dedf275f70d839ae06802e Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Fri, 26 Jan 2024 07:58:04 -0500 Subject: [PATCH 070/718] Add whoami provisioning API (#428) --- provisioning.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/provisioning.go b/provisioning.go index 7256512..c603902 100644 --- a/provisioning.go +++ b/provisioning.go @@ -68,6 +68,7 @@ func (prov *ProvisioningAPI) Init() { r.Use(hlog.NewHandler(prov.log)) r.Use(requestlog.AccessLogger(true)) r.Use(prov.AuthMiddleware) + r.HandleFunc("/v2/whoami", prov.WhoAmI).Methods(http.MethodGet) r.HandleFunc("/v2/link/new", prov.LinkNew).Methods(http.MethodPost) r.HandleFunc("/v2/link/wait/scan", prov.LinkWaitForScan).Methods(http.MethodPost) r.HandleFunc("/v2/link/wait/account", prov.LinkWaitForAccount).Methods(http.MethodPost) @@ -128,6 +129,19 @@ type Response struct { *ResolveIdentifierResponse } +type WhoAmIResponse struct { + Permissions int `json:"permissions"` + MXID string `json:"mxid"` + Signal *WhoAmIResponseSignal `json:"signal,omitempty"` +} + +type WhoAmIResponseSignal struct { + Number string `json:"number"` + UUID string `json:"uuid"` + Name string `json:"name"` + Ok bool `json:"ok"` +} + type ResolveIdentifierResponse struct { RoomID id.RoomID `json:"room_id"` ChatID ResolveIdentifierResponseChatID `json:"chat_id"` @@ -388,6 +402,32 @@ func (prov *ProvisioningAPI) checkSessionAndReturnHandle(ctx context.Context, w return handle } +func (prov *ProvisioningAPI) WhoAmI(w http.ResponseWriter, r *http.Request) { + user := r.Context().Value(provisioningUserKey).(*User) + log := prov.log.With(). + Str("action", "whoami"). + Str("user_id", user.MXID.String()). + Logger() + log.Debug().Msg("getting whoami") + + data := WhoAmIResponse{ + Permissions: int(user.PermissionLevel), + MXID: user.MXID.String(), + } + if user.IsLoggedIn() { + data.Signal = &WhoAmIResponseSignal{ + Number: user.SignalUsername, + UUID: user.SignalID.String(), + Ok: user.Client.IsConnected(), + } + puppet := user.bridge.GetPuppetBySignalID(user.SignalID) + if puppet != nil { + data.Signal.Name = puppet.Name + } + } + jsonResponse(w, http.StatusOK, data) +} + func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) log := prov.log.With(). From ea4522bd179119e7e9ccb1ecf7f293445aaf33d2 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Fri, 26 Jan 2024 07:58:43 -0500 Subject: [PATCH 071/718] Deduplicate users' UUIDs during schema upgrade (#429) Otherwise, upgrading to v16 may hit conflicts if two users share the same Signal UUID, which was possible in prior DB versions. --- This is useful only when upgrading a DB from the signald version of the bridge, where some Matrix users had logged into the same Signal account (and thus shared the same UUID in the "users" table). Though this removes Signal UUID associations from Matrix users, migrating from the signald version requires re-logging in anyways. The only time this would not be safe is when migrating a DB that had already been migrated from signald (i.e. a v13-v15 version) and users logged back in, with some sharing the same Signal UUID. --- database/upgrades/16-refactor-postgres.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/database/upgrades/16-refactor-postgres.sql b/database/upgrades/16-refactor-postgres.sql index 331a6ae..eeca7fa 100644 --- a/database/upgrades/16-refactor-postgres.sql +++ b/database/upgrades/16-refactor-postgres.sql @@ -101,6 +101,9 @@ ALTER TABLE puppet ALTER COLUMN avatar_url SET NOT NULL; ALTER TABLE puppet ALTER COLUMN access_token SET NOT NULL; ALTER TABLE puppet ALTER COLUMN name_quality DROP DEFAULT; +UPDATE "user" + SET uuid=NULL + WHERE uuid IN (SELECT DISTINCT uuid FROM "user" WHERE uuid IS NOT NULL GROUP BY uuid HAVING COUNT(*)>1); ALTER TABLE "user" ADD CONSTRAINT user_uuid_unique UNIQUE(uuid); ALTER TABLE "user" RENAME COLUMN username TO phone; From ee5932bbd985e0fd969d8a7abb4d6aa1259b80e6 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Fri, 26 Jan 2024 08:00:03 -0500 Subject: [PATCH 072/718] Ensure user is invited to portal on message (#430) --- portal.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/portal.go b/portal.go index 79ca90c..d7b5b5f 100644 --- a/portal.go +++ b/portal.go @@ -1052,6 +1052,8 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet log.Error().Err(err).Msg("Failed to create portal room") return } + } else if !portal.ensureUserInvited(ctx, source) { + log.Warn().Stringer("user_id", source.MXID).Msg("Failed to ensure source user is joined to portal") } existingMessage, err := portal.bridge.DB.Message.GetBySignalID(ctx, sender.SignalID, msg.GetTimestamp(), 0, portal.Receiver) From f5468a6e8c79eddd0337bb5f06a847a7d6dbc291 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Fri, 26 Jan 2024 08:42:34 -0500 Subject: [PATCH 073/718] Avoid nil dereference on existing reaction lookup (#433) Otherwise, the bridge crashes when it sees a reaction from Signal. --- This fixes a crash introduced by 666ccf1. --- portal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portal.go b/portal.go index d7b5b5f..a946fe2 100644 --- a/portal.go +++ b/portal.go @@ -937,7 +937,7 @@ func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataM if err != nil { log.Err(err).Msg("Failed to get existing reaction from database") return - } else if existingReaction.Emoji == react.GetEmoji() { + } else if existingReaction != nil && existingReaction.Emoji == react.GetEmoji() { log.Debug().Msg("Ignoring duplicate reaction") return } From cb0412075769a360aea7caa7f071648a99e377c5 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Mon, 29 Jan 2024 14:54:20 -0500 Subject: [PATCH 074/718] Check dm.Quote for nil --- msgconv/from-signal.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index e73ea0f..9b2c917 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -33,6 +33,7 @@ import ( "golang.org/x/exp/slices" "maunium.net/go/mautrix/crypto/attachment" "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/msgconv/signalfmt" "go.mau.fi/mautrix-signal/pkg/signalmeow" @@ -138,7 +139,11 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa }, }) } - replyTo, sender := mc.GetMatrixReply(ctx, dm.Quote) + var replyTo id.EventID + var sender id.UserID + if dm.Quote != nil { + replyTo, sender = mc.GetMatrixReply(ctx, dm.Quote) + } for _, part := range cm.Parts { if part.Content.Mentions == nil { part.Content.Mentions = &event.Mentions{} From 103666990f30a692c63dd84a499b0dd390cef8a4 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Wed, 31 Jan 2024 10:39:33 -0500 Subject: [PATCH 075/718] Use clang when building for Android and darwin (#435) --- pkg/libsignalgo/serviceid_clang.go | 2 +- pkg/libsignalgo/serviceid_gcc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/serviceid_clang.go b/pkg/libsignalgo/serviceid_clang.go index 8de76b2..067d9d1 100644 --- a/pkg/libsignalgo/serviceid_clang.go +++ b/pkg/libsignalgo/serviceid_clang.go @@ -1,4 +1,4 @@ -//go:build darwin +//go:build darwin || android package libsignalgo diff --git a/pkg/libsignalgo/serviceid_gcc.go b/pkg/libsignalgo/serviceid_gcc.go index 4152fba..0d0f5c8 100644 --- a/pkg/libsignalgo/serviceid_gcc.go +++ b/pkg/libsignalgo/serviceid_gcc.go @@ -1,4 +1,4 @@ -//go:build !darwin +//go:build !(darwin || android) package libsignalgo From af4de369bde2fba45f8a6ed303bbf1d4ee19fe20 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Sat, 10 Feb 2024 07:35:56 -0500 Subject: [PATCH 076/718] Satisfy static checks (#440) --- commands.go | 10 +++++----- main.go | 8 ++++---- metrics.go | 30 ++++++++++++++++++------------ puppet.go | 3 --- user.go | 3 +-- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/commands.go b/commands.go index 9d93ded..f24f34e 100644 --- a/commands.go +++ b/commands.go @@ -379,7 +379,7 @@ func fnLogin(ce *WrappedCommandEvent) { // First get the provisioning URL provChan, err := ce.User.Login() if err != nil { - ce.Log.Errorln("Failure logging in:", err) + ce.ZLog.Err(err).Msg("Failure logging in") ce.Reply("Failure logging in: %v", err) return } @@ -447,7 +447,7 @@ func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg i } resp, err := ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) if err != nil { - ce.Log.Errorln("Failed to send QR code to user:", err) + ce.ZLog.Err(err).Msg("Failed to send QR code to user") } else if len(prevQR) == 0 { prevQR = resp.EventID } @@ -462,7 +462,7 @@ func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg i } resp, err = ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) if err != nil { - ce.Log.Errorln("Failed to send raw code to user:", err) + ce.ZLog.Err(err).Msg("Failed to send raw code to user") } else if len(prevMsg) == 0 { prevMsg = resp.EventID } @@ -473,7 +473,7 @@ func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (event.MessageE const size = 512 qrCode, err := qrcode.Encode(code, qrcode.Low, size) if err != nil { - ce.Log.Errorln("Failed to encode QR code:", err) + ce.ZLog.Err(err).Msg("Failed to encode QR code") ce.Reply("Failed to encode QR code: %v", err) return event.MessageEventContent{}, false } @@ -482,7 +482,7 @@ func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (event.MessageE resp, err := bot.UploadBytes(ce.Ctx, qrCode, "image/png") if err != nil { - ce.Log.Errorln("Failed to upload QR code:", err) + ce.ZLog.Err(err).Msg("Failed to upload QR code") ce.Reply("Failed to upload QR code: %v", err) return event.MessageEventContent{}, false } diff --git a/main.go b/main.go index 3b3354a..a1dfc2a 100644 --- a/main.go +++ b/main.go @@ -114,7 +114,7 @@ func (br *SignalBridge) Init() { Bridge: br, } - br.Metrics = NewMetricsHandler(br.Config.Metrics.Listen, br.Log.Sub("Metrics"), br.DB) + br.Metrics = NewMetricsHandler(br.Config.Metrics.Listen, br.ZLog.With().Str("component", "metrics").Logger(), br.DB) br.MatrixHandler.TrackEventDuration = br.Metrics.TrackMatrixEvent signalFormatParams = &signalfmt.FormatParams{ @@ -180,11 +180,11 @@ func (br *SignalBridge) Start() { go br.logLostPortals(context.TODO()) err := br.MeowStore.Upgrade(context.TODO()) if err != nil { - br.Log.Fatalln("Failed to upgrade signalmeow database: %v", err) + br.ZLog.Fatal().Err(err).Msg("Failed to upgrade signalmeow database") os.Exit(15) } if br.provisioning != nil { - br.Log.Debugln("Initializing provisioning API") + br.ZLog.Debug().Msg("Initializing provisioning API") br.provisioning.Init() } go br.StartUsers() @@ -197,7 +197,7 @@ func (br *SignalBridge) Start() { func (br *SignalBridge) Stop() { br.Metrics.Stop() for _, user := range br.usersByMXID { - br.Log.Debugln("Disconnecting", user.MXID) + br.ZLog.Debug().Stringer("user_id", user.MXID).Msg("Disconnecting user") user.Disconnect() } } diff --git a/metrics.go b/metrics.go index 783a6ad..018b97d 100644 --- a/metrics.go +++ b/metrics.go @@ -27,7 +27,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" - log "maunium.net/go/maulogger/v2" + "github.com/rs/zerolog" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -37,7 +37,7 @@ import ( type MetricsHandler struct { db *database.Database server *http.Server - log log.Logger + log zerolog.Logger running bool ctx context.Context @@ -67,7 +67,7 @@ type MetricsHandler struct { loggedInStateLock sync.Mutex } -func NewMetricsHandler(address string, log log.Logger, db *database.Database) *MetricsHandler { +func NewMetricsHandler(address string, log zerolog.Logger, db *database.Database) *MetricsHandler { portalCount := promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "bridge_portals_total", Help: "Number of portal rooms on Matrix", @@ -231,7 +231,7 @@ func (mh *MetricsHandler) updateStats() { var puppetCount int err := mh.db.QueryRow(mh.ctx, "SELECT COUNT(*) FROM puppet").Scan(&puppetCount) if err != nil { - mh.log.Warnln("Failed to scan number of puppets:", err) + mh.log.Warn().Err(err).Msg("Failed to scan number of puppets") } else { mh.puppetCount.Set(float64(puppetCount)) } @@ -239,7 +239,7 @@ func (mh *MetricsHandler) updateStats() { var userCount int err = mh.db.QueryRow(mh.ctx, `SELECT COUNT(*) FROM "user"`).Scan(&userCount) if err != nil { - mh.log.Warnln("Failed to scan number of users:", err) + mh.log.Warn().Err(err).Msg("Failed to scan number of users:") } else { mh.userCount.Set(float64(userCount)) } @@ -247,7 +247,7 @@ func (mh *MetricsHandler) updateStats() { var messageCount int err = mh.db.QueryRow(mh.ctx, "SELECT COUNT(*) FROM message").Scan(&messageCount) if err != nil { - mh.log.Warnln("Failed to scan number of messages:", err) + mh.log.Warn().Err(err).Msg("Failed to scan number of messages") } else { mh.messageCount.Set(float64(messageCount)) } @@ -264,7 +264,7 @@ func (mh *MetricsHandler) updateStats() { FROM portal WHERE mxid<>'' `).Scan(&encryptedGroupCount, &encryptedPrivateCount, &unencryptedGroupCount, &unencryptedPrivateCount) if err != nil { - mh.log.Warnln("Failed to scan number of portals:", err) + mh.log.Warn().Err(err).Msg("Failed to scan number of portals") } else { mh.encryptedGroupCount.Set(float64(encryptedGroupCount)) mh.encryptedPrivateCount.Set(float64(encryptedPrivateCount)) @@ -276,9 +276,15 @@ func (mh *MetricsHandler) updateStats() { func (mh *MetricsHandler) startUpdatingStats() { defer func() { - err := recover() - if err != nil { - mh.log.Fatalfln("Panic in metric updater: %v\n%s", err, string(debug.Stack())) + r := recover() + if r != nil { + evt := mh.log.Fatal().Str("stack", string(debug.Stack())) + if err, ok := r.(error); ok { + evt = evt.Err(err) + } else { + evt = evt.Any("error", r) + } + evt.Msg("Panic in metric updater") } }() ticker := time.Tick(10 * time.Second) @@ -299,7 +305,7 @@ func (mh *MetricsHandler) Start() { err := mh.server.ListenAndServe() mh.running = false if err != nil && err != http.ErrServerClosed { - mh.log.Fatalln("Error in metrics listener:", err) + mh.log.Fatal().Err(err).Msg("Error in metrics listener") } } @@ -310,6 +316,6 @@ func (mh *MetricsHandler) Stop() { mh.stopRecorder() err := mh.server.Close() if err != nil { - mh.log.Errorln("Error closing metrics listener:", err) + mh.log.Err(err).Msg("Error closing metrics listener") } } diff --git a/puppet.go b/puppet.go index 67418fd..82777aa 100644 --- a/puppet.go +++ b/puppet.go @@ -23,7 +23,6 @@ import ( "fmt" "net/http" "regexp" - "sync" "github.com/google/uuid" "github.com/rs/zerolog" @@ -191,8 +190,6 @@ type Puppet struct { customIntent *appservice.IntentAPI customUser *User - - syncLock sync.Mutex } var userIDRegex *regexp.Regexp diff --git a/user.go b/user.go index b6cdcca..313bfeb 100644 --- a/user.go +++ b/user.go @@ -166,8 +166,7 @@ type User struct { Client *signalmeow.Client - BridgeState *bridge.BridgeStateQueue - bridgeStateLock sync.Mutex + BridgeState *bridge.BridgeStateQueue spaceMembershipChecked bool spaceCreateLock sync.Mutex From 7761199303c645502706cce56ce95669b973e83a Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Sat, 10 Feb 2024 07:36:05 -0500 Subject: [PATCH 077/718] Use Stringer with zerolog (#441) Satisfies the "zerolog-use-stringer" pre-commit hook --- commands.go | 2 +- database/userportal.go | 10 ++++----- disappearing.go | 14 ++++++------ main.go | 8 +++---- messagetracking.go | 16 +++++++------- pkg/signalmeow/contact.go | 2 +- pkg/signalmeow/receiving.go | 2 +- portal.go | 44 ++++++++++++++++++------------------- provisioning.go | 14 ++++++------ user.go | 10 ++++----- 10 files changed, 61 insertions(+), 61 deletions(-) diff --git a/commands.go b/commands.go index f24f34e..3f3c80d 100644 --- a/commands.go +++ b/commands.go @@ -507,7 +507,7 @@ func canDeletePortal(ctx context.Context, portal *Portal, userID id.UserID) bool members, err := portal.MainIntent().JoinedMembers(ctx, portal.MXID) if err != nil { portal.log.Err(err). - Str("user_id", userID.String()). + Stringer("user_id", userID). Msg("Failed to get joined members to check if user can delete portal") return false } diff --git a/database/userportal.go b/database/userportal.go index c1ba828..6081ee8 100644 --- a/database/userportal.go +++ b/database/userportal.go @@ -48,7 +48,7 @@ func (u *User) GetLastReadTS(ctx context.Context, portal PortalKey) uint64 { err := u.qh.GetDB().QueryRow(ctx, getLastReadTSQuery, u.MXID, portal.ChatID, portal.Receiver).Scan(&ts) if err != nil && !errors.Is(err, sql.ErrNoRows) { zerolog.Ctx(ctx).Err(err). - Str("user_id", u.MXID.String()). + Stringer("user_id", u.MXID). Any("portal_key", portal). Msg("Failed to query last read timestamp") return 0 @@ -63,12 +63,12 @@ func (u *User) SetLastReadTS(ctx context.Context, portal PortalKey, ts uint64) { err := u.qh.Exec(ctx, setLastReadTSQuery, u.MXID, portal.ChatID, portal.Receiver, int64(ts)) if err != nil { zerolog.Ctx(ctx).Err(err). - Str("user_id", u.MXID.String()). + Stringer("user_id", u.MXID). Any("portal_key", portal). Msg("Failed to update last read timestamp") } else { zerolog.Ctx(ctx).Debug(). - Str("user_id", u.MXID.String()). + Stringer("user_id", u.MXID). Any("portal_key", portal). Uint64("last_read_ts", ts). Msg("Updated last read timestamp of portal") @@ -86,7 +86,7 @@ func (u *User) IsInSpace(ctx context.Context, portal PortalKey) bool { err := u.qh.GetDB().QueryRow(ctx, getIsInSpaceQuery, u.MXID, portal.ChatID, portal.Receiver).Scan(&inSpace) if err != nil && !errors.Is(err, sql.ErrNoRows) { zerolog.Ctx(ctx).Err(err). - Str("user_id", u.MXID.String()). + Stringer("user_id", u.MXID). Any("portal_key", portal). Msg("Failed to query in space status") return false @@ -101,7 +101,7 @@ func (u *User) MarkInSpace(ctx context.Context, portal PortalKey) { err := u.qh.Exec(ctx, setIsInSpaceQuery, u.MXID, portal.ChatID, portal.Receiver) if err != nil { zerolog.Ctx(ctx).Err(err). - Str("user_id", u.MXID.String()). + Stringer("user_id", u.MXID). Any("portal_key", portal). Msg("Failed to update in space status") } else { diff --git a/disappearing.go b/disappearing.go index ede68f0..5b84d41 100644 --- a/disappearing.go +++ b/disappearing.go @@ -48,7 +48,7 @@ func (dmm *DisappearingMessagesManager) ScheduleDisappearingForRoom(ctx context. log.Err(err).Msg("Failed to schedule disappearing message") } else { log.Debug(). - Str("event_id", disappearingMessage.EventID.String()). + Stringer("event_id", disappearingMessage.EventID). Time("expire_at", disappearingMessage.ExpireAt). Msg("Scheduling disappearing message") } @@ -103,7 +103,7 @@ func (dmm *DisappearingMessagesManager) redactExpiredMessages(ctx context.Contex err = msg.Delete(ctx) if err != nil { log.Err(err). - Str("event_id", msg.EventID.String()). + Stringer("event_id", msg.EventID). Msg("Failed to delete disappearing message row in database") } continue @@ -114,19 +114,19 @@ func (dmm *DisappearingMessagesManager) redactExpiredMessages(ctx context.Contex }) if err != nil { log.Err(err). - Str("event_id", msg.EventID.String()). - Str("room_id", msg.RoomID.String()). + Stringer("event_id", msg.EventID). + Stringer("room_id", msg.RoomID). Msg("Failed to redact message") } else { log.Err(err). - Str("event_id", msg.EventID.String()). - Str("room_id", msg.RoomID.String()). + Stringer("event_id", msg.EventID). + Stringer("room_id", msg.RoomID). Msg("Redacted message") } err = msg.Delete(ctx) if err != nil { log.Err(err). - Str("event_id", msg.EventID.String()). + Stringer("event_id", msg.EventID). Msg("Failed to delete disappearing message row in database") } } diff --git a/main.go b/main.go index a1dfc2a..18b4ca2 100644 --- a/main.go +++ b/main.go @@ -237,9 +237,9 @@ func (br *SignalBridge) CreatePrivatePortal(roomID id.RoomID, brInviter bridge.U log := br.ZLog.With(). Str("action", "create private portal"). - Str("target_room_id", roomID.String()). - Str("inviter_mxid", brInviter.GetMXID().String()). - Str("invitee_uuid", puppet.SignalID.String()). + Stringer("target_room_id", roomID). + Stringer("inviter_mxid", brInviter.GetMXID()). + Stringer("invitee_uuid", puppet.SignalID). Logger() log.Debug().Msg("Creating private chat portal") @@ -252,7 +252,7 @@ func (br *SignalBridge) CreatePrivatePortal(roomID id.RoomID, brInviter bridge.U return } log.Debug(). - Str("existing_room_id", portal.MXID.String()). + Stringer("existing_room_id", portal.MXID). Msg("Existing private chat portal found, trying to invite user") ok := portal.ensureUserInvited(ctx, inviter) diff --git a/messagetracking.go b/messagetracking.go index a106ee6..e95abb4 100644 --- a/messagetracking.go +++ b/messagetracking.go @@ -249,15 +249,15 @@ func niceRound(dur time.Duration) time.Duration { func (mt *messageTimings) MarshalZerologObject(evt *zerolog.Event) { evt. Dict("bridge", zerolog.Dict(). - Str("init_receive", niceRound(mt.initReceive).String()). - Str("decrypt", niceRound(mt.decrypt).String()). - Str("queue", niceRound(mt.portalQueue).String()). - Str("total_hs_to_portal", niceRound(mt.totalReceive).String())). + Stringer("init_receive", niceRound(mt.initReceive)). + Stringer("decrypt", niceRound(mt.decrypt)). + Stringer("queue", niceRound(mt.portalQueue)). + Stringer("total_hs_to_portal", niceRound(mt.totalReceive))). Dict("portal", zerolog.Dict(). - Str("implicit_rr", niceRound(mt.implicitRR).String()). - Str("preproc", niceRound(mt.preproc).String()). - Str("convert", niceRound(mt.convert).String()). - Str("total_send", niceRound(mt.totalSend).String())) + Stringer("implicit_rr", niceRound(mt.implicitRR)). + Stringer("preproc", niceRound(mt.preproc)). + Stringer("convert", niceRound(mt.convert)). + Stringer("total_send", niceRound(mt.totalSend))) } type metricSender struct { diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index 5ec22c3..7682c99 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -42,7 +42,7 @@ func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDeta } log := zerolog.Ctx(ctx).With(). Str("action", "store contact details as contact"). - Str("uuid", parsedUUID.String()). + Stringer("uuid", parsedUUID). Logger() existingContact, err := cli.Store.ContactStore.LoadContact(ctx, parsedUUID) if err != nil { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 2ee008b..1c3f62b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -330,7 +330,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Err(err).Msg("GetContents error") } log = log.With(). - Str("sender_uuid", senderUUID.String()). + Stringer("sender_uuid", senderUUID). Uint32("sender_device_id", senderDeviceID). Str("sender_e164", senderE164). Logger() diff --git a/portal.go b/portal.go index a946fe2..73647e9 100644 --- a/portal.go +++ b/portal.go @@ -346,7 +346,7 @@ func (portal *Portal) messageLoop() { func (portal *Portal) handleMatrixMessages(msg portalMatrixMessage) { log := portal.log.With(). Str("action", "handle matrix event"). - Str("event_id", msg.evt.ID.String()). + Stringer("event_id", msg.evt.ID). Str("event_type", msg.evt.Type.String()). Logger() ctx := log.WithContext(context.TODO()) @@ -379,7 +379,7 @@ func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt messageAge := timings.totalReceive ms := metricSender{portal: portal, timings: &timings, ctx: ctx} log.Debug(). - Str("sender", evt.Sender.String()). + Stringer("sender", evt.Sender). Dur("age", messageAge). Msg("Received message") @@ -559,14 +559,14 @@ func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, e }) if err != nil { log.Err(err). - Str("part_event_id", otherPart.MXID.String()). + Stringer("part_event_id", otherPart.MXID). Int("part_index", otherPart.PartIndex). Msg("Failed to redact other part of redacted message") } err = otherPart.Delete(ctx) if err != nil { log.Err(err). - Str("part_event_id", otherPart.MXID.String()). + Stringer("part_event_id", otherPart.MXID). Int("part_index", otherPart.PartIndex). Msg("Failed to delete other part of redacted message from database") } @@ -670,7 +670,7 @@ func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, ev func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Content, sender *User, evtID id.EventID) error { log := zerolog.Ctx(ctx).With(). Str("action", "send signal message"). - Str("event_id", evtID.String()). + Stringer("event_id", evtID). Str("portal_chat_id", portal.ChatID). Logger() ctx = log.WithContext(ctx) @@ -816,11 +816,11 @@ func (portal *Portal) GetSignalReply(ctx context.Context, content *event.Message replyToMsg, err := portal.bridge.DB.Message.GetByMXID(ctx, replyToID) if err != nil { zerolog.Ctx(ctx).Err(err). - Str("reply_to_mxid", replyToID.String()). + Stringer("reply_to_mxid", replyToID). Msg("Failed to get reply target message from database") } else if replyToMsg == nil { zerolog.Ctx(ctx).Warn(). - Str("reply_to_mxid", replyToID.String()). + Stringer("reply_to_mxid", replyToID). Msg("Reply target message not found") } else { return &signalpb.DataMessage_Quote{ @@ -841,7 +841,7 @@ func (portal *Portal) handleSignalMessage(portalMessage portalSignalMessage) { sender := portal.bridge.GetPuppetBySignalID(portalMessage.evt.Info.Sender) if sender == nil { portal.log.Warn(). - Str("sender_uuid", portalMessage.evt.Info.Sender.String()). + Stringer("sender_uuid", portalMessage.evt.Info.Sender). Msg("Couldn't get puppet for message") return } @@ -893,7 +893,7 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg default: portal.log.Warn(). Str("action", "handle signal message"). - Str("sender_uuid", sender.SignalID.String()). + Stringer("sender_uuid", sender.SignalID). Uint64("msg_ts", msg.GetTimestamp()). Msg("Unrecognized content in message") } @@ -902,7 +902,7 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, groupMeta *signalpb.GroupContextV2, ts uint64) { log := portal.log.With(). Str("action", "handle signal group change"). - Str("sender_uuid", sender.SignalID.String()). + Stringer("sender_uuid", sender.SignalID). Uint64("change_ts", ts). Uint32("new_revision", groupMeta.GetRevision()). Logger() @@ -914,7 +914,7 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataMessage_Reaction, ts uint64) { log := portal.log.With(). Str("action", "handle signal reaction"). - Str("sender_uuid", sender.SignalID.String()). + Stringer("sender_uuid", sender.SignalID). Uint64("target_msg_ts", react.GetTargetSentTimestamp()). Str("target_msg_sender", react.GetTargetAuthorAci()). Bool("remove", react.GetRemove()). @@ -1006,7 +1006,7 @@ func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataM func (portal *Portal) handleSignalDelete(sender *Puppet, delete *signalpb.DataMessage_Delete, ts uint64) { log := portal.log.With(). Str("action", "handle signal delete"). - Str("sender_uuid", sender.SignalID.String()). + Stringer("sender_uuid", sender.SignalID). Uint64("target_msg_ts", delete.GetTargetSentTimestamp()). Uint64("delete_ts", ts). Logger() @@ -1027,7 +1027,7 @@ func (portal *Portal) handleSignalDelete(sender *Puppet, delete *signalpb.DataMe if err != nil { log.Err(err). Int("part_index", part.PartIndex). - Str("event_id", part.MXID.String()). + Stringer("event_id", part.MXID). Msg("Failed to redact message") } err = part.Delete(ctx) @@ -1042,7 +1042,7 @@ func (portal *Portal) handleSignalDelete(sender *Puppet, delete *signalpb.DataMe func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet, msg *signalpb.DataMessage) { log := portal.log.With(). Str("action", "handle signal message"). - Str("sender_uuid", sender.SignalID.String()). + Stringer("sender_uuid", sender.SignalID). Uint64("msg_ts", msg.GetTimestamp()). Logger() ctx := log.WithContext(context.TODO()) @@ -1087,7 +1087,7 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet func (portal *Portal) handleSignalEditMessage(sender *Puppet, timestamp uint64, msg *signalpb.DataMessage) { log := portal.log.With(). Str("action", "handle signal edit"). - Str("sender_uuid", sender.SignalID.String()). + Stringer("sender_uuid", sender.SignalID). Uint64("target_msg_ts", timestamp). Uint64("edit_msg_ts", msg.GetTimestamp()). Logger() @@ -1158,7 +1158,7 @@ func (portal *Portal) handleSignalTypingMessage(sender *Puppet, msg *signalpb.Ty } if err != nil { portal.log.Err(err). - Str("user_id", sender.SignalID.String()). + Stringer("user_id", sender.SignalID). Msg("Failed to handle Signal typing notification") } } @@ -1292,8 +1292,8 @@ func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, return } logWith := portal.log.With(). - Str("event_id", eventID.String()). - Str("sender", sender.MXID.String()). + Stringer("event_id", eventID). + Stringer("sender", sender.MXID). Bool("explicit", isExplicit) if isExplicit { logWith = logWith.Str("action", "handle matrix read receipt") @@ -1829,14 +1829,14 @@ func (portal *Portal) addToPersonalSpace(ctx context.Context, user *User) bool { }) if err != nil { zerolog.Ctx(ctx).Err(err). - Str("user_id", user.MXID.String()). - Str("space_id", spaceID.String()). + Stringer("user_id", user.MXID). + Stringer("space_id", spaceID). Msg("Failed to add room to user's personal filtering space") return false } else { zerolog.Ctx(ctx).Debug(). - Str("user_id", user.MXID.String()). - Str("space_id", spaceID.String()). + Stringer("user_id", user.MXID). + Stringer("space_id", spaceID). Msg("Added room to user's personal filtering space") user.MarkInSpace(ctx, portal.PortalKey) return true diff --git a/provisioning.go b/provisioning.go index c603902..117fa1b 100644 --- a/provisioning.go +++ b/provisioning.go @@ -209,7 +209,7 @@ func (prov *ProvisioningAPI) ResolveIdentifier(w http.ResponseWriter, r *http.Re log := prov.log.With(). Str("action", "resolve_identifier"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Str("phone_num", phoneNum). Logger() ctx := log.WithContext(r.Context()) @@ -244,7 +244,7 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { log := prov.log.With(). Str("action", "start_pm"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Str("phone_num", phoneNum). Logger() ctx := log.WithContext(r.Context()) @@ -406,7 +406,7 @@ func (prov *ProvisioningAPI) WhoAmI(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) log := prov.log.With(). Str("action", "whoami"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Logger() log.Debug().Msg("getting whoami") @@ -432,7 +432,7 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) log := prov.log.With(). Str("action", "link_new"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Logger() ctx := log.WithContext(r.Context()) log.Debug().Msg("starting login") @@ -517,7 +517,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ log := prov.log.With(). Str("action", "link_wait_for_scan"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Str("session_id", body.SessionID). Logger() ctx := log.WithContext(r.Context()) @@ -610,7 +610,7 @@ func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.R log := prov.log.With(). Str("action", "link_wait_for_account"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Int("session_id", sessionID). Str("device_name", deviceName). Logger() @@ -669,7 +669,7 @@ func (prov *ProvisioningAPI) Logout(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) log := prov.log.With(). Str("action", "logout"). - Str("user_id", user.MXID.String()). + Stringer("user_id", user.MXID). Logger() ctx := log.WithContext(r.Context()) log.Debug().Msg("Logout called (but not logging out)") diff --git a/user.go b/user.go index 313bfeb..7d8aeae 100644 --- a/user.go +++ b/user.go @@ -409,7 +409,7 @@ func (user *User) startupTryConnect(retryCount int) { var connectionStatus signalmeow.SignalConnectionStatus if peekedConnectionStatus.Event != signalmeow.SignalConnectionEventNone { user.log.Debug(). - Str("peeked_connection_status_event", peekedConnectionStatus.Event.String()). + Stringer("peeked_connection_status_event", peekedConnectionStatus.Event). Msg("Using peeked connectionStatus event") connectionStatus = peekedConnectionStatus peekedConnectionStatus = signalmeow.SignalConnectionStatus{} @@ -596,7 +596,7 @@ func (user *User) populateSignalDevice() *signalmeow.Client { defer user.Unlock() log := user.log.With(). Str("action", "populate signal device"). - Str("signal_id", user.SignalID.String()). + Stringer("signal_id", user.SignalID). Logger() if user.SignalID == uuid.Nil { @@ -627,8 +627,8 @@ func (user *User) populateSignalDevice() *signalmeow.Client { func (user *User) handleReceipt(evt *events.Receipt) { log := user.log.With(). Str("action", "handle receipt"). - Str("receipt_type", evt.Content.GetType().String()). - Str("sender_uuid", evt.Sender.String()). + Stringer("receipt_type", evt.Content.GetType()). + Stringer("sender_uuid", evt.Sender). Logger() ctx := log.WithContext(context.TODO()) messages, err := user.bridge.DB.Message.GetManyBySignalID(ctx, user.SignalID, evt.Content.GetTimestamp(), user.SignalID, false) @@ -728,7 +728,7 @@ func (user *User) handleReadSelf(evt *events.ReadSelf) { Str("action", "handle read self"). Str("chat_id", msg.SignalChatID). Uint64("msg_timestamp", msg.Timestamp). - Str("msg_mxid", msg.MXID.String()). + Stringer("msg_mxid", msg.MXID). Msg("Bridging own read receipt") portal.ScheduleDisappearing() user.SetLastReadTS(ctx, portal.PortalKey, msg.Timestamp) From ae7ccf4fdf42289e766d464ce7bee68c93f41634 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Sat, 10 Feb 2024 07:37:02 -0500 Subject: [PATCH 078/718] Restore debug build & remote debugging for Docker builds (#436) --- Dockerfile | 20 +++++++++++++++++--- Makefile | 18 +++++++----------- build-go.sh | 11 ++++++++--- build-rust.sh | 9 +++++++++ docker-run.sh | 4 ++-- 5 files changed, 43 insertions(+), 19 deletions(-) create mode 100755 build-rust.sh diff --git a/Dockerfile b/Dockerfile index 6e6b20d..de716c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,9 +5,10 @@ RUN apk add --no-cache git make cmake protoc musl-dev g++ clang-dev WORKDIR /build # Copy all files needed for Rust build, and no Go files COPY pkg/libsignalgo/libsignal/. pkg/libsignalgo/libsignal/. +COPY build-rust.sh . -ENV RUSTFLAGS="-Ctarget-feature=-crt-static" RUSTC_WRAPPER="" -RUN cd pkg/libsignalgo/libsignal/ && cargo build -p libsignal-ffi --release +ARG DBG=0 +RUN ./build-rust.sh # -- Build mautrix-signal (with Go) -- FROM golang:1-alpine3.19 AS go-builder @@ -24,8 +25,16 @@ COPY database/. database/. COPY msgconv/. msgconv/. COPY .git .git +ARG DBG=0 ENV LIBRARY_PATH=. -COPY --from=rust-builder /build/pkg/libsignalgo/libsignal/target/release/libsignal_ffi.a /build/libsignal_ffi.a +COPY --from=rust-builder /build/pkg/libsignalgo/libsignal/target/*/libsignal_ffi.a ./ +RUN </dev/null) -X main.Commit=$$(git rev-parse HEAD) -X 'main.BuildTime=`date '+%b %_d %Y, %H:%M:%S'`'" + LIBRARY_PATH="$${LIBRARY_PATH}:." ./build-go.sh clean: rm -f ./$(LIBRARY_FILENAME) diff --git a/build-go.sh b/build-go.sh index 91123ec..89cf0b0 100755 --- a/build-go.sh +++ b/build-go.sh @@ -1,4 +1,9 @@ #!/bin/sh -export MAUTRIX_VERSION=$(cat go.mod | grep 'maunium.net/go/mautrix ' | awk '{ print $2 }') -export GO_LDFLAGS="-s -w -X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date '+%b %_d %Y, %H:%M:%S'`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" -go build -ldflags "$GO_LDFLAGS" -o mautrix-signal +MAUTRIX_VERSION=$(cat go.mod | grep 'maunium.net/go/mautrix ' | awk '{ print $2 }') +GO_LDFLAGS="-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date '+%b %_d %Y, %H:%M:%S'`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" +if [ "$DBG" = 1 ]; then + GO_GCFLAGS='all=-N -l' +else + GO_LDFLAGS="-s -w ${GO_LDFLAGS}" +fi +go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal diff --git a/build-rust.sh b/build-rust.sh new file mode 100755 index 0000000..4201bb4 --- /dev/null +++ b/build-rust.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# TODO fix linking with debug library +#if [ "$DBG" != 1 ]; then +# RUST_PROFILE=release +#else +# RUST_PROFILE=dev +#fi +RUST_PROFILE=release +cd pkg/libsignalgo/libsignal && RUSTFLAGS="-Ctarget-feature=-crt-static" RUSTC_WRAPPER="" cargo build -p libsignal-ffi --profile=$RUST_PROFILE diff --git a/docker-run.sh b/docker-run.sh index f4285ed..c760f6b 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -36,8 +36,8 @@ fixperms EXE=/usr/bin/mautrix-signal DLV=/usr/bin/dlv -if [[ -x $DLV ]]; then - if [[ $DBGWAIT -ne 1 ]]; then +if [ -x "$DLV" ]; then + if [ "$DBGWAIT" != 1 ]; then NOWAIT=1 fi EXE="${DLV} exec ${EXE} ${NOWAIT:+--continue --accept-multiclient} --api-version 2 --headless -l :4040" From 8de9493edc39cf7be736172fe91d36f6a805eddc Mon Sep 17 00:00:00 2001 From: David AUFFRAY <31964077+Davidffry@users.noreply.github.com> Date: Sat, 10 Feb 2024 13:37:58 +0100 Subject: [PATCH 079/718] Fix word in example config (#446) --- example-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example-config.yaml b/example-config.yaml index 1a208a4..372d8bb 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -9,7 +9,7 @@ homeserver: # Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here. software: standard # The URL to push real-time bridge status to. - # If set, the bridge will make POST requests to this URL whenever a user's discord connection state changes. + # If set, the bridge will make POST requests to this URL whenever a user's Signal connection state changes. # The bridge will use the appservice as_token to authorize requests. status_endpoint: null # Endpoint for reporting per-message status. From 27d6ae89ea0abd6fa91c839a6d31696d2cd2832d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 28 Jan 2024 15:46:16 +0200 Subject: [PATCH 080/718] Remove some unnecessary logs --- user.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/user.go b/user.go index 7d8aeae..94e09fd 100644 --- a/user.go +++ b/user.go @@ -241,10 +241,7 @@ func (user *User) ensureInvited(ctx context.Context, intent *appservice.IntentAP } customPuppet := user.bridge.GetPuppetByCustomMXID(user.MXID) if customPuppet != nil && customPuppet.CustomIntent() != nil { - log.Debug().Msg("adding will_auto_accept to invite content") extraContent["fi.mau.will_auto_accept"] = true - } else { - log.Debug().Msg("NOT adding will_auto_accept to invite content") } _, err := intent.InviteUser(ctx, roomID, &mautrix.ReqInviteUser{UserID: user.MXID}, extraContent) var httpErr mautrix.HTTPError @@ -262,7 +259,6 @@ func (user *User) ensureInvited(ctx context.Context, intent *appservice.IntentAP } if customPuppet != nil && customPuppet.CustomIntent() != nil { - log.Debug().Msg("ensuring custom puppet is joined") err = customPuppet.CustomIntent().EnsureJoined(ctx, roomID, appservice.EnsureJoinedParams{IgnoreCache: true}) if err != nil { log.Warn().Err(err).Msg("Failed to auto-join custom puppet") From 2109782afdbda3700ca292f98282e437cb45075d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Feb 2024 00:10:04 +0200 Subject: [PATCH 081/718] Remove info parameter in Puppet.UpdateInfo --- portal.go | 10 +++------- puppet.go | 14 ++++++-------- user.go | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/portal.go b/portal.go index 73647e9..8b65643 100644 --- a/portal.go +++ b/portal.go @@ -865,11 +865,7 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg Uint64("msg_ts", msg.GetTimestamp()). Logger().WithContext(context.TODO()) // Always update sender info when we receive a message from them, there's caching inside the function - sender.UpdateInfo( - genericCtx, - source, - nil, - ) + sender.UpdateInfo(genericCtx, source) // Handle earlier missed group changes here. // If this message is a group change, don't handle it here, it's handled below. if msg.GetGroupV2().GetGroupChange() == nil && portal.Revision < msg.GetGroupV2().GetRevision() { @@ -1487,7 +1483,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev var groupInfo *signalmeow.Group if portal.IsPrivateChat() { dmPuppet = portal.GetDMPuppet() - dmPuppet.UpdateInfo(ctx, user, nil) + dmPuppet.UpdateInfo(ctx, user) portal.UpdateDMInfo(ctx, false) } else { groupInfo = portal.UpdateGroupInfo(ctx, user, nil, groupRevision, true) @@ -1797,7 +1793,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * log.Warn().Stringer("signal_user_id", member.UserID).Msg("Couldn't get puppet for group member") continue } - puppet.UpdateInfo(ctx, source, nil) + puppet.UpdateInfo(ctx, source) intent := puppet.IntentFor(portal) userIDs = append(userIDs, intent.UserID) if portal.MXID != "" { diff --git a/puppet.go b/puppet.go index 82777aa..34f08ee 100644 --- a/puppet.go +++ b/puppet.go @@ -232,20 +232,18 @@ func (puppet *Puppet) GetAvatarURL() id.ContentURI { return puppet.AvatarURL } -func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, info *types.Contact) { +func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { log := zerolog.Ctx(ctx).With(). Str("function", "Puppet.UpdateInfo"). Stringer("signal_user_id", puppet.SignalID). Logger() ctx = log.WithContext(ctx) var err error - if info == nil { - log.Debug().Msg("Fetching contact info to update puppet") - info, err = source.Client.ContactByID(ctx, puppet.SignalID) - if err != nil { - log.Err(err).Msg("Failed to fetch contact info") - return - } + log.Debug().Msg("Fetching contact info to update puppet") + info, err := source.Client.ContactByID(ctx, puppet.SignalID) + if err != nil { + log.Err(err).Msg("Failed to fetch contact info") + return } log.Trace().Msg("Updating puppet info") diff --git a/user.go b/user.go index 94e09fd..6f8732e 100644 --- a/user.go +++ b/user.go @@ -742,7 +742,7 @@ func (user *User) handleContactList(evt *events.ContactList) { if puppet == nil { return } - puppet.UpdateInfo(ctx, user, contact) + puppet.UpdateInfo(ctx, user) } } From 53547f9201cb60f4196573589a31a718b55b29c3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Feb 2024 00:10:12 +0200 Subject: [PATCH 082/718] Revert "Check dm.Quote for nil" This reverts commit cb0412075769a360aea7caa7f071648a99e377c5. --- msgconv/from-signal.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index 9b2c917..e73ea0f 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -33,7 +33,6 @@ import ( "golang.org/x/exp/slices" "maunium.net/go/mautrix/crypto/attachment" "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/msgconv/signalfmt" "go.mau.fi/mautrix-signal/pkg/signalmeow" @@ -139,11 +138,7 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa }, }) } - var replyTo id.EventID - var sender id.UserID - if dm.Quote != nil { - replyTo, sender = mc.GetMatrixReply(ctx, dm.Quote) - } + replyTo, sender := mc.GetMatrixReply(ctx, dm.Quote) for _, part := range cm.Parts { if part.Content.Mentions == nil { part.Content.Mentions = &event.Mentions{} From c9d97fd1e522714b5cb795a0a71ba5e19bede8a0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Feb 2024 14:23:31 +0200 Subject: [PATCH 083/718] Run actions on Go 1.21 and 1.22 --- .github/workflows/go.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 844bdba..558ac4f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -5,13 +5,19 @@ on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + go-version: ["1.21", "1.22"] + name: Lint ${{ matrix.go-version == '1.22' && '(latest)' || '(old)' }} + steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: ${{ matrix.go-version }} cache: true - name: Install libolm @@ -31,7 +37,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.20", "1.21"] + go-version: ["1.21", "1.22"] + name: Test ${{ matrix.go-version == '1.22' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 From 9495ea70206aebd74d8e0050c79fa59d70ea5d30 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Feb 2024 14:24:43 +0200 Subject: [PATCH 084/718] Update dependencies and minimum Go version --- go.mod | 22 +++++++++++----------- go.sum | 47 ++++++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index a810ac3..162816c 100644 --- a/go.mod +++ b/go.mod @@ -1,27 +1,27 @@ module go.mau.fi/mautrix-signal -go 1.20 +go 1.21 require ( github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 - github.com/google/uuid v1.5.0 + github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/lib/pq v1.10.9 github.com/mattn/go-pointer v0.0.1 - github.com/mattn/go-sqlite3 v1.14.19 + github.com/mattn/go-sqlite3 v1.14.22 github.com/prometheus/client_golang v1.18.0 - github.com/rs/zerolog v1.31.0 + github.com/rs/zerolog v1.32.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.0 - go.mau.fi/util v0.3.0 - golang.org/x/crypto v0.18.0 - golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 - golang.org/x/net v0.20.0 + go.mau.fi/util v0.3.1-0.20240209114727-da0b16df0446 + golang.org/x/crypto v0.19.0 + golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 + golang.org/x/net v0.21.0 google.golang.org/protobuf v1.32.0 maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.17.0 + maunium.net/go/mautrix v0.17.1-0.20240209185014-2f279590facc nhooyr.io/websocket v1.8.10 ) @@ -43,9 +43,9 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.6.0 // indirect + github.com/yuin/goldmark v1.7.0 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index e9ba207..bd1b5df 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ -github.com/DATA-DOG/go-sqlmock v1.5.1 h1:FK6RCIUSfmbnI/imIICmboyQBkOckutaa6R5YYlLZyo= +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/beeper/libserv v0.0.0-20231231202820-c7303abfc32c h1:WqjRVgUO039eiISCjsZC4F9onOEV93DJAk6v33rsZzY= github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c/go.mod h1:b9FFm9y4mEm36G8ytVmS1vkNzJa0KepmcdVY+qf7qRU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -14,13 +15,15 @@ github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHC github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -32,8 +35,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/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.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= -github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -48,10 +51,11 @@ github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGy github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= 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= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= -github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -65,27 +69,28 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/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.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= -github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mau.fi/util v0.3.0 h1:Lt3lbRXP6ZBqTINK0EieRWor3zEwwwrDT14Z5N8RUCs= -go.mau.fi/util v0.3.0/go.mod h1:9dGsBCCbZJstx16YgnVMVi3O2bOizELoKpugLD4FoGs= +github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= +github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.mau.fi/util v0.3.1-0.20240209114727-da0b16df0446 h1:goGC5wdUKIAdD/rMcA282viTTwUzvLwI/94cxYaKAjI= +go.mau.fi/util v0.3.1-0.20240209114727-da0b16df0446/go.mod h1:rRypwgXVEPILomtFPyQcnbOeuRqf+nRN84vh/CICq4w= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -94,7 +99,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.17.0 h1:scc1qlUbzPn+wc+3eAPquyD+3gZwwy/hBANBm+iGKK8= -maunium.net/go/mautrix v0.17.0/go.mod h1:j+puTEQCEydlVxhJ/dQP5chfa26TdvBO7X6F3Ataav8= +maunium.net/go/mautrix v0.17.1-0.20240209185014-2f279590facc h1:SFyBhMlBL3z97WGWKj1bbKiipoZ3PGq8Vwou96APg0Q= +maunium.net/go/mautrix v0.17.1-0.20240209185014-2f279590facc/go.mod h1:tMIBWuMXrtjXAqMtaD1VHiT0B3TCxraYlqtncLIyKF0= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From b21ad301805653095c338a02de59eb9f2856e7cc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Feb 2024 14:38:56 +0200 Subject: [PATCH 085/718] Allow custom parameters to build-go.sh --- build-go.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-go.sh b/build-go.sh index 89cf0b0..ecf8907 100755 --- a/build-go.sh +++ b/build-go.sh @@ -6,4 +6,4 @@ if [ "$DBG" = 1 ]; then else GO_LDFLAGS="-s -w ${GO_LDFLAGS}" fi -go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal +go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal "$@" From d778a14fba2da50758e45928c89aba4093ccbf5a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 25 Jan 2024 15:52:51 +0200 Subject: [PATCH 086/718] Add license exceptions --- LICENSE.exceptions | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 LICENSE.exceptions diff --git a/LICENSE.exceptions b/LICENSE.exceptions new file mode 100644 index 0000000..6beefaa --- /dev/null +++ b/LICENSE.exceptions @@ -0,0 +1,15 @@ +The mautrix-signal developers grant the following special exceptions: + +* to Beeper the right to embed the program in the Beeper clients and servers, + and use and distribute the collective work without applying the license to + the whole. +* to Element the right to distribute compiled binaries of the program as a part + of the Element Server Suite and other server bundles without applying the + license. + +All exceptions are only valid under the condition that any modifications to +the source code of mautrix-signal (including signalmeow and libsignalgo) remain +publicly available under the terms of the GNU AGPL version 3 or later. + +Note: mautrix-signal depends on libsignal, which is also licensed under the AGPL. +A license exception for libsignal must be acquired separately from Signal. From ed4a14811aff36aa1b6f02aeec310e6b627cc5ce Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Sun, 11 Feb 2024 17:17:52 +0100 Subject: [PATCH 087/718] Handle group changes properly (#432) Handle the actual changes instead of resyncing the whole group when something changes --- config/bridge.go | 1 + config/upgrade.go | 1 + example-config.yaml | 3 + pkg/libsignalgo/verifysignature.go | 46 +++ pkg/signalmeow/groups.go | 446 ++++++++++++++++++++++++++++- portal.go | 307 ++++++++++++++++++-- 6 files changed, 777 insertions(+), 27 deletions(-) create mode 100644 pkg/libsignalgo/verifysignature.go diff --git a/config/bridge.go b/config/bridge.go index 521c56d..5adc635 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -48,6 +48,7 @@ type BridgeConfig struct { MessageErrorNotices bool `yaml:"message_error_notices"` SyncDirectChatList bool `yaml:"sync_direct_chat_list"` ResendBridgeInfo bool `yaml:"resend_bridge_info"` + PublicPortals bool `yaml:"public_portals"` CaptionInMessage bool `yaml:"caption_in_message"` FederateRooms bool `yaml:"federate_rooms"` diff --git a/config/upgrade.go b/config/upgrade.go index ba0daf9..eb924d2 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -93,6 +93,7 @@ func DoUpgrade(helper *up.Helper) { helper.Copy(up.Bool, "bridge", "message_error_notices") helper.Copy(up.Bool, "bridge", "sync_direct_chat_list") helper.Copy(up.Bool, "bridge", "resend_bridge_info") + helper.Copy(up.Bool, "bridge", "public_portals") helper.Copy(up.Bool, "bridge", "caption_in_message") helper.Copy(up.Bool, "bridge", "federate_rooms") helper.Copy(up.Map, "bridge", "double_puppet_server_map") diff --git a/example-config.yaml b/example-config.yaml index 372d8bb..87f5a34 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -131,6 +131,9 @@ bridge: # Set this to true to tell the bridge to re-send m.bridge events to all rooms on the next run. # This field will automatically be changed back to false after it, except if the config file is not writable. resend_bridge_info: false + # Whether or not to make portals of groups that don't need approval of an admin to join by invite + # link publicly joinable on Matrix. + public_portals: false # Send captions in the same message as images. This will send data compatible with both MSC2530. # This is currently not supported in most clients. caption_in_message: false diff --git a/pkg/libsignalgo/verifysignature.go b/pkg/libsignalgo/verifysignature.go new file mode 100644 index 0000000..69d354e --- /dev/null +++ b/pkg/libsignalgo/verifysignature.go @@ -0,0 +1,46 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2023 Scott Weber +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#cgo LDFLAGS: -lsignal_ffi -ldl -lm +#include "./libsignal-ffi.h" +#include +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type NotarySignature [C.SignalSIGNATURE_LEN]byte + +func ServerPublicParamsVerifySignature( + serverPublicParams ServerPublicParams, + messageBytes []byte, + NotarySignature NotarySignature, +) error { + c_notarySignature := (*[C.SignalSIGNATURE_LEN]C.uint8_t)(unsafe.Pointer(&NotarySignature[0])) + c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) + signalFfiError := C.signal_server_public_params_verify_signature( + c_serverPublicParams, + BytesToBuffer(messageBytes), + c_notarySignature, + ) + runtime.KeepAlive(messageBytes) + return wrapError(signalFfiError) +} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index d485264..ff93789 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -40,6 +40,11 @@ import ( type GroupMemberRole int32 +type GroupAvatarMeta interface { + getGroupMasterKey() types.SerializedGroupMasterKey + GetAvatarPath() *string +} + const ( // Note: right now we assume these match the equivalent values in the protobuf (signalpb.Member_Role) GroupMember_UNKNOWN GroupMemberRole = 0 @@ -47,6 +52,16 @@ const ( GroupMember_ADMINISTRATOR GroupMemberRole = 2 ) +type AccessControl int32 + +const ( + AccessControl_UNKNOWN AccessControl = 0 + AccessControl_ANY AccessControl = 1 + AccessControl_MEMBER AccessControl = 2 + AccessControl_ADMINISTRATOR AccessControl = 3 + AccessControl_UNSATISFIABLE AccessControl = 4 +) + type GroupMember struct { UserID uuid.UUID Role GroupMemberRole @@ -74,6 +89,90 @@ type Group struct { //BannedMembers []*BannedMember } +func (group *Group) getGroupMasterKey() types.SerializedGroupMasterKey { + return group.groupMasterKey +} +func (group *Group) GetAvatarPath() *string { + return &group.AvatarPath +} + +type AddMember struct { + GroupMember + JoinFromInviteLink bool +} + +type PendingMember struct { + GroupMember + AddedByUserID uuid.UUID + Timestamp uint64 +} + +type ProfileKeyMember struct { + UserID uuid.UUID + ProfileKey libsignalgo.ProfileKey + //Presentation []byte +} + +type RequestingMember struct { + UserID uuid.UUID + ProfileKey libsignalgo.ProfileKey + Timestamp uint64 + //Presentation []byte +} + +type PromotePniAciMember struct { + UserID uuid.UUID + ProfileKey libsignalgo.ProfileKey + PNI uuid.UUID + //Presentation []byte +} + +type RoleMember struct { + UserID uuid.UUID + Role GroupMemberRole +} + +type BannedMember struct { + UserID uuid.UUID + Timestamp uint64 +} + +type GroupChange struct { + groupMasterKey types.SerializedGroupMasterKey + + Revision uint32 + AddMembers []*AddMember + DeleteMembers []*uuid.UUID + ModifyMemberRoles []*RoleMember + ModifyMemberProfileKeys []*ProfileKeyMember + AddPendingMembers []*PendingMember + DeletePendingMembers []*uuid.UUID + PromotePendingMembers []*ProfileKeyMember + ModifyTitle *string + ModifyAvatar *string + ModifyDisappearingMessagesDuration *uint32 + ModifyAttributesAccess *AccessControl + ModifyMemberAccess *AccessControl + ModifyAddFromInviteLinkAccess *AccessControl + AddRequestingMembers []*RequestingMember + DeleteRequestingMembers []*uuid.UUID + PromoteRequestingMembers []*RoleMember + ModifyDescription *string + ModifyAnnouncementsOnly *bool + AddBannedMembers []*BannedMember + DeleteBannedMembers []*uuid.UUID + //PromotePendingPniAciMembers []*PromotePniAciMember + //ModifyInviteLinkPassword []byte +} + +func (groupChange *GroupChange) getGroupMasterKey() types.SerializedGroupMasterKey { + return groupChange.groupMasterKey +} + +func (groupChange *GroupChange) GetAvatarPath() *string { + return groupChange.ModifyAvatar +} + type GroupAuth struct { Username string Password string @@ -401,14 +500,16 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier return group, nil } -func (cli *Client) DownloadGroupAvatar(ctx context.Context, group *Group) ([]byte, error) { +func (cli *Client) DownloadGroupAvatar(ctx context.Context, group GroupAvatarMeta) ([]byte, error) { + groupMasterKey := group.getGroupMasterKey() + avatarPath := group.GetAvatarPath() username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, Username: &username, Password: &password, } - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, group.AvatarPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, *avatarPath, opts) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } @@ -420,7 +521,7 @@ func (cli *Client) DownloadGroupAvatar(ctx context.Context, group *Group) ([]byt return nil, fmt.Errorf("failed to read response: %w", err) } - decrypted, err := decryptGroupAvatar(encryptedAvatar, group.groupMasterKey) + decrypted, err := decryptGroupAvatar(encryptedAvatar, groupMasterKey) if err != nil { return nil, fmt.Errorf("failed to decrypt avatar: %w", err) } @@ -494,3 +595,342 @@ type GroupCache struct { lastFetched map[types.GroupIdentifier]time.Time activeCalls map[types.GroupIdentifier]string } + +func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalpb.GroupContextV2) (*GroupChange, error) { + masterKeyBytes := libsignalgo.GroupMasterKey(groupContext.MasterKey) + groupMasterKey := masterKeyFromBytes(masterKeyBytes) + log := zerolog.Ctx(ctx).With().Str("action", "decrypt group change").Logger() + + encryptedGroupChange := &signalpb.GroupChange{} + + groupChangeBytes := groupContext.GroupChange + err := proto.Unmarshal(groupChangeBytes, encryptedGroupChange) + if err != nil { + return nil, fmt.Errorf("Error unmarshalling group change: %w", err) + } + serverSignature := encryptedGroupChange.ServerSignature + encryptedActionsBytes := encryptedGroupChange.Actions + + err = libsignalgo.ServerPublicParamsVerifySignature(prodServerPublicParams, encryptedActionsBytes, libsignalgo.NotarySignature(serverSignature)) + if err != nil { + return nil, fmt.Errorf("Failed to verify Server Signature: %w", err) + } + + encryptedActions := signalpb.GroupChange_Actions{} + + err = proto.Unmarshal(encryptedActionsBytes, &encryptedActions) + if err != nil { + return nil, fmt.Errorf("Error unmashalling group change actions: %w", err) + } + + groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) + if err != nil { + log.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") + return nil, err + } + + decryptedGroupChange := &GroupChange{ + groupMasterKey: groupMasterKey, + Revision: encryptedActions.Revision, + } + + if encryptedActions.ModifyTitle != nil { + titleBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedActions.ModifyTitle.Title) + if err != nil { + return nil, err + } + // The actual title is in the blob + newTitle := cleanupStringProperty(titleBlob.GetTitle()) + decryptedGroupChange.ModifyTitle = &newTitle + } + if encryptedActions.ModifyAvatar != nil { + decryptedGroupChange.ModifyAvatar = &encryptedActions.ModifyAvatar.Avatar + } + if encryptedActions.ModifyDescription != nil { + descriptionBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedActions.ModifyDescription.Description) + if err == nil { + // treat a failure in obtaining the description as non-fatal + newDescription := cleanupStringProperty(descriptionBlob.GetDescription()) + decryptedGroupChange.ModifyDescription = &newDescription + } + } + + for _, addMember := range encryptedActions.AddMembers { + if addMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(addMember.Added.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(addMember.Added.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + decryptedGroupChange.AddMembers = append(decryptedGroupChange.AddMembers, &AddMember{ + GroupMember: GroupMember{ + UserID: userID, + ProfileKey: *profileKey, + Role: GroupMemberRole(addMember.Added.Role), + JoinedAtRevision: addMember.Added.JoinedAtRevision, + }, + JoinFromInviteLink: addMember.JoinFromInviteLink, + }) + err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + if err != nil { + log.Err(err).Msg("failed to store profile key") + return nil, err + } + } + + for _, deleteMember := range encryptedActions.DeleteMembers { + if deleteMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(deleteMember.DeletedUserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &userID) + } + + for _, modifyMemberRole := range encryptedActions.ModifyMemberRoles { + encryptedUserID := libsignalgo.UUIDCiphertext(modifyMemberRole.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.ModifyMemberRoles = append(decryptedGroupChange.ModifyMemberRoles, &RoleMember{ + UserID: userID, + Role: GroupMemberRole(modifyMemberRole.Role), + }) + } + + for _, modifyProfileKey := range encryptedActions.ModifyMemberProfileKeys { + if modifyProfileKey == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(modifyProfileKey.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(modifyProfileKey.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + decryptedGroupChange.ModifyMemberProfileKeys = append(decryptedGroupChange.ModifyMemberProfileKeys, &ProfileKeyMember{ + UserID: userID, + ProfileKey: *profileKey, + }) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + if err != nil { + log.Err(err).Msg("failed to store profile key") + return nil, err + } + } + + for _, addPendingMember := range encryptedActions.AddPendingMembers { + if addPendingMember == nil { + continue + } + pendingMember := addPendingMember.Added + encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(pendingMember.Member.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + encryptedAddedByUserID := pendingMember.AddedByUserId + addedByUserId, err := groupSecretParams.DecryptUUID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) + if err != nil { + log.Err(err).Msg("DecryptUUID addedByUserId error") + return nil, err + } + decryptedGroupChange.AddPendingMembers = append(decryptedGroupChange.AddPendingMembers, &PendingMember{ + GroupMember: GroupMember{ + UserID: userID, + ProfileKey: *profileKey, + Role: GroupMemberRole(pendingMember.Member.Role), + JoinedAtRevision: pendingMember.Member.JoinedAtRevision, + }, + AddedByUserID: addedByUserId, + Timestamp: addPendingMember.Added.Timestamp, + }) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + if err != nil { + log.Err(err).Msg("failed to store profile key") + return nil, err + } + } + + for _, deletePendingMember := range encryptedActions.DeletePendingMembers { + if deletePendingMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(deletePendingMember.DeletedUserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.DeletePendingMembers = append(decryptedGroupChange.DeletePendingMembers, &userID) + } + + for _, promotePendingMember := range encryptedActions.PromotePendingMembers { + if promotePendingMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ + UserID: userID, + ProfileKey: *profileKey, + }) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + if err != nil { + log.Err(err).Msg("failed to store profile key") + return nil, err + } + } + + for _, addRequestingMember := range encryptedActions.AddRequestingMembers { + if addRequestingMember == nil { + continue + } + requestingMember := addRequestingMember.Added + encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + decryptedGroupChange.AddRequestingMembers = append(decryptedGroupChange.AddRequestingMembers, &RequestingMember{ + UserID: userID, + ProfileKey: *profileKey, + Timestamp: addRequestingMember.Added.Timestamp, + }) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + if err != nil { + log.Err(err).Msg("failed to store profile key") + return nil, err + } + } + + for _, deleteRequestingMember := range encryptedActions.DeleteRequestingMembers { + if deleteRequestingMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(deleteRequestingMember.DeletedUserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &userID) + } + + for _, promoteRequestingMember := range encryptedActions.PromoteRequestingMembers { + if promoteRequestingMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(promoteRequestingMember.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.PromoteRequestingMembers = append(decryptedGroupChange.PromoteRequestingMembers, &RoleMember{ + UserID: userID, + Role: GroupMemberRole(promoteRequestingMember.Role), + }) + } + + for _, addBannedMember := range encryptedActions.AddBannedMembers { + if addBannedMember == nil { + continue + } + bannedMember := addBannedMember.Added + encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.AddBannedMembers = append(decryptedGroupChange.AddBannedMembers, &BannedMember{ + UserID: userID, + Timestamp: addBannedMember.Added.Timestamp, + }) + } + + for _, deleteBannedMember := range encryptedActions.DeleteBannedMembers { + if deleteBannedMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(deleteBannedMember.DeletedUserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + decryptedGroupChange.DeleteBannedMembers = append(decryptedGroupChange.DeleteBannedMembers, &userID) + } + + if encryptedActions.ModifyAttributesAccess != nil { + decryptedGroupChange.ModifyAttributesAccess = (*AccessControl)(&encryptedActions.ModifyAttributesAccess.AttributesAccess) + } + + if encryptedActions.ModifyMemberAccess != nil { + decryptedGroupChange.ModifyMemberAccess = (*AccessControl)(&encryptedActions.ModifyMemberAccess.MembersAccess) + } + + if encryptedActions.ModifyAddFromInviteLinkAccess != nil { + decryptedGroupChange.ModifyAddFromInviteLinkAccess = (*AccessControl)(&encryptedActions.ModifyAddFromInviteLinkAccess.AddFromInviteLinkAccess) + } + + if encryptedActions.ModifyAnnouncementsOnly != nil { + decryptedGroupChange.ModifyAnnouncementsOnly = &encryptedActions.ModifyAnnouncementsOnly.AnnouncementsOnly + } + if encryptedActions.ModifyDisappearingMessagesTimer != nil && len(encryptedActions.ModifyDisappearingMessagesTimer.Timer) > 0 { + timerBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedActions.ModifyDisappearingMessagesTimer.Timer) + if err != nil { + return nil, err + } + newDisappaeringMessagesDuration := timerBlob.GetDisappearingMessagesDuration() + decryptedGroupChange.ModifyDisappearingMessagesDuration = &newDisappaeringMessagesDuration + } + + return decryptedGroupChange, nil +} diff --git a/portal.go b/portal.go index 8b65643..925c2ae 100644 --- a/portal.go +++ b/portal.go @@ -895,6 +895,14 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg } } +type groupChangeMemberAction struct { + userID uuid.UUID + membership event.Membership + ensureJoined bool + joinFromInviteLink bool + action string +} + func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, groupMeta *signalpb.GroupContextV2, ts uint64) { log := portal.log.With(). Str("action", "handle signal group change"). @@ -903,8 +911,234 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou Uint32("new_revision", groupMeta.GetRevision()). Logger() ctx := log.WithContext(context.TODO()) - // TODO handle group changes properly - portal.UpdateInfo(ctx, source, nil, groupMeta.GetRevision()) + groupChange, err := source.Client.DecryptGroupChange(ctx, groupMeta) + if err != nil { + log.Err(err).Msg("Handling GroupChange failed") + return + } + if groupChange.Revision <= portal.Revision { + return + } + portal.Revision = groupChange.Revision + if groupChange.ModifyTitle != nil { + portal.updateName(ctx, *groupChange.ModifyTitle, sender) + } + if groupChange.ModifyDescription != nil { + portal.updateTopic(ctx, *groupChange.ModifyDescription, sender) + } + if groupChange.ModifyAvatar != nil { + portal.updateAvatarWithInfo(ctx, source, groupChange, sender) + } + if groupChange.ModifyDisappearingMessagesDuration != nil { + portal.updateExpirationTimer(ctx, *groupChange.ModifyDisappearingMessagesDuration) + } + intent := sender.IntentFor(portal) + modifyRoles := groupChange.ModifyMemberRoles + for _, deleteBannedMember := range groupChange.DeleteBannedMembers { + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteBannedMember, event.MembershipLeave, "unbanned") + if err != nil { + log.Warn().Stringer("signal_user_id", deleteBannedMember).Msg("Couldn't get puppet for unban") + } + } + for _, addMember := range groupChange.AddMembers { + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: addMember.UserID, Role: addMember.Role}) + var puppet *Puppet + if addMember.JoinFromInviteLink { + puppet = portal.bridge.GetPuppetBySignalID(addMember.UserID) + if puppet != nil { + if puppet.customIntent == nil { + user := portal.bridge.GetUserBySignalID(addMember.UserID) + if user != nil { + portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, user.MXID, event.MembershipInvite, "Joined via invite Link") + } + } + _, err = puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") + if errors.Is(err, mautrix.MForbidden) { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipInvite, "Joined via invite Link") + } else if err == nil { + continue + } + } + } else { + puppet, _ = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.UserID, event.MembershipInvite, "added") + } + if puppet != nil { + puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") + } else { + log.Warn().Stringer("signal_user_id", addMember.UserID).Msg("Couldn't get puppet for invite") + } + } + bannedMembers := make(map[uuid.UUID]bool) + for _, addBannedMember := range groupChange.AddBannedMembers { + bannedMembers[addBannedMember.UserID] = true + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addBannedMember.UserID, event.MembershipBan, "banned") + if err != nil { + log.Warn().Stringer("signal_user_id", addBannedMember.UserID).Msg("Couldn't get puppet for ban") + } + } + for _, deleteMember := range groupChange.DeleteMembers { + if bannedMembers[*deleteMember] { + continue + } + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteMember, event.MembershipLeave, "deleted") + if err != nil { + log.Warn().Stringer("signal_user_id", deleteMember).Msg("Couldn't get puppet for removal") + } + } + for _, deletePendingMember := range groupChange.DeletePendingMembers { + if bannedMembers[*deletePendingMember] { + continue + } + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deletePendingMember, event.MembershipLeave, "invite withdrawn") + if err != nil { + log.Warn().Stringer("signal_user_id", deletePendingMember).Msg("Couldn't get puppet for removal") + } + } + for _, deleteRequestingMember := range groupChange.DeleteRequestingMembers { + if bannedMembers[*deleteRequestingMember] { + continue + } + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteRequestingMember, event.MembershipLeave, "request rejected") + if err != nil { + log.Warn().Stringer("signal_user_id", deleteRequestingMember).Msg("Couldn't get puppet for removal") + } + } + for _, promotePendingMember := range groupChange.PromotePendingMembers { + puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promotePendingMember.UserID, event.MembershipInvite, "request accepted") + if err == nil { + puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) + } else { + log.Warn().Stringer("signal_user_id", promotePendingMember.UserID).Msg("Couldn't get puppet for invite") + } + } + for _, addPendingMember := range groupChange.AddPendingMembers { + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addPendingMember.UserID, event.MembershipInvite, "invited") + if err != nil { + log.Warn().Stringer("signal_user_id", addPendingMember.UserID).Msg("Couldn't get puppet for invite") + } + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: addPendingMember.UserID, Role: addPendingMember.Role}) + } + for _, promoteRequestingMember := range groupChange.PromoteRequestingMembers { + puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promoteRequestingMember.UserID, event.MembershipInvite, "accepted") + if err == nil { + err = puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) + if err != nil { + log.Warn().Stringer("signal_user_id", promoteRequestingMember.UserID).Msg("failed to join puppet") + } + } else { + log.Warn().Stringer("signal_user_id", promoteRequestingMember.UserID).Msg("Couldn't get puppet for join") + } + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: promoteRequestingMember.UserID, Role: promoteRequestingMember.Role}) + } + for _, addRequestingMember := range groupChange.AddRequestingMembers { + // sender and target should be the same SignalID + puppet := portal.bridge.GetPuppetBySignalID(addRequestingMember.UserID) + if puppet != nil { + portal.sendMembershipWithPuppet(ctx, sender, puppet.IntentFor(portal).UserID, event.MembershipKnock, "knocked") + } + } + + if groupChange.ModifyAttributesAccess != nil || groupChange.ModifyAnnouncementsOnly != nil || groupChange.ModifyMemberAccess != nil || len(modifyRoles) > 0 { + levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) + if err != nil { + log.Err(err).Msg("Couldn't get power levels") + } else { + for _, modifyRole := range modifyRoles { + puppet := portal.bridge.GetPuppetBySignalID(modifyRole.UserID) + if puppet == nil { + log.Warn().Stringer("signal_user_id", modifyRole.UserID).Msg("Couldn't get puppet for power level change") + continue + } + powerLevel := 0 + if modifyRole.Role == signalmeow.GroupMember_ADMINISTRATOR { + powerLevel = 50 + } + levels.EnsureUserLevel(puppet.IntentFor(portal).UserID, powerLevel) + if puppet.customIntent == nil { + user := portal.bridge.GetUserBySignalID(modifyRole.UserID) + if user != nil { + levels.EnsureUserLevel(user.MXID, powerLevel) + } + } + } + if groupChange.ModifyAnnouncementsOnly != nil { + levels.EventsDefault = 0 + if *groupChange.ModifyAnnouncementsOnly { + levels.EventsDefault = 50 + } + } + if groupChange.ModifyAttributesAccess != nil { + level := 0 + if *groupChange.ModifyAttributesAccess == signalmeow.AccessControl_ADMINISTRATOR { + level = 50 + } + levels.EnsureEventLevel(event.StateRoomName, level) + levels.EnsureEventLevel(event.StateTopic, level) + levels.EnsureEventLevel(event.StateRoomAvatar, level) + } + if groupChange.ModifyMemberAccess != nil { + level := 0 + if *groupChange.ModifyMemberAccess == signalmeow.AccessControl_ADMINISTRATOR { + level = 50 + } + levels.InvitePtr = &level + } + _, err = intent.SetPowerLevels(ctx, portal.MXID, levels) + if errors.Is(err, mautrix.MForbidden) { + _, err = portal.MainIntent().SetPowerLevels(ctx, portal.MXID, levels) + } + if err != nil { + log.Err(err).Msg("Couldn't set power levels") + } + } + } + if groupChange.ModifyAddFromInviteLinkAccess != nil { + joinRule := event.JoinRuleInvite + if *groupChange.ModifyAddFromInviteLinkAccess == signalmeow.AccessControl_ADMINISTRATOR { + joinRule = event.JoinRuleKnock + } else if *groupChange.ModifyAddFromInviteLinkAccess == signalmeow.AccessControl_ANY && portal.bridge.Config.Bridge.PublicPortals { + joinRule = event.JoinRulePublic + } + _, err = intent.SendMassagedStateEvent(ctx, portal.MXID, event.StateJoinRules, "", &event.JoinRulesEventContent{JoinRule: joinRule}, int64(ts)) + if errors.Is(err, mautrix.MForbidden) { + _, err = portal.MainIntent().SendMassagedStateEvent(ctx, portal.MXID, event.StateJoinRules, "", &event.JoinRulesEventContent{JoinRule: joinRule}, int64(ts)) + } + if err != nil { + log.Err(err).Msg("Couldn't set join rule") + } + } + err = portal.Update(ctx) + if err != nil { + log.Err(err).Msg("Failed to save portal in database after processing group change") + } + portal.UpdateBridgeInfo(ctx) +} + +func (portal *Portal) sendMembershipForPuppetAndUser(ctx context.Context, sender *Puppet, target uuid.UUID, membership event.Membership, action string) (puppet *Puppet, err error) { + puppet = portal.bridge.GetPuppetBySignalID(target) + if puppet == nil { + err = fmt.Errorf("couldn't get Puppet for Signal uuid %s", target) + return + } + err = portal.sendMembershipWithPuppet(ctx, sender, puppet.IntentFor(portal).UserID, membership, action) + if puppet.customIntent == nil { + user := portal.bridge.GetUserBySignalID(target) + if user != nil { + err = portal.sendMembershipWithPuppet(ctx, sender, user.MXID, membership, action) + } + } + return +} + +func (portal *Portal) sendMembershipWithPuppet(ctx context.Context, sender *Puppet, target id.UserID, membership event.Membership, action string) (err error) { + _, err = sender.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, target, membership, "") + if errors.Is(err, mautrix.MForbidden) { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, target, membership, fmt.Sprintf("%s by %s", action, sender.GetDisplayname())) + } + if err != nil { + zerolog.Ctx(ctx).Warn().Stringer("Membership Action failed for user", target).Msg(action) + } + return } func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataMessage_Reaction, ts uint64) { @@ -1584,21 +1818,21 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { noteToSelfAvatar := portal.bridge.Config.Bridge.NoteToSelfAvatar.ParseOrIgnore() avatarHash := sha256.Sum256([]byte(noteToSelfAvatar.String())) - update = portal.updateName(ctx, NoteToSelfName) || update + update = portal.updateName(ctx, NoteToSelfName, nil) || update update = portal.updateAvatarWithMXC(ctx, "notetoself", hex.EncodeToString(avatarHash[:]), noteToSelfAvatar) || update } else if portal.shouldSetDMRoomMetadata() { - update = portal.updateName(ctx, puppet.Name) || update + update = portal.updateName(ctx, puppet.Name, nil) || update update = portal.updateAvatarWithMXC(ctx, puppet.AvatarPath, puppet.AvatarHash, puppet.AvatarURL) || update } topic := PrivateChatTopic if portal.bridge.Config.Bridge.NumberInTopic && puppet.Number != "" { topic = fmt.Sprintf("%s with %s", topic, puppet.Number) } - update = portal.updateTopic(ctx, topic) || update + update = portal.updateTopic(ctx, topic, nil) || update if update { err := portal.Update(ctx) if err != nil { - log.Err(err).Msg("Failed to save portal in database after updatin group info") + log.Err(err).Msg("Failed to save portal in database after updating group info") } portal.UpdateBridgeInfo(ctx) } @@ -1643,14 +1877,14 @@ func (portal *Portal) UpdateGroupInfo(ctx context.Context, source *User, info *s portal.Revision = info.Revision update = true } - update = portal.updateName(ctx, info.Title) || update - update = portal.updateTopic(ctx, info.Description) || update - update = portal.updateAvatarWithInfo(ctx, source, info) || update + update = portal.updateName(ctx, info.Title, nil) || update + update = portal.updateTopic(ctx, info.Description, nil) || update + update = portal.updateAvatarWithInfo(ctx, source, info, nil) || update update = portal.updateExpirationTimer(ctx, info.DisappearingMessagesDuration) || update if update { err := portal.Update(ctx) if err != nil { - log.Err(err).Msg("Failed to save portal in database after updatin group info") + log.Err(err).Msg("Failed to save portal in database after updating group info") } portal.UpdateBridgeInfo(ctx) } @@ -1672,14 +1906,21 @@ func (portal *Portal) updateExpirationTimer(ctx context.Context, newExpirationTi return true } -func (portal *Portal) updateName(ctx context.Context, newName string) bool { +func (portal *Portal) updateName(ctx context.Context, newName string, sender *Puppet) bool { if portal.Name == newName && (portal.NameSet || portal.MXID == "") { return false } portal.Name = newName portal.NameSet = false if portal.MXID != "" { - _, err := portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) + intent := portal.MainIntent() + if sender != nil { + intent = sender.IntentFor(portal) + } + _, err := intent.SetRoomName(ctx, portal.MXID, portal.Name) + if errors.Is(err, mautrix.MForbidden) && intent != portal.MainIntent() { + _, err = portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) + } if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to update room name") } else { @@ -1689,14 +1930,21 @@ func (portal *Portal) updateName(ctx context.Context, newName string) bool { return true } -func (portal *Portal) updateTopic(ctx context.Context, newTopic string) bool { +func (portal *Portal) updateTopic(ctx context.Context, newTopic string, sender *Puppet) bool { if portal.Topic == newTopic && (portal.TopicSet || portal.MXID == "") { return false } portal.Topic = newTopic portal.TopicSet = false if portal.MXID != "" { - _, err := portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) + intent := portal.MainIntent() + if sender != nil { + intent = sender.IntentFor(portal) + } + _, err := intent.SetRoomTopic(ctx, portal.MXID, portal.Topic) + if errors.Is(err, mautrix.MForbidden) && intent != portal.MainIntent() { + _, err = portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) + } if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to update room topic") } else { @@ -1706,22 +1954,26 @@ func (portal *Portal) updateTopic(ctx context.Context, newTopic string) bool { return true } -func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, group *signalmeow.Group) bool { +func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, group signalmeow.GroupAvatarMeta, sender *Puppet) bool { // If the avatar path is different, the avatar probably changed - if portal.AvatarPath == group.AvatarPath && + avatarPath := group.GetAvatarPath() + if avatarPath == nil { + return false + } + if portal.AvatarPath == *avatarPath && // If the avatar mxc isn't set, we need to reupload it (except if the avatar is unset in Signal) - (!portal.AvatarURL.IsEmpty() || group.AvatarPath == "") && + (!portal.AvatarURL.IsEmpty() || *avatarPath == "") && // If the avatar isn't set in the room, we need to update the room state (except if there's no Matrix room yet) (portal.AvatarSet || portal.MXID == "") { return false } - if portal.AvatarPath == "" { + if *avatarPath == "" { portal.AvatarPath = "" portal.AvatarSet = false portal.AvatarURL = id.ContentURI{} portal.AvatarHash = "" // Just clear the Matrix room avatar and return - portal.updateAvatarInRoom(ctx) + portal.updateAvatarInRoom(ctx, sender) return true } log := zerolog.Ctx(ctx) @@ -1737,7 +1989,7 @@ func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, gr // No need to change anything else, but save the new path to the database return true } - portal.AvatarPath = group.AvatarPath + portal.AvatarPath = *avatarPath portal.AvatarSet = false portal.AvatarURL = id.ContentURI{} portal.AvatarHash = newAvatarHash @@ -1747,7 +1999,7 @@ func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, gr log.Err(err).Msg("Failed to upload new avatar for portal") } else { portal.AvatarURL = resp.ContentURI - portal.updateAvatarInRoom(ctx) + portal.updateAvatarInRoom(ctx, sender) } return true } @@ -1760,11 +2012,11 @@ func (portal *Portal) updateAvatarWithMXC(ctx context.Context, newAvatarPath, ne portal.AvatarHash = newAvatarHash portal.AvatarURL = newAvatarURI portal.AvatarSet = false - portal.updateAvatarInRoom(ctx) + portal.updateAvatarInRoom(ctx, nil) return true } -func (portal *Portal) updateAvatarInRoom(ctx context.Context) { +func (portal *Portal) updateAvatarInRoom(ctx context.Context, sender *Puppet) { if portal.MXID == "" || portal.AvatarSet { return } @@ -1773,7 +2025,14 @@ func (portal *Portal) updateAvatarInRoom(ctx context.Context) { Str("avatar_hash", portal.AvatarHash). Stringer("avatar_mxc", portal.AvatarURL). Msg("Updating avatar in Matrix room") - _, err := portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) + intent := portal.MainIntent() + if sender != nil { + intent = sender.IntentFor(portal) + } + _, err := intent.SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) + if errors.Is(err, mautrix.MForbidden) && intent != portal.MainIntent() { + _, err = portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) + } if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to update room avatar") } else { From a7a15735c89ee6e1efd9c13b87d3c9afa3297651 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 11 Feb 2024 18:12:34 +0200 Subject: [PATCH 088/718] Update changelog --- CHANGELOG.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ff61f..b00ef60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,15 @@ # v0.5.0 (unreleased) * Rewrote bridge in Go. - * The bridge doesn't use signald anymore. - * All users will have to re-link the bridge. + * To migrate the bridge, simply upgrade in-place. The database and config + will be migrated automatically, although some parts of the config aren't + migrated (e.g. log config). If you prevented the bridge from writing to + the config file, you'll have to temporarily allow it or update it yourself. + * The bridge doesn't use signald anymore, all users will have to re-link the + bridge. signald can be deleted after upgrading. * Primary device mode is no longer supported, signal-cli is recommended if you don't want to use the official Signal mobile apps. - * Some old features are not yet supported (e.g. membership action bridging, - join rules and getting group invite links). + * Some old features are not yet supported (e.g. group management features). * Renamed main branch from `master` to `main`. * Added support for edits and message formatting. From fac25aa36597ecc294332a5c68b0b50c00cc9574 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 13 Feb 2024 19:28:42 +0200 Subject: [PATCH 089/718] Fix signal file reply hack --- portal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portal.go b/portal.go index 925c2ae..1ac7269 100644 --- a/portal.go +++ b/portal.go @@ -831,7 +831,7 @@ func (portal *Portal) GetSignalReply(ctx context.Context, content *event.Message // This is a hack to make Signal iOS and desktop render replies to file messages. // Unfortunately it also makes Signal Desktop show a file icon on replies to text messages. // TODO store file or text flag in database and fill this field only when replying to file messages. - Attachments: make([]*signalpb.DataMessage_Quote_QuotedAttachment, 0), + Attachments: make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1), } } return nil From 024938f9c73aeff720ec964ffbc1f7301a3ef608 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:43:34 +0100 Subject: [PATCH 090/718] Remove unnecessary struct (#452) --- portal.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/portal.go b/portal.go index 1ac7269..979fc34 100644 --- a/portal.go +++ b/portal.go @@ -895,14 +895,6 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg } } -type groupChangeMemberAction struct { - userID uuid.UUID - membership event.Membership - ensureJoined bool - joinFromInviteLink bool - action string -} - func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, groupMeta *signalpb.GroupContextV2, ts uint64) { log := portal.log.With(). Str("action", "handle signal group change"). From 25ba56bf9bf04c4154f5a41b903156207a45c874 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Fri, 16 Feb 2024 17:55:21 +0200 Subject: [PATCH 091/718] Fix things in DB migration Closes #451 Might fix #425 --- database/upgrades/16-refactor-postgres.sql | 27 ++++++++++++++-------- database/upgrades/17-refactor-sqlite.sql | 6 ++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/database/upgrades/16-refactor-postgres.sql b/database/upgrades/16-refactor-postgres.sql index eeca7fa..9ab94e8 100644 --- a/database/upgrades/16-refactor-postgres.sql +++ b/database/upgrades/16-refactor-postgres.sql @@ -18,15 +18,12 @@ ALTER TABLE message ALTER COLUMN part_index SET NOT NULL; ALTER TABLE reaction ADD COLUMN _part_index INTEGER NOT NULL DEFAULT 0; -- Re-add the dropped constraints (but with part index and no chat) +DELETE FROM message + WHERE (sender, timestamp, part_index, signal_receiver) + IN (SELECT DISTINCT sender, timestamp, part_index, signal_receiver FROM message GROUP BY (sender, timestamp, part_index, signal_receiver) HAVING COUNT(*)>1); ALTER TABLE message ADD PRIMARY KEY (sender, timestamp, part_index, signal_receiver); ALTER TABLE message DROP CONSTRAINT IF EXISTS message_signal_chat_id_signal_receiver_fkey; ALTER TABLE message DROP CONSTRAINT IF EXISTS message_signal_chat_id_fkey; -ALTER TABLE message ADD CONSTRAINT message_portal_fkey - FOREIGN KEY (signal_chat_id, signal_receiver) - REFERENCES portal (chat_id, receiver) - ON DELETE CASCADE ON UPDATE CASCADE; -ALTER TABLE reaction ADD CONSTRAINT reaction_message_fkey FOREIGN KEY (msg_author, msg_timestamp, _part_index, signal_receiver) - REFERENCES message (sender, timestamp, part_index, signal_receiver) ON DELETE CASCADE ON UPDATE CASCADE; -- Also update the reaction primary key ALTER TABLE reaction DROP CONSTRAINT reaction_pkey; ALTER TABLE reaction ADD PRIMARY KEY (author, msg_author, msg_timestamp, signal_receiver); @@ -48,13 +45,23 @@ INSERT INTO lost_portals SELECT mxid, chat_id, receiver FROM portal WHERE mxid<> UPDATE portal SET mxid=NULL WHERE mxid=''; ALTER TABLE portal ADD CONSTRAINT portal_mxid_unique UNIQUE(mxid); -- Delete any portals that aren't associated with logged-in users. -DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE uuid IS NOT NULL); +DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE username IS NOT NULL AND uuid IS NOT NULL); +-- CASCADE manually +DELETE FROM message + WHERE (signal_chat_id, signal_receiver) + NOT IN (SELECT DISTINCT signal_chat_id, signal_receiver FROM message WHERE (signal_chat_id, signal_receiver) IN (SELECT DISTINCT chat_id, receiver FROM portal)); +DELETE FROM reaction + WHERE (author, msg_author, msg_timestamp, signal_receiver) + NOT IN (SELECT DISTINCT author, msg_author, msg_timestamp, signal_receiver FROM reaction WHERE (msg_author, msg_timestamp, _part_index, signal_receiver) IN (SELECT DISTINCT sender, timestamp, part_index, signal_receiver FROM message)); -- Change receiver to uuid instead of phone number, also add nil uuid for groups. UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver AND uuid IS NOT NULL LIMIT 1) WHERE receiver<>''; UPDATE portal SET receiver='00000000-0000-0000-0000-000000000000' WHERE receiver=''; --- Drop the foreign keys again to allow changing types (the ON UPDATE CASCADEs are needed for the above step) -ALTER TABLE message DROP CONSTRAINT message_portal_fkey; -ALTER TABLE reaction DROP CONSTRAINT reaction_message_fkey; +-- CASCADE manually +UPDATE message SET signal_receiver=(SELECT uuid FROM "user" WHERE username=signal_receiver AND uuid IS NOT NULL LIMIT 1) WHERE signal_receiver<>''; +UPDATE message SET signal_receiver='00000000-0000-0000-0000-000000000000' WHERE signal_receiver=''; +UPDATE reaction SET signal_receiver=(SELECT uuid FROM "user" WHERE username=signal_receiver AND uuid IS NOT NULL LIMIT 1) WHERE signal_receiver<>''; +UPDATE reaction SET signal_receiver='00000000-0000-0000-0000-000000000000' WHERE signal_receiver=''; +-- Change column types ALTER TABLE portal ALTER COLUMN receiver TYPE uuid USING receiver::uuid; ALTER TABLE message ALTER COLUMN signal_receiver TYPE uuid USING signal_receiver::uuid; ALTER TABLE reaction ALTER COLUMN signal_receiver TYPE uuid USING signal_receiver::uuid; diff --git a/database/upgrades/17-refactor-sqlite.sql b/database/upgrades/17-refactor-sqlite.sql index c1edd5b..58011ce 100644 --- a/database/upgrades/17-refactor-sqlite.sql +++ b/database/upgrades/17-refactor-sqlite.sql @@ -50,6 +50,10 @@ CREATE TABLE reaction_new ( ); +DELETE FROM message + WHERE (sender, timestamp, part_index, signal_receiver) + IN (SELECT sender, timestamp, part_index, signal_receiver FROM message GROUP BY sender, timestamp, part_index, signal_receiver HAVING COUNT(*)>1); + INSERT INTO message_new SELECT sender, CASE WHEN timestamp > 1500000000000000 THEN timestamp / 1000 ELSE timestamp END, @@ -90,7 +94,7 @@ CREATE TABLE lost_portals ( receiver TEXT ); INSERT INTO lost_portals SELECT mxid, chat_id, receiver FROM portal WHERE mxid<>''; -DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE uuid<>''); +DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE username IS NOT NULL AND uuid<>''); UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver AND uuid<>'' LIMIT 1) WHERE receiver<>''; UPDATE portal SET receiver='00000000-0000-0000-0000-000000000000' WHERE receiver=''; DELETE FROM portal WHERE chat_id NOT LIKE '________-____-____-____-____________' AND LENGTH(chat_id) <> 44; From 1d6ea9dcc12d345f6fe8f3034d664c60b93f6b47 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Feb 2024 18:00:53 +0200 Subject: [PATCH 092/718] Bump version to v0.5.0 --- CHANGELOG.md | 2 +- go.mod | 10 +++++----- go.sum | 16 ++++++++-------- main.go | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b00ef60..acce96f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v0.5.0 (unreleased) +# v0.5.0 (2024-02-16) * Rewrote bridge in Go. * To migrate the bridge, simply upgrade in-place. The database and config diff --git a/go.mod b/go.mod index 162816c..59bd60f 100644 --- a/go.mod +++ b/go.mod @@ -14,14 +14,13 @@ require ( github.com/rs/zerolog v1.32.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 - github.com/tidwall/gjson v1.17.0 - go.mau.fi/util v0.3.1-0.20240209114727-da0b16df0446 + github.com/tidwall/gjson v1.17.1 + go.mau.fi/util v0.4.0 golang.org/x/crypto v0.19.0 - golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/net v0.21.0 google.golang.org/protobuf v1.32.0 - maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.17.1-0.20240209185014-2f279590facc + maunium.net/go/mautrix v0.18.0-beta.1 nhooyr.io/websocket v1.8.10 ) @@ -49,4 +48,5 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect + maunium.net/go/maulogger/v2 v2.4.1 // indirect ) diff --git a/go.sum b/go.sum index bd1b5df..8ff1bae 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= -github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -71,14 +71,14 @@ 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.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.3.1-0.20240209114727-da0b16df0446 h1:goGC5wdUKIAdD/rMcA282viTTwUzvLwI/94cxYaKAjI= -go.mau.fi/util v0.3.1-0.20240209114727-da0b16df0446/go.mod h1:rRypwgXVEPILomtFPyQcnbOeuRqf+nRN84vh/CICq4w= +go.mau.fi/util v0.4.0 h1:S2X3qU4pUcb/vxBRfAuZjbrR9xVMAXSjQojNBLPBbhs= +go.mau.fi/util v0.4.0/go.mod h1:leeiHtgVBuN+W9aDii3deAXnfC563iN3WK6BF8/AjNw= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -99,7 +99,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.17.1-0.20240209185014-2f279590facc h1:SFyBhMlBL3z97WGWKj1bbKiipoZ3PGq8Vwou96APg0Q= -maunium.net/go/mautrix v0.17.1-0.20240209185014-2f279590facc/go.mod h1:tMIBWuMXrtjXAqMtaD1VHiT0B3TCxraYlqtncLIyKF0= +maunium.net/go/mautrix v0.18.0-beta.1 h1:YAr4PxmcrJzUHR56p/MLDQ0qS7PsvaqXERAtC4aSkYA= +maunium.net/go/mautrix v0.18.0-beta.1/go.mod h1:1Q8P5C/uNmSBmull6DSqcawpg/E7hcGLQCD+JoU+vUo= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index 18b4ca2..6a8df7d 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.4.99", + Version: "0.5.0", ProtocolName: "Signal", BeeperServiceName: "signal", BeeperNetworkName: "signal", From 616c227219d757179c6f82fbfdbc1906b0f9a9d1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Feb 2024 20:41:01 +0200 Subject: [PATCH 093/718] Fix SQLite db migration. Fixes #454 --- database/upgrades/17-refactor-sqlite.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/upgrades/17-refactor-sqlite.sql b/database/upgrades/17-refactor-sqlite.sql index 58011ce..f55dc0b 100644 --- a/database/upgrades/17-refactor-sqlite.sql +++ b/database/upgrades/17-refactor-sqlite.sql @@ -51,8 +51,8 @@ CREATE TABLE reaction_new ( DELETE FROM message - WHERE (sender, timestamp, part_index, signal_receiver) - IN (SELECT sender, timestamp, part_index, signal_receiver FROM message GROUP BY sender, timestamp, part_index, signal_receiver HAVING COUNT(*)>1); + WHERE (sender, timestamp, signal_receiver) + IN (SELECT sender, timestamp, signal_receiver FROM message GROUP BY sender, timestamp, signal_receiver HAVING COUNT(*)>1); INSERT INTO message_new SELECT sender, From 9c201ca890b2964499c45565c7002533f3270287 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 19 Feb 2024 12:20:02 +0200 Subject: [PATCH 094/718] Update to libsignal 0.40.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 44 ++++++++++++++++++++++++++++----- pkg/libsignalgo/version.go | 2 +- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 5436160..7ef4efd 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 5436160313d4fa43ea225918138866d05f2da6f7 +Subproject commit 7ef4efdb85d8b2ebd77f3cf1e2b542a2115033c5 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 9cac926..dae3999 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -211,6 +211,10 @@ typedef struct SignalKeySecret SignalKeySecret; typedef struct SignalKyberPreKeyRecord SignalKyberPreKeyRecord; +typedef struct SignalMessageBackupKey SignalMessageBackupKey; + +typedef struct SignalMessageBackupValidationOutcome SignalMessageBackupValidationOutcome; + typedef struct SignalNonSuspendingBackgroundThreadRuntime SignalNonSuspendingBackgroundThreadRuntime; typedef struct SignalOtherTestingHandleType SignalOtherTestingHandleType; @@ -268,16 +272,26 @@ typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMe typedef struct SignalValidatingMac SignalValidatingMac; -typedef struct { - const unsigned char *base; - size_t length; -} SignalBorrowedBuffer; - typedef struct { unsigned char *base; size_t length; } SignalOwnedBuffer; +typedef struct { + size_t *base; + size_t length; +} SignalOwnedBufferOfusize; + +typedef struct { + SignalOwnedBuffer bytes; + SignalOwnedBufferOfusize lengths; +} SignalStringArray; + +typedef struct { + const unsigned char *base; + size_t length; +} SignalBorrowedBuffer; + typedef int (*SignalLoadSession)(void *store_ctx, SignalSessionRecord **recordp, const SignalProtocolAddress *address); typedef int (*SignalStoreSession)(void *store_ctx, const SignalProtocolAddress *address, const SignalSessionRecord *record); @@ -458,6 +472,8 @@ void signal_free_string(const char *buf); void signal_free_buffer(const unsigned char *buf, size_t buf_len); +void signal_free_string_array(SignalStringArray array); + SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalProtocolAddress **out); @@ -1190,6 +1206,8 @@ SignalFfiError *signal_group_send_credential_response_check_valid_contents(Signa SignalFfiError *signal_group_send_credential_response_receive(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_aci, uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); +SignalFfiError *signal_group_send_credential_response_receive_with_ciphertexts(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, const unsigned char (*requester)[SignalUUID_CIPHERTEXT_LEN], uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); + SignalFfiError *signal_group_send_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); SignalFfiError *signal_group_send_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); @@ -1236,13 +1254,25 @@ SignalFfiError *signal_validating_mac_update(int32_t *out, SignalValidatingMac * SignalFfiError *signal_validating_mac_finalize(int32_t *out, SignalValidatingMac *mac); +SignalFfiError *signal_message_backup_key_destroy(SignalMessageBackupKey *p); + +SignalFfiError *signal_message_backup_key_new(SignalMessageBackupKey **out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMessageBackupValidationOutcome *p); + +SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, const SignalMessageBackupValidationOutcome *outcome); + +SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, const SignalMessageBackupValidationOutcome *outcome); + +SignalFfiError *signal_message_backup_validator_validate(SignalMessageBackupValidationOutcome **out, const SignalMessageBackupKey *key, const SignalInputStream *first_stream, const SignalInputStream *second_stream, uint64_t len); + SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); SignalFfiError *signal_username_proof(SignalOwnedBuffer *out, const char *username, SignalBorrowedBuffer randomness); SignalFfiError *signal_username_verify(SignalBorrowedBuffer proof, SignalBorrowedBuffer hash); -SignalFfiError *signal_username_candidates_from(const char **out, const char *nickname, uint32_t min_len, uint32_t max_len); +SignalFfiError *signal_username_candidates_from(SignalStringArray *out, const char *nickname, uint32_t min_len, uint32_t max_len); SignalFfiError *signal_username_hash_from_parts(uint8_t (*out)[32], const char *nickname, const char *discriminator, uint32_t min_len, uint32_t max_len); @@ -1340,4 +1370,6 @@ SignalFfiError *signal_testing_error_on_return_async(const void **out, const voi SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); +SignalFfiError *signal_testing_return_string_array(SignalStringArray *out); + #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index ba75e00..605caba 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.39.2" +const Version = "v0.40.0" From dcd134ad8f23bdfb58e540ac218be92701a67986 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Sat, 24 Feb 2024 12:31:04 +0100 Subject: [PATCH 095/718] Handle power levels and other group info in initial sync (#448) --- ROADMAP.md | 14 +-- pkg/signalmeow/groups.go | 227 ++++++++++++++++++++++++------------ portal.go | 246 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 392 insertions(+), 95 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 3899a4a..a060c0d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -52,13 +52,13 @@ * [x] Name * [x] Avatar * [x] Topic - * [ ] Membership actions - * [ ] Join - * [ ] Invite - * [ ] Request join (via invite link, requires a client that supports knocks) - * [ ] Leave - * [ ] Kick/Ban/Unban - * [ ] Group permissions + * [x] Membership actions + * [x] Join + * [x] Invite + * [x] Request join (via invite link, requires a client that supports knocks) + * [x] Leave + * [x] Kick/Ban/Unban + * [x] Group permissions * [x] Typing notifications * [x] Read receipts * [ ] Delivery receipts (there's no good way to bridge these) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index ff93789..4147170 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -81,12 +81,18 @@ type Group struct { AnnouncementsOnly bool Revision uint32 DisappearingMessagesDuration uint32 + AccessControl *GroupAccessControl + PendingMembers []*PendingMember + RequestingMembers []*RequestingMember + BannedMembers []*BannedMember //PublicKey *libsignalgo.PublicKey - //AccessControl *AccessControl - //PendingMembers []*PendingMember - //RequestingMembers []*RequestingMember //InviteLinkPassword []byte - //BannedMembers []*BannedMember +} + +type GroupAccessControl struct { + Members AccessControl + AddFromInviteLink AccessControl + Attributes AccessControl } func (group *Group) getGroupMasterKey() types.SerializedGroupMasterKey { @@ -370,31 +376,62 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast decryptedGroup.Revision = encryptedGroup.Revision // Decrypt members - decryptedGroup.Members = make([]*GroupMember, 0) for _, member := range encryptedGroup.Members { if member == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(member.UserId) + decryptedMember, err := decryptMember(ctx, member, groupSecretParams) + if err != nil { + return nil, err + } + decryptedGroup.Members = append(decryptedGroup.Members, decryptedMember) + } + + for _, pendingMember := range encryptedGroup.PendingMembers { + if pendingMember == nil { + continue + } + decryptedPendingMember, err := decryptPendingMember(ctx, pendingMember, groupSecretParams) + if err != nil { + return nil, err + } + decryptedGroup.PendingMembers = append(decryptedGroup.PendingMembers, decryptedPendingMember) + } + + for _, requestingMember := range encryptedGroup.RequestingMembers { + if requestingMember == nil { + continue + } + decryptedRequestingMember, err := decryptRequestingMember(ctx, requestingMember, groupSecretParams) + if err != nil { + return nil, err + } + decryptedGroup.RequestingMembers = append(decryptedGroup.RequestingMembers, decryptedRequestingMember) + } + + for _, bannedMember := range encryptedGroup.BannedMembers { + if bannedMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error") return nil, err } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(member.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") - return nil, err - } - decryptedGroup.Members = append(decryptedGroup.Members, &GroupMember{ - UserID: userID, - ProfileKey: *profileKey, - Role: GroupMemberRole(member.Role), - JoinedAtRevision: member.JoinedAtRevision, + decryptedGroup.BannedMembers = append(decryptedGroup.BannedMembers, &BannedMember{ + UserID: userID, + Timestamp: bannedMember.Timestamp, }) } + if encryptedGroup.AccessControl != nil { + decryptedGroup.AccessControl = &GroupAccessControl{ + Members: (AccessControl)(encryptedGroup.AccessControl.Members), + Attributes: (AccessControl)(encryptedGroup.AccessControl.Attributes), + AddFromInviteLink: (AccessControl)(encryptedGroup.AccessControl.AddFromInviteLink), + } + } return decryptedGroup, nil } @@ -497,6 +534,18 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier return nil, fmt.Errorf("failed to store profile key: %w", err) } } + for _, pendingMember := range group.PendingMembers { + err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, pendingMember.UserID, pendingMember.ProfileKey) + if err != nil { + return nil, fmt.Errorf("failed to store profile key: %w", err) + } + } + for _, requestingMember := range group.RequestingMembers { + err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, requestingMember.UserID, requestingMember.ProfileKey) + if err != nil { + return nil, fmt.Errorf("failed to store profile key: %w", err) + } + } return group, nil } @@ -659,28 +708,15 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp if addMember == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(addMember.Added.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + decryptedMember, err := decryptMember(ctx, addMember.Added, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") - return nil, err - } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(addMember.Added.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") return nil, err } decryptedGroupChange.AddMembers = append(decryptedGroupChange.AddMembers, &AddMember{ - GroupMember: GroupMember{ - UserID: userID, - ProfileKey: *profileKey, - Role: GroupMemberRole(addMember.Added.Role), - JoinedAtRevision: addMember.Added.JoinedAtRevision, - }, + GroupMember: *decryptedMember, JoinFromInviteLink: addMember.JoinFromInviteLink, }) - err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, decryptedMember.UserID, decryptedMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -745,35 +781,12 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } pendingMember := addPendingMember.Added - encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + decryptedPendingMember, err := decryptPendingMember(ctx, pendingMember, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") return nil, err } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(pendingMember.Member.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") - return nil, err - } - encryptedAddedByUserID := pendingMember.AddedByUserId - addedByUserId, err := groupSecretParams.DecryptUUID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) - if err != nil { - log.Err(err).Msg("DecryptUUID addedByUserId error") - return nil, err - } - decryptedGroupChange.AddPendingMembers = append(decryptedGroupChange.AddPendingMembers, &PendingMember{ - GroupMember: GroupMember{ - UserID: userID, - ProfileKey: *profileKey, - Role: GroupMemberRole(pendingMember.Member.Role), - JoinedAtRevision: pendingMember.Member.JoinedAtRevision, - }, - AddedByUserID: addedByUserId, - Timestamp: addPendingMember.Added.Timestamp, - }) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + decryptedGroupChange.AddPendingMembers = append(decryptedGroupChange.AddPendingMembers, decryptedPendingMember) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, decryptedPendingMember.UserID, decryptedPendingMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -824,25 +837,12 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp if addRequestingMember == nil { continue } - requestingMember := addRequestingMember.Added - encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + decryptedRequestingMember, err := decryptRequestingMember(ctx, addRequestingMember.Added, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") return nil, err } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") - return nil, err - } - decryptedGroupChange.AddRequestingMembers = append(decryptedGroupChange.AddRequestingMembers, &RequestingMember{ - UserID: userID, - ProfileKey: *profileKey, - Timestamp: addRequestingMember.Added.Timestamp, - }) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + decryptedGroupChange.AddRequestingMembers = append(decryptedGroupChange.AddRequestingMembers, decryptedRequestingMember) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, decryptedRequestingMember.UserID, decryptedRequestingMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -891,7 +891,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp } decryptedGroupChange.AddBannedMembers = append(decryptedGroupChange.AddBannedMembers, &BannedMember{ UserID: userID, - Timestamp: addBannedMember.Added.Timestamp, + Timestamp: bannedMember.Timestamp, }) } @@ -934,3 +934,78 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp return decryptedGroupChange, nil } + +func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretParams libsignalgo.GroupSecretParams) (*GroupMember, error) { + log := zerolog.Ctx(ctx) + encryptedUserID := libsignalgo.UUIDCiphertext(member.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(member.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + return &GroupMember{ + UserID: userID, + ProfileKey: *profileKey, + Role: GroupMemberRole(member.Role), + JoinedAtRevision: member.JoinedAtRevision, + }, err +} + +func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMember, groupSecretParams libsignalgo.GroupSecretParams) (*PendingMember, error) { + log := zerolog.Ctx(ctx) + encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(pendingMember.Member.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + encryptedAddedByUserID := pendingMember.AddedByUserId + addedByUserId, err := groupSecretParams.DecryptUUID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) + if err != nil { + log.Err(err).Msg("DecryptUUID addedByUserId error") + return nil, err + } + return &PendingMember{ + GroupMember: GroupMember{ + UserID: userID, + ProfileKey: *profileKey, + Role: GroupMemberRole(pendingMember.Member.Role), + JoinedAtRevision: pendingMember.Member.JoinedAtRevision, + }, + AddedByUserID: addedByUserId, + Timestamp: pendingMember.Timestamp, + }, nil +} + +func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.RequestingMember, groupSecretParams libsignalgo.GroupSecretParams) (*RequestingMember, error) { + log := zerolog.Ctx(ctx) + encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, err + } + return &RequestingMember{ + UserID: userID, + ProfileKey: *profileKey, + Timestamp: requestingMember.Timestamp, + }, nil +} diff --git a/portal.go b/portal.go index 979fc34..9661e6c 100644 --- a/portal.go +++ b/portal.go @@ -1717,7 +1717,9 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev portal.log.Error().Msg("Didn't get group info after updating portal") return errors.New("failed to get group info") } - invite = append(invite, portal.SyncParticipants(ctx, user, groupInfo)...) + for member := range portal.SyncParticipants(ctx, user, groupInfo) { + invite = append(invite, member) + } } req := &mautrix.ReqCreateRoom{ @@ -1790,7 +1792,8 @@ func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *s } groupInfo = portal.UpdateGroupInfo(ctx, source, groupInfo, revision, false) if groupInfo != nil { - portal.SyncParticipants(ctx, source, groupInfo) + members := portal.SyncParticipants(ctx, source, groupInfo) + portal.updatePowerLevelsAndJoinRule(ctx, groupInfo, members) } } @@ -1830,6 +1833,77 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { } } +func (portal *Portal) updatePowerLevelsAndJoinRule(ctx context.Context, info *signalmeow.Group, members map[id.UserID]int) { + log := zerolog.Ctx(ctx).With(). + Str("function", "updatePowerLevelsAndJoinRule"). + Logger() + log.Trace().Msg("Updating power levels and join rule") + joinRuleContent := event.JoinRulesEventContent{} + err := portal.MainIntent().StateEvent(ctx, portal.MXID, event.StateJoinRules, "", &joinRuleContent) + if err != nil { + log.Err(err).Msg("Failed to get join rule") + return + } + joinRule := joinRuleContent.JoinRule + newJoinRule := event.JoinRuleInvite + levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) + if err != nil { + log.Err(err).Msg("Failed to get power levels") + return + } + botLevel := levels.GetUserLevel(portal.MainIntent().UserID) + changed := false + for mxid, level := range members { + oldLevel := levels.GetUserLevel(mxid) + difference := oldLevel - level + if oldLevel < botLevel && (difference < 0 || difference > 49) { + changed = levels.EnsureUserLevel(mxid, level) || changed + } + } + newEventsDefault := 0 + if info.AnnouncementsOnly { + newEventsDefault = 50 + } + if newEventsDefault != levels.EventsDefault { + levels.EventsDefault = newEventsDefault + changed = true + } + if info.AccessControl != nil { + level := 0 + if info.AccessControl.Attributes == signalmeow.AccessControl_ADMINISTRATOR { + level = 50 + } + changed = levels.EnsureEventLevel(event.StateRoomName, level) || changed + changed = levels.EnsureEventLevel(event.StateTopic, level) || changed + changed = levels.EnsureEventLevel(event.StateRoomAvatar, level) || changed + level = 0 + if info.AccessControl.Members == signalmeow.AccessControl_ADMINISTRATOR { + level = 50 + } + if levels.InvitePtr == nil || *levels.InvitePtr != level { + levels.InvitePtr = &level + changed = true + } + if info.AccessControl.AddFromInviteLink == signalmeow.AccessControl_ADMINISTRATOR { + newJoinRule = event.JoinRuleKnock + } else if info.AccessControl.AddFromInviteLink == signalmeow.AccessControl_ANY && (portal.bridge.Config.Bridge.PublicPortals || joinRule == event.JoinRulePublic) { + newJoinRule = event.JoinRulePublic + } + } + if newJoinRule != joinRule { + _, err = portal.MainIntent().SendStateEvent(ctx, portal.MXID, event.StateJoinRules, "", &event.JoinRulesEventContent{JoinRule: joinRule}) + if err != nil { + log.Err(err).Msg("Failed to set join rule") + } + } + if changed { + _, err = portal.MainIntent().SetPowerLevels(ctx, portal.MXID, levels) + if err != nil { + log.Err(err).Msg("Failed to set power levels") + } + } +} + func (portal *Portal) UpdateGroupInfo(ctx context.Context, source *User, info *signalmeow.Group, revision uint32, forceFetch bool) *signalmeow.Group { logWith := zerolog.Ctx(ctx).With(). Str("function", "UpdateGroupInfo"). @@ -2032,13 +2106,23 @@ func (portal *Portal) updateAvatarInRoom(ctx context.Context, sender *Puppet) { } } -func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info *signalmeow.Group) []id.UserID { +func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info *signalmeow.Group) map[id.UserID]int { log := zerolog.Ctx(ctx) - userIDs := make([]id.UserID, 0, len(info.Members)) - for _, member := range info.Members { - if member.UserID == source.SignalID { - continue + userIDs := make(map[id.UserID]int) + currentMembers := make(map[id.UserID]event.Membership) + var err error + if portal.MXID != "" { + memberEventData, err := portal.MainIntent().Members(ctx, portal.MXID, mautrix.ReqMembers{}) + if err != nil { + log.Err(err).Msg("couldn't get portal members") + return nil } + for _, evt := range memberEventData.Chunk { + evt.Content.ParseRaw(event.StateMember) + currentMembers[id.UserID(*evt.StateKey)] = evt.Content.AsMember().Membership + } + } + for _, member := range info.Members { puppet := portal.bridge.GetPuppetBySignalID(member.UserID) if puppet == nil { log.Warn().Stringer("signal_user_id", member.UserID).Msg("Couldn't get puppet for group member") @@ -2046,15 +2130,153 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } puppet.UpdateInfo(ctx, source) intent := puppet.IntentFor(portal) - userIDs = append(userIDs, intent.UserID) + if member.UserID != source.SignalID && portal.MXID != "" { + userIDs[intent.UserID] = ((int)(member.Role) >> 1) * 50 + } + delete(currentMembers, intent.UserID) if portal.MXID != "" { - err := intent.EnsureJoined(ctx, portal.MXID) - if err != nil { - log.Err(err).Stringer("signal_user_id", member.UserID).Msg("Failed to ensure user is joined to portal") + if currentMembers[intent.UserID] != event.MembershipJoin { + err := intent.EnsureJoined(ctx, portal.MXID) + if err != nil { + log.Err(err).Stringer("signal_user_id", member.UserID).Msg("Failed to ensure user is joined to portal") + } + } + if puppet.customIntent == nil { + user := portal.bridge.GetUserBySignalID(member.UserID) + if user != nil { + delete(currentMembers, user.MXID) + userIDs[user.MXID] = ((int)(member.Role) >> 1) * 50 + currentMembership := currentMembers[user.MXID] + if currentMembership == event.MembershipJoin || currentMembership == event.MembershipInvite { + continue + } + user.ensureInvited(ctx, intent, portal.MXID, false) + } + } + } + } + if portal.MXID == "" { + return userIDs + } + for _, pendingMember := range info.PendingMembers { + puppet := portal.bridge.GetPuppetBySignalID(pendingMember.UserID) + if puppet == nil { + log.Warn().Stringer("signal_user_id", pendingMember.UserID).Msg("Couldn't get puppet for group member") + continue + } + mxid := puppet.IntentFor(portal).UserID + membership := currentMembers[mxid] + if membership == event.MembershipJoin || membership == event.MembershipBan { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") + } + } + if membership != event.MembershipInvite { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipInvite, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to invite") + } + } + userIDs[mxid] = ((int)(pendingMember.Role) >> 1) * 50 + delete(currentMembers, mxid) + if puppet.customIntent == nil { + user := portal.bridge.GetUserBySignalID(pendingMember.UserID) + if user == nil { + continue + } + mxid = user.MXID + membership := currentMembers[mxid] + err = nil + if membership == event.MembershipJoin || membership == event.MembershipBan { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") + } + } + if membership != event.MembershipInvite { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipInvite, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to invite") + } + } + userIDs[mxid] = ((int)(pendingMember.Role) >> 1) * 50 + delete(currentMembers, mxid) + } + } + for _, requestingMember := range info.RequestingMembers { + puppet := portal.bridge.GetPuppetBySignalID(requestingMember.UserID) + if puppet == nil { + log.Warn().Stringer("signal_user_id", requestingMember.UserID).Msg("Couldn't get puppet for group member") + continue + } + mxid := puppet.IntentFor(portal).UserID + membership := currentMembers[mxid] + if membership == event.MembershipJoin || membership == event.MembershipBan { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") + } + } + if membership != event.MembershipKnock { + _, err = puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipKnock, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to knock") + } + } + delete(currentMembers, mxid) + } + for _, bannedMember := range info.BannedMembers { + puppet := portal.bridge.GetPuppetBySignalID(bannedMember.UserID) + if puppet == nil { + log.Warn().Stringer("signal_user_id", bannedMember.UserID).Msg("Couldn't get puppet for group member") + continue + } + mxid := puppet.IntentFor(portal).UserID + if currentMembers[mxid] != event.MembershipBan { + _, err := portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipBan, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to ban") + } + } + delete(currentMembers, mxid) + if puppet.customIntent == nil { + user := portal.bridge.GetUserBySignalID(bannedMember.UserID) + if user == nil { + continue + } + mxid = user.MXID + if currentMembers[mxid] != event.MembershipBan { + _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipBan, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to ban") + } + } + delete(currentMembers, mxid) + } + } + for mxid, membership := range currentMembers { + if membership == event.MembershipLeave { + continue + } + puppet := portal.bridge.GetPuppetByMXID(mxid) + if puppet != nil { + _, err := portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") + } + } else { + user := portal.bridge.GetUserByMXIDIfExists(mxid) + if user != nil { + if user.IsLoggedIn() { + _, err := portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") + if err != nil { + log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") + } + } } } } - // TODO kick extra members on Matrix, handle pending and requesting participants on Signal return userIDs } From 51d87f3dc0dbc3d70c90e31821023be89a5a7200 Mon Sep 17 00:00:00 2001 From: Mark Collins Date: Sat, 24 Feb 2024 12:31:20 +0100 Subject: [PATCH 096/718] Fix !wa => !signal in example-config.yaml (#456) --- example-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example-config.yaml b/example-config.yaml index 87f5a34..086d6a5 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -280,7 +280,7 @@ bridge: # Settings for relay mode relay: - # Whether relay mode should be allowed. If allowed, `!wa set-relay` can be used to turn any + # Whether relay mode should be allowed. If allowed, `!signal set-relay` can be used to turn any # authenticated user into a relaybot for that chat. enabled: false # Should only admins be allowed to set themselves as relay users? From 2717c537b6655d35341468bcdeef6d79cd133f03 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Sat, 24 Feb 2024 06:31:40 -0500 Subject: [PATCH 097/718] Restore missing metrics & remove unused ones (#463) Fixes #453 --- metrics.go | 68 +++++++++++------------------------------------------- portal.go | 11 ++++++++- user.go | 9 ++++++++ 3 files changed, 33 insertions(+), 55 deletions(-) diff --git a/metrics.go b/metrics.go index 018b97d..2e76a04 100644 --- a/metrics.go +++ b/metrics.go @@ -20,16 +20,15 @@ import ( "context" "net/http" "runtime/debug" - "strconv" "sync" "time" + "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/zerolog" "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/database" ) @@ -47,9 +46,6 @@ type MetricsHandler struct { signalMessageAge prometheus.Histogram signalMessageHandling *prometheus.HistogramVec countCollection prometheus.Histogram - disconnections *prometheus.CounterVec - incomingRetryReceipts *prometheus.CounterVec - connectionFailures *prometheus.CounterVec puppetCount prometheus.Gauge userCount prometheus.Gauge messageCount prometheus.Gauge @@ -60,16 +56,16 @@ type MetricsHandler struct { unencryptedPrivateCount prometheus.Gauge connected prometheus.Gauge - connectedState map[string]bool + connectedState map[uuid.UUID]bool connectedStateLock sync.Mutex loggedIn prometheus.Gauge - loggedInState map[string]bool + loggedInState map[uuid.UUID]bool loggedInStateLock sync.Mutex } func NewMetricsHandler(address string, log zerolog.Logger, db *database.Database) *MetricsHandler { portalCount := promauto.NewGaugeVec(prometheus.GaugeOpts{ - Name: "bridge_portals_total", + Name: "signal_portals_total", Help: "Number of portal rooms on Matrix", }, []string{"type", "encrypted"}) return &MetricsHandler{ @@ -92,31 +88,19 @@ func NewMetricsHandler(address string, log zerolog.Logger, db *database.Database Help: "Time spent processing Signal messages", }, []string{"message_type"}), countCollection: promauto.NewHistogram(prometheus.HistogramOpts{ - Name: "bridge_count_collection", + Name: "signal_count_collection", Help: "Time spent collecting the bridge_*_total metrics", }), - disconnections: promauto.NewCounterVec(prometheus.CounterOpts{ - Name: "bridge_disconnections", - Help: "Number of times a Matrix user has been disconnected from Signal", - }, []string{"user_id"}), - connectionFailures: promauto.NewCounterVec(prometheus.CounterOpts{ - Name: "bridge_connection_failures", - Help: "Number of times a connection has failed to Signal", - }, []string{"reason"}), - incomingRetryReceipts: promauto.NewCounterVec(prometheus.CounterOpts{ - Name: "bridge_incoming_retry_receipts", - Help: "Number of times a remote Signal user has requested a retry from the bridge. retry_count = 5 is usually the last attempt (and very likely means a failed message)", - }, []string{"retry_count", "message_found"}), puppetCount: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "bridge_puppets_total", + Name: "signal_puppets_total", Help: "Number of Signal users bridged into Matrix", }), userCount: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "bridge_users_total", + Name: "signal_users_total", Help: "Number of Matrix users using the bridge", }), messageCount: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "bridge_messages_total", + Name: "signal_messages_total", Help: "Number of messages bridged", }), portalCount: portalCount, @@ -129,12 +113,12 @@ func NewMetricsHandler(address string, log zerolog.Logger, db *database.Database Name: "bridge_logged_in", Help: "Bridge users logged into Signal", }), - loggedInState: make(map[string]bool), + loggedInState: make(map[uuid.UUID]bool), connected: promauto.NewGauge(prometheus.GaugeOpts{ Name: "bridge_connected", Help: "Bridge users connected to Signal", }), - connectedState: make(map[string]bool), + connectedState: make(map[uuid.UUID]bool), } } @@ -168,31 +152,7 @@ func (mh *MetricsHandler) TrackSignalMessage(timestamp time.Time, messageType st } } -func (mh *MetricsHandler) TrackDisconnection(userID id.UserID) { - if !mh.running { - return - } - mh.disconnections.With(prometheus.Labels{"user_id": string(userID)}).Inc() -} - -func (mh *MetricsHandler) TrackConnectionFailure(reason string) { - if !mh.running { - return - } - mh.connectionFailures.With(prometheus.Labels{"reason": reason}).Inc() -} - -func (mh *MetricsHandler) TrackRetryReceipt(count int, found bool) { - if !mh.running { - return - } - mh.incomingRetryReceipts.With(prometheus.Labels{ - "retry_count": strconv.Itoa(count), - "message_found": strconv.FormatBool(found), - }).Inc() -} - -func (mh *MetricsHandler) TrackLoginState(signalID string, loggedIn bool) { +func (mh *MetricsHandler) TrackLoginState(signalID uuid.UUID, loggedIn bool) { if !mh.running { return } @@ -203,13 +163,13 @@ func (mh *MetricsHandler) TrackLoginState(signalID string, loggedIn bool) { mh.loggedInState[signalID] = loggedIn if loggedIn { mh.loggedIn.Inc() - } else { + } else if ok { mh.loggedIn.Dec() } } } -func (mh *MetricsHandler) TrackConnectionState(signalID string, connected bool) { +func (mh *MetricsHandler) TrackConnectionState(signalID uuid.UUID, connected bool) { if !mh.running { return } @@ -220,7 +180,7 @@ func (mh *MetricsHandler) TrackConnectionState(signalID string, connected bool) mh.connectedState[signalID] = connected if connected { mh.connected.Inc() - } else { + } else if ok { mh.connected.Dec() } } diff --git a/portal.go b/portal.go index 9661e6c..357a14b 100644 --- a/portal.go +++ b/portal.go @@ -845,18 +845,27 @@ func (portal *Portal) handleSignalMessage(portalMessage portalSignalMessage) { Msg("Couldn't get puppet for message") return } + var msgType string + var timestamp uint64 switch typedEvt := portalMessage.evt.Event.(type) { case *signalpb.DataMessage: + msgType = "data" + timestamp = typedEvt.GetTimestamp() portal.handleSignalDataMessage(portalMessage.user, sender, typedEvt) case *signalpb.TypingMessage: + msgType = "typing" + timestamp = typedEvt.GetTimestamp() portal.handleSignalTypingMessage(sender, typedEvt) case *signalpb.EditMessage: - portal.handleSignalEditMessage(sender, typedEvt.GetTargetSentTimestamp(), typedEvt.GetDataMessage()) + msgType = "edit" + timestamp = typedEvt.GetTargetSentTimestamp() + portal.handleSignalEditMessage(sender, timestamp, typedEvt.GetDataMessage()) default: portal.log.Error(). Type("data_type", typedEvt). Msg("Invalid inner event type inside ChatEvent") } + portal.bridge.Metrics.TrackSignalMessage(time.UnixMilli(int64(timestamp)), msgType) } func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg *signalpb.DataMessage) { diff --git a/user.go b/user.go index 6f8732e..ab36113 100644 --- a/user.go +++ b/user.go @@ -423,6 +423,8 @@ func (user *User) startupTryConnect(retryCount int) { case signalmeow.SignalConnectionEventConnected: user.log.Debug().Msg("Sending Connected BridgeState") user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) + user.bridge.Metrics.TrackConnectionState(user.SignalID, true) + user.bridge.Metrics.TrackLoginState(user.SignalID, true) case signalmeow.SignalConnectionEventDisconnected: user.log.Debug().Msg("Received SignalConnectionEventDisconnected") @@ -472,6 +474,7 @@ func (user *User) startupTryConnect(retryCount int) { } else { user.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) } + user.bridge.Metrics.TrackConnectionState(user.SignalID, false) } } @@ -482,6 +485,8 @@ func (user *User) startupTryConnect(retryCount int) { } else { user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: err.Error()}) } + user.bridge.Metrics.TrackConnectionState(user.SignalID, false) + user.bridge.Metrics.TrackLoginState(user.SignalID, false) user.clearKeysAndDisconnect() if managementRoom := user.GetManagementRoomID(); managementRoom != "" { _, _ = user.bridge.Bot.SendText(ctx, managementRoom, "You've been logged out of Signal") @@ -490,6 +495,7 @@ func (user *User) startupTryConnect(retryCount int) { case signalmeow.SignalConnectionEventError: user.log.Debug().Msg("Sending UnknownError BridgeState") user.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + user.bridge.Metrics.TrackConnectionState(user.SignalID, false) case signalmeow.SignalConnectionCleanShutdown: if user.Client.IsLoggedIn() { @@ -498,6 +504,7 @@ func (user *User) startupTryConnect(retryCount int) { user.log.Debug().Msg("Clean Shutdown, but logged out - Sending BadCredentials BridgeState") user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) } + user.bridge.Metrics.TrackConnectionState(user.SignalID, false) } } }() @@ -569,6 +576,7 @@ func (user *User) saveSignalID(ctx context.Context, id uuid.UUID, number string) Stringer("previous_user", existingUser.MXID). Stringer("signal_uuid", id). Msg("Another user is already logged in with same UUID, logging out previous user") + existingUser.bridge.Metrics.TrackLoginState(user.SignalID, false) _ = existingUser.Disconnect() existingUser.SignalID = uuid.Nil existingUser.SignalUsername = "" @@ -812,6 +820,7 @@ func (user *User) Logout() error { loggedOutDevice, err := user.disconnectNoLock() user.bridge.MeowStore.DeleteDevice(context.TODO(), &loggedOutDevice.Store.DeviceData) user.bridge.GetPuppetByCustomMXID(user.MXID).ClearCustomMXID() + user.bridge.Metrics.TrackLoginState(user.SignalID, false) return err } From a78a88c7412fbf1cbb55525169a9307dacf170e7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 28 Feb 2024 15:21:24 +0200 Subject: [PATCH 098/718] Prevent downgrading ghost user info by default (#464) Fixes #396 Closes #449 --- config/bridge.go | 5 +- config/upgrade.go | 1 + database/puppet.go | 28 +++++---- database/upgrades/00-latest.sql | 7 ++- .../upgrades/20-puppet-profile-fetch-ts.sql | 2 + example-config.yaml | 2 + go.mod | 4 +- go.sum | 8 +-- pkg/libsignalgo/profilekey.go | 12 +++- pkg/signalmeow/contact.go | 57 +++++++------------ pkg/signalmeow/profile.go | 43 +++++++------- pkg/signalmeow/store/contact_store.go | 44 ++++++++------ pkg/signalmeow/store/upgrades/00-latest.sql | 23 ++++---- .../store/upgrades/08-profile-fetch-time.sql | 11 ++++ .../store/upgrades/08-resync-schema-449.sql | 12 ++++ pkg/signalmeow/types/contact.go | 34 +++++++---- puppet.go | 21 +++++-- 17 files changed, 185 insertions(+), 129 deletions(-) create mode 100644 database/upgrades/20-puppet-profile-fetch-ts.sql create mode 100644 pkg/signalmeow/store/upgrades/08-profile-fetch-time.sql create mode 100644 pkg/signalmeow/store/upgrades/08-resync-schema-449.sql diff --git a/config/bridge.go b/config/bridge.go index 5adc635..088d286 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -35,6 +35,7 @@ type BridgeConfig struct { DisplaynameTemplate string `yaml:"displayname_template"` PrivateChatPortalMeta string `yaml:"private_chat_portal_meta"` UseContactAvatars bool `yaml:"use_contact_avatars"` + UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` NumberInTopic bool `yaml:"number_in_topic"` NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` @@ -169,12 +170,12 @@ type DisplaynameParams struct { func (bc BridgeConfig) FormatDisplayname(contact *types.Contact) string { var buffer strings.Builder _ = bc.displaynameTemplate.Execute(&buffer, DisplaynameParams{ - ProfileName: contact.ProfileName, + ProfileName: contact.Profile.Name, ContactName: contact.ContactName, //Username: contact.Username, PhoneNumber: contact.E164, UUID: contact.UUID.String(), - AboutEmoji: contact.ProfileAboutEmoji, + AboutEmoji: contact.Profile.AboutEmoji, }) return buffer.String() } diff --git a/config/upgrade.go b/config/upgrade.go index eb924d2..cb0ab06 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -83,6 +83,7 @@ func DoUpgrade(helper *up.Helper) { } helper.Copy(up.Str, "bridge", "private_chat_portal_meta") helper.Copy(up.Bool, "bridge", "use_contact_avatars") + helper.Copy(up.Bool, "bridge", "use_outdated_profiles") helper.Copy(up.Bool, "bridge", "number_in_topic") helper.Copy(up.Str, "bridge", "note_to_self_avatar") helper.Copy(up.Int, "bridge", "portal_message_buffer") diff --git a/database/puppet.go b/database/puppet.go index 8c300df..99a65ff 100644 --- a/database/puppet.go +++ b/database/puppet.go @@ -19,6 +19,7 @@ package database import ( "context" "database/sql" + "time" "github.com/google/uuid" "go.mau.fi/util/dbutil" @@ -28,7 +29,7 @@ import ( const ( puppetBaseSelect = ` SELECT uuid, number, name, name_quality, avatar_path, avatar_hash, avatar_url, name_set, avatar_set, - contact_info_set, is_registered, custom_mxid, access_token + contact_info_set, is_registered, profile_fetched_at, custom_mxid, access_token FROM puppet ` getPuppetBySignalIDQuery = puppetBaseSelect + `WHERE uuid=$1` @@ -38,18 +39,18 @@ const ( updatePuppetQuery = ` UPDATE puppet SET number=$2, name=$3, name_quality=$4, avatar_path=$5, avatar_hash=$6, avatar_url=$7, - name_set=$8, avatar_set=$9, contact_info_set=$10, is_registered=$11, - custom_mxid=$12, access_token=$13 + name_set=$8, avatar_set=$9, contact_info_set=$10, is_registered=$11, profile_fetched_at=$12, + custom_mxid=$13, access_token=$14 WHERE uuid=$1 ` insertPuppetQuery = ` INSERT INTO puppet ( uuid, number, name, name_quality, avatar_path, avatar_hash, avatar_url, - name_set, avatar_set, contact_info_set, is_registered, + name_set, avatar_set, contact_info_set, is_registered, profile_fetched_at, custom_mxid, access_token ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14 ) ` ) @@ -71,11 +72,12 @@ type Puppet struct { NameSet bool AvatarSet bool - IsRegistered bool + IsRegistered bool + ContactInfoSet bool + ProfileFetchedAt time.Time - CustomMXID id.UserID - AccessToken string - ContactInfoSet bool + CustomMXID id.UserID + AccessToken string } func newPuppet(qh *dbutil.QueryHelper[*Puppet]) *Puppet { @@ -100,6 +102,7 @@ func (pq *PuppetQuery) GetAllWithCustomMXID(ctx context.Context) ([]*Puppet, err func (p *Puppet) Scan(row dbutil.Scannable) (*Puppet, error) { var number, customMXID sql.NullString + var profileFetchedAt sql.NullInt64 err := row.Scan( &p.SignalID, &number, @@ -112,14 +115,18 @@ func (p *Puppet) Scan(row dbutil.Scannable) (*Puppet, error) { &p.AvatarSet, &p.ContactInfoSet, &p.IsRegistered, + &profileFetchedAt, &customMXID, &p.AccessToken, ) if err != nil { - return nil, nil + return nil, err } p.Number = number.String p.CustomMXID = id.UserID(customMXID.String) + if profileFetchedAt.Valid { + p.ProfileFetchedAt = time.UnixMilli(profileFetchedAt.Int64) + } return p, nil } @@ -136,6 +143,7 @@ func (p *Puppet) sqlVariables() []any { p.AvatarSet, p.ContactInfoSet, p.IsRegistered, + dbutil.UnixMilliPtr(p.ProfileFetchedAt), dbutil.StrPtr(p.CustomMXID), p.AccessToken, } diff --git a/database/upgrades/00-latest.sql b/database/upgrades/00-latest.sql index ae8e157..4dec3ff 100644 --- a/database/upgrades/00-latest.sql +++ b/database/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v19 (compatible with v17+): Latest revision +-- v0 -> v20 (compatible with v17+): Latest revision CREATE TABLE portal ( chat_id TEXT NOT NULL, @@ -33,8 +33,9 @@ CREATE TABLE puppet ( name_set BOOLEAN NOT NULL DEFAULT false, avatar_set BOOLEAN NOT NULL DEFAULT false, - is_registered BOOLEAN NOT NULL DEFAULT false, - contact_info_set BOOLEAN NOT NULL DEFAULT false, + is_registered BOOLEAN NOT NULL DEFAULT false, + contact_info_set BOOLEAN NOT NULL DEFAULT false, + profile_fetched_at BIGINT, custom_mxid TEXT, access_token TEXT NOT NULL, diff --git a/database/upgrades/20-puppet-profile-fetch-ts.sql b/database/upgrades/20-puppet-profile-fetch-ts.sql new file mode 100644 index 0000000..b398b2f --- /dev/null +++ b/database/upgrades/20-puppet-profile-fetch-ts.sql @@ -0,0 +1,2 @@ +-- v20 (compatible with v17+): Add profile fetch timestamp for puppets +ALTER TABLE puppet ADD profile_fetched_at BIGINT; diff --git a/example-config.yaml b/example-config.yaml index 086d6a5..a509a0c 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -106,6 +106,8 @@ bridge: private_chat_portal_meta: default # Should avatars from the user's contact list be used? This is not safe on multi-user instances. use_contact_avatars: false + # Should the bridge sync ghost user info even if profile fetching fails? This is not safe on multi-user instances. + use_outdated_profiles: false # Should the Signal user's phone number be included in the room topic in private chat portal rooms? number_in_topic: true # Avatar image for the Note to Self room. diff --git a/go.mod b/go.mod index 59bd60f..8e3abaa 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.8.4 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.0 + go.mau.fi/util v0.4.1-0.20240222202553-953608f657a3 golang.org/x/crypto v0.19.0 golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/net v0.21.0 google.golang.org/protobuf v1.32.0 - maunium.net/go/mautrix v0.18.0-beta.1 + maunium.net/go/mautrix v0.18.0-beta.1.0.20240223191208-581aa8015501 nhooyr.io/websocket v1.8.10 ) diff --git a/go.sum b/go.sum index 8ff1bae..db6ca00 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.0 h1:S2X3qU4pUcb/vxBRfAuZjbrR9xVMAXSjQojNBLPBbhs= -go.mau.fi/util v0.4.0/go.mod h1:leeiHtgVBuN+W9aDii3deAXnfC563iN3WK6BF8/AjNw= +go.mau.fi/util v0.4.1-0.20240222202553-953608f657a3 h1:NcRrdzORHKab5bP1Z8BpH0nxsxsvH0iPPZLpOUN+UIc= +go.mau.fi/util v0.4.1-0.20240222202553-953608f657a3/go.mod h1:leeiHtgVBuN+W9aDii3deAXnfC563iN3WK6BF8/AjNw= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= @@ -99,7 +99,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.18.0-beta.1 h1:YAr4PxmcrJzUHR56p/MLDQ0qS7PsvaqXERAtC4aSkYA= -maunium.net/go/mautrix v0.18.0-beta.1/go.mod h1:1Q8P5C/uNmSBmull6DSqcawpg/E7hcGLQCD+JoU+vUo= +maunium.net/go/mautrix v0.18.0-beta.1.0.20240223191208-581aa8015501 h1:3STixn49dd7VXL+p4hW0AEWy5/BeZlgA3i3BVsIgtqM= +maunium.net/go/mautrix v0.18.0-beta.1.0.20240223191208-581aa8015501/go.mod h1:1Q8P5C/uNmSBmull6DSqcawpg/E7hcGLQCD+JoU+vUo= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index 2cd1000..ba43a60 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -35,19 +35,25 @@ type ProfileKeyCommitment [C.SignalPROFILE_KEY_COMMITMENT_LEN]byte type ProfileKeyVersion [C.SignalPROFILE_KEY_VERSION_ENCODED_LEN]byte type AccessKey [C.SignalACCESS_KEY_LEN]byte +var blankProfileKey ProfileKey + +func (pk *ProfileKey) IsEmpty() bool { + return pk == nil || *pk == blankProfileKey +} + func (ak *AccessKey) String() string { - return string((*ak)[:]) + return string(ak[:]) } func (pv *ProfileKeyVersion) String() string { - return string((*pv)[:]) + return string(pv[:]) } func (pk *ProfileKey) Slice() []byte { if pk == nil { return nil } - return (*pk)[:] + return pk[:] } func (pk *ProfileKey) GetCommitment(u uuid.UUID) (*ProfileKeyCommitment, error) { diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index 7682c99..c4eacf2 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -22,6 +22,7 @@ import ( "crypto/sha256" "encoding/binary" "encoding/hex" + "errors" "fmt" "net/http" "strings" @@ -46,27 +47,23 @@ func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDeta Logger() existingContact, err := cli.Store.ContactStore.LoadContact(ctx, parsedUUID) if err != nil { - log.Err(err).Msg("error loading contact") + log.Err(err).Msg("Failed to load contact from database") return nil, err } if existingContact == nil { - log.Debug().Msg("creating new contact") existingContact = &types.Contact{ UUID: parsedUUID, } - } else { - log.Debug().Msg("updating existing contact") } existingContact.E164 = contactDetails.GetNumber() existingContact.ContactName = contactDetails.GetName() if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { profileKey := libsignalgo.ProfileKey(profileKeyString) - existingContact.ProfileKey = &profileKey + existingContact.Profile.Key = profileKey err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, existingContact.UUID, profileKey) if err != nil { - log.Err(err).Msg("storing profile key") - //return *existingContact, nil, err + log.Err(err).Msg("Failed to store profile key from contact") } } @@ -86,10 +83,9 @@ func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDeta } } - log.Debug().Msg("storing contact") storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) if storeErr != nil { - log.Err(storeErr).Msg("error storing contact") + log.Err(storeErr).Msg("Failed to save contact") return existingContact, storeErr } return existingContact, nil @@ -104,7 +100,7 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, existingContact, err := cli.Store.ContactStore.LoadContact(ctx, profileUUID) if err != nil { - log.Err(err).Msg("error loading contact") + log.Err(err).Msg("Failed to load contact from database") return nil, err } if existingContact == nil { @@ -118,38 +114,26 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, } profile, err := cli.RetrieveProfileByID(ctx, profileUUID) if err != nil { - log.Err(err).Msg("error retrieving profile") - //return nil, nil, err - // Don't return here, we still want to return what we have + logLevel := zerolog.ErrorLevel + if errors.Is(err, errProfileKeyNotFound) { + logLevel = zerolog.DebugLevel + } + log.WithLevel(logLevel).Err(err).Msg("Failed to fetch profile") + // Continue to return contact without profile } if profile != nil { - if existingContact.ProfileName != profile.Name { - existingContact.ProfileName = profile.Name - contactChanged = true - } - if existingContact.ProfileAbout != profile.About { - existingContact.ProfileAbout = profile.About - contactChanged = true - } - if existingContact.ProfileAboutEmoji != profile.AboutEmoji { - existingContact.ProfileAboutEmoji = profile.AboutEmoji - contactChanged = true - } - if existingContact.ProfileAvatarPath != profile.AvatarPath { - existingContact.ProfileAvatarPath = profile.AvatarPath - contactChanged = true - } - if existingContact.ProfileKey == nil || *existingContact.ProfileKey != profile.Key { - existingContact.ProfileKey = &profile.Key + // Don't bother saving every fetched timestamp to the database, but save if anything else changed + if !existingContact.Profile.Equals(profile) || existingContact.Profile.FetchedAt.IsZero() { contactChanged = true } + existingContact.Profile = *profile } if contactChanged { - err := cli.Store.ContactStore.StoreContact(ctx, *existingContact) + err = cli.Store.ContactStore.StoreContact(ctx, *existingContact) if err != nil { - log.Err(err).Msg("error storing contact") + log.Err(err).Msg("Failed to save contact") return nil, err } } @@ -164,21 +148,18 @@ func (cli *Client) UpdateContactE164(ctx context.Context, uuid uuid.UUID, e164 s Logger() existingContact, err := cli.Store.ContactStore.LoadContact(ctx, uuid) if err != nil { - log.Err(err).Msg("error loading contact") + log.Err(err).Msg("Failed to load contact from database") return err } if existingContact == nil { - log.Debug().Msg("creating new contact") existingContact = &types.Contact{ UUID: uuid, } - } else { - log.Debug().Msg("found existing contact") } if existingContact.E164 == e164 { return nil } - log.Debug().Msg("e164 changed for contact") + log.Debug().Msg("Contact phone number changed") existingContact.E164 = e164 return cli.Store.ContactStore.StoreContact(ctx, *existingContact) } diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 69cb240..f27db40 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -35,6 +35,7 @@ import ( "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -70,16 +71,8 @@ type ProfileResponse struct { //PaymentAddress []byte `json:"paymentAddress"` } -type Profile struct { - Name string - About string - AboutEmoji string - AvatarPath string - Key libsignalgo.ProfileKey -} - type ProfileCache struct { - profiles map[string]*Profile + profiles map[string]*types.Profile errors map[string]*error lastFetched map[string]time.Time } @@ -118,10 +111,10 @@ func (cli *Client) ProfileKeyForSignalID(ctx context.Context, signalACI uuid.UUI var errProfileKeyNotFound = errors.New("profile key not found") -func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) (*Profile, error) { +func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) (*types.Profile, error) { if cli.ProfileCache == nil { cli.ProfileCache = &ProfileCache{ - profiles: make(map[string]*Profile), + profiles: make(map[string]*types.Profile), errors: make(map[string]*error), lastFetched: make(map[string]time.Time), } @@ -144,6 +137,7 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) // If we get here, we don't have a cached profile, so fetch it profile, err := cli.fetchProfileByID(ctx, signalID) if err != nil { + // TODO this check is wrong and most likely doesn't work, errors shouldn't use string comparisons // If we get a 401 or 5xx error, we should not retry until the cache expires if strings.HasPrefix(err.Error(), "401") || strings.HasPrefix(err.Error(), "5") { cli.ProfileCache.errors[signalID.String()] = &err @@ -151,9 +145,6 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) } return nil, err } - if profile == nil { - return nil, errProfileKeyNotFound - } // If we get here, we have a valid profile, so cache it cli.ProfileCache.profiles[signalID.String()] = profile @@ -162,15 +153,13 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) return profile, nil } -func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*Profile, error) { +func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*types.Profile, error) { log := zerolog.Ctx(ctx) profileKey, err := cli.ProfileKeyForSignalID(ctx, signalID) if err != nil { return nil, fmt.Errorf("error getting profile key: %w", err) - } - if profileKey == nil { - log.Warn().Msg("profileKey is nil") - return nil, nil + } else if profileKey == nil { + return nil, errProfileKeyNotFound } profileKeyVersion, err := profileKey.GetProfileKeyVersion(signalID) @@ -211,7 +200,17 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P if err != nil { return nil, fmt.Errorf("error sending request: %w", err) } - log.Trace().Msg("Got profile response") + var profile types.Profile + profile.FetchedAt = time.Now() + logEvt := log.Trace().Uint32("status_code", resp.GetStatus()) + if logEvt.Enabled() { + if json.Valid(resp.Body) { + logEvt.RawJSON("response_data", resp.Body) + } else { + logEvt.Str("invalid_response_data", base64.StdEncoding.EncodeToString(resp.Body)) + } + } + logEvt.Msg("Got profile response") if *resp.Status < 200 || *resp.Status >= 300 { return nil, fmt.Errorf("error getting profile (unsuccessful status code %d)", *resp.Status) } @@ -220,7 +219,6 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P if err != nil { return nil, fmt.Errorf("error unmarshalling profile response: %w", err) } - var profile Profile if len(profileResponse.Name) > 0 { profile.Name, err = decryptString(profileKey, profileResponse.Name) if err != nil { @@ -241,13 +239,14 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*P return nil, fmt.Errorf("error decrypting profile aboutEmoji: %w", err) } } + // TODO store other metadata fields? profile.AvatarPath = profileResponse.Avatar profile.Key = *profileKey return &profile, nil } -func (cli *Client) DownloadUserAvatar(ctx context.Context, avatarPath string, profileKey *libsignalgo.ProfileKey) ([]byte, error) { +func (cli *Client) DownloadUserAvatar(ctx context.Context, avatarPath string, profileKey libsignalgo.ProfileKey) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go index 2d7247f..f556124 100644 --- a/pkg/signalmeow/store/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -20,6 +20,7 @@ import ( "context" "database/sql" "errors" + "time" "github.com/google/uuid" "go.mau.fi/util/dbutil" @@ -50,7 +51,7 @@ const ( profile_about, profile_about_emoji, profile_avatar_path, - profile_avatar_hash + profile_fetched_at FROM signalmeow_contacts ` getAllContactsOfUserQuery = getAllContactsQuery + `WHERE our_aci_uuid = $1` @@ -68,7 +69,7 @@ const ( profile_about, profile_about_emoji, profile_avatar_path, - profile_avatar_hash + profile_fetched_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ON CONFLICT (our_aci_uuid, aci_uuid) DO UPDATE SET @@ -80,7 +81,7 @@ const ( profile_about = excluded.profile_about, profile_about_emoji = excluded.profile_about_emoji, profile_avatar_path = excluded.profile_avatar_path, - profile_avatar_hash = excluded.profile_avatar_hash + profile_fetched_at = excluded.profile_fetched_at ` upsertContactPhoneQuery = ` INSERT INTO signalmeow_contacts ( @@ -94,9 +95,9 @@ const ( profile_about, profile_about_emoji, profile_avatar_path, - profile_avatar_hash + profile_fetched_at ) - VALUES ($1, $2, $3, '', '', NULL, '', '', '', '', '') + VALUES ($1, $2, $3, '', '', NULL, '', '', '', '', NULL) ON CONFLICT (our_aci_uuid, aci_uuid) DO UPDATE SET e164_number = excluded.e164_number ` @@ -105,26 +106,29 @@ const ( func scanContact(row dbutil.Scannable) (*types.Contact, error) { var contact types.Contact var profileKey []byte + var profileFetchedAt sql.NullInt64 err := row.Scan( &contact.UUID, &contact.E164, &contact.ContactName, &contact.ContactAvatar.Hash, &profileKey, - &contact.ProfileName, - &contact.ProfileAbout, - &contact.ProfileAboutEmoji, - &contact.ProfileAvatarPath, - &contact.ProfileAvatarHash, + &contact.Profile.Name, + &contact.Profile.About, + &contact.Profile.AboutEmoji, + &contact.Profile.AvatarPath, + &profileFetchedAt, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil } else if err != nil { return nil, err } + if profileFetchedAt.Valid { + contact.Profile.FetchedAt = time.UnixMilli(profileFetchedAt.Int64) + } if len(profileKey) != 0 { - profileKeyConverted := libsignalgo.ProfileKey(profileKey) - contact.ProfileKey = &profileKeyConverted + contact.Profile.Key = libsignalgo.ProfileKey(profileKey) } return &contact, err } @@ -146,6 +150,10 @@ func (s *SQLStore) AllContacts(ctx context.Context) ([]*types.Contact, error) { } func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) error { + var profileKey []byte + if contact.Profile.Key.IsEmpty() { + profileKey = contact.Profile.Key[:] + } _, err := s.db.Exec( ctx, upsertContactQuery, @@ -154,12 +162,12 @@ func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) erro contact.E164, contact.ContactName, contact.ContactAvatar.Hash, - contact.ProfileKey.Slice(), - contact.ProfileName, - contact.ProfileAbout, - contact.ProfileAboutEmoji, - contact.ProfileAvatarPath, - contact.ProfileAvatarHash, + profileKey, + contact.Profile.Name, + contact.Profile.About, + contact.Profile.AboutEmoji, + contact.Profile.AvatarPath, + dbutil.UnixMilliPtr(contact.Profile.FetchedAt), ) return err } diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 73d0270..37e6e71 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v6: Latest revision +-- v0 -> v7: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -76,18 +76,17 @@ CREATE TABLE signalmeow_groups ( ); CREATE TABLE signalmeow_contacts ( - our_aci_uuid TEXT NOT NULL, - aci_uuid TEXT NOT NULL, - -- TODO make all fields not null - e164_number TEXT, - contact_name TEXT, - contact_avatar_hash TEXT, + our_aci_uuid TEXT NOT NULL, + aci_uuid TEXT NOT NULL, + e164_number TEXT NOT NULL, + contact_name TEXT NOT NULL, + contact_avatar_hash TEXT NOT NULL, profile_key bytea, - profile_name TEXT, - profile_about TEXT, - profile_about_emoji TEXT, - profile_avatar_path TEXT NOT NULL DEFAULT '', - profile_avatar_hash TEXT, + profile_name TEXT NOT NULL, + profile_about TEXT NOT NULL, + profile_about_emoji TEXT NOT NULL, + profile_avatar_path TEXT NOT NULL, + profile_fetched_at BIGINT, PRIMARY KEY (our_aci_uuid, aci_uuid), FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE diff --git a/pkg/signalmeow/store/upgrades/08-profile-fetch-time.sql b/pkg/signalmeow/store/upgrades/08-profile-fetch-time.sql new file mode 100644 index 0000000..414245c --- /dev/null +++ b/pkg/signalmeow/store/upgrades/08-profile-fetch-time.sql @@ -0,0 +1,11 @@ +-- v6 -> v8: Add profile_fetched_at and make other columns not null +ALTER TABLE signalmeow_contacts DROP COLUMN profile_avatar_hash; +ALTER TABLE signalmeow_contacts ADD COLUMN profile_fetched_at BIGINT; +-- only: postgres until "end only" +ALTER TABLE signalmeow_contacts ALTER COLUMN e164_number SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN contact_name SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN contact_avatar_hash SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_name SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_about SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_about_emoji SET NOT NULL; +-- end only postgres diff --git a/pkg/signalmeow/store/upgrades/08-resync-schema-449.sql b/pkg/signalmeow/store/upgrades/08-resync-schema-449.sql new file mode 100644 index 0000000..95af775 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/08-resync-schema-449.sql @@ -0,0 +1,12 @@ +-- v7 -> v8: Migration from https://github.com/mautrix/signal/pull/449 to match the new v8 upgrade +ALTER TABLE signalmeow_contacts DROP COLUMN profile_avatar_hash; +ALTER TABLE signalmeow_contacts RENAME COLUMN profile_fetch_ts TO profile_fetched_at; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_fetched_at DROP DEFAULT; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_fetched_at DROP NOT NULL; +UPDATE signalmeow_contacts SET profile_fetched_at = NULL WHERE profile_fetched_at <= 0; +ALTER TABLE signalmeow_contacts ALTER COLUMN e164_number SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN contact_name SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN contact_avatar_hash SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_name SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_about SET NOT NULL; +ALTER TABLE signalmeow_contacts ALTER COLUMN profile_about_emoji SET NOT NULL; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index 11a73fb..f00c89b 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -17,27 +17,41 @@ package types import ( + "time" + "github.com/google/uuid" "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) +type Profile struct { + Name string + About string + AboutEmoji string + AvatarPath string + Key libsignalgo.ProfileKey + FetchedAt time.Time +} + +func (p *Profile) Equals(other *Profile) bool { + return p.Name == other.Name && + p.About == other.About && + p.AboutEmoji == other.AboutEmoji && + p.AvatarPath == other.AvatarPath && + p.Key == other.Key +} + // The Contact struct combines information from two sources: // - A Signal "contact": contact info harvested from our user's phone's contact list // - A Signal "profile": contact info entered by the target user when registering for Signal // Users of this Contact struct should prioritize "contact" information, but fall back // to "profile" information if the contact information is not available. type Contact struct { - UUID uuid.UUID - E164 string - ContactName string - ContactAvatar ContactAvatar - ProfileKey *libsignalgo.ProfileKey - ProfileName string - ProfileAbout string - ProfileAboutEmoji string - ProfileAvatarPath string - ProfileAvatarHash string + UUID uuid.UUID + E164 string + ContactName string + ContactAvatar ContactAvatar + Profile Profile } type ContactAvatar struct { diff --git a/puppet.go b/puppet.go index 34f08ee..1ecc240 100644 --- a/puppet.go +++ b/puppet.go @@ -245,10 +245,21 @@ func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { log.Err(err).Msg("Failed to fetch contact info") return } + if !puppet.bridge.Config.Bridge.UseOutdatedProfiles && puppet.ProfileFetchedAt.After(info.Profile.FetchedAt) { + log.Debug(). + Time("contact_profile_fetched_at", info.Profile.FetchedAt). + Time("puppet_profile_fetched_at", puppet.ProfileFetchedAt). + Msg("Ignoring outdated contact info") + return + } log.Trace().Msg("Updating puppet info") update := false + if puppet.ProfileFetchedAt.IsZero() && !info.Profile.FetchedAt.IsZero() { + update = true + } + puppet.ProfileFetchedAt = info.Profile.FetchedAt if info.E164 != "" && puppet.Number != info.E164 { puppet.Number = info.E164 update = true @@ -317,10 +328,10 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type puppet.AvatarSet = false puppet.AvatarPath = "" } else { - if puppet.AvatarPath == info.ProfileAvatarPath && puppet.AvatarSet { + if puppet.AvatarPath == info.Profile.AvatarPath && puppet.AvatarSet { return false } - if info.ProfileAvatarPath == "" { + if info.Profile.AvatarPath == "" { puppet.AvatarURL = id.ContentURI{} puppet.AvatarPath = "" puppet.AvatarHash = "" @@ -335,10 +346,10 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type return true } var err error - avatarData, err = source.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, info.ProfileKey) + avatarData, err = source.Client.DownloadUserAvatar(ctx, info.Profile.AvatarPath, info.Profile.Key) if err != nil { log.Err(err). - Str("profile_avatar_path", info.ProfileAvatarPath). + Str("profile_avatar_path", info.Profile.AvatarPath). Msg("Failed to download new user avatar") return true } @@ -354,7 +365,7 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type // Path changed, but actual avatar didn't return true } - puppet.AvatarPath = info.ProfileAvatarPath + puppet.AvatarPath = info.Profile.AvatarPath puppet.AvatarHash = newHash puppet.AvatarSet = false puppet.AvatarURL = id.ContentURI{} From 26e27fe9f2db56543d6a0b461b22aaa7a9bfb1f5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 28 Feb 2024 18:56:38 +0200 Subject: [PATCH 099/718] Fix initial schema for signalmeow databases --- pkg/signalmeow/store/upgrades/00-latest.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 37e6e71..6c7dc4b 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v7: Latest revision +-- v0 -> v8: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, From 100a81ab5e19e18f2f7c05b8b60a42bad4abd7ae Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Thu, 29 Feb 2024 22:48:42 -0500 Subject: [PATCH 100/718] Add LastConnectionStatus() to signalmeow --- pkg/signalmeow/client.go | 7 ++++--- pkg/signalmeow/receiving.go | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index de1a8cd..6757316 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -42,9 +42,10 @@ type Client struct { encryptionLock sync.Mutex - AuthedWS *web.SignalWebsocket - UnauthedWS *web.SignalWebsocket - WSCancel context.CancelFunc + AuthedWS *web.SignalWebsocket + UnauthedWS *web.SignalWebsocket + WSCancel context.CancelFunc + lastConnectionStatus SignalConnectionStatus EventHandler func(events.SignalEvent) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 1c3f62b..67564c5 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -93,7 +93,6 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection defer close(statusChan) defer cancel() var currentStatus, lastAuthStatus, lastUnauthStatus web.SignalWebsocketConnectionStatus - var lastSentStatus SignalConnectionStatus for { select { case <-ctx.Done(): @@ -172,10 +171,10 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection Event: SignalConnectionCleanShutdown, } } - if statusToSend.Event != 0 && statusToSend.Event != lastSentStatus.Event { + if statusToSend.Event != 0 && statusToSend.Event != cli.lastConnectionStatus.Event { log.Info().Any("status_to_send", statusToSend).Msg("Sending connection status") statusChan <- statusToSend - lastSentStatus = statusToSend + cli.lastConnectionStatus = statusToSend } } }() @@ -220,6 +219,10 @@ func (cli *Client) StopReceiveLoops() error { return nil } +func (cli *Client) LastConnectionStatus() SignalConnectionStatus { + return cli.lastConnectionStatus +} + func (cli *Client) ClearKeysAndDisconnect(ctx context.Context) error { // Essentially logout, clearing sessions and keys, and disconnecting websockets // but don't clear ACI UUID or profile keys or contacts, or anything else that From 02a496276787bc9360244e047b80c8ccf05cc0f2 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Thu, 7 Mar 2024 15:04:45 -0500 Subject: [PATCH 101/718] Get file:// attachments from local filesystem --- msgconv/from-matrix.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/msgconv/from-matrix.go b/msgconv/from-matrix.go index fd89cd6..4163945 100644 --- a/msgconv/from-matrix.go +++ b/msgconv/from-matrix.go @@ -20,6 +20,8 @@ import ( "context" "errors" "fmt" + "net/url" + "os" "time" "github.com/rs/zerolog" @@ -130,9 +132,24 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. if content.File != nil { mxc = content.File.URL } - data, err := mc.DownloadMatrixMedia(ctx, mxc) + + uri, err := url.Parse(string(mxc)) if err != nil { - return nil, exerrors.NewDualError(ErrMediaDownloadFailed, err) + return nil, fmt.Errorf("invalid mxc URI: %w", err) + } + + var data []byte + // If it's a file:// URI, read the file from disk. Otherwise, download it from the homeserver. + if uri.Scheme == "file" { + data, err = os.ReadFile(uri.Path) + if err != nil { + return nil, fmt.Errorf("failed to read file: %w", err) + } + } else { + data, err = mc.DownloadMatrixMedia(ctx, mxc) + if err != nil { + return nil, exerrors.NewDualError(ErrMediaDownloadFailed, err) + } } if content.File != nil { err = content.File.DecryptInPlace(data) From 1fb0c95b46c6029c8e1212bcf04fe9085c71c37c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 7 Mar 2024 22:22:34 +0200 Subject: [PATCH 102/718] Revert "Get file:// attachments from local filesystem" This reverts commit 02a496276787bc9360244e047b80c8ccf05cc0f2. --- msgconv/from-matrix.go | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/msgconv/from-matrix.go b/msgconv/from-matrix.go index 4163945..fd89cd6 100644 --- a/msgconv/from-matrix.go +++ b/msgconv/from-matrix.go @@ -20,8 +20,6 @@ import ( "context" "errors" "fmt" - "net/url" - "os" "time" "github.com/rs/zerolog" @@ -132,24 +130,9 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. if content.File != nil { mxc = content.File.URL } - - uri, err := url.Parse(string(mxc)) + data, err := mc.DownloadMatrixMedia(ctx, mxc) if err != nil { - return nil, fmt.Errorf("invalid mxc URI: %w", err) - } - - var data []byte - // If it's a file:// URI, read the file from disk. Otherwise, download it from the homeserver. - if uri.Scheme == "file" { - data, err = os.ReadFile(uri.Path) - if err != nil { - return nil, fmt.Errorf("failed to read file: %w", err) - } - } else { - data, err = mc.DownloadMatrixMedia(ctx, mxc) - if err != nil { - return nil, exerrors.NewDualError(ErrMediaDownloadFailed, err) - } + return nil, exerrors.NewDualError(ErrMediaDownloadFailed, err) } if content.File != nil { err = content.File.DecryptInPlace(data) From ecc78fabe758f771b722afd4049265591c46c8c2 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Fri, 8 Mar 2024 11:15:29 -0500 Subject: [PATCH 103/718] Don't clear keys on "invalid signed prekey identifier" --- pkg/signalmeow/receiving.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 67564c5..0c9ca06 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -247,8 +247,10 @@ func (cli *Client) checkDecryptionErrorAndDisconnect(ctx context.Context, err er return } log := zerolog.Ctx(ctx).With().Str("action", "check decryption error and disconnect").Logger() - if strings.Contains(err.Error(), "30: invalid PreKey message: decryption failed") || - strings.Contains(err.Error(), "70: invalid signed prekey identifier") { + if strings.Contains(err.Error(), "70: invalid signed prekey identifier") { + log.Warn().Msg("Failed decrypting a SignedPreKey message, invalid signed prekey identifier") + } + if strings.Contains(err.Error(), "30: invalid PreKey message: decryption failed") { log.Warn().Msg("Failed decrypting a PreKey message, probably our prekeys are broken, force re-registration") disconnectErr := cli.ClearKeysAndDisconnect(ctx) if disconnectErr != nil { From 0ec6bb8da2701b57ffc12bbd7a83e24cc2ab3f36 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:36:00 +0100 Subject: [PATCH 104/718] Try to fix pending member parsing issues (#467) Might fix #465 Might fix #466 --- pkg/libsignalgo/serviceid.go | 4 +- pkg/signalmeow/groups.go | 93 ++++++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 39 deletions(-) diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index baffe22..0e2eeb4 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -23,7 +23,7 @@ package libsignalgo */ import "C" import ( - "errors" + "fmt" "runtime" "unsafe" @@ -67,7 +67,7 @@ func SignalServiceIDToUUID(serviceId *C.SignalServiceIdFixedWidthBinaryBytes) (u } uuidBytes := CopySignalOwnedBufferToBytes(result) if len(uuidBytes) != 16 { - return uuid.UUID{}, errors.New("invalid UUID length") + return uuid.UUID{}, fmt.Errorf("invalid UUID length: %d. UUID: %x", len(uuidBytes), uuidBytes) } return uuid.UUID(uuidBytes), nil } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 4147170..4c658fc 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -126,12 +126,12 @@ type RequestingMember struct { //Presentation []byte } -type PromotePniAciMember struct { - UserID uuid.UUID - ProfileKey libsignalgo.ProfileKey - PNI uuid.UUID - //Presentation []byte -} +// type PromotePniAciMember struct { +// UserID uuid.UUID +// ProfileKey libsignalgo.ProfileKey +// PNI uuid.UUID +// Presentation []byte +// } type RoleMember struct { UserID uuid.UUID @@ -167,8 +167,8 @@ type GroupChange struct { ModifyAnnouncementsOnly *bool AddBannedMembers []*BannedMember DeleteBannedMembers []*uuid.UUID - //PromotePendingPniAciMembers []*PromotePniAciMember - //ModifyInviteLinkPassword []byte + PromotePendingPniAciMembers []*ProfileKeyMember + // ModifyInviteLinkPassword []byte } func (groupChange *GroupChange) getGroupMasterKey() types.SerializedGroupMasterKey { @@ -393,7 +393,8 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast } decryptedPendingMember, err := decryptPendingMember(ctx, pendingMember, groupSecretParams) if err != nil { - return nil, err + continue + // decryptPendingMember returns an error if the userID is a PNI, keep decrypting } decryptedGroup.PendingMembers = append(decryptedGroup.PendingMembers, decryptedPendingMember) } @@ -730,7 +731,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(deleteMember.DeletedUserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for deleteMember") return nil, err } decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &userID) @@ -740,7 +741,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(modifyMemberRole.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for modifyMemberRole") return nil, err } decryptedGroupChange.ModifyMemberRoles = append(decryptedGroupChange.ModifyMemberRoles, &RoleMember{ @@ -756,13 +757,13 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(modifyProfileKey.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for modifyProfileKey") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(modifyProfileKey.ProfileKey) profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") + log.Err(err).Msg("DecryptProfileKey ProfileKey error for modifyProfileKey") return nil, err } decryptedGroupChange.ModifyMemberProfileKeys = append(decryptedGroupChange.ModifyMemberProfileKeys, &ProfileKeyMember{ @@ -783,14 +784,10 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp pendingMember := addPendingMember.Added decryptedPendingMember, err := decryptPendingMember(ctx, pendingMember, groupSecretParams) if err != nil { - return nil, err + continue + // decryptPendingMember returns an error if the userID is a PNI, keep decrypting } decryptedGroupChange.AddPendingMembers = append(decryptedGroupChange.AddPendingMembers, decryptedPendingMember) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, decryptedPendingMember.UserID, decryptedPendingMember.ProfileKey) - if err != nil { - log.Err(err).Msg("failed to store profile key") - return nil, err - } } for _, deletePendingMember := range encryptedActions.DeletePendingMembers { @@ -800,7 +797,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(deletePendingMember.DeletedUserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for deletePendingMember") return nil, err } decryptedGroupChange.DeletePendingMembers = append(decryptedGroupChange.DeletePendingMembers, &userID) @@ -813,13 +810,41 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for promotePendingMember") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") + log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingMember") + return nil, err + } + decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ + UserID: userID, + ProfileKey: *profileKey, + }) + cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + if err != nil { + log.Err(err).Msg("failed to store profile key") + return nil, err + } + } + + for _, promotePendingMember := range encryptedActions.PromotePendingPniAciMembers { + // TODO: pretending this is a PendingMember should do for mautrix-signal, but we probably want to treat them separately at some point + if promotePendingMember == nil { + continue + } + encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) + userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID UserId error for promotePendingPniAciMember") + return nil, err + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if err != nil { + log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingPniAciMember") return nil, err } decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ @@ -856,7 +881,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(deleteRequestingMember.DeletedUserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for deleteRequestingMember") return nil, err } decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &userID) @@ -869,7 +894,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(promoteRequestingMember.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for promoteRequestingMember") return nil, err } decryptedGroupChange.PromoteRequestingMembers = append(decryptedGroupChange.PromoteRequestingMembers, &RoleMember{ @@ -886,7 +911,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for addBannedMember") return nil, err } decryptedGroupChange.AddBannedMembers = append(decryptedGroupChange.AddBannedMembers, &BannedMember{ @@ -902,7 +927,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp encryptedUserID := libsignalgo.UUIDCiphertext(deleteBannedMember.DeletedUserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for deleteBannedMember") return nil, err } decryptedGroupChange.DeleteBannedMembers = append(decryptedGroupChange.DeleteBannedMembers, &userID) @@ -962,25 +987,19 @@ func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMe encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") - return nil, err - } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(pendingMember.Member.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") + log.Err(err).Msg("DecryptUUID UserId error for pendingMember") return nil, err } + // pendingMembers don't have profile keys encryptedAddedByUserID := pendingMember.AddedByUserId addedByUserId, err := groupSecretParams.DecryptUUID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) if err != nil { - log.Err(err).Msg("DecryptUUID addedByUserId error") + log.Err(err).Msg("DecryptUUID addedByUserId error for pendingMember") return nil, err } return &PendingMember{ GroupMember: GroupMember{ UserID: userID, - ProfileKey: *profileKey, Role: GroupMemberRole(pendingMember.Member.Role), JoinedAtRevision: pendingMember.Member.JoinedAtRevision, }, @@ -994,13 +1013,13 @@ func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.Req encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) userID, err := groupSecretParams.DecryptUUID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") + log.Err(err).Msg("DecryptUUID UserId error for requestingMember") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") + log.Err(err).Msg("DecryptProfileKey ProfileKey error for requestingMember") return nil, err } return &RequestingMember{ From 32f5584ed039c8f46e7e3af33b756dd27b91e7d8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 8 Mar 2024 23:26:16 +0200 Subject: [PATCH 105/718] Update to libsignal v0.41.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 130 +- pkg/libsignalgo/version.go | 2 +- pkg/signalmeow/protobuf/SignalService.pb.go | 1203 ++++++++++-------- pkg/signalmeow/protobuf/SignalService.proto | 24 +- pkg/signalmeow/protobuf/StorageService.pb.go | 451 +++---- pkg/signalmeow/protobuf/StorageService.proto | 3 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 8 files changed, 1035 insertions(+), 784 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 7ef4efd..ce37388 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 7ef4efdb85d8b2ebd77f3cf1e2b542a2115033c5 +Subproject commit ce3738855295cdafd04f377810ace289a6172d11 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index dae3999..3fdfdd7 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -182,6 +182,11 @@ typedef enum { SignalErrorCodeIoError = 130, SignalErrorCodeInvalidMediaInput = 131, SignalErrorCodeUnsupportedMediaInput = 132, + SignalErrorCodeNetwork = 133, + SignalErrorCodeNetworkProtocol = 134, + SignalErrorCodeRateLimited = 135, + SignalErrorCodeSvrDataMissing = 150, + SignalErrorCodeSvrRestoreFailed = 151, } SignalErrorCode; /** @@ -195,14 +200,22 @@ typedef struct SignalAes256GcmEncryption SignalAes256GcmEncryption; typedef struct SignalAes256GcmSiv SignalAes256GcmSiv; +typedef struct SignalCdsiLookup SignalCdsiLookup; + +typedef struct SignalChat SignalChat; + typedef struct SignalCiphertextMessage SignalCiphertextMessage; +typedef struct SignalConnectionManager SignalConnectionManager; + typedef struct SignalDecryptionErrorMessage SignalDecryptionErrorMessage; typedef struct SignalFingerprint SignalFingerprint; typedef struct SignalHsmEnclaveClient SignalHsmEnclaveClient; +typedef struct SignalHttpRequest SignalHttpRequest; + typedef struct SignalIncrementalMac SignalIncrementalMac; typedef struct SignalKeyPair SignalKeyPair; @@ -211,6 +224,8 @@ typedef struct SignalKeySecret SignalKeySecret; typedef struct SignalKyberPreKeyRecord SignalKyberPreKeyRecord; +typedef struct SignalLookupRequest SignalLookupRequest; + typedef struct SignalMessageBackupKey SignalMessageBackupKey; typedef struct SignalMessageBackupValidationOutcome SignalMessageBackupValidationOutcome; @@ -268,17 +283,51 @@ typedef struct SignalSignedPreKeyRecord SignalSignedPreKeyRecord; typedef struct SignalTestingHandleType SignalTestingHandleType; +typedef struct SignalTokioAsyncContext SignalTokioAsyncContext; + typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMessageContent; typedef struct SignalValidatingMac SignalValidatingMac; +typedef struct { + /** + * Telephone number, as an unformatted e164. + */ + uint64_t e164; + uint8_t rawAciUuid[16]; + uint8_t rawPniUuid[16]; +} SignalFfiCdsiLookupResponseEntry; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalFfiCdsiLookupResponseEntry *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfFfiCdsiLookupResponseEntry; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ typedef struct { unsigned char *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ size_t length; } SignalOwnedBuffer; +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ typedef struct { size_t *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ size_t length; } SignalOwnedBufferOfusize; @@ -412,6 +461,35 @@ typedef struct { SignalStoreSenderKey store_sender_key; } SignalSenderKeyStore; +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseCdsiLookup)(SignalFfiError *error, SignalCdsiLookup *const *result, const void *context); + +typedef struct { + SignalOwnedBufferOfFfiCdsiLookupResponseEntry entries; + int32_t debug_permits_used; +} SignalFfiCdsiLookupResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseFfiCdsiLookupResponse)(SignalFfiError *error, const SignalFfiCdsiLookupResponse *result, const void *context); + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseOwnedBufferOfc_uchar)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); + typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); typedef int (*SignalSkip)(void *ctx, uint64_t amount); @@ -472,6 +550,8 @@ void signal_free_string(const char *buf); void signal_free_buffer(const unsigned char *buf, size_t buf_len); +void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); + void signal_free_string_array(SignalStringArray array); SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); @@ -482,6 +562,8 @@ SignalFfiError *signal_error_get_uuid(const SignalFfiError *err, uint8_t (*out)[ uint32_t signal_error_get_type(const SignalFfiError *err); +SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); + void signal_error_free(SignalFfiError *err); SignalFfiError *signal_identitykeypair_deserialize(SignalPrivateKey **private_key, SignalPublicKey **public_key, SignalBorrowedBuffer input); @@ -1218,6 +1300,48 @@ SignalFfiError *signal_group_send_credential_presentation_verify(SignalBorrowedB SignalFfiError *signal_verify_signature(bool *out, SignalBorrowedBuffer cert_pem, SignalBorrowedBuffer body, SignalBorrowedBuffer signature, uint64_t current_timestamp); +SignalFfiError *signal_tokio_async_context_new(SignalTokioAsyncContext **out); + +SignalFfiError *signal_tokio_async_context_destroy(SignalTokioAsyncContext *p); + +SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment); + +SignalFfiError *signal_connection_manager_destroy(SignalConnectionManager *p); + +SignalFfiError *signal_lookup_request_new(SignalLookupRequest **out); + +SignalFfiError *signal_lookup_request_add_e164(const SignalLookupRequest *request, const char *e164); + +SignalFfiError *signal_lookup_request_add_previous_e164(const SignalLookupRequest *request, const char *e164); + +SignalFfiError *signal_lookup_request_set_token(const SignalLookupRequest *request, SignalBorrowedBuffer token); + +SignalFfiError *signal_lookup_request_add_aci_and_access_key(const SignalLookupRequest *request, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer access_key); + +SignalFfiError *signal_lookup_request_set_return_acis_without_uaks(const SignalLookupRequest *request, bool return_acis_without_uaks); + +SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); + +SignalFfiError *signal_cdsi_lookup_destroy(SignalCdsiLookup *p); + +SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request, uint32_t timeout_millis); + +SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, const SignalCdsiLookup *lookup); + +SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalCdsiLookup *lookup); + +SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); + +SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); + +SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password, uint32_t op_timeout_ms); + +SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password, uint32_t op_timeout_ms); + +SignalFfiError *signal_chat_destroy(SignalChat *p); + +SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); + SignalFfiError *signal_pin_hash_destroy(SignalPinHash *p); SignalFfiError *signal_pin_hash_clone(SignalPinHash **new_obj, const SignalPinHash *obj); @@ -1264,7 +1388,7 @@ SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, const SignalMessageBackupValidationOutcome *outcome); -SignalFfiError *signal_message_backup_validator_validate(SignalMessageBackupValidationOutcome **out, const SignalMessageBackupKey *key, const SignalInputStream *first_stream, const SignalInputStream *second_stream, uint64_t len); +SignalFfiError *signal_message_backup_validator_validate(SignalMessageBackupValidationOutcome **out, const SignalMessageBackupKey *key, const SignalInputStream *first_stream, const SignalInputStream *second_stream, uint64_t len, uint8_t purpose); SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); @@ -1372,4 +1496,8 @@ SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer promi SignalFfiError *signal_testing_return_string_array(SignalStringArray *out); +SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime); + +SignalFfiError *signal_testing_cdsi_lookup_error_convert(bool *out); + #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 605caba..b977e45 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.40.0" +const Version = "v0.41.0" diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index c27e635..aa5d674 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -1209,6 +1209,8 @@ const ( SyncMessage_MessageRequestResponse_DELETE SyncMessage_MessageRequestResponse_Type = 2 SyncMessage_MessageRequestResponse_BLOCK SyncMessage_MessageRequestResponse_Type = 3 SyncMessage_MessageRequestResponse_BLOCK_AND_DELETE SyncMessage_MessageRequestResponse_Type = 4 + SyncMessage_MessageRequestResponse_SPAM SyncMessage_MessageRequestResponse_Type = 5 + SyncMessage_MessageRequestResponse_BLOCK_AND_SPAM SyncMessage_MessageRequestResponse_Type = 6 ) // Enum value maps for SyncMessage_MessageRequestResponse_Type. @@ -1219,6 +1221,8 @@ var ( 2: "DELETE", 3: "BLOCK", 4: "BLOCK_AND_DELETE", + 5: "SPAM", + 6: "BLOCK_AND_SPAM", } SyncMessage_MessageRequestResponse_Type_value = map[string]int32{ "UNKNOWN": 0, @@ -1226,6 +1230,8 @@ var ( "DELETE": 2, "BLOCK": 3, "BLOCK_AND_DELETE": 4, + "SPAM": 5, + "BLOCK_AND_SPAM": 6, } ) @@ -1452,19 +1458,78 @@ func (SyncMessage_CallEvent_Event) EnumDescriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{12, 14, 2} } +type SyncMessage_CallLinkUpdate_Type int32 + +const ( + SyncMessage_CallLinkUpdate_UPDATE SyncMessage_CallLinkUpdate_Type = 0 + SyncMessage_CallLinkUpdate_DELETE SyncMessage_CallLinkUpdate_Type = 1 +) + +// Enum value maps for SyncMessage_CallLinkUpdate_Type. +var ( + SyncMessage_CallLinkUpdate_Type_name = map[int32]string{ + 0: "UPDATE", + 1: "DELETE", + } + SyncMessage_CallLinkUpdate_Type_value = map[string]int32{ + "UPDATE": 0, + "DELETE": 1, + } +) + +func (x SyncMessage_CallLinkUpdate_Type) Enum() *SyncMessage_CallLinkUpdate_Type { + p := new(SyncMessage_CallLinkUpdate_Type) + *p = x + return p +} + +func (x SyncMessage_CallLinkUpdate_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SyncMessage_CallLinkUpdate_Type) Descriptor() protoreflect.EnumDescriptor { + return file_SignalService_proto_enumTypes[23].Descriptor() +} + +func (SyncMessage_CallLinkUpdate_Type) Type() protoreflect.EnumType { + return &file_SignalService_proto_enumTypes[23] +} + +func (x SyncMessage_CallLinkUpdate_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *SyncMessage_CallLinkUpdate_Type) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = SyncMessage_CallLinkUpdate_Type(num) + return nil +} + +// Deprecated: Use SyncMessage_CallLinkUpdate_Type.Descriptor instead. +func (SyncMessage_CallLinkUpdate_Type) EnumDescriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 15, 0} +} + type SyncMessage_CallLogEvent_Type int32 const ( - SyncMessage_CallLogEvent_CLEAR SyncMessage_CallLogEvent_Type = 0 + SyncMessage_CallLogEvent_CLEAR SyncMessage_CallLogEvent_Type = 0 + SyncMessage_CallLogEvent_MARKED_AS_READ SyncMessage_CallLogEvent_Type = 1 ) // Enum value maps for SyncMessage_CallLogEvent_Type. var ( SyncMessage_CallLogEvent_Type_name = map[int32]string{ 0: "CLEAR", + 1: "MARKED_AS_READ", } SyncMessage_CallLogEvent_Type_value = map[string]int32{ - "CLEAR": 0, + "CLEAR": 0, + "MARKED_AS_READ": 1, } ) @@ -1479,11 +1544,11 @@ func (x SyncMessage_CallLogEvent_Type) String() string { } func (SyncMessage_CallLogEvent_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[23].Descriptor() + return file_SignalService_proto_enumTypes[24].Descriptor() } func (SyncMessage_CallLogEvent_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[23] + return &file_SignalService_proto_enumTypes[24] } func (x SyncMessage_CallLogEvent_Type) Number() protoreflect.EnumNumber { @@ -1538,11 +1603,11 @@ func (x AttachmentPointer_Flags) String() string { } func (AttachmentPointer_Flags) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[24].Descriptor() + return file_SignalService_proto_enumTypes[25].Descriptor() } func (AttachmentPointer_Flags) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[24] + return &file_SignalService_proto_enumTypes[25] } func (x AttachmentPointer_Flags) Number() protoreflect.EnumNumber { @@ -1603,11 +1668,11 @@ func (x GroupContext_Type) String() string { } func (GroupContext_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[25].Descriptor() + return file_SignalService_proto_enumTypes[26].Descriptor() } func (GroupContext_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[25] + return &file_SignalService_proto_enumTypes[26] } func (x GroupContext_Type) Number() protoreflect.EnumNumber { @@ -3034,7 +3099,7 @@ type AttachmentPointer struct { Size *uint32 `protobuf:"varint,4,opt,name=size" json:"size,omitempty"` Thumbnail []byte `protobuf:"bytes,5,opt,name=thumbnail" json:"thumbnail,omitempty"` Digest []byte `protobuf:"bytes,6,opt,name=digest" json:"digest,omitempty"` - IncrementalMac []byte `protobuf:"bytes,18,opt,name=incrementalMac" json:"incrementalMac,omitempty"` + IncrementalMac []byte `protobuf:"bytes,19,opt,name=incrementalMac" json:"incrementalMac,omitempty"` IncrementalMacChunkSize *uint32 `protobuf:"varint,17,opt,name=incrementalMacChunkSize" json:"incrementalMacChunkSize,omitempty"` FileName *string `protobuf:"bytes,7,opt,name=fileName" json:"fileName,omitempty"` Flags *uint32 `protobuf:"varint,8,opt,name=flags" json:"flags,omitempty"` @@ -6634,8 +6699,9 @@ type SyncMessage_CallLinkUpdate struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` - AdminPassKey []byte `protobuf:"bytes,2,opt,name=adminPassKey" json:"adminPassKey,omitempty"` + RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` + AdminPassKey []byte `protobuf:"bytes,2,opt,name=adminPassKey" json:"adminPassKey,omitempty"` + Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` } func (x *SyncMessage_CallLinkUpdate) Reset() { @@ -6684,6 +6750,13 @@ func (x *SyncMessage_CallLinkUpdate) GetAdminPassKey() []byte { return nil } +func (x *SyncMessage_CallLinkUpdate) GetType() SyncMessage_CallLinkUpdate_Type { + if x != nil && x.Type != nil { + return *x.Type + } + return SyncMessage_CallLinkUpdate_UPDATE +} + type SyncMessage_CallLogEvent struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6744,8 +6817,9 @@ type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` + DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` + DestinationIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationIdentityKey" json:"destinationIdentityKey,omitempty"` } func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { @@ -6794,6 +6868,13 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetUnidentified() bool { return false } +func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationIdentityKey() []byte { + if x != nil { + return x.DestinationIdentityKey + } + return nil +} + type SyncMessage_Sent_StoryMessageRecipient struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -7779,7 +7860,7 @@ var file_SignalService_proto_rawDesc = []byte{ 0x67, 0x65, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xb3, 0x29, 0x0a, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x8f, 0x2b, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, @@ -7863,7 +7944,7 @@ var file_SignalService_proto_rawDesc = []byte{ 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x61, 0x6c, - 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0xab, 0x07, 0x0a, 0x04, 0x53, 0x65, + 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0xf0, 0x07, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x12, 0x32, 0x0a, 0x14, @@ -7904,377 +7985,391 @@ var file_SignalService_proto_rawDesc = []byte{ 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, - 0x7a, 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, - 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, - 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa9, 0x01, 0x0a, 0x15, - 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, - 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x69, 0x73, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, - 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, - 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x1a, 0x63, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x63, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x52, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x0a, 0x08, 0x63, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, - 0x73, 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x53, 0x0a, 0x07, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x69, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x61, 0x63, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x73, 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x0a, 0x04, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, - 0x07, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, - 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x08, 0x0a, - 0x04, 0x4b, 0x45, 0x59, 0x53, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4e, 0x49, 0x5f, 0x49, - 0x44, 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0x06, 0x1a, 0x48, 0x0a, 0x04, 0x52, 0x65, 0x61, - 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, - 0x01, 0x10, 0x02, 0x1a, 0x4a, 0x0a, 0x06, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, - 0x83, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, - 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, - 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x75, - 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, - 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, - 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x6c, - 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x4a, - 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xb3, 0x01, 0x0a, 0x14, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, - 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, - 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, - 0x12, 0x48, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, - 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1f, 0x0a, 0x04, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, - 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x01, 0x1a, 0x50, 0x0a, 0x0c, 0x56, - 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa5, 0x01, - 0x0a, 0x0b, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x55, - 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x50, 0x52, 0x4f, - 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, - 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x49, 0x46, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, - 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x55, 0x53, 0x10, 0x03, 0x1a, 0x46, 0x0a, 0x04, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26, 0x0a, - 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x1a, 0xf0, 0x01, - 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, - 0x61, 0x64, 0x41, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x68, 0x72, - 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x12, 0x4a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4c, 0x0a, 0x04, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, - 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x4c, 0x4f, - 0x43, 0x4b, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x41, 0x4e, - 0x44, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, - 0x1a, 0x8e, 0x04, 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, - 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, - 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, - 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, - 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x1a, 0xcc, 0x02, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, - 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, 0x65, 0x63, 0x69, - 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, - 0x6f, 0x62, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, - 0x6f, 0x62, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x32, 0x0a, 0x14, - 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, - 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, - 0x42, 0x0f, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x1a, 0xd7, 0x01, 0x0a, 0x0f, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, - 0x22, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, - 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, - 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, - 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, 0x04, 0x0a, 0x09, - 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, - 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x4c, - 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, - 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x05, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x59, - 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x55, 0x44, 0x49, - 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x49, 0x44, 0x45, - 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x47, 0x52, 0x4f, 0x55, - 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x44, 0x5f, 0x48, - 0x4f, 0x43, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x04, 0x22, 0x3e, 0x0a, 0x09, 0x44, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, - 0x08, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, - 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x43, - 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, - 0x50, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, - 0x10, 0x03, 0x1a, 0x4e, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, - 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, - 0x65, 0x79, 0x1a, 0x81, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, - 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x22, 0x11, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x43, - 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x11, - 0x10, 0x12, 0x22, 0xdd, 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, - 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x64, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, - 0x12, 0x18, 0x0a, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, - 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, - 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, - 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x72, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, - 0x12, 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, - 0x61, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, - 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, - 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, - 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, - 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x64, - 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, - 0x64, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, - 0x73, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, - 0x47, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x4c, 0x45, - 0x53, 0x53, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x04, 0x22, 0x04, 0x08, - 0x03, 0x10, 0x03, 0x42, 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x10, - 0x10, 0x11, 0x22, 0xf0, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, - 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, - 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, - 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, - 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, - 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x55, 0x49, - 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, - 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, - 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, - 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, - 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, - 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, - 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, - 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, - 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, - 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, - 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, - 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x20, - 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, - 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, - 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, - 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, - 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, - 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, - 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, - 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5f, 0x0a, - 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, - 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x6f, 0x62, - 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x4b, - 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, + 0xb8, 0x01, 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, + 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x4a, 0x04, + 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xa9, 0x01, 0x0a, 0x15, 0x53, + 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, + 0x69, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x73, + 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, + 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x1a, 0x63, 0x0a, 0x08, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x12, 0x21, + 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x1a, 0x53, 0x0a, 0x07, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x69, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x63, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x5d, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x53, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x03, 0x12, + 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x4b, 0x45, 0x59, 0x53, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, + 0x50, 0x4e, 0x49, 0x5f, 0x49, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0x06, 0x1a, 0x48, + 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, + 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x4a, 0x0a, 0x06, 0x56, 0x69, 0x65, 0x77, + 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, - 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x13, 0x50, 0x6e, - 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, - 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x75, - 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, + 0x08, 0x01, 0x10, 0x02, 0x1a, 0x83, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, + 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x75, 0x6e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x1e, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, + 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, + 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xb3, 0x01, 0x0a, 0x14, 0x53, + 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, + 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x1f, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, + 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x01, + 0x1a, 0x50, 0x0a, 0x0c, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x1a, 0xa5, 0x01, 0x0a, 0x0b, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x2b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, + 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x55, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x43, 0x41, + 0x4c, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, + 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x49, 0x46, 0x45, 0x53, 0x54, 0x10, + 0x02, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x10, 0x03, 0x1a, 0x46, 0x0a, 0x04, 0x4b, 0x65, + 0x79, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, + 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x1a, 0x8e, 0x02, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x12, 0x18, 0x0a, 0x07, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x4a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x6a, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, + 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x09, + 0x0a, 0x05, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x4c, 0x4f, + 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x04, 0x12, + 0x08, 0x0a, 0x04, 0x53, 0x50, 0x41, 0x4d, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x42, 0x4c, 0x4f, + 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x53, 0x50, 0x41, 0x4d, 0x10, 0x06, 0x4a, 0x04, 0x08, + 0x01, 0x10, 0x02, 0x1a, 0x8e, 0x04, 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, + 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, + 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x6d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, + 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x43, 0x6f, 0x69, 0x6e, 0x1a, 0xcc, 0x02, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, + 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x24, 0x0a, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, + 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, + 0x4d, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, + 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, + 0x32, 0x0a, 0x14, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, + 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c, + 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x26, 0x0a, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, + 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x1a, 0xd7, 0x01, 0x0a, 0x0f, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, + 0x69, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, + 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, + 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, + 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, + 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x40, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x22, 0x59, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, + 0x55, 0x44, 0x49, 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, + 0x49, 0x44, 0x45, 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x47, + 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x41, + 0x44, 0x5f, 0x48, 0x4f, 0x43, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x04, 0x22, 0x3e, 0x0a, 0x09, + 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, + 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, + 0x0a, 0x08, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, + 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, + 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, + 0x45, 0x54, 0x45, 0x10, 0x03, 0x1a, 0xb2, 0x01, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, + 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, + 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, + 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, + 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x42, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1e, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0a, + 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x01, 0x1a, 0x95, 0x01, 0x0a, 0x0c, 0x43, + 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x25, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x12, 0x12, + 0x0a, 0x0e, 0x4d, 0x41, 0x52, 0x4b, 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, + 0x10, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x22, 0xe3, + 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x06, + 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, + 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, + 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x12, 0x38, 0x0a, 0x17, + 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x69, + 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, + 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, + 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x11, 0x0a, + 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, + 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x4c, 0x45, 0x53, 0x53, 0x10, 0x02, + 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x04, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x42, + 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, + 0x08, 0x12, 0x10, 0x13, 0x22, 0xf0, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, + 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, + 0x38, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, + 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, + 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, + 0x55, 0x49, 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, + 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, + 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, + 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, + 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, + 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, + 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, + 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, + 0x6c, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, + 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, + 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, + 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, + 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xc9, 0x01, 0x0a, + 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x5f, 0x0a, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x1a, 0x4b, 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x09, 0x0a, + 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, 0x44, 0x65, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, + 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x13, + 0x50, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x70, 0x75, 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, } var ( @@ -8289,7 +8384,7 @@ func file_SignalService_proto_rawDescGZIP() []byte { return file_SignalService_proto_rawDescData } -var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 26) +var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 27) var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 74) var file_SignalService_proto_goTypes = []interface{}{ (Envelope_Type)(0), // 0: signalservice.Envelope.Type @@ -8315,195 +8410,197 @@ var file_SignalService_proto_goTypes = []interface{}{ (SyncMessage_CallEvent_Type)(0), // 20: signalservice.SyncMessage.CallEvent.Type (SyncMessage_CallEvent_Direction)(0), // 21: signalservice.SyncMessage.CallEvent.Direction (SyncMessage_CallEvent_Event)(0), // 22: signalservice.SyncMessage.CallEvent.Event - (SyncMessage_CallLogEvent_Type)(0), // 23: signalservice.SyncMessage.CallLogEvent.Type - (AttachmentPointer_Flags)(0), // 24: signalservice.AttachmentPointer.Flags - (GroupContext_Type)(0), // 25: signalservice.GroupContext.Type - (*Envelope)(nil), // 26: signalservice.Envelope - (*Content)(nil), // 27: signalservice.Content - (*CallMessage)(nil), // 28: signalservice.CallMessage - (*BodyRange)(nil), // 29: signalservice.BodyRange - (*DataMessage)(nil), // 30: signalservice.DataMessage - (*NullMessage)(nil), // 31: signalservice.NullMessage - (*ReceiptMessage)(nil), // 32: signalservice.ReceiptMessage - (*TypingMessage)(nil), // 33: signalservice.TypingMessage - (*StoryMessage)(nil), // 34: signalservice.StoryMessage - (*Preview)(nil), // 35: signalservice.Preview - (*TextAttachment)(nil), // 36: signalservice.TextAttachment - (*Verified)(nil), // 37: signalservice.Verified - (*SyncMessage)(nil), // 38: signalservice.SyncMessage - (*AttachmentPointer)(nil), // 39: signalservice.AttachmentPointer - (*GroupContext)(nil), // 40: signalservice.GroupContext - (*GroupContextV2)(nil), // 41: signalservice.GroupContextV2 - (*ContactDetails)(nil), // 42: signalservice.ContactDetails - (*GroupDetails)(nil), // 43: signalservice.GroupDetails - (*PaymentAddress)(nil), // 44: signalservice.PaymentAddress - (*DecryptionErrorMessage)(nil), // 45: signalservice.DecryptionErrorMessage - (*PniSignatureMessage)(nil), // 46: signalservice.PniSignatureMessage - (*EditMessage)(nil), // 47: signalservice.EditMessage - (*CallMessage_Offer)(nil), // 48: signalservice.CallMessage.Offer - (*CallMessage_Answer)(nil), // 49: signalservice.CallMessage.Answer - (*CallMessage_IceUpdate)(nil), // 50: signalservice.CallMessage.IceUpdate - (*CallMessage_Busy)(nil), // 51: signalservice.CallMessage.Busy - (*CallMessage_Hangup)(nil), // 52: signalservice.CallMessage.Hangup - (*CallMessage_Opaque)(nil), // 53: signalservice.CallMessage.Opaque - (*DataMessage_Quote)(nil), // 54: signalservice.DataMessage.Quote - (*DataMessage_Contact)(nil), // 55: signalservice.DataMessage.Contact - (*DataMessage_Sticker)(nil), // 56: signalservice.DataMessage.Sticker - (*DataMessage_Reaction)(nil), // 57: signalservice.DataMessage.Reaction - (*DataMessage_Delete)(nil), // 58: signalservice.DataMessage.Delete - (*DataMessage_GroupCallUpdate)(nil), // 59: signalservice.DataMessage.GroupCallUpdate - (*DataMessage_StoryContext)(nil), // 60: signalservice.DataMessage.StoryContext - (*DataMessage_Payment)(nil), // 61: signalservice.DataMessage.Payment - (*DataMessage_GiftBadge)(nil), // 62: signalservice.DataMessage.GiftBadge - (*DataMessage_Quote_QuotedAttachment)(nil), // 63: signalservice.DataMessage.Quote.QuotedAttachment - (*DataMessage_Contact_Name)(nil), // 64: signalservice.DataMessage.Contact.Name - (*DataMessage_Contact_Phone)(nil), // 65: signalservice.DataMessage.Contact.Phone - (*DataMessage_Contact_Email)(nil), // 66: signalservice.DataMessage.Contact.Email - (*DataMessage_Contact_PostalAddress)(nil), // 67: signalservice.DataMessage.Contact.PostalAddress - (*DataMessage_Contact_Avatar)(nil), // 68: signalservice.DataMessage.Contact.Avatar - (*DataMessage_Payment_Amount)(nil), // 69: signalservice.DataMessage.Payment.Amount - (*DataMessage_Payment_Notification)(nil), // 70: signalservice.DataMessage.Payment.Notification - (*DataMessage_Payment_Activation)(nil), // 71: signalservice.DataMessage.Payment.Activation - (*DataMessage_Payment_Amount_MobileCoin)(nil), // 72: signalservice.DataMessage.Payment.Amount.MobileCoin - (*DataMessage_Payment_Notification_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Notification.MobileCoin - (*TextAttachment_Gradient)(nil), // 74: signalservice.TextAttachment.Gradient - (*SyncMessage_Sent)(nil), // 75: signalservice.SyncMessage.Sent - (*SyncMessage_Contacts)(nil), // 76: signalservice.SyncMessage.Contacts - (*SyncMessage_Blocked)(nil), // 77: signalservice.SyncMessage.Blocked - (*SyncMessage_Request)(nil), // 78: signalservice.SyncMessage.Request - (*SyncMessage_Read)(nil), // 79: signalservice.SyncMessage.Read - (*SyncMessage_Viewed)(nil), // 80: signalservice.SyncMessage.Viewed - (*SyncMessage_Configuration)(nil), // 81: signalservice.SyncMessage.Configuration - (*SyncMessage_StickerPackOperation)(nil), // 82: signalservice.SyncMessage.StickerPackOperation - (*SyncMessage_ViewOnceOpen)(nil), // 83: signalservice.SyncMessage.ViewOnceOpen - (*SyncMessage_FetchLatest)(nil), // 84: signalservice.SyncMessage.FetchLatest - (*SyncMessage_Keys)(nil), // 85: signalservice.SyncMessage.Keys - (*SyncMessage_MessageRequestResponse)(nil), // 86: signalservice.SyncMessage.MessageRequestResponse - (*SyncMessage_OutgoingPayment)(nil), // 87: signalservice.SyncMessage.OutgoingPayment - (*SyncMessage_PniChangeNumber)(nil), // 88: signalservice.SyncMessage.PniChangeNumber - (*SyncMessage_CallEvent)(nil), // 89: signalservice.SyncMessage.CallEvent - (*SyncMessage_CallLinkUpdate)(nil), // 90: signalservice.SyncMessage.CallLinkUpdate - (*SyncMessage_CallLogEvent)(nil), // 91: signalservice.SyncMessage.CallLogEvent - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 92: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 93: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 94: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*GroupContext_Member)(nil), // 95: signalservice.GroupContext.Member - (*ContactDetails_Avatar)(nil), // 96: signalservice.ContactDetails.Avatar - (*GroupDetails_Avatar)(nil), // 97: signalservice.GroupDetails.Avatar - (*GroupDetails_Member)(nil), // 98: signalservice.GroupDetails.Member - (*PaymentAddress_MobileCoinAddress)(nil), // 99: signalservice.PaymentAddress.MobileCoinAddress + (SyncMessage_CallLinkUpdate_Type)(0), // 23: signalservice.SyncMessage.CallLinkUpdate.Type + (SyncMessage_CallLogEvent_Type)(0), // 24: signalservice.SyncMessage.CallLogEvent.Type + (AttachmentPointer_Flags)(0), // 25: signalservice.AttachmentPointer.Flags + (GroupContext_Type)(0), // 26: signalservice.GroupContext.Type + (*Envelope)(nil), // 27: signalservice.Envelope + (*Content)(nil), // 28: signalservice.Content + (*CallMessage)(nil), // 29: signalservice.CallMessage + (*BodyRange)(nil), // 30: signalservice.BodyRange + (*DataMessage)(nil), // 31: signalservice.DataMessage + (*NullMessage)(nil), // 32: signalservice.NullMessage + (*ReceiptMessage)(nil), // 33: signalservice.ReceiptMessage + (*TypingMessage)(nil), // 34: signalservice.TypingMessage + (*StoryMessage)(nil), // 35: signalservice.StoryMessage + (*Preview)(nil), // 36: signalservice.Preview + (*TextAttachment)(nil), // 37: signalservice.TextAttachment + (*Verified)(nil), // 38: signalservice.Verified + (*SyncMessage)(nil), // 39: signalservice.SyncMessage + (*AttachmentPointer)(nil), // 40: signalservice.AttachmentPointer + (*GroupContext)(nil), // 41: signalservice.GroupContext + (*GroupContextV2)(nil), // 42: signalservice.GroupContextV2 + (*ContactDetails)(nil), // 43: signalservice.ContactDetails + (*GroupDetails)(nil), // 44: signalservice.GroupDetails + (*PaymentAddress)(nil), // 45: signalservice.PaymentAddress + (*DecryptionErrorMessage)(nil), // 46: signalservice.DecryptionErrorMessage + (*PniSignatureMessage)(nil), // 47: signalservice.PniSignatureMessage + (*EditMessage)(nil), // 48: signalservice.EditMessage + (*CallMessage_Offer)(nil), // 49: signalservice.CallMessage.Offer + (*CallMessage_Answer)(nil), // 50: signalservice.CallMessage.Answer + (*CallMessage_IceUpdate)(nil), // 51: signalservice.CallMessage.IceUpdate + (*CallMessage_Busy)(nil), // 52: signalservice.CallMessage.Busy + (*CallMessage_Hangup)(nil), // 53: signalservice.CallMessage.Hangup + (*CallMessage_Opaque)(nil), // 54: signalservice.CallMessage.Opaque + (*DataMessage_Quote)(nil), // 55: signalservice.DataMessage.Quote + (*DataMessage_Contact)(nil), // 56: signalservice.DataMessage.Contact + (*DataMessage_Sticker)(nil), // 57: signalservice.DataMessage.Sticker + (*DataMessage_Reaction)(nil), // 58: signalservice.DataMessage.Reaction + (*DataMessage_Delete)(nil), // 59: signalservice.DataMessage.Delete + (*DataMessage_GroupCallUpdate)(nil), // 60: signalservice.DataMessage.GroupCallUpdate + (*DataMessage_StoryContext)(nil), // 61: signalservice.DataMessage.StoryContext + (*DataMessage_Payment)(nil), // 62: signalservice.DataMessage.Payment + (*DataMessage_GiftBadge)(nil), // 63: signalservice.DataMessage.GiftBadge + (*DataMessage_Quote_QuotedAttachment)(nil), // 64: signalservice.DataMessage.Quote.QuotedAttachment + (*DataMessage_Contact_Name)(nil), // 65: signalservice.DataMessage.Contact.Name + (*DataMessage_Contact_Phone)(nil), // 66: signalservice.DataMessage.Contact.Phone + (*DataMessage_Contact_Email)(nil), // 67: signalservice.DataMessage.Contact.Email + (*DataMessage_Contact_PostalAddress)(nil), // 68: signalservice.DataMessage.Contact.PostalAddress + (*DataMessage_Contact_Avatar)(nil), // 69: signalservice.DataMessage.Contact.Avatar + (*DataMessage_Payment_Amount)(nil), // 70: signalservice.DataMessage.Payment.Amount + (*DataMessage_Payment_Notification)(nil), // 71: signalservice.DataMessage.Payment.Notification + (*DataMessage_Payment_Activation)(nil), // 72: signalservice.DataMessage.Payment.Activation + (*DataMessage_Payment_Amount_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Amount.MobileCoin + (*DataMessage_Payment_Notification_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Notification.MobileCoin + (*TextAttachment_Gradient)(nil), // 75: signalservice.TextAttachment.Gradient + (*SyncMessage_Sent)(nil), // 76: signalservice.SyncMessage.Sent + (*SyncMessage_Contacts)(nil), // 77: signalservice.SyncMessage.Contacts + (*SyncMessage_Blocked)(nil), // 78: signalservice.SyncMessage.Blocked + (*SyncMessage_Request)(nil), // 79: signalservice.SyncMessage.Request + (*SyncMessage_Read)(nil), // 80: signalservice.SyncMessage.Read + (*SyncMessage_Viewed)(nil), // 81: signalservice.SyncMessage.Viewed + (*SyncMessage_Configuration)(nil), // 82: signalservice.SyncMessage.Configuration + (*SyncMessage_StickerPackOperation)(nil), // 83: signalservice.SyncMessage.StickerPackOperation + (*SyncMessage_ViewOnceOpen)(nil), // 84: signalservice.SyncMessage.ViewOnceOpen + (*SyncMessage_FetchLatest)(nil), // 85: signalservice.SyncMessage.FetchLatest + (*SyncMessage_Keys)(nil), // 86: signalservice.SyncMessage.Keys + (*SyncMessage_MessageRequestResponse)(nil), // 87: signalservice.SyncMessage.MessageRequestResponse + (*SyncMessage_OutgoingPayment)(nil), // 88: signalservice.SyncMessage.OutgoingPayment + (*SyncMessage_PniChangeNumber)(nil), // 89: signalservice.SyncMessage.PniChangeNumber + (*SyncMessage_CallEvent)(nil), // 90: signalservice.SyncMessage.CallEvent + (*SyncMessage_CallLinkUpdate)(nil), // 91: signalservice.SyncMessage.CallLinkUpdate + (*SyncMessage_CallLogEvent)(nil), // 92: signalservice.SyncMessage.CallLogEvent + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 93: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 94: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 95: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*GroupContext_Member)(nil), // 96: signalservice.GroupContext.Member + (*ContactDetails_Avatar)(nil), // 97: signalservice.ContactDetails.Avatar + (*GroupDetails_Avatar)(nil), // 98: signalservice.GroupDetails.Avatar + (*GroupDetails_Member)(nil), // 99: signalservice.GroupDetails.Member + (*PaymentAddress_MobileCoinAddress)(nil), // 100: signalservice.PaymentAddress.MobileCoinAddress } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type - 30, // 1: signalservice.Content.dataMessage:type_name -> signalservice.DataMessage - 38, // 2: signalservice.Content.syncMessage:type_name -> signalservice.SyncMessage - 28, // 3: signalservice.Content.callMessage:type_name -> signalservice.CallMessage - 31, // 4: signalservice.Content.nullMessage:type_name -> signalservice.NullMessage - 32, // 5: signalservice.Content.receiptMessage:type_name -> signalservice.ReceiptMessage - 33, // 6: signalservice.Content.typingMessage:type_name -> signalservice.TypingMessage - 34, // 7: signalservice.Content.storyMessage:type_name -> signalservice.StoryMessage - 46, // 8: signalservice.Content.pniSignatureMessage:type_name -> signalservice.PniSignatureMessage - 47, // 9: signalservice.Content.editMessage:type_name -> signalservice.EditMessage - 48, // 10: signalservice.CallMessage.offer:type_name -> signalservice.CallMessage.Offer - 49, // 11: signalservice.CallMessage.answer:type_name -> signalservice.CallMessage.Answer - 50, // 12: signalservice.CallMessage.iceUpdate:type_name -> signalservice.CallMessage.IceUpdate - 51, // 13: signalservice.CallMessage.busy:type_name -> signalservice.CallMessage.Busy - 52, // 14: signalservice.CallMessage.hangup:type_name -> signalservice.CallMessage.Hangup - 53, // 15: signalservice.CallMessage.opaque:type_name -> signalservice.CallMessage.Opaque + 31, // 1: signalservice.Content.dataMessage:type_name -> signalservice.DataMessage + 39, // 2: signalservice.Content.syncMessage:type_name -> signalservice.SyncMessage + 29, // 3: signalservice.Content.callMessage:type_name -> signalservice.CallMessage + 32, // 4: signalservice.Content.nullMessage:type_name -> signalservice.NullMessage + 33, // 5: signalservice.Content.receiptMessage:type_name -> signalservice.ReceiptMessage + 34, // 6: signalservice.Content.typingMessage:type_name -> signalservice.TypingMessage + 35, // 7: signalservice.Content.storyMessage:type_name -> signalservice.StoryMessage + 47, // 8: signalservice.Content.pniSignatureMessage:type_name -> signalservice.PniSignatureMessage + 48, // 9: signalservice.Content.editMessage:type_name -> signalservice.EditMessage + 49, // 10: signalservice.CallMessage.offer:type_name -> signalservice.CallMessage.Offer + 50, // 11: signalservice.CallMessage.answer:type_name -> signalservice.CallMessage.Answer + 51, // 12: signalservice.CallMessage.iceUpdate:type_name -> signalservice.CallMessage.IceUpdate + 52, // 13: signalservice.CallMessage.busy:type_name -> signalservice.CallMessage.Busy + 53, // 14: signalservice.CallMessage.hangup:type_name -> signalservice.CallMessage.Hangup + 54, // 15: signalservice.CallMessage.opaque:type_name -> signalservice.CallMessage.Opaque 4, // 16: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style - 39, // 17: signalservice.DataMessage.attachments:type_name -> signalservice.AttachmentPointer - 41, // 18: signalservice.DataMessage.groupV2:type_name -> signalservice.GroupContextV2 - 54, // 19: signalservice.DataMessage.quote:type_name -> signalservice.DataMessage.Quote - 55, // 20: signalservice.DataMessage.contact:type_name -> signalservice.DataMessage.Contact - 35, // 21: signalservice.DataMessage.preview:type_name -> signalservice.Preview - 56, // 22: signalservice.DataMessage.sticker:type_name -> signalservice.DataMessage.Sticker - 57, // 23: signalservice.DataMessage.reaction:type_name -> signalservice.DataMessage.Reaction - 58, // 24: signalservice.DataMessage.delete:type_name -> signalservice.DataMessage.Delete - 29, // 25: signalservice.DataMessage.bodyRanges:type_name -> signalservice.BodyRange - 59, // 26: signalservice.DataMessage.groupCallUpdate:type_name -> signalservice.DataMessage.GroupCallUpdate - 61, // 27: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment - 60, // 28: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext - 62, // 29: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge + 40, // 17: signalservice.DataMessage.attachments:type_name -> signalservice.AttachmentPointer + 42, // 18: signalservice.DataMessage.groupV2:type_name -> signalservice.GroupContextV2 + 55, // 19: signalservice.DataMessage.quote:type_name -> signalservice.DataMessage.Quote + 56, // 20: signalservice.DataMessage.contact:type_name -> signalservice.DataMessage.Contact + 36, // 21: signalservice.DataMessage.preview:type_name -> signalservice.Preview + 57, // 22: signalservice.DataMessage.sticker:type_name -> signalservice.DataMessage.Sticker + 58, // 23: signalservice.DataMessage.reaction:type_name -> signalservice.DataMessage.Reaction + 59, // 24: signalservice.DataMessage.delete:type_name -> signalservice.DataMessage.Delete + 30, // 25: signalservice.DataMessage.bodyRanges:type_name -> signalservice.BodyRange + 60, // 26: signalservice.DataMessage.groupCallUpdate:type_name -> signalservice.DataMessage.GroupCallUpdate + 62, // 27: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment + 61, // 28: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext + 63, // 29: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge 12, // 30: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type 13, // 31: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action - 41, // 32: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 - 39, // 33: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer - 36, // 34: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment - 29, // 35: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange - 39, // 36: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer + 42, // 32: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 + 40, // 33: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer + 37, // 34: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment + 30, // 35: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange + 40, // 36: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer 14, // 37: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style - 35, // 38: signalservice.TextAttachment.preview:type_name -> signalservice.Preview - 74, // 39: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient + 36, // 38: signalservice.TextAttachment.preview:type_name -> signalservice.Preview + 75, // 39: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient 15, // 40: signalservice.Verified.state:type_name -> signalservice.Verified.State - 75, // 41: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent - 76, // 42: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts - 78, // 43: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request - 79, // 44: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read - 77, // 45: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked - 37, // 46: signalservice.SyncMessage.verified:type_name -> signalservice.Verified - 81, // 47: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration - 82, // 48: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation - 83, // 49: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen - 84, // 50: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest - 85, // 51: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys - 86, // 52: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse - 87, // 53: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment - 80, // 54: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed - 88, // 55: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber - 89, // 56: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent - 90, // 57: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate - 91, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 25, // 59: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type - 95, // 60: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member - 39, // 61: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer - 96, // 62: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 37, // 63: signalservice.ContactDetails.verified:type_name -> signalservice.Verified - 98, // 64: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member - 97, // 65: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar - 99, // 66: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress - 30, // 67: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 76, // 41: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent + 77, // 42: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts + 79, // 43: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request + 80, // 44: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read + 78, // 45: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked + 38, // 46: signalservice.SyncMessage.verified:type_name -> signalservice.Verified + 82, // 47: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration + 83, // 48: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation + 84, // 49: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen + 85, // 50: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest + 86, // 51: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys + 87, // 52: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse + 88, // 53: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment + 81, // 54: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed + 89, // 55: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber + 90, // 56: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent + 91, // 57: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate + 92, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent + 26, // 59: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type + 96, // 60: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member + 40, // 61: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer + 97, // 62: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 38, // 63: signalservice.ContactDetails.verified:type_name -> signalservice.Verified + 99, // 64: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member + 98, // 65: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar + 100, // 66: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress + 31, // 67: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage 1, // 68: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type 2, // 69: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type 3, // 70: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 63, // 71: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 29, // 72: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 64, // 71: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 30, // 72: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange 7, // 73: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 64, // 74: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 65, // 75: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 66, // 76: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 67, // 77: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 68, // 78: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 39, // 79: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 70, // 80: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 71, // 81: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 39, // 82: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 65, // 74: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 66, // 75: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 67, // 76: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 68, // 77: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 69, // 78: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 79: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 71, // 80: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 72, // 81: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 40, // 82: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer 8, // 83: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type 9, // 84: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type 10, // 85: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 39, // 86: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 72, // 87: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 73, // 88: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 40, // 86: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 73, // 87: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 74, // 88: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin 11, // 89: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 30, // 90: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 92, // 91: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 34, // 92: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 93, // 93: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 47, // 94: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 39, // 95: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 31, // 90: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 93, // 91: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 92: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 94, // 93: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 48, // 94: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 95: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer 16, // 96: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type 17, // 97: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type 18, // 98: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type 19, // 99: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 94, // 100: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 95, // 100: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin 20, // 101: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type 21, // 102: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction 22, // 103: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 23, // 104: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 105, // [105:105] is the sub-list for method output_type - 105, // [105:105] is the sub-list for method input_type - 105, // [105:105] is the sub-list for extension type_name - 105, // [105:105] is the sub-list for extension extendee - 0, // [0:105] is the sub-list for field type_name + 23, // 104: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 24, // 105: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 106, // [106:106] is the sub-list for method output_type + 106, // [106:106] is the sub-list for method input_type + 106, // [106:106] is the sub-list for extension type_name + 106, // [106:106] is the sub-list for extension extendee + 0, // [0:106] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -9438,7 +9535,7 @@ func file_SignalService_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_SignalService_proto_rawDesc, - NumEnums: 26, + NumEnums: 27, NumMessages: 74, NumExtensions: 0, NumServices: 0, diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 866343f..2cf83ba 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -439,9 +439,11 @@ message Verified { message SyncMessage { message Sent { message UnidentifiedDeliveryStatus { - reserved /*destinationE164*/ 1; - optional string destinationServiceId = 3; - optional bool unidentified = 2; + reserved /*destinationE164*/ 1; + optional string destinationServiceId = 3; + optional bool unidentified = 2; + reserved /*destinationPni*/ 4; + optional bytes destinationIdentityKey = 5; } message StoryMessageRecipient { @@ -460,6 +462,8 @@ message SyncMessage { optional StoryMessage storyMessage = 8; repeated StoryMessageRecipient storyMessageRecipients = 9; optional EditMessage editMessage = 10; + reserved /*destinationPni*/ 11; + // NEXT ID: 12 } message Contacts { @@ -549,6 +553,8 @@ message SyncMessage { DELETE = 2; BLOCK = 3; BLOCK_AND_DELETE = 4; + SPAM = 5; + BLOCK_AND_SPAM = 6; } reserved /*threadE164*/ 1; @@ -619,13 +625,20 @@ message SyncMessage { } message CallLinkUpdate { + enum Type { + UPDATE = 0; + DELETE = 1; + } + optional bytes rootKey = 1; optional bytes adminPassKey = 2; + optional Type type = 3; } message CallLogEvent { enum Type { - CLEAR = 0; + CLEAR = 0; + MARKED_AS_READ = 1; } optional Type type = 1; @@ -673,7 +686,8 @@ message AttachmentPointer { optional bytes thumbnail = 5; optional bytes digest = 6; reserved 16; - optional bytes incrementalMac = 18; + reserved 18; + optional bytes incrementalMac = 19; optional uint32 incrementalMacChunkSize = 17; optional string fileName = 7; optional uint32 flags = 8; diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 1476794..f4894ec 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -831,7 +831,8 @@ type ContactRecord struct { SystemGivenName string `protobuf:"bytes,17,opt,name=systemGivenName,proto3" json:"systemGivenName,omitempty"` SystemFamilyName string `protobuf:"bytes,18,opt,name=systemFamilyName,proto3" json:"systemFamilyName,omitempty"` SystemNickname string `protobuf:"bytes,19,opt,name=systemNickname,proto3" json:"systemNickname,omitempty"` - Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` // NEXT ID: 21 + Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` + PniSignatureVerified bool `protobuf:"varint,21,opt,name=pniSignatureVerified,proto3" json:"pniSignatureVerified,omitempty"` // NEXT ID: 22 } func (x *ContactRecord) Reset() { @@ -1006,6 +1007,13 @@ func (x *ContactRecord) GetHidden() bool { return false } +func (x *ContactRecord) GetPniSignatureVerified() bool { + if x != nil { + return x.PniSignatureVerified + } + return false +} + type GroupV1Record struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1988,7 +1996,7 @@ var file_StorageService_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x15, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x22, 0x8d, 0x06, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, + 0x22, 0xc1, 0x06, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, @@ -2033,226 +2041,229 @@ var file_StorageService_proto_rawDesc = []byte{ 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x22, 0x3a, 0x0a, 0x0d, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, - 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, - 0x22, 0xcd, 0x01, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, - 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, - 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, - 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, - 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, - 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x22, 0xce, 0x03, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, - 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, - 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, - 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, - 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, - 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, - 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, - 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, - 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, - 0x0a, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, - 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x64, 0x64, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x14, 0x70, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x22, 0x3a, 0x0a, 0x0d, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, + 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x02, 0x22, 0xcd, 0x01, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, + 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, + 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, + 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x22, 0xce, 0x03, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, + 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, + 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, + 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, + 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, - 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, - 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, - 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, - 0x6f, 0x64, 0x65, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, - 0x64, 0x65, 0x22, 0x37, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, - 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, - 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, 0x10, - 0x0a, 0x22, 0x3e, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, - 0x70, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, - 0x79, 0x22, 0x9a, 0x12, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x50, 0x61, - 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x55, 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, - 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, - 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, - 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x73, - 0x65, 0x61, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, - 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, 0x65, 0x61, - 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, - 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, - 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, - 0x36, 0x0a, 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, - 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, - 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, - 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, - 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, 0x6b, 0x0a, 0x16, 0x70, - 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, - 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, - 0x52, 0x16, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, - 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x75, 0x6e, 0x6c, 0x69, - 0x73, 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x50, - 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x61, 0x0a, 0x13, 0x70, 0x69, - 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, - 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, - 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, - 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x73, 0x12, 0x33, 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x08, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, - 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x11, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x45, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, - 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, 0x73, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, - 0x73, 0x53, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x13, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x36, 0x0a, 0x16, 0x70, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, - 0x6a, 0x69, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, - 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, 0x64, - 0x18, 0x15, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x72, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x16, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x36, 0x0a, 0x16, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, - 0x79, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x6b, 0x65, - 0x65, 0x70, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x6b, 0x65, 0x65, 0x70, - 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, - 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, - 0x6f, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, - 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x12, 0x3a, 0x0a, 0x18, 0x68, 0x61, - 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x68, 0x61, - 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, - 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x12, 0x57, 0x0a, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, - 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1e, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x52, - 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, - 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x1f, 0x68, 0x61, 0x73, - 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, - 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, 0x18, 0x20, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, - 0x65, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x46, 0x0a, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, - 0x67, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, - 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, - 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x1a, 0x86, 0x02, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x6e, 0x65, - 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, - 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x65, 0x67, - 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0e, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, - 0x72, 0x4b, 0x65, 0x79, 0x1a, 0x3b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, - 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, - 0xf8, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, - 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, - 0x2e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0x6b, 0x0a, - 0x05, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, - 0x05, 0x57, 0x48, 0x49, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x45, 0x59, - 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x4c, 0x49, 0x56, 0x45, 0x10, 0x04, 0x12, 0x09, 0x0a, - 0x05, 0x47, 0x52, 0x45, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x52, 0x41, 0x4e, - 0x47, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x4b, 0x10, 0x07, 0x12, 0x0a, - 0x0a, 0x06, 0x50, 0x55, 0x52, 0x50, 0x4c, 0x45, 0x10, 0x08, 0x22, 0x40, 0x0a, 0x16, 0x50, 0x68, + 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, + 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, + 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, + 0x74, 0x6f, 0x72, 0x79, 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, + 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, + 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, + 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x37, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, + 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x4a, + 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x3e, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, + 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x6f, 0x70, 0x79, 0x22, 0x9a, 0x12, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, + 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x6e, + 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, + 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x72, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, + 0x36, 0x0a, 0x16, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, + 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x16, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, + 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, + 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, + 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, + 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, + 0x6b, 0x0a, 0x16, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, + 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x33, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, - 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x01, - 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, - 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1f, 0x10, 0x20, 0x22, 0xfb, - 0x01, 0x0a, 0x1b, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, - 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x49, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, - 0x70, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, - 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x34, 0x0a, 0x0c, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x09, 0x0a, 0x05, - 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, - 0x10, 0x02, 0x42, 0x3c, 0x0a, 0x38, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, - 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x50, 0x01, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x16, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x13, + 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, + 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x61, + 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, + 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x70, 0x69, + 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x73, 0x12, 0x33, 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x52, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, + 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x28, + 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, + 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, + 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x36, 0x0a, 0x16, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x6d, 0x6f, 0x6a, 0x69, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x72, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, + 0x64, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x72, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, + 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x16, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, + 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, + 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, + 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x36, + 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, + 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, + 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, + 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, + 0x53, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x12, 0x3a, + 0x0a, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, + 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1d, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, + 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, + 0x6f, 0x6f, 0x6c, 0x52, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, + 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, + 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, + 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x68, 0x61, 0x73, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x4d, 0x0a, 0x0c, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x0c, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x1a, 0x86, 0x02, 0x0a, 0x12, 0x50, + 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x53, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, + 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x28, + 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x1a, 0x3b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x65, 0x31, 0x36, 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x1a, 0xf8, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x4c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x22, 0x6b, 0x0a, 0x05, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x55, 0x45, 0x10, + 0x01, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x48, 0x49, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, + 0x47, 0x52, 0x45, 0x59, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x4c, 0x49, 0x56, 0x45, 0x10, + 0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, 0x45, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, + 0x4f, 0x52, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x4b, + 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x52, 0x50, 0x4c, 0x45, 0x10, 0x08, 0x22, 0x40, + 0x0a, 0x16, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, + 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4f, + 0x44, 0x59, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x02, + 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1f, + 0x10, 0x20, 0x22, 0xfb, 0x01, 0x0a, 0x1b, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, + 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, + 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, + 0x2a, 0x34, 0x0a, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, + 0x12, 0x09, 0x0a, 0x05, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, + 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x42, 0x3c, 0x0a, 0x38, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x73, 0x50, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index c8873ff..f9370b0 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -99,7 +99,8 @@ message ContactRecord { string systemFamilyName = 18; string systemNickname = 19; bool hidden = 20; - // NEXT ID: 21 + bool pniSignatureVerified = 21; + // NEXT ID: 22 } message GroupV1Record { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 76bb6ae..4aefdb7 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-c725a2fabb76f88d555c9f8b3c4f1cbdde4d4593} -DESKTOP_GIT_REVISION=${1:-060c58be527396918fa3753ace4f9f38d7c67876} +ANDROID_GIT_REVISION=${1:-915b3f0cd32628c6dfddb40934d1c3b47c52e991} +DESKTOP_GIT_REVISION=${1:-3eed6cb350f5e54df09e18a9012f4db74cecb7b6} update_proto() { case "$1" in From 2f7d81f97fd384b0ae00266e50756840ce5f5620 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 11 Mar 2024 20:44:43 +0200 Subject: [PATCH 106/718] Update dependencies --- go.mod | 22 ++++++++++------------ go.sum | 48 ++++++++++++++++++++++-------------------------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index 8e3abaa..65ef452 100644 --- a/go.mod +++ b/go.mod @@ -10,17 +10,17 @@ require ( github.com/lib/pq v1.10.9 github.com/mattn/go-pointer v0.0.1 github.com/mattn/go-sqlite3 v1.14.22 - github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_golang v1.19.0 github.com/rs/zerolog v1.32.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.1-0.20240222202553-953608f657a3 - golang.org/x/crypto v0.19.0 - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a - golang.org/x/net v0.21.0 - google.golang.org/protobuf v1.32.0 - maunium.net/go/mautrix v0.18.0-beta.1.0.20240223191208-581aa8015501 + go.mau.fi/util v0.4.1-0.20240311141448-53cb04950f7e + golang.org/x/crypto v0.21.0 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 + golang.org/x/net v0.22.0 + google.golang.org/protobuf v1.33.0 + maunium.net/go/mautrix v0.18.0-beta.1.0.20240311183606-94246ffc85aa nhooyr.io/websocket v1.8.10 ) @@ -33,10 +33,9 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rs/xid v1.5.0 // indirect github.com/tidwall/match v1.1.1 // indirect @@ -44,9 +43,8 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.0 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect - maunium.net/go/maulogger/v2 v2.4.1 // indirect ) diff --git a/go.sum b/go.sum index db6ca00..71cd8d6 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA= github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -37,17 +37,15 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -58,8 +56,8 @@ github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -71,23 +69,23 @@ 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.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.1-0.20240222202553-953608f657a3 h1:NcRrdzORHKab5bP1Z8BpH0nxsxsvH0iPPZLpOUN+UIc= -go.mau.fi/util v0.4.1-0.20240222202553-953608f657a3/go.mod h1:leeiHtgVBuN+W9aDii3deAXnfC563iN3WK6BF8/AjNw= +go.mau.fi/util v0.4.1-0.20240311141448-53cb04950f7e h1:e1jDj/MjleSS5r9DMRbuCZYKy5Rr+sbsu8eWjtLqrGk= +go.mau.fi/util v0.4.1-0.20240311141448-53cb04950f7e/go.mod h1:jOAREC/go8T6rGic01cu6WRa90xi9U4z3QmDjRf8xpo= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= @@ -97,9 +95,7 @@ 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/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= -maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.18.0-beta.1.0.20240223191208-581aa8015501 h1:3STixn49dd7VXL+p4hW0AEWy5/BeZlgA3i3BVsIgtqM= -maunium.net/go/mautrix v0.18.0-beta.1.0.20240223191208-581aa8015501/go.mod h1:1Q8P5C/uNmSBmull6DSqcawpg/E7hcGLQCD+JoU+vUo= +maunium.net/go/mautrix v0.18.0-beta.1.0.20240311183606-94246ffc85aa h1:TLSWIAWKIWxLghgzWfp7o92pVCcFR3yLsArc0s/tsMs= +maunium.net/go/mautrix v0.18.0-beta.1.0.20240311183606-94246ffc85aa/go.mod h1:0sfLB2ejW+lhgio4UlZMmn5i9SuZ8mxFkonFSamrfTE= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 3d1fda406250637974f274bc732d68c2e8f2f332 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Tue, 12 Mar 2024 14:57:00 -0600 Subject: [PATCH 107/718] parsing: add context throughout the process --- main.go | 4 ++-- msgconv/from-matrix.go | 2 +- msgconv/from-signal.go | 6 +++--- msgconv/matrixfmt/convert.go | 10 ++++++---- msgconv/matrixfmt/convert_test.go | 11 ++++++----- msgconv/matrixfmt/html.go | 9 ++++++--- msgconv/signalfmt/convert.go | 7 ++++--- msgconv/signalfmt/convert_test.go | 5 +++-- 8 files changed, 31 insertions(+), 23 deletions(-) diff --git a/main.go b/main.go index 6a8df7d..8f53ef3 100644 --- a/main.go +++ b/main.go @@ -118,7 +118,7 @@ func (br *SignalBridge) Init() { br.MatrixHandler.TrackEventDuration = br.Metrics.TrackMatrixEvent signalFormatParams = &signalfmt.FormatParams{ - GetUserInfo: func(u uuid.UUID) signalfmt.UserInfo { + GetUserInfo: func(ctx context.Context, u uuid.UUID) signalfmt.UserInfo { puppet := br.GetPuppetBySignalID(u) if puppet == nil { return signalfmt.UserInfo{} @@ -137,7 +137,7 @@ func (br *SignalBridge) Init() { }, } matrixFormatParams = &matrixfmt.HTMLParser{ - GetUUIDFromMXID: func(userID id.UserID) uuid.UUID { + GetUUIDFromMXID: func(ctx context.Context, userID id.UserID) uuid.UUID { parsed, ok := br.ParsePuppetMXID(userID) if ok { return parsed diff --git a/msgconv/from-matrix.go b/msgconv/from-matrix.go index fd89cd6..791ea9e 100644 --- a/msgconv/from-matrix.go +++ b/msgconv/from-matrix.go @@ -69,7 +69,7 @@ func (mc *MessageConverter) ToSignal(ctx context.Context, evt *event.Event, cont content.FormattedBody = "/me " + content.FormattedBody } } - body, bodyRanges := matrixfmt.Parse(mc.MatrixFmtParams, content) + body, bodyRanges := matrixfmt.Parse(ctx, mc.MatrixFmtParams, content) switch content.MsgType { case event.MsgText, event.MsgNotice, event.MsgEmote: dm.Body = proto.String(body) diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index e73ea0f..9b47cca 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -176,7 +176,7 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C } func (mc *MessageConverter) convertTextToMatrix(ctx context.Context, dm *signalpb.DataMessage) *ConvertedMessagePart { - content := signalfmt.Parse(dm.GetBody(), dm.GetBodyRanges(), mc.SignalFmtParams) + content := signalfmt.Parse(ctx, dm.GetBody(), dm.GetBodyRanges(), mc.SignalFmtParams) extra := map[string]any{} if len(dm.Preview) > 0 { extra["com.beeper.linkpreviews"] = mc.convertURLPreviewsToBeeper(ctx, dm.Preview) @@ -188,7 +188,7 @@ func (mc *MessageConverter) convertTextToMatrix(ctx context.Context, dm *signalp } } -func (mc *MessageConverter) convertPaymentToMatrix(ctx context.Context, payment *signalpb.DataMessage_Payment) *ConvertedMessagePart { +func (mc *MessageConverter) convertPaymentToMatrix(_ context.Context, payment *signalpb.DataMessage_Payment) *ConvertedMessagePart { return &ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ @@ -201,7 +201,7 @@ func (mc *MessageConverter) convertPaymentToMatrix(ctx context.Context, payment } } -func (mc *MessageConverter) convertGiftBadgeToMatrix(ctx context.Context, giftBadge *signalpb.DataMessage_GiftBadge) *ConvertedMessagePart { +func (mc *MessageConverter) convertGiftBadgeToMatrix(_ context.Context, giftBadge *signalpb.DataMessage_GiftBadge) *ConvertedMessagePart { return &ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ diff --git a/msgconv/matrixfmt/convert.go b/msgconv/matrixfmt/convert.go index 8e20e52..5318735 100644 --- a/msgconv/matrixfmt/convert.go +++ b/msgconv/matrixfmt/convert.go @@ -17,18 +17,20 @@ package matrixfmt import ( + "context" + "maunium.net/go/mautrix/event" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) -func Parse(parser *HTMLParser, content *event.MessageEventContent) (string, []*signalpb.BodyRange) { +func Parse(ctx context.Context, parser *HTMLParser, content *event.MessageEventContent) (string, []*signalpb.BodyRange) { if content.Format != event.FormatHTML { return content.Body, nil } - ctx := NewContext() - ctx.AllowedMentions = content.Mentions - parsed := parser.Parse(content.FormattedBody, ctx) + parseCtx := NewContext(ctx) + parseCtx.AllowedMentions = content.Mentions + parsed := parser.Parse(content.FormattedBody, parseCtx) if parsed == nil { return "", nil } diff --git a/msgconv/matrixfmt/convert_test.go b/msgconv/matrixfmt/convert_test.go index 0ee2514..6f9d66e 100644 --- a/msgconv/matrixfmt/convert_test.go +++ b/msgconv/matrixfmt/convert_test.go @@ -1,6 +1,7 @@ package matrixfmt_test import ( + "context" "fmt" "testing" @@ -14,7 +15,7 @@ import ( ) var formatParams = &matrixfmt.HTMLParser{ - GetUUIDFromMXID: func(id id.UserID) uuid.UUID { + GetUUIDFromMXID: func(_ context.Context, id id.UserID) uuid.UUID { if id.Homeserver() == "signal" { return uuid.MustParse(id.Localpart()) } @@ -23,7 +24,7 @@ var formatParams = &matrixfmt.HTMLParser{ } func TestParse_Empty(t *testing.T) { - text, entities := matrixfmt.Parse(formatParams, &event.MessageEventContent{ + text, entities := matrixfmt.Parse(context.TODO(), formatParams, &event.MessageEventContent{ MsgType: event.MsgText, Body: "", }) @@ -32,7 +33,7 @@ func TestParse_Empty(t *testing.T) { } func TestParse_EmptyHTML(t *testing.T) { - text, entities := matrixfmt.Parse(formatParams, &event.MessageEventContent{ + text, entities := matrixfmt.Parse(context.TODO(), formatParams, &event.MessageEventContent{ MsgType: event.MsgText, Body: "", Format: event.FormatHTML, @@ -43,7 +44,7 @@ func TestParse_EmptyHTML(t *testing.T) { } func TestParse_Plaintext(t *testing.T) { - text, entities := matrixfmt.Parse(formatParams, &event.MessageEventContent{ + text, entities := matrixfmt.Parse(context.TODO(), formatParams, &event.MessageEventContent{ MsgType: event.MsgText, Body: "Hello world!", }) @@ -152,7 +153,7 @@ func TestParse_HTML(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { fmt.Println("--------------------------------------------------------------------------------") - parsed := formatParams.Parse(test.in, matrixfmt.NewContext()) + parsed := formatParams.Parse(test.in, matrixfmt.NewContext(context.TODO())) assert.Equal(t, test.out, parsed.String.String()) assert.Equal(t, test.ent, parsed.Entities) }) diff --git a/msgconv/matrixfmt/html.go b/msgconv/matrixfmt/html.go index 88dc975..94571da 100644 --- a/msgconv/matrixfmt/html.go +++ b/msgconv/matrixfmt/html.go @@ -1,6 +1,7 @@ package matrixfmt import ( + "context" "fmt" "math" "strconv" @@ -201,13 +202,15 @@ func (ts TagStack) Has(tag string) bool { } type Context struct { + Ctx context.Context AllowedMentions *event.Mentions TagStack TagStack PreserveWhitespace bool } -func NewContext() Context { +func NewContext(ctx context.Context) Context { return Context{ + Ctx: ctx, TagStack: make(TagStack, 0, 4), } } @@ -224,7 +227,7 @@ func (ctx Context) WithWhitespace() Context { // HTMLParser is a somewhat customizable Matrix HTML parser. type HTMLParser struct { - GetUUIDFromMXID func(id.UserID) uuid.UUID + GetUUIDFromMXID func(context.Context, id.UserID) uuid.UUID } // TaggedString is a string that also contains a HTML tag. @@ -355,7 +358,7 @@ func (parser *HTMLParser) linkToString(node *html.Node, ctx Context) *EntityStri // Mention not allowed, use name as-is return str } - u := parser.GetUUIDFromMXID(mxid) + u := parser.GetUUIDFromMXID(ctx.Ctx, mxid) if u == uuid.Nil { // Don't include the link for mentions of non-Signal users, the name is enough return str diff --git a/msgconv/signalfmt/convert.go b/msgconv/signalfmt/convert.go index 317374d..06bbe7b 100644 --- a/msgconv/signalfmt/convert.go +++ b/msgconv/signalfmt/convert.go @@ -17,6 +17,7 @@ package signalfmt import ( + "context" "html" "strings" @@ -35,7 +36,7 @@ type UserInfo struct { } type FormatParams struct { - GetUserInfo func(uuid uuid.UUID) UserInfo + GetUserInfo func(ctx context.Context, uuid uuid.UUID) UserInfo } type formatContext struct { @@ -49,7 +50,7 @@ func (ctx formatContext) TextToHTML(text string) string { return event.TextToHTML(text) } -func Parse(message string, ranges []*signalpb.BodyRange, params *FormatParams) *event.MessageEventContent { +func Parse(ctx context.Context, message string, ranges []*signalpb.BodyRange, params *FormatParams) *event.MessageEventContent { content := &event.MessageEventContent{ MsgType: event.MsgText, Body: message, @@ -92,7 +93,7 @@ func Parse(message string, ranges []*signalpb.BodyRange, params *FormatParams) * if err != nil { continue } - userInfo := params.GetUserInfo(parsed) + userInfo := params.GetUserInfo(ctx, parsed) if userInfo.MXID == "" { continue } diff --git a/msgconv/signalfmt/convert_test.go b/msgconv/signalfmt/convert_test.go index eaed12d..1b2d693 100644 --- a/msgconv/signalfmt/convert_test.go +++ b/msgconv/signalfmt/convert_test.go @@ -17,6 +17,7 @@ package signalfmt_test import ( + "context" "testing" "github.com/google/uuid" @@ -33,7 +34,7 @@ var realUser = uuid.New() func TestParse(t *testing.T) { formatParams := &signalfmt.FormatParams{ - GetUserInfo: func(uuid uuid.UUID) signalfmt.UserInfo { + GetUserInfo: func(ctx context.Context, uuid uuid.UUID) signalfmt.UserInfo { if uuid == realUser { return signalfmt.UserInfo{ MXID: "@test:example.com", @@ -168,7 +169,7 @@ func TestParse(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - parsed := signalfmt.Parse(test.ins, test.ine, formatParams) + parsed := signalfmt.Parse(context.TODO(), test.ins, test.ine, formatParams) assert.Equal(t, test.body, parsed.Body) assert.Equal(t, test.html, parsed.FormattedBody) }) From 78b9e84ed39203e9a45be7892c73c770e03b1df5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 14 Mar 2024 01:20:37 +0200 Subject: [PATCH 108/718] Fix sending messages to groups --- pkg/libsignalgo/authcredential.go | 2 +- pkg/signalmeow/groups.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/authcredential.go b/pkg/libsignalgo/authcredential.go index a0a0bc9..c7c029a 100644 --- a/pkg/libsignalgo/authcredential.go +++ b/pkg/libsignalgo/authcredential.go @@ -57,7 +57,7 @@ func ReceiveAuthCredentialWithPni( } c_authCredResponse := (*[C.SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN]C.uchar)(unsafe.Pointer(&authCredResponse[0])) - signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_aci( + signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_service_id( &c_result, c_serverPublicParams, c_aci, diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 4c658fc..ed9ed1d 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -189,7 +189,7 @@ func (cli *Client) fetchNewGroupCreds(ctx context.Context, today time.Time) (*Gr Str("action", "fetch new group creds"). Logger() sevenDaysOut := today.Add(7 * 24 * time.Hour) - path := fmt.Sprintf("/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d", today.Unix(), sevenDaysOut.Unix()) + path := fmt.Sprintf("/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d&pniAsServiceId=true", today.Unix(), sevenDaysOut.Unix()) authRequest := web.CreateWSRequest(http.MethodGet, path, nil, nil, nil) resp, err := cli.AuthedWS.SendRequest(ctx, authRequest) if err != nil { From cdab7f86a84de20d146dcda4062e57191ecf4af3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 16 Mar 2024 13:41:50 +0200 Subject: [PATCH 109/718] Bump version to v0.5.1 --- CHANGELOG.md | 8 ++++++++ go.mod | 6 +++--- go.sum | 12 ++++++------ main.go | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acce96f..5a63f40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# v0.5.1 (2024-03-16) + +* Updated to libsignal v0.41.0. +* Fixed sending messages to groups. +* Fixed some cases of ghost user info changing repeatedly on multi-user + instances. +* Fixed migrating SQLite databases from Python version. + # v0.5.0 (2024-02-16) * Rewrote bridge in Go. diff --git a/go.mod b/go.mod index 65ef452..7359b16 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.1-0.20240311141448-53cb04950f7e + go.mau.fi/util v0.4.1 golang.org/x/crypto v0.21.0 - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 + golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f golang.org/x/net v0.22.0 google.golang.org/protobuf v1.33.0 - maunium.net/go/mautrix v0.18.0-beta.1.0.20240311183606-94246ffc85aa + maunium.net/go/mautrix v0.18.0 nhooyr.io/websocket v1.8.10 ) diff --git a/go.sum b/go.sum index 71cd8d6..3bb4666 100644 --- a/go.sum +++ b/go.sum @@ -69,14 +69,14 @@ 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.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.1-0.20240311141448-53cb04950f7e h1:e1jDj/MjleSS5r9DMRbuCZYKy5Rr+sbsu8eWjtLqrGk= -go.mau.fi/util v0.4.1-0.20240311141448-53cb04950f7e/go.mod h1:jOAREC/go8T6rGic01cu6WRa90xi9U4z3QmDjRf8xpo= +go.mau.fi/util v0.4.1 h1:3EC9KxIXo5+h869zDGf5OOZklRd/FjeVnimTwtm3owg= +go.mau.fi/util v0.4.1/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw= +golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -95,7 +95,7 @@ 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.18.0-beta.1.0.20240311183606-94246ffc85aa h1:TLSWIAWKIWxLghgzWfp7o92pVCcFR3yLsArc0s/tsMs= -maunium.net/go/mautrix v0.18.0-beta.1.0.20240311183606-94246ffc85aa/go.mod h1:0sfLB2ejW+lhgio4UlZMmn5i9SuZ8mxFkonFSamrfTE= +maunium.net/go/mautrix v0.18.0 h1:sNsApeSWB8x0hLjGcdmi5JqO6Tvp2PVkiSStz+Yas6k= +maunium.net/go/mautrix v0.18.0/go.mod h1:STwJZ+6CAeiEQs7fYCkd5aC12XR5DXANE6Swy/PBKGo= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index 8f53ef3..4251d45 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.5.0", + Version: "0.5.1", ProtocolName: "Signal", BeeperServiceName: "signal", BeeperNetworkName: "signal", From 25f0efc7e035db06ae7c414acd96c081c483d503 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 15 Mar 2024 15:30:44 +0200 Subject: [PATCH 110/718] Refactor sending to use service IDs --- pkg/libsignalgo/address.go | 16 +-- pkg/libsignalgo/authcredential.go | 12 +- pkg/libsignalgo/groupsecretparams.go | 16 +-- pkg/libsignalgo/profilekey.go | 15 +- pkg/libsignalgo/serviceid.go | 129 ++++++++++++----- pkg/signalmeow/groups.go | 4 + pkg/signalmeow/keys.go | 6 +- pkg/signalmeow/provisioning.go | 2 +- pkg/signalmeow/receiving.go | 17 ++- pkg/signalmeow/sending.go | 131 +++++++++--------- pkg/signalmeow/store/device.go | 4 + pkg/signalmeow/store/identity_store.go | 28 ++-- pkg/signalmeow/store/session_store.go | 43 +++--- pkg/signalmeow/store/upgrades/00-latest.sql | 24 ++-- .../store/upgrades/09-pni-sending.sql | 3 + portal.go | 7 +- 16 files changed, 260 insertions(+), 197 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/09-pni-sending.sql diff --git a/pkg/libsignalgo/address.go b/pkg/libsignalgo/address.go index fc6efa2..e1aa64e 100644 --- a/pkg/libsignalgo/address.go +++ b/pkg/libsignalgo/address.go @@ -23,8 +23,6 @@ package libsignalgo import "C" import ( "runtime" - - "github.com/google/uuid" ) type Address struct { @@ -38,16 +36,12 @@ func wrapAddress(ptr *C.SignalProtocolAddress) *Address { return address } -func NewUUIDAddress(u uuid.UUID, deviceID uint) (*Address, error) { - return newAddress(u.String(), deviceID) -} - func NewUUIDAddressFromString(uuidStr string, deviceID uint) (*Address, error) { - parsed, err := uuid.Parse(uuidStr) + serviceID, err := ServiceIDFromString(uuidStr) if err != nil { return nil, err } - return NewUUIDAddress(parsed, deviceID) + return serviceID.Address(deviceID) } // Deprecated: phone addresses are not used anymore @@ -93,12 +87,12 @@ func (pa *Address) Name() (string, error) { return CopyCStringToString(name), nil } -func (pa *Address) NameUUID() (uuid.UUID, error) { +func (pa *Address) NameServiceID() (ServiceID, error) { name, err := pa.Name() if err != nil { - return uuid.Nil, err + return ServiceID{}, err } - return uuid.Parse(name) + return ServiceIDFromString(name) } func (pa *Address) DeviceID() (uint, error) { diff --git a/pkg/libsignalgo/authcredential.go b/pkg/libsignalgo/authcredential.go index c7c029a..193f5b8 100644 --- a/pkg/libsignalgo/authcredential.go +++ b/pkg/libsignalgo/authcredential.go @@ -47,21 +47,13 @@ func ReceiveAuthCredentialWithPni( ) (*AuthCredentialWithPni, error) { c_result := [C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN]C.uchar{} c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) - c_aci, err := SignalServiceIDFromUUID(aci) - if err != nil { - return nil, err - } - c_pni, err := SignalPNIServiceIDFromUUID(pni) - if err != nil { - return nil, err - } c_authCredResponse := (*[C.SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN]C.uchar)(unsafe.Pointer(&authCredResponse[0])) signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_service_id( &c_result, c_serverPublicParams, - c_aci, - c_pni, + NewACIServiceID(aci).CFixedBytes(), + NewPNIServiceID(pni).CFixedBytes(), C.uint64_t(redemptionTime), c_authCredResponse, ) diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 4861868..6e1fc9f 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -23,6 +23,7 @@ package libsignalgo import "C" import ( "crypto/rand" + "fmt" "runtime" "unsafe" @@ -129,27 +130,24 @@ func (gsp *GroupSecretParams) DecryptUUID(ciphertextUUID UUIDCiphertext) (uuid.U return uuid.Nil, wrapError(signalFfiError) } - result, err := SignalServiceIDToUUID(&u) - if err != nil { - return uuid.Nil, err + serviceID := ServiceIDFromCFixedBytes(&u) + if serviceID.Type != ServiceIDTypeACI { + return uuid.Nil, fmt.Errorf("unexpected service ID type %d", serviceID.Type) } - return result, nil + return serviceID.UUID, nil } func (gsp *GroupSecretParams) DecryptProfileKey(ciphertextProfileKey ProfileKeyCiphertext, u uuid.UUID) (*ProfileKey, error) { profileKey := [C.SignalPROFILE_KEY_LEN]C.uchar{} - serviceId, err := SignalServiceIDFromUUID(u) - if err != nil { - return nil, err - } 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)), - serviceId, + NewACIServiceID(u).CFixedBytes(), ) runtime.KeepAlive(gsp) runtime.KeepAlive(ciphertextProfileKey) + runtime.KeepAlive(u) if signalFfiError != nil { return nil, wrapError(signalFfiError) } diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index ba43a60..bcf9d49 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -59,10 +59,7 @@ func (pk *ProfileKey) Slice() []byte { 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, err := SignalServiceIDFromUUID(u) - if err != nil { - return nil, err - } + c_uuid := NewACIServiceID(u).CFixedBytes() signalFfiError := C.signal_profile_key_get_commitment( &c_result, @@ -84,10 +81,7 @@ func (pk *ProfileKey) GetCommitment(u uuid.UUID) (*ProfileKeyCommitment, error) 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, err := SignalServiceIDFromUUID(u) - if err != nil { - return nil, err - } + c_uuid := NewACIServiceID(u).CFixedBytes() signalFfiError := C.signal_profile_key_get_profile_key_version( &c_result, @@ -137,10 +131,7 @@ func CreateProfileKeyCredentialRequestContext(serverPublicParams ServerPublicPar 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, err := SignalServiceIDFromUUID(u) - if err != nil { - return nil, err - } + c_uuid := NewACIServiceID(u).CFixedBytes() signalFfiError := C.signal_server_public_params_create_profile_key_credential_request_context_deterministic( &c_result, diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index 0e2eeb4..31d4141 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -1,5 +1,5 @@ // mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber +// Copyright (C) 2024 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 @@ -24,7 +24,7 @@ package libsignalgo import "C" import ( "fmt" - "runtime" + "strings" "unsafe" "github.com/google/uuid" @@ -36,38 +36,105 @@ func init() { } } -func SignalServiceIDFromUUID(uuid uuid.UUID) (cPNIType, error) { - var result C.SignalServiceIdFixedWidthBinaryBytes - signalFfiError := C.signal_service_id_parse_from_service_id_binary(&result, BytesToBuffer(uuid[:])) - runtime.KeepAlive(uuid) - if signalFfiError != nil { - return nil, wrapError(signalFfiError) +type ServiceIDType byte + +const ( + ServiceIDTypeACI ServiceIDType = 0 + ServiceIDTypePNI ServiceIDType = 1 +) + +func (st ServiceIDType) String() string { + switch st { + case ServiceIDTypeACI: + return "ACI" + case ServiceIDTypePNI: + return "PNI" + default: + panic(fmt.Sprintf("invalid ServiceIDType: %d", st)) } - return cPNIType(unsafe.Pointer(&result)), nil } -func SignalPNIServiceIDFromUUID(uuid uuid.UUID) (cPNIType, error) { - var result C.SignalServiceIdFixedWidthBinaryBytes - // Prepend a 0x01 to the UUID to indicate that it is a PNI UUID - pniUUID := append([]byte{0x01}, uuid[:]...) - signalFfiError := C.signal_service_id_parse_from_service_id_binary(&result, BytesToBuffer(pniUUID)) - runtime.KeepAlive(pniUUID) - if signalFfiError != nil { - return nil, wrapError(signalFfiError) - } - return cPNIType(unsafe.Pointer(&result)), nil +func (st ServiceIDType) GoString() string { + return fmt.Sprintf("libsignalgo.ServiceIDType%s", st.String()) } -func SignalServiceIDToUUID(serviceId *C.SignalServiceIdFixedWidthBinaryBytes) (uuid.UUID, error) { - result := C.SignalOwnedBuffer{} - serviceIdBytes := cPNIType(unsafe.Pointer(serviceId)) // Hack around gcc bug, not needed for clang - signalFfiError := C.signal_service_id_service_id_binary(&result, serviceIdBytes) - if signalFfiError != nil { - return uuid.UUID{}, wrapError(signalFfiError) - } - uuidBytes := CopySignalOwnedBufferToBytes(result) - if len(uuidBytes) != 16 { - return uuid.UUID{}, fmt.Errorf("invalid UUID length: %d. UUID: %x", len(uuidBytes), uuidBytes) - } - return uuid.UUID(uuidBytes), nil +type ServiceID struct { + Type ServiceIDType + UUID uuid.UUID +} + +func NewPNIServiceID(uuid uuid.UUID) ServiceID { + return ServiceID{ + Type: ServiceIDTypePNI, + UUID: uuid, + } +} + +func NewACIServiceID(uuid uuid.UUID) ServiceID { + return ServiceID{ + Type: ServiceIDTypeACI, + UUID: uuid, + } +} + +func (s ServiceID) Address(deviceID uint) (*Address, error) { + return newAddress(s.String(), deviceID) +} + +func (s ServiceID) Bytes() []byte { + if s.Type == ServiceIDTypeACI { + return s.UUID[:] + } + return append([]byte{byte(s.Type)}, s.UUID[:]...) +} + +func (s ServiceID) String() string { + if s.Type == ServiceIDTypeACI { + return s.UUID.String() + } + return fmt.Sprintf("%s:%s", s.Type, s.UUID) +} + +func (s ServiceID) GoString() string { + return fmt.Sprintf(`libsignalgo.ServiceID{Type: %#v, UUID: uuid.MustParse("%s")}`, s.Type, s.UUID) +} + +type ServiceIDFixedBytes [17]byte + +func (s ServiceID) FixedBytes() *ServiceIDFixedBytes { + var result ServiceIDFixedBytes + result[0] = byte(s.Type) + copy(result[1:], s.UUID[:]) + return &result +} + +func ServiceIDFromString(val string) (ServiceID, error) { + if len(val) < 36 { + return ServiceID{}, fmt.Errorf("invalid UUID string: %s", val) + } + if strings.ToUpper(val[:4]) == "PNI:" { + parsed, err := uuid.Parse(val[4:]) + if err != nil { + return ServiceID{}, err + } + return NewPNIServiceID(parsed), nil + } else { + parsed, err := uuid.Parse(val) + if err != nil { + return ServiceID{}, err + } + return NewACIServiceID(parsed), nil + } +} + +func ServiceIDFromCFixedBytes(serviceID *C.SignalServiceIdFixedWidthBinaryBytes) ServiceID { + var id ServiceID + fixedBytes := (*ServiceIDFixedBytes)(unsafe.Pointer(serviceID)) + id.Type = ServiceIDType(fixedBytes[0]) + copy(id.UUID[:], fixedBytes[1:]) + return id +} + +func (s ServiceID) CFixedBytes() cPNIType { + return cPNIType(unsafe.Pointer(s.FixedBytes())) } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index ed9ed1d..8978bbd 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -70,6 +70,10 @@ type GroupMember struct { //Presentation []byte } +func (gm *GroupMember) UserServiceID() libsignalgo.ServiceID { + return libsignalgo.NewACIServiceID(gm.UserID) +} + type Group struct { groupMasterKey types.SerializedGroupMasterKey // We should keep this relatively private GroupIdentifier types.GroupIdentifier // This is what we should use to identify a group outside this file diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 48a70a9..eafa2db 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -341,13 +341,13 @@ func addBase64PaddingAndDecode(data string) ([]byte, error) { return base64.StdEncoding.DecodeString(data) } -func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUID, specificDeviceID int) error { +func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, specificDeviceID int) error { // Fetch prekey deviceIDPath := "/*" if specificDeviceID >= 0 { deviceIDPath = "/" + fmt.Sprint(specificDeviceID) } - path := "/v2/keys/" + theirUUID.String() + deviceIDPath + "?pq=true" + path := "/v2/keys/" + theirServiceID.String() + deviceIDPath + "?pq=true" username, password := cli.Store.BasicAuthCreds() resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) if err != nil { @@ -436,7 +436,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirUUID uuid.UUI if err != nil { return fmt.Errorf("error creating prekey bundle: %w", err) } - address, err := libsignalgo.NewUUIDAddress(theirUUID, uint(d.DeviceID)) + address, err := theirServiceID.Address(uint(d.DeviceID)) if err != nil { return fmt.Errorf("error creating address: %w", err) } diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 5f959d6..b9889b4 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -187,7 +187,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev device.ClearDeviceKeys(ctx) // Store identity keys? - address, err := libsignalgo.NewUUIDAddress(device.ACI, uint(device.DeviceID)) + address, err := libsignalgo.NewACIServiceID(device.ACI).Address(uint(device.DeviceID)) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 0c9ca06..05d208e 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -322,7 +322,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if err != nil { log.Err(err).Msg("GetDeviceID error") } - senderAddress, err := libsignalgo.NewUUIDAddress(senderUUID, uint(senderDeviceID)) + senderAddress, err := libsignalgo.NewACIServiceID(senderUUID).Address(uint(senderDeviceID)) if err != nil { log.Err(err).Msg("NewAddress error") } @@ -587,11 +587,17 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } } - theirUUID, err := result.SenderAddress.NameUUID() + theirServiceID, err := result.SenderAddress.NameServiceID() if err != nil { log.Err(err).Msg("Name error") return nil, err + } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { + log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") + return &web.SimpleResponse{ + Status: responseCode, + }, nil } + theirUUID := theirServiceID.UUID // TODO: handle more sync messages if content.SyncMessage != nil { @@ -855,7 +861,7 @@ func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps // Send delivery receipts if len(deliveredTimestamps) > 0 { receipt := DeliveredReceiptMessageForTimestamps(deliveredTimestamps) - result := cli.SendMessage(ctx, senderUUID, receipt) + result := cli.SendMessage(ctx, libsignalgo.NewACIServiceID(senderUUID), receipt) if !result.WasSuccessful { return fmt.Errorf("failed to send delivery receipts: %v", result) } @@ -906,10 +912,7 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E if err != nil { return nil, fmt.Errorf("stripPadding error: %w", err) } - address, err := libsignalgo.NewUUIDAddress( - result.Sender.UUID, - uint(result.Sender.DeviceID), - ) + address, err := libsignalgo.NewACIServiceID(result.Sender.UUID).Address(uint(result.Sender.DeviceID)) if err != nil { return nil, fmt.Errorf("NewAddress error: %w", err) } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 33cd93f..ba9e8e0 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -144,7 +144,7 @@ func checkForErrorWithSessions(err error, addresses []*libsignalgo.Address, sess } func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { - addresses, _, err := cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, cli.Store.ACI) + addresses, _, err := cli.Store.SessionStoreExtras.AllSessionsForServiceID(ctx, cli.Store.ACIServiceID()) if err != nil { return 0 } @@ -163,21 +163,21 @@ func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { return otherDevices } -func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.UUID, content *signalpb.Content, unauthenticated bool) ([]MyMessage, error) { +func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalgo.ServiceID, content *signalpb.Content, unauthenticated bool) ([]MyMessage, error) { // We need to prevent multiple encryption operations from happening at once, or else ratchets can race cli.encryptionLock.Lock() defer cli.encryptionLock.Unlock() messages := []MyMessage{} - addresses, sessionRecords, err := cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) + addresses, sessionRecords, err := cli.Store.SessionStoreExtras.AllSessionsForServiceID(ctx, recipient) if err == nil && (len(addresses) == 0 || len(sessionRecords) == 0) { // No sessions, make one with prekey - err = cli.FetchAndProcessPreKey(ctx, recipientUUID, -1) + err = cli.FetchAndProcessPreKey(ctx, recipient, -1) if err != nil { return nil, err } - addresses, sessionRecords, err = cli.Store.SessionStoreExtras.AllSessionsForUUID(ctx, recipientUUID) + addresses, sessionRecords, err = cli.Store.SessionStoreExtras.AllSessionsForServiceID(ctx, recipient) } err = checkForErrorWithSessions(err, addresses, sessionRecords) if err != nil { @@ -191,7 +191,7 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.U } // Don't send to this device that we are sending from - if recipientUUID == cli.Store.ACI && recipientDeviceID == uint(cli.Store.DeviceID) { + if recipient == cli.Store.ACIServiceID() && recipientDeviceID == uint(cli.Store.DeviceID) { zerolog.Ctx(ctx).Debug(). Uint("recipient_device_id", recipientDeviceID). Msg("Not sending to the device I'm sending from") @@ -203,7 +203,7 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipientUUID uuid.U if err != nil { return nil, err } - paddedMessage, err := addPadding(3, []byte(serializedMessage)) // TODO: figure out how to get actual version + paddedMessage, err := addPadding(3, serializedMessage) // TODO: figure out how to get actual version if err != nil { return nil, err } @@ -286,12 +286,12 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l } type SuccessfulSendResult struct { - RecipientUUID uuid.UUID - Unidentified bool + Recipient libsignalgo.ServiceID + Unidentified bool } type FailedSendResult struct { - RecipientUUID uuid.UUID - Error error + Recipient libsignalgo.ServiceID + Error error } type SendMessageResult struct { WasSuccessful bool @@ -312,7 +312,7 @@ func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} for _, result := range results { unidentifiedStatuses = append(unidentifiedStatuses, &signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ - DestinationServiceId: proto.String(result.RecipientUUID.String()), + DestinationServiceId: proto.String(result.Recipient.String()), Unidentified: &result.Unidentified, }) } @@ -330,7 +330,7 @@ func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} for _, result := range results { unidentifiedStatuses = append(unidentifiedStatuses, &signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ - DestinationServiceId: proto.String(result.RecipientUUID.String()), + DestinationServiceId: proto.String(result.Recipient.String()), Unidentified: &result.Unidentified, }) } @@ -350,11 +350,11 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ Message: dataMessage, - DestinationServiceId: proto.String(result.RecipientUUID.String()), + DestinationServiceId: proto.String(result.Recipient.String()), Timestamp: dataMessage.Timestamp, UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.RecipientUUID.String()), + DestinationServiceId: proto.String(result.Recipient.String()), Unidentified: &result.Unidentified, }, }, @@ -368,11 +368,11 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ EditMessage: editMessage, - DestinationServiceId: proto.String(result.RecipientUUID.String()), + DestinationServiceId: proto.String(result.Recipient.String()), Timestamp: editMessage.DataMessage.Timestamp, UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.RecipientUUID.String()), + DestinationServiceId: proto.String(result.Recipient.String()), Unidentified: &result.Unidentified, }, }, @@ -391,18 +391,23 @@ func syncMessageForContactRequest() *signalpb.Content { } } -func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender uuid.UUID) *signalpb.Content { +func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender libsignalgo.ServiceID) *signalpb.Content { if *receiptMessage.Type != signalpb.ReceiptMessage_READ { zerolog.Ctx(ctx).Warn(). Any("receipt_message_type", receiptMessage.Type). Msg("syncMessageFromReadReceiptMessage called with non-read receipt message") return nil + } else if messageSender.Type != libsignalgo.ServiceIDTypeACI { + zerolog.Ctx(ctx).Warn(). + Stringer("message_sender", messageSender). + Msg("syncMessageFromReadReceiptMessage called with non-ACI message sender") + return nil } read := []*signalpb.SyncMessage_Read{} for _, timestamp := range receiptMessage.Timestamp { read = append(read, &signalpb.SyncMessage_Read{ Timestamp: proto.Uint64(timestamp), - SenderAci: proto.String(messageSender.String()), + SenderAci: proto.String(messageSender.UUID.String()), }) } return &signalpb.Content{ @@ -431,7 +436,7 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { } groupRequest := syncMessageForContactRequest() - _, err := cli.sendContent(ctx, cli.Store.ACI, uint64(currentUnixTime), groupRequest, 0, true) + _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(currentUnixTime), groupRequest, 0, true) if err != nil { log.Err(err).Msg("Failed to send contact sync request message to myself") return err @@ -543,17 +548,17 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } log := log.With().Stringer("member", member.UserID).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, member.UserID, messageTimestamp, content, 0, true) + sentUnidentified, err := cli.sendContent(ctx, member.UserServiceID(), messageTimestamp, content, 0, true) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ - RecipientUUID: member.UserID, - Error: err, + Recipient: member.UserServiceID(), + Error: err, }) log.Err(err).Msg("Failed to send to user") } else { result.SuccessfullySentTo = append(result.SuccessfullySentTo, SuccessfulSendResult{ - RecipientUUID: member.UserID, - Unidentified: sentUnidentified, + Recipient: member.UserServiceID(), + Unidentified: sentUnidentified, }) log.Trace().Msg("Successfully sent to user") } @@ -567,7 +572,7 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } else if content.GetEditMessage() != nil { syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) } - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTimestamp, syncContent, 0, true) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true) if selfSendErr != nil { log.Err(selfSendErr).Msg("Failed to send sync message to myself") } @@ -593,10 +598,10 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, } else if content.GetEditMessage() != nil { syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { - syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.RecipientUUID) + syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) } if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACI, messageTS, syncContent, 0, true) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } else { @@ -607,7 +612,7 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, return false } -func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, content *signalpb.Content) SendMessageResult { +func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.ServiceID, content *signalpb.Content) SendMessageResult { // Assemble the content to send var messageTimestamp uint64 if content.GetDataMessage() != nil { @@ -619,10 +624,10 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, conte } isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY - if recipientID == cli.Store.ACI && !isDeliveryReceipt { + if recipientID == cli.Store.ACIServiceID() && !isDeliveryReceipt { res := &SuccessfulSendResult{ - RecipientUUID: recipientID, - Unidentified: false, + Recipient: recipientID, + Unidentified: false, } ok := cli.sendSyncCopy(ctx, content, messageTimestamp, res) return SendMessageResult{ @@ -637,16 +642,16 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID uuid.UUID, conte return SendMessageResult{ WasSuccessful: false, FailedSendResult: &FailedSendResult{ - RecipientUUID: recipientID, - Error: err, + Recipient: recipientID, + Error: err, }, } } result := SendMessageResult{ WasSuccessful: true, SuccessfulSendResult: &SuccessfulSendResult{ - RecipientUUID: recipientID, - Unidentified: sentUnidentified, + Recipient: recipientID, + Unidentified: sentUnidentified, }, } @@ -661,7 +666,7 @@ func currentMessageTimestamp() uint64 { func (cli *Client) sendContent( ctx context.Context, - recipientUUID uuid.UUID, + recipient libsignalgo.ServiceID, messageTimestamp uint64, content *signalpb.Content, retryCount int, @@ -669,7 +674,7 @@ func (cli *Client) sendContent( ) (sentUnidentified bool, err error) { log := zerolog.Ctx(ctx).With(). Str("action", "send content"). - Stringer("recipient", recipientUUID). + Stringer("recipient", recipient). Uint64("timestamp", messageTimestamp). Logger() ctx = log.WithContext(ctx) @@ -691,13 +696,18 @@ func (cli *Client) sendContent( return false, fmt.Errorf("too many retries") } - // Don't use unauthed websocket to send a payload to my own other devices - if recipientUUID == cli.Store.ACI { + if recipient.Type == libsignalgo.ServiceIDTypePNI && recipient.UUID == cli.Store.PNI { + return false, fmt.Errorf("can't send to own PNI") + } else if recipient.Type == libsignalgo.ServiceIDTypeACI && recipient.UUID == cli.Store.ACI { + // Don't use unauthed websocket to send a payload to my own other devices + useUnidentifiedSender = false + } else if recipient.Type == libsignalgo.ServiceIDTypePNI { + // Can't use unidentified sender for PNIs because only ACIs have profile keys useUnidentifiedSender = false } var accessKey *libsignalgo.AccessKey if useUnidentifiedSender { - profileKey, err := cli.ProfileKeyForSignalID(ctx, recipientUUID) + profileKey, err := cli.ProfileKeyForSignalID(ctx, recipient.UUID) if err != nil { return false, fmt.Errorf("failed to get profile key: %w", err) } else if profileKey == nil { @@ -710,7 +720,7 @@ func (cli *Client) sendContent( } var messages []MyMessage - messages, err = cli.buildMessagesToSend(ctx, recipientUUID, content, useUnidentifiedSender) + messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender) if err != nil { log.Err(err).Msg("Error building messages to send") return false, err @@ -726,7 +736,7 @@ func (cli *Client) sendContent( if err != nil { return false, err } - path := fmt.Sprintf("/v1/messages/%v", recipientUUID) + path := fmt.Sprintf("/v1/messages/%s", recipient) request := web.CreateWSRequest(http.MethodPut, path, jsonBytes, nil, nil) var response *signalpb.WebSocketResponseMessage @@ -769,17 +779,17 @@ func (cli *Client) sendContent( if needToRetry { var err error if *response.Status == 409 { - err = cli.handle409(ctx, recipientUUID, response) + err = cli.handle409(ctx, recipient, response) } else if *response.Status == 410 { - err = cli.handle410(ctx, recipientUUID, response) + err = cli.handle410(ctx, recipient, response) } else if *response.Status == 428 { - err = cli.handle428(ctx, recipientUUID, response) + err = cli.handle428(ctx, recipient, response) } if err != nil { return false, err } // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1, sentUnidentified) + sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, sentUnidentified) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err @@ -787,7 +797,7 @@ func (cli *Client) sendContent( } else if *response.Status == 401 && useUnidentifiedSender { log.Debug().Msg("Retrying send without sealed sender") // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipientUUID, messageTimestamp, content, retryCount+1, false) + sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, false) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err @@ -800,7 +810,7 @@ func (cli *Client) sendContent( } // A 409 means our device list was out of date, so we will fix it up -func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { +func (cli *Client) handle409(ctx context.Context, recipient libsignalgo.ServiceID, response *signalpb.WebSocketResponseMessage) error { log := zerolog.Ctx(ctx) // Decode json body // TODO use an actual struct for this @@ -816,7 +826,7 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo log.Debug().Any("missing_devices", missingDevices).Msg("missing devices found in 409 response") // TODO: establish session with missing devices for _, missingDevice := range missingDevices { - err = cli.FetchAndProcessPreKey(ctx, recipientUUID, int(missingDevice.(float64))) + err = cli.FetchAndProcessPreKey(ctx, recipient, int(missingDevice.(float64))) if err != nil { return nil } @@ -826,16 +836,12 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo extraDevices := body["extraDevices"].([]any) log.Debug().Any("extra_devices", extraDevices).Msg("extra devices found in 409 response") for _, extraDevice := range extraDevices { - // Remove extra device from the sessionstore - recipient, err := libsignalgo.NewUUIDAddress( - recipientUUID, - uint(extraDevice.(float64)), - ) + recipientAddr, err := recipient.Address(uint(extraDevice.(float64))) if err != nil { log.Err(err).Msg("NewAddress error") return err } - err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipient) + err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipientAddr) if err != nil { log.Err(err).Msg("RemoveSession error") return err @@ -846,7 +852,7 @@ func (cli *Client) handle409(ctx context.Context, recipientUUID uuid.UUID, respo } // A 410 means we have a stale device, so get rid of it -func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { +func (cli *Client) handle410(ctx context.Context, recipient libsignalgo.ServiceID, response *signalpb.WebSocketResponseMessage) error { log := zerolog.Ctx(ctx) // Decode json body // TODO use an actual struct @@ -861,20 +867,17 @@ func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, respo staleDevices := body["staleDevices"].([]any) log.Debug().Any("stale_devices", staleDevices).Msg("stale devices found in 410 response") for _, staleDevice := range staleDevices { - recipient, err := libsignalgo.NewUUIDAddress( - recipientUUID, - uint(staleDevice.(float64)), - ) + recipientAddr, err := recipient.Address(uint(staleDevice.(float64))) if err != nil { log.Err(err).Msg("error creating new UUID Address") return err } - err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipient) + err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipientAddr) if err != nil { log.Err(err).Msg("RemoveSession error") return err } - err = cli.FetchAndProcessPreKey(ctx, recipientUUID, int(staleDevice.(float64))) + err = cli.FetchAndProcessPreKey(ctx, recipient, int(staleDevice.(float64))) if err != nil { return err } @@ -886,7 +889,7 @@ func (cli *Client) handle410(ctx context.Context, recipientUUID uuid.UUID, respo // We got rate limited. // We ~~will~~ could try sending a "pushChallenge" response, but if that doesn't work we just gotta wait. // TODO: explore captcha response -func (cli *Client) handle428(ctx context.Context, recipientUUID uuid.UUID, response *signalpb.WebSocketResponseMessage) error { +func (cli *Client) handle428(ctx context.Context, recipient libsignalgo.ServiceID, response *signalpb.WebSocketResponseMessage) error { log := zerolog.Ctx(ctx) // Decode json body // TODO use an actual struct diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index 16d3c1e..6a10b4b 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -36,6 +36,10 @@ type DeviceData struct { Password string } +func (d *DeviceData) ACIServiceID() libsignalgo.ServiceID { + return libsignalgo.NewACIServiceID(d.ACI) +} + func (d *DeviceData) BasicAuthCreds() (string, string) { username := fmt.Sprintf("%s.%d", d.ACI, d.DeviceID) password := d.Password diff --git a/pkg/signalmeow/store/identity_store.go b/pkg/signalmeow/store/identity_store.go index 14276a1..73cb2ce 100644 --- a/pkg/signalmeow/store/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -33,18 +33,18 @@ const ( getIdentityKeyPairQuery = `SELECT aci_identity_key_pair FROM signalmeow_device WHERE aci_uuid=$1` getRegistrationLocalIDQuery = `SELECT registration_id FROM signalmeow_device WHERE aci_uuid=$1` insertIdentityKeyQuery = ` - INSERT INTO signalmeow_identity_keys (our_aci_uuid, their_aci_uuid, their_device_id, key, trust_level) + INSERT INTO signalmeow_identity_keys (our_aci_uuid, their_service_id, their_device_id, key, trust_level) VALUES ($1, $2, $3, $4, $5) - ON CONFLICT (our_aci_uuid, their_aci_uuid, their_device_id) DO UPDATE + ON CONFLICT (our_aci_uuid, their_service_id, their_device_id) DO UPDATE SET key=excluded.key, trust_level=excluded.trust_level ` getIdentityKeyTrustLevelQuery = ` SELECT trust_level FROM signalmeow_identity_keys - WHERE our_aci_uuid=$1 AND their_aci_uuid=$2 AND their_device_id=$3 + WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3 ` getIdentityKeyQuery = ` SELECT key FROM signalmeow_identity_keys - WHERE our_aci_uuid=$1 AND their_aci_uuid=$2 AND their_device_id=$3 + WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3 ` ) @@ -89,15 +89,15 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add if err != nil { return false, fmt.Errorf("failed to serialize identity key: %w", err) } - theirUUID, err := address.Name() + theirServiceID, err := address.Name() if err != nil { - return false, fmt.Errorf("failed to get their uuid: %w", err) + return false, fmt.Errorf("failed to get their service ID: %w", err) } deviceID, err := address.DeviceID() if err != nil { return false, fmt.Errorf("failed to get device ID: %w", err) } - oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirUUID, deviceID)) + oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirServiceID, deviceID)) if err != nil { return false, fmt.Errorf("failed to get old identity key: %w", err) } @@ -110,7 +110,7 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add // We are replacing the old key if the old key exists, and it is not equal to the new key replacing = !equal } - _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.ACI, theirUUID, deviceID, serialized, trustLevel) + _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.ACI, theirServiceID, deviceID, serialized, trustLevel) if err != nil { return replacing, fmt.Errorf("failed to insert new identity key: %w", err) } @@ -119,16 +119,16 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { // TODO: this should check direction, and probably some other stuff (though whisperfish is pretty basic) - theirUUID, err := address.Name() + theirServiceID, err := address.Name() if err != nil { - return false, fmt.Errorf("failed to get their uuid: %w", err) + return false, fmt.Errorf("failed to get their service ID: %w", err) } deviceID, err := address.DeviceID() if err != nil { return false, fmt.Errorf("failed to get device ID: %w", err) } var trustLevel string - err = s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.ACI, theirUUID, deviceID).Scan(&trustLevel) + err = s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.ACI, theirServiceID, deviceID).Scan(&trustLevel) if errors.Is(err, sql.ErrNoRows) { // If no rows, they are a new identity, so trust by default return true, nil @@ -140,15 +140,15 @@ func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.A } func (s *SQLStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.IdentityKey, error) { - theirUUID, err := address.Name() + theirServiceID, err := address.Name() if err != nil { - return nil, fmt.Errorf("failed to get their uuid: %w", err) + return nil, fmt.Errorf("failed to get their service ID: %w", err) } deviceID, err := address.DeviceID() if err != nil { return nil, fmt.Errorf("failed to get device ID: %w", err) } - key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirUUID, deviceID)) + key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirServiceID, deviceID)) if err != nil { return nil, fmt.Errorf("failed to get identity key from database: %w", err) } diff --git a/pkg/signalmeow/store/session_store.go b/pkg/signalmeow/store/session_store.go index 5c190da..bb6f18a 100644 --- a/pkg/signalmeow/store/session_store.go +++ b/pkg/signalmeow/store/session_store.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" - "github.com/google/uuid" "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -32,15 +31,19 @@ var _ libsignalgo.SessionStore = (*SQLStore)(nil) var _ SessionStoreExtras = (*SQLStore)(nil) const ( - loadSessionQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_aci_uuid=$2 AND their_device_id=$3` - storeSessionQuery = `INSERT INTO signalmeow_sessions (our_aci_uuid, their_aci_uuid, their_device_id, record) VALUES ($1, $2, $3, $4) ON CONFLICT (our_aci_uuid, their_aci_uuid, their_device_id) DO UPDATE SET record=excluded.record` - allSessionsQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_aci_uuid=$2` - removeSessionQuery = `DELETE FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_aci_uuid=$2 AND their_device_id=$3` + loadSessionQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3` + storeSessionQuery = ` + INSERT INTO signalmeow_sessions (our_aci_uuid, their_service_id, their_device_id, record) + VALUES ($1, $2, $3, $4) + ON CONFLICT (our_aci_uuid, their_service_id, their_device_id) DO UPDATE SET record=excluded.record + ` + allSessionsQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_service_id=$2` + removeSessionQuery = `DELETE FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3` ) type SessionStoreExtras interface { - // AllSessionsForUUID returns all sessions for the given UUID. - AllSessionsForUUID(ctx context.Context, theirUUID uuid.UUID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) + // AllSessionsForServiceID returns all sessions for the given service ID. + AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) // RemoveSession removes the session for the given address. RemoveSession(ctx context.Context, address *libsignalgo.Address) error // RemoveAllSessions removes all sessions for our ACI UUID @@ -61,20 +64,20 @@ func scanRecord(row dbutil.Scannable) (int, *libsignalgo.SessionRecord, error) { } func (s *SQLStore) RemoveSession(ctx context.Context, address *libsignalgo.Address) error { - theirUUID, err := address.Name() + theirServiceID, err := address.Name() if err != nil { - return fmt.Errorf("failed to get their UUID: %w", err) + return fmt.Errorf("failed to get their service ID: %w", err) } deviceID, err := address.DeviceID() if err != nil { return fmt.Errorf("failed to get their device ID: %w", err) } - _, err = s.db.Exec(ctx, removeSessionQuery, s.ACI, theirUUID, deviceID) + _, err = s.db.Exec(ctx, removeSessionQuery, s.ACI, theirServiceID, deviceID) return err } -func (s *SQLStore) AllSessionsForUUID(ctx context.Context, theirUUID uuid.UUID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) { - rows, err := s.db.Query(ctx, allSessionsQuery, s.ACI, theirUUID) +func (s *SQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) { + rows, err := s.db.Query(ctx, allSessionsQuery, s.ACI, theirID.String()) if err != nil { return nil, nil, err } @@ -82,12 +85,12 @@ func (s *SQLStore) AllSessionsForUUID(ctx context.Context, theirUUID uuid.UUID) var records []*libsignalgo.SessionRecord var addresses []*libsignalgo.Address for rows.Next() { - deviceId, record, err := scanRecord(rows) + deviceID, record, err := scanRecord(rows) if err != nil { return nil, nil, err } records = append(records, record) - address, err := libsignalgo.NewUUIDAddress(theirUUID, uint(deviceId)) + address, err := theirID.Address(uint(deviceID)) if err != nil { return nil, nil, err } @@ -97,22 +100,22 @@ func (s *SQLStore) AllSessionsForUUID(ctx context.Context, theirUUID uuid.UUID) } func (s *SQLStore) LoadSession(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.SessionRecord, error) { - theirUUID, err := address.Name() + theirServiceID, err := address.Name() if err != nil { - return nil, fmt.Errorf("failed to get their UUID: %w", err) + return nil, fmt.Errorf("failed to get their service ID: %w", err) } deviceID, err := address.DeviceID() if err != nil { return nil, fmt.Errorf("failed to get their device ID: %w", err) } - _, record, err := scanRecord(s.db.QueryRow(ctx, loadSessionQuery, s.ACI, theirUUID, deviceID)) + _, record, err := scanRecord(s.db.QueryRow(ctx, loadSessionQuery, s.ACI, theirServiceID, deviceID)) return record, err } func (s *SQLStore) StoreSession(ctx context.Context, address *libsignalgo.Address, record *libsignalgo.SessionRecord) error { - theirUUID, err := address.Name() + theirServiceID, err := address.Name() if err != nil { - return fmt.Errorf("failed to get their UUID: %w", err) + return fmt.Errorf("failed to get their service ID: %w", err) } deviceID, err := address.DeviceID() if err != nil { @@ -122,7 +125,7 @@ func (s *SQLStore) StoreSession(ctx context.Context, address *libsignalgo.Addres if err != nil { return fmt.Errorf("failed to serialize session record: %w", err) } - _, err = s.db.Exec(ctx, storeSessionQuery, s.ACI, theirUUID, deviceID, serialized) + _, err = s.db.Exec(ctx, storeSessionQuery, s.ACI, theirServiceID, deviceID, serialized) return err } diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 6c7dc4b..f4cdeac 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v8: Latest revision +-- v0 -> v9: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -27,23 +27,23 @@ CREATE TABLE signalmeow_pre_keys ( ); CREATE TABLE signalmeow_identity_keys ( - our_aci_uuid TEXT NOT NULL, - their_aci_uuid TEXT NOT NULL, - their_device_id INTEGER NOT NULL, - key bytea NOT NULL, - trust_level TEXT NOT NULL, + our_aci_uuid TEXT NOT NULL, + their_service_id TEXT NOT NULL, + their_device_id INTEGER NOT NULL, + key bytea NOT NULL, + trust_level TEXT NOT NULL, - PRIMARY KEY (our_aci_uuid, their_aci_uuid, their_device_id), + PRIMARY KEY (our_aci_uuid, their_service_id, their_device_id), FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_sessions ( - our_aci_uuid TEXT NOT NULL, - their_aci_uuid TEXT NOT NULL, - their_device_id INTEGER NOT NULL, - record bytea NOT NULL, + our_aci_uuid TEXT NOT NULL, + their_service_id TEXT NOT NULL, + their_device_id INTEGER NOT NULL, + record bytea NOT NULL, - PRIMARY KEY (our_aci_uuid, their_aci_uuid, their_device_id), + PRIMARY KEY (our_aci_uuid, their_service_id, their_device_id), FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); diff --git a/pkg/signalmeow/store/upgrades/09-pni-sending.sql b/pkg/signalmeow/store/upgrades/09-pni-sending.sql new file mode 100644 index 0000000..d3c1cb4 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/09-pni-sending.sql @@ -0,0 +1,3 @@ +-- v9: Add support for sending to PNIs +ALTER TABLE signalmeow_sessions RENAME COLUMN their_aci_uuid TO their_service_id; +ALTER TABLE signalmeow_identity_keys RENAME COLUMN their_aci_uuid TO their_service_id; diff --git a/portal.go b/portal.go index 357a14b..98a27cd 100644 --- a/portal.go +++ b/portal.go @@ -45,6 +45,7 @@ import ( "go.mau.fi/mautrix-signal/msgconv" "go.mau.fi/mautrix-signal/msgconv/matrixfmt" "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -680,7 +681,7 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte // Check to see if portal.ChatID is a standard UUID (with dashes) if portal.IsPrivateChat() { // this is a 1:1 chat - result := sender.Client.SendMessage(ctx, portal.UserID(), msg) + result := sender.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(portal.UserID()), msg) if !result.WasSuccessful { return result.Error } @@ -1493,7 +1494,7 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { portal.log.Debug().Msg("Sending Typing event to Signal") ctx := context.TODO() typingMessage := signalmeow.TypingMessage(isTyping) - result := user.Client.SendMessage(ctx, portal.UserID(), typingMessage) + result := user.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(portal.UserID()), typingMessage) if !result.WasSuccessful { portal.log.Err(result.FailedSendResult.Error).Msg("Error sending event to Signal") } @@ -1584,7 +1585,7 @@ func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, // Don't use portal.sendSignalMessage because we're sending this straight to // who sent the original message, not the portal's ChatID ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - result := sender.Client.SendMessage(ctx, destination, signalmeow.ReadReceptMessageForTimestamps(messages)) + result := sender.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(destination), signalmeow.ReadReceptMessageForTimestamps(messages)) cancel() if !result.WasSuccessful { log.Err(result.FailedSendResult.Error). From b0947b21fda91c547c99e2edce774cfd6ec1281f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 19 Mar 2024 19:15:30 +0200 Subject: [PATCH 111/718] Refactor prekey and session tables to add own service ID --- main.go | 2 +- pkg/libsignalgo/kyberprekey.go | 4 +- pkg/libsignalgo/prekey.go | 4 +- pkg/libsignalgo/serviceid.go | 5 + pkg/libsignalgo/signedprekey.go | 4 +- pkg/signalmeow/keys.go | 126 +++--- pkg/signalmeow/provisioning.go | 23 +- pkg/signalmeow/receiving.go | 62 +-- pkg/signalmeow/sending.go | 18 +- pkg/signalmeow/store/contact_store.go | 22 +- pkg/signalmeow/store/container.go | 49 ++- pkg/signalmeow/store/device.go | 66 ++-- pkg/signalmeow/store/group_store.go | 10 +- pkg/signalmeow/store/identity_store.go | 24 +- pkg/signalmeow/store/prekey_store.go | 373 +++++++----------- pkg/signalmeow/store/profile_key_store.go | 14 +- pkg/signalmeow/store/sender_key_store.go | 10 +- pkg/signalmeow/store/session_store.go | 49 +-- pkg/signalmeow/store/upgrades/00-latest.sql | 50 +-- .../10-prekey-store-service-id.postgres.sql | 31 ++ .../10-prekey-store-service-id.sqlite.sql | 59 +++ 21 files changed, 530 insertions(+), 475 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/10-prekey-store-service-id.postgres.sql create mode 100644 pkg/signalmeow/store/upgrades/10-prekey-store-service-id.sqlite.sql diff --git a/main.go b/main.go index 4251d45..cd9e156 100644 --- a/main.go +++ b/main.go @@ -59,7 +59,7 @@ type SignalBridge struct { Config *config.Config DB *database.Database Metrics *MetricsHandler - MeowStore *store.StoreContainer + MeowStore *store.Container provisioning *ProvisioningAPI diff --git a/pkg/libsignalgo/kyberprekey.go b/pkg/libsignalgo/kyberprekey.go index 63c9fc7..d049d0a 100644 --- a/pkg/libsignalgo/kyberprekey.go +++ b/pkg/libsignalgo/kyberprekey.go @@ -187,14 +187,14 @@ func (kpkr *KyberPreKeyRecord) GetSignature() ([]byte, error) { return CopySignalOwnedBufferToBytes(signature), nil } -func (kpkr *KyberPreKeyRecord) GetID() (uint, error) { +func (kpkr *KyberPreKeyRecord) GetID() (uint32, error) { var id C.uint32_t signalFfiError := C.signal_kyber_pre_key_record_get_id(&id, kpkr.ptr) runtime.KeepAlive(kpkr) if signalFfiError != nil { return 0, wrapError(signalFfiError) } - return uint(id), nil + return uint32(id), nil } func (kpkr *KyberPreKeyRecord) GetTimestamp() (time.Time, error) { diff --git a/pkg/libsignalgo/prekey.go b/pkg/libsignalgo/prekey.go index 7c4ed6b..82b2cd1 100644 --- a/pkg/libsignalgo/prekey.go +++ b/pkg/libsignalgo/prekey.go @@ -117,14 +117,14 @@ func (pkr *PreKeyRecord) Serialize() ([]byte, error) { return CopySignalOwnedBufferToBytes(serialized), nil } -func (pkr *PreKeyRecord) GetID() (uint, error) { +func (pkr *PreKeyRecord) GetID() (uint32, error) { var id C.uint32_t signalFfiError := C.signal_pre_key_record_get_id(&id, pkr.ptr) runtime.KeepAlive(pkr) if signalFfiError != nil { return 0, wrapError(signalFfiError) } - return uint(id), nil + return uint32(id), nil } func (pkr *PreKeyRecord) GetPublicKey() (*PublicKey, error) { diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index 31d4141..0214f65 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -23,6 +23,7 @@ package libsignalgo */ import "C" import ( + "database/sql/driver" "fmt" "strings" "unsafe" @@ -88,6 +89,10 @@ func (s ServiceID) Bytes() []byte { return append([]byte{byte(s.Type)}, s.UUID[:]...) } +func (s ServiceID) Value() (driver.Value, error) { + return s.String(), nil +} + func (s ServiceID) String() string { if s.Type == ServiceIDTypeACI { return s.UUID.String() diff --git a/pkg/libsignalgo/signedprekey.go b/pkg/libsignalgo/signedprekey.go index 0b1daac..e3aa926 100644 --- a/pkg/libsignalgo/signedprekey.go +++ b/pkg/libsignalgo/signedprekey.go @@ -106,14 +106,14 @@ func (spkr *SignedPreKeyRecord) GetSignature() ([]byte, error) { return CopySignalOwnedBufferToBytes(signature), nil } -func (spkr *SignedPreKeyRecord) GetID() (uint, error) { +func (spkr *SignedPreKeyRecord) GetID() (uint32, error) { var id C.uint32_t signalFfiError := C.signal_signed_pre_key_record_get_id(&id, spkr.ptr) runtime.KeepAlive(spkr) if signalFfiError != nil { return 0, wrapError(signalFfiError) } - return uint(id), nil + return uint32(id), nil } func (spkr *SignedPreKeyRecord) GetTimestamp() (time.Time, error) { diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index eafa2db..645f02e 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -26,11 +26,10 @@ import ( "strings" "time" - "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -42,18 +41,18 @@ type GeneratedPreKeys struct { IdentityKey []uint8 } -func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { - _, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) +func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, pks store.PreKeyStore) error { + _, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, pks) if err != nil { return fmt.Errorf("failed to generate and save next prekey batch: %w", err) } - _, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) + _, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks) if err != nil { return fmt.Errorf("failed to generate and save next kyber prekey batch: %w", err) } // We need to upload all currently valid prekeys, not just the ones we just generated - err = cli.RegisterAllPreKeys(ctx, uuidKind) + err = cli.RegisterAllPreKeys(ctx, pks) if err != nil { return fmt.Errorf("failed to register prekey batches: %w", err) } @@ -61,20 +60,22 @@ func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, uuidKind type return err } -func (cli *Client) RegisterAllPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { +func (cli *Client) RegisterAllPreKeys(ctx context.Context, pks store.PreKeyStore) error { var identityKeyPair *libsignalgo.IdentityKeyPair - if uuidKind == types.UUIDKindPNI { + var pni bool + if pks.GetServiceID().Type == libsignalgo.ServiceIDTypePNI { + pni = true identityKeyPair = cli.Store.PNIIdentityKeyPair } else { identityKeyPair = cli.Store.ACIIdentityKeyPair } // Get all prekeys and kyber prekeys from the database - preKeys, err := cli.Store.PreKeyStoreExtras.AllPreKeys(ctx, uuidKind) + preKeys, err := pks.AllPreKeys(ctx) if err != nil { return fmt.Errorf("failed to get all prekeys: %w", err) } - kyberPreKeys, err := cli.Store.PreKeyStoreExtras.AllNormalKyberPreKeys(ctx, uuidKind) + kyberPreKeys, err := pks.AllNormalKyberPreKeys(ctx) if err != nil { return fmt.Errorf("failed to get all kyber prekeys: %w", err) } @@ -94,42 +95,25 @@ func (cli *Client) RegisterAllPreKeys(ctx context.Context, uuidKind types.UUIDKi KyberPreKeys: kyberPreKeys, IdentityKey: identityKey, } - preKeyUsername := cli.Store.Number - if cli.Store.ACI != uuid.Nil { - preKeyUsername = cli.Store.ACI.String() - } - preKeyUsername = fmt.Sprintf("%s.%d", preKeyUsername, cli.Store.DeviceID) + preKeyUsername := fmt.Sprintf("%s.%d", cli.Store.ACI, cli.Store.DeviceID) log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() log.Debug().Int("num_prekeys", len(preKeys)).Int("num_kyber_prekeys", len(kyberPreKeys)).Msg("Registering prekeys") - err = RegisterPreKeys(ctx, &generatedPreKeys, uuidKind, preKeyUsername, cli.Store.Password) + err = RegisterPreKeys(ctx, &generatedPreKeys, pni, preKeyUsername, cli.Store.Password) if err != nil { return fmt.Errorf("failed to register prekeys: %w", err) } - // Mark prekeys as registered - // (kyber prekeys don't have "mark as uploaded" we just assume they always are) - // TODO: we don't need to mark prekeys as uploaded, since we just upload all unused prekeys each time. - // So we can drop this column and remove these methods - lastPreKeyID, err := preKeys[len(preKeys)-1].GetID() - if err != nil { - return fmt.Errorf("failed to get last prekey ID: %w", err) - } - err = cli.Store.PreKeyStoreExtras.MarkPreKeysAsUploaded(ctx, uuidKind, lastPreKeyID) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to mark prekeys as uploaded") - } - return err } -func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.PreKeyRecord, error) { - nextPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextPreKeyID(ctx, uuidKind) +func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, pks store.PreKeyStore) ([]*libsignalgo.PreKeyRecord, error) { + nextPreKeyID, err := pks.GetNextPreKeyID(ctx) if err != nil { return nil, fmt.Errorf("failed to get next prekey ID: %w", err) } - preKeys := GeneratePreKeys(nextPreKeyID, PREKEY_BATCH_SIZE, uuidKind) + preKeys := GeneratePreKeys(nextPreKeyID, PREKEY_BATCH_SIZE) for _, preKey := range preKeys { - err = cli.Store.PreKeyStoreExtras.SavePreKey(ctx, uuidKind, preKey, false) + err = pks.StorePreKey(ctx, 0, preKey) if err != nil { return nil, fmt.Errorf("failed to save prekey: %w", err) } @@ -137,20 +121,20 @@ func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, uuidKind return preKeys, nil } -func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.KyberPreKeyRecord, error) { +func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, pks store.PreKeyStore) ([]*libsignalgo.KyberPreKeyRecord, error) { var identityKeyPair *libsignalgo.IdentityKeyPair - if uuidKind == types.UUIDKindPNI { + if pks.GetServiceID().Type == libsignalgo.ServiceIDTypePNI { identityKeyPair = cli.Store.PNIIdentityKeyPair } else { identityKeyPair = cli.Store.ACIIdentityKeyPair } - nextKyberPreKeyID, err := cli.Store.PreKeyStoreExtras.GetNextKyberPreKeyID(ctx, uuidKind) + nextKyberPreKeyID, err := pks.GetNextKyberPreKeyID(ctx) if err != nil { return nil, fmt.Errorf("failed to get next kyber prekey ID: %w", err) } - kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, PREKEY_BATCH_SIZE, uuidKind, identityKeyPair) + kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, PREKEY_BATCH_SIZE, identityKeyPair) for _, kyberPreKey := range kyberPreKeys { - err = cli.Store.PreKeyStoreExtras.SaveKyberPreKey(ctx, uuidKind, kyberPreKey, false) + err = pks.StoreKyberPreKey(ctx, 0, kyberPreKey) if err != nil { return nil, fmt.Errorf("failed to save kyber prekey: %w", err) } @@ -158,14 +142,14 @@ func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, uuid return kyberPreKeys, nil } -func GeneratePreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind) []*libsignalgo.PreKeyRecord { - generatedPreKeys := []*libsignalgo.PreKeyRecord{} - for i := startKeyId; i < startKeyId+count; i++ { +func GeneratePreKeys(startKeyID uint32, count uint32) []*libsignalgo.PreKeyRecord { + generatedPreKeys := make([]*libsignalgo.PreKeyRecord, 0, count) + for keyID := startKeyID; keyID < startKeyID+count; keyID++ { privateKey, err := libsignalgo.GeneratePrivateKey() if err != nil { panic(fmt.Errorf("error generating private key: %w", err)) } - preKey, err := libsignalgo.NewPreKeyRecordFromPrivateKey(uint32(i), privateKey) + preKey, err := libsignalgo.NewPreKeyRecordFromPrivateKey(keyID, privateKey) if err != nil { panic(fmt.Errorf("error creating prekey record: %w", err)) } @@ -174,9 +158,9 @@ func GeneratePreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind) []*li return generatedPreKeys } -func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind, identityKeyPair *libsignalgo.IdentityKeyPair) []*libsignalgo.KyberPreKeyRecord { - generatedKyberPreKeys := []*libsignalgo.KyberPreKeyRecord{} - for i := startKeyId; i < startKeyId+count; i++ { +func GenerateKyberPreKeys(startKeyID uint32, count uint32, identityKeyPair *libsignalgo.IdentityKeyPair) []*libsignalgo.KyberPreKeyRecord { + generatedKyberPreKeys := make([]*libsignalgo.KyberPreKeyRecord, 0, count) + for keyID := startKeyID; keyID < startKeyID+count; keyID++ { kyberPreKeyPair, err := libsignalgo.KyberKeyPairGenerate() if err != nil { panic(fmt.Errorf("error generating kyber key pair: %w", err)) @@ -193,7 +177,7 @@ func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind, if err != nil { panic(fmt.Errorf("error signing kyber public key: %w", err)) } - preKey, err := libsignalgo.NewKyberPreKeyRecord(uint32(i), time.Now(), kyberPreKeyPair, signature) + preKey, err := libsignalgo.NewKyberPreKeyRecord(keyID, time.Now(), kyberPreKeyPair, signature) if err != nil { panic(fmt.Errorf("error creating kyber prekey record: %w", err)) @@ -203,7 +187,7 @@ func GenerateKyberPreKeys(startKeyId uint, count uint, uuidKind types.UUIDKind, return generatedKyberPreKeys } -func GenerateSignedPreKey(startSignedKeyId uint32, uuidKind types.UUIDKind, identityKeyPair *libsignalgo.IdentityKeyPair) *libsignalgo.SignedPreKeyRecord { +func GenerateSignedPreKey(startSignedKeyId uint32, identityKeyPair *libsignalgo.IdentityKeyPair) *libsignalgo.SignedPreKeyRecord { // Generate a signed prekey privateKey, err := libsignalgo.GeneratePrivateKey() if err != nil { @@ -267,7 +251,7 @@ func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) map[string]in return kyberPreKeyJson } -func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, uuidKind types.UUIDKind, username string, password string) error { +func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pni bool, username string, password string) error { log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() // Convert generated prekeys to JSON preKeysJson := []map[string]interface{}{} @@ -289,14 +273,13 @@ func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, uu } // Send request - keysPath := "/v2/keys?identity=" + string(uuidKind) jsonBytes, err := json.Marshal(register_json) if err != nil { log.Err(err).Msg("Error marshalling register JSON") return err } opts := &web.HTTPReqOpt{Body: jsonBytes, Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(ctx, http.MethodPut, keysPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodPut, keysPath(pni), opts) if err != nil { log.Err(err).Msg("Error sending request") return err @@ -444,7 +427,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib ctx, preKeyBundle, address, - cli.Store.SessionStore, + cli.Store.ACISessionStore, cli.Store.IdentityStore, ) if err != nil { @@ -455,11 +438,22 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib return err } -func (cli *Client) GetMyKeyCounts(ctx context.Context, uuidKind types.UUIDKind) (int, int, error) { +const ( + aciKeysPath = "/v2/keys?identity=aci" + pniKeysPath = "/v2/keys?identity=pni" +) + +func keysPath(pni bool) string { + if pni { + return pniKeysPath + } + return aciKeysPath +} + +func (cli *Client) GetMyKeyCounts(ctx context.Context, pni bool) (int, int, error) { log := zerolog.Ctx(ctx).With().Str("action", "get my key counts").Logger() username, password := cli.Store.BasicAuthCreds() - path := "/v2/keys?identity=" + string(uuidKind) - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, keysPath(pni), &web.HTTPReqOpt{Username: &username, Password: &password}) if err != nil { log.Err(err).Msg("Error sending request") return 0, 0, err @@ -473,10 +467,10 @@ func (cli *Client) GetMyKeyCounts(ctx context.Context, uuidKind types.UUIDKind) return preKeyCountResponse.Count, preKeyCountResponse.PQCount, err } -func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types.UUIDKind) error { +func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, pks store.PreKeyStore) error { log := zerolog.Ctx(ctx).With().Str("action", "check and upload new prekeys").Logger() // Check if we need to upload prekeys - preKeyCount, kyberPreKeyCount, err := cli.GetMyKeyCounts(ctx, uuidKind) + preKeyCount, kyberPreKeyCount, err := cli.GetMyKeyCounts(ctx, pks.GetServiceID().Type == libsignalgo.ServiceIDTypePNI) if err != nil { log.Err(err).Msg("Error getting prekey counts") return err @@ -487,7 +481,7 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types. var kyberPreKeys []*libsignalgo.KyberPreKeyRecord if preKeyCount < 10 { log.Info().Int("preKeyCount", preKeyCount).Msg("Generating and saving new prekeys") - preKeys, err = cli.GenerateAndSaveNextPreKeyBatch(ctx, uuidKind) + preKeys, err = cli.GenerateAndSaveNextPreKeyBatch(ctx, pks) if err != nil { log.Err(err).Msg("Error generating and saving next prekey batch") return err @@ -495,7 +489,7 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types. } if kyberPreKeyCount < 10 { log.Info().Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Generating and saving new kyber prekeys") - kyberPreKeys, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, uuidKind) + kyberPreKeys, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks) if err != nil { log.Err(err).Msg("Error generating and saving next kyber prekey batch") return err @@ -505,7 +499,7 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types. log.Debug().Msg("No new prekeys to upload") return nil } - err = cli.RegisterAllPreKeys(ctx, uuidKind) + err = cli.RegisterAllPreKeys(ctx, pks) if err != nil { log.Err(err).Msg("Error registering prekey batches") return err @@ -513,7 +507,7 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, uuidKind types. return nil } -func (cli *Client) StartKeyCheckLoop(ctx context.Context, uuidKind types.UUIDKind) { +func (cli *Client) StartKeyCheckLoop(ctx context.Context) { log := zerolog.Ctx(ctx).With().Str("action", "start key check loop").Logger() go func() { // Do the initial check within an hour of starting the loop @@ -528,9 +522,17 @@ func (cli *Client) StartKeyCheckLoop(ctx context.Context, uuidKind types.UUIDKin case <-ctx.Done(): return case <-time.After(check_time): - err := cli.CheckAndUploadNewPreKeys(ctx, uuidKind) + err := cli.CheckAndUploadNewPreKeys(ctx, cli.Store.ACIPreKeyStore) if err != nil { - log.Err(err).Msg("Error checking and uploading new prekeys") + log.Err(err).Msg("Error checking and uploading new prekeys for ACI identity") + // Retry within half an hour + window_start = 5 + window_size = 25 + continue + } + err = cli.CheckAndUploadNewPreKeys(ctx, cli.Store.PNIPreKeyStore) + if err != nil { + log.Err(err).Msg("Error checking and uploading new prekeys for PNI identity") // Retry within half an hour window_start = 5 window_size = 25 diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index b9889b4..576e6c1 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -36,7 +36,6 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" "go.mau.fi/mautrix-signal/pkg/signalmeow/wspb" ) @@ -125,12 +124,10 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev code := provisioningMessage.ProvisioningCode registrationId := mrand.Intn(16383) + 1 pniRegistrationId := mrand.Intn(16383) + 1 - aciSignedPreKey := GenerateSignedPreKey(1, types.UUIDKindACI, aciIdentityKeyPair) - pniSignedPreKey := GenerateSignedPreKey(2, types.UUIDKindPNI, pniIdentityKeyPair) - aciPQLastResortPreKeys := GenerateKyberPreKeys(1, 1, types.UUIDKindACI, aciIdentityKeyPair) - pniPQLastResortPreKeys := GenerateKyberPreKeys(1, 1, types.UUIDKindPNI, pniIdentityKeyPair) - aciPQLastResortPreKey := aciPQLastResortPreKeys[0] - pniPQLastResortPreKey := pniPQLastResortPreKeys[0] + aciSignedPreKey := GenerateSignedPreKey(1, aciIdentityKeyPair) + pniSignedPreKey := GenerateSignedPreKey(1, pniIdentityKeyPair) + aciPQLastResortPreKey := GenerateKyberPreKeys(1, 1, aciIdentityKeyPair)[0] + pniPQLastResortPreKey := GenerateKyberPreKeys(1, 1, pniIdentityKeyPair)[0] deviceResponse, err := confirmDevice( ctx, username, @@ -205,10 +202,10 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev } // Store signed prekeys (now that we have a device) - device.PreKeyStoreExtras.SaveSignedPreKey(ctx, types.UUIDKindACI, aciSignedPreKey, true) - device.PreKeyStoreExtras.SaveSignedPreKey(ctx, types.UUIDKindPNI, pniSignedPreKey, true) - device.PreKeyStoreExtras.SaveKyberPreKey(ctx, types.UUIDKindACI, aciPQLastResortPreKey, true) - device.PreKeyStoreExtras.SaveKyberPreKey(ctx, types.UUIDKindPNI, pniPQLastResortPreKey, true) + device.ACIPreKeyStore.StoreSignedPreKey(ctx, 1, aciSignedPreKey) + device.PNIPreKeyStore.StoreSignedPreKey(ctx, 1, pniSignedPreKey) + device.ACIPreKeyStore.StoreLastResortKyberPreKey(ctx, 1, aciPQLastResortPreKey) + device.PNIPreKeyStore.StoreLastResortKyberPreKey(ctx, 1, pniPQLastResortPreKey) // Store our profile key err = device.ProfileKeyStore.StoreProfileKey(ctx, data.ACI, profileKey) @@ -226,7 +223,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev // Generate, store, and register prekeys // TODO hacky client construction cli := &Client{Store: device} - err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindACI) + err = cli.GenerateAndRegisterPreKeys(ctx, device.ACIPreKeyStore) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, @@ -234,7 +231,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev } return } - err = cli.GenerateAndRegisterPreKeys(ctx, types.UUIDKindPNI) + err = cli.GenerateAndRegisterPreKeys(ctx, device.PNIPreKeyStore) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 05d208e..14fb688 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -195,7 +195,7 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection }() // Start loop to check for and upload more prekeys - cli.StartKeyCheckLoop(ctx, types.UUIDKindACI) + cli.StartKeyCheckLoop(ctx) return statusChan, nil } @@ -280,7 +280,7 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web // TODO: we should split this up into multiple functions func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { - log := zerolog.Ctx(ctx).With().Str("handler_type", "incoming API message handler").Logger() + log := *zerolog.Ctx(ctx) responseCode := 200 envelope := &signalpb.Envelope{} err := proto.Unmarshal(req.Body, envelope) @@ -288,10 +288,20 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Err(err).Msg("Unmarshal error") return nil, err } + destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) + if err != nil { + log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") + return nil, err + } var result *DecryptionResult switch *envelope.Type { case signalpb.Envelope_UNIDENTIFIED_SENDER: + if destinationServiceID != cli.Store.ACIServiceID() { + log.Warn().Stringer("destination_service_id", destinationServiceID). + Msg("Received envelope type UNIDENTIFIED_SENDER for non-ACI destination") + break + } log.Trace().Msg("Received envelope type UNIDENTIFIED_SENDER") usmc, err := libsignalgo.SealedSenderDecryptToUSMC( ctx, @@ -381,7 +391,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. case libsignalgo.CiphertextMessageTypePreKey: log.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") - result, err = cli.prekeyDecrypt(ctx, senderAddress, usmcContents) + result, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) if err != nil { log.Err(err).Msg("prekeyDecrypt error") } @@ -396,7 +406,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. ctx, message, senderAddress, - cli.Store.SessionStore, + cli.Store.ACISessionStore, cli.Store.IdentityStore, ) if err != nil { @@ -479,7 +489,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if err != nil { return nil, fmt.Errorf("NewAddress error: %v", err) } - result, err = cli.prekeyDecrypt(ctx, sender, envelope.Content) + result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) if err != nil { log.Err(err).Msg("prekeyDecrypt error") cli.checkDecryptionErrorAndDisconnect(ctx, err) @@ -506,11 +516,15 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if err != nil { return nil, fmt.Errorf("NewAddress error: %w", err) } + sessionStore := cli.Store.SessionStore(destinationServiceID) + if sessionStore == nil { + return nil, fmt.Errorf("no session store for destination service ID %s", destinationServiceID) + } decryptedText, err := libsignalgo.Decrypt( ctx, message, senderAddress, - cli.Store.SessionStore, + sessionStore, cli.Store.IdentityStore, ) if err != nil { @@ -898,10 +912,10 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E localAddress, prodServerTrustRootKey, timestamp, - cli.Store.SessionStore, + cli.Store.ACISessionStore, cli.Store.IdentityStore, - cli.Store.PreKeyStore, - cli.Store.SignedPreKeyStore, + cli.Store.ACIPreKeyStore, + cli.Store.ACIPreKeyStore, ) if err != nil { return nil, fmt.Errorf("SealedSenderDecrypt error: %w", err) @@ -921,33 +935,37 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E if err != nil { return nil, fmt.Errorf("Unmarshal error: %w", err) } - DecryptionResult := &DecryptionResult{ + return &DecryptionResult{ SenderAddress: address, Content: content, - } - return DecryptionResult, nil + }, nil } -func (cli *Client) prekeyDecrypt(ctx context.Context, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { +func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.ServiceID, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) if err != nil { - err = fmt.Errorf("DeserializePreKeyMessage error: %v", err) - return nil, err + return nil, fmt.Errorf("failed to deserialize prekey message: %w", err) + } else if preKeyMessage == nil { + return nil, fmt.Errorf("deserializing prekey message returned nil") } - if preKeyMessage == nil { - err = fmt.Errorf("preKeyMessage is nil") - return nil, err + pks := cli.Store.PreKeyStore(destination) + if pks == nil { + return nil, fmt.Errorf("no prekey store found for %s", destination) + } + ss := cli.Store.SessionStore(destination) + if ss == nil { + return nil, fmt.Errorf("no session store found for %s", destination) } data, err := libsignalgo.DecryptPreKey( ctx, preKeyMessage, sender, - cli.Store.SessionStore, + ss, cli.Store.IdentityStore, - cli.Store.PreKeyStore, - cli.Store.SignedPreKeyStore, - cli.Store.KyberPreKeyStore, + pks, + pks, + pks, ) if err != nil { err = fmt.Errorf("DecryptPreKey error: %v", err) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index ba9e8e0..5bc5161 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -144,7 +144,7 @@ func checkForErrorWithSessions(err error, addresses []*libsignalgo.Address, sess } func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { - addresses, _, err := cli.Store.SessionStoreExtras.AllSessionsForServiceID(ctx, cli.Store.ACIServiceID()) + addresses, _, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, cli.Store.ACIServiceID()) if err != nil { return 0 } @@ -170,14 +170,14 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg messages := []MyMessage{} - addresses, sessionRecords, err := cli.Store.SessionStoreExtras.AllSessionsForServiceID(ctx, recipient) + addresses, sessionRecords, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) if err == nil && (len(addresses) == 0 || len(sessionRecords) == 0) { // No sessions, make one with prekey err = cli.FetchAndProcessPreKey(ctx, recipient, -1) if err != nil { return nil, err } - addresses, sessionRecords, err = cli.Store.SessionStoreExtras.AllSessionsForServiceID(ctx, recipient) + addresses, sessionRecords, err = cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) } err = checkForErrorWithSessions(err, addresses, sessionRecords) if err != nil { @@ -239,9 +239,9 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { cipherTextMessage, err := libsignalgo.Encrypt( ctx, - []byte(paddedMessage), + paddedMessage, recipientAddress, - cli.Store.SessionStore, + cli.Store.ACISessionStore, cli.Store.IdentityStore, ) if err != nil { @@ -271,10 +271,10 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l } encryptedPayload, err = libsignalgo.SealedSenderEncryptPlaintext( ctx, - []byte(paddedMessage), + paddedMessage, recipientAddress, cert, - cli.Store.SessionStore, + cli.Store.ACISessionStore, cli.Store.IdentityStore, ) if err != nil { @@ -841,7 +841,7 @@ func (cli *Client) handle409(ctx context.Context, recipient libsignalgo.ServiceI log.Err(err).Msg("NewAddress error") return err } - err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipientAddr) + err = cli.Store.ACISessionStore.RemoveSession(ctx, recipientAddr) if err != nil { log.Err(err).Msg("RemoveSession error") return err @@ -872,7 +872,7 @@ func (cli *Client) handle410(ctx context.Context, recipient libsignalgo.ServiceI log.Err(err).Msg("error creating new UUID Address") return err } - err = cli.Store.SessionStoreExtras.RemoveSession(ctx, recipientAddr) + err = cli.Store.ACISessionStore.RemoveSession(ctx, recipientAddr) if err != nil { log.Err(err).Msg("RemoveSession error") return err diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go index f556124..9e2017b 100644 --- a/pkg/signalmeow/store/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -37,7 +37,7 @@ type ContactStore interface { UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error } -var _ ContactStore = (*SQLStore)(nil) +var _ ContactStore = (*sqlStore)(nil) const ( getAllContactsQuery = ` @@ -133,23 +133,23 @@ func scanContact(row dbutil.Scannable) (*types.Contact, error) { return &contact, err } -func (s *SQLStore) LoadContact(ctx context.Context, theirUUID uuid.UUID) (*types.Contact, error) { - return scanContact(s.db.QueryRow(ctx, getContactByUUIDQuery, s.ACI, theirUUID)) +func (s *sqlStore) LoadContact(ctx context.Context, theirUUID uuid.UUID) (*types.Contact, error) { + return scanContact(s.db.QueryRow(ctx, getContactByUUIDQuery, s.AccountID, theirUUID)) } -func (s *SQLStore) LoadContactByE164(ctx context.Context, e164 string) (*types.Contact, error) { - return scanContact(s.db.QueryRow(ctx, getContactByPhoneQuery, s.ACI, e164)) +func (s *sqlStore) LoadContactByE164(ctx context.Context, e164 string) (*types.Contact, error) { + return scanContact(s.db.QueryRow(ctx, getContactByPhoneQuery, s.AccountID, e164)) } -func (s *SQLStore) AllContacts(ctx context.Context) ([]*types.Contact, error) { - rows, err := s.db.Query(ctx, getAllContactsOfUserQuery, s.ACI) +func (s *sqlStore) AllContacts(ctx context.Context) ([]*types.Contact, error) { + rows, err := s.db.Query(ctx, getAllContactsOfUserQuery, s.AccountID) if err != nil { return nil, err } return dbutil.NewRowIter(rows, scanContact).AsList() } -func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) error { +func (s *sqlStore) StoreContact(ctx context.Context, contact types.Contact) error { var profileKey []byte if contact.Profile.Key.IsEmpty() { profileKey = contact.Profile.Key[:] @@ -157,7 +157,7 @@ func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) erro _, err := s.db.Exec( ctx, upsertContactQuery, - s.ACI, + s.AccountID, contact.UUID, contact.E164, contact.ContactName, @@ -172,9 +172,9 @@ func (s *SQLStore) StoreContact(ctx context.Context, contact types.Contact) erro return err } -func (s *SQLStore) UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error { +func (s *sqlStore) UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error { _, err := s.db.Exec( - ctx, upsertContactPhoneQuery, s.ACI, theirUUID, newE164, + ctx, upsertContactPhoneQuery, s.AccountID, theirUUID, newE164, ) return err } diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index a173597..626c77e 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -14,20 +14,20 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/store/upgrades" ) -var _ DeviceStore = (*StoreContainer)(nil) +var _ DeviceStore = (*Container)(nil) type DeviceStore interface { PutDevice(ctx context.Context, dd *DeviceData) error DeviceByACI(ctx context.Context, aci uuid.UUID) (*Device, error) } -// StoreContainer is a wrapper for a SQL database that can contain multiple signalmeow sessions. -type StoreContainer struct { +// Container is a wrapper for a SQL database that can contain multiple signalmeow sessions. +type Container struct { db *dbutil.Database } -func NewStore(db *dbutil.Database, log dbutil.DatabaseLogger) *StoreContainer { - return &StoreContainer{db: db.Child("signalmeow_version", upgrades.Table, log)} +func NewStore(db *dbutil.Database, log dbutil.DatabaseLogger) *Container { + return &Container{db: db.Child("signalmeow_version", upgrades.Table, log)} } const getAllDevicesQuery = ` @@ -40,11 +40,11 @@ FROM signalmeow_device const getDeviceQuery = getAllDevicesQuery + " WHERE aci_uuid=$1" -func (c *StoreContainer) Upgrade(ctx context.Context) error { +func (c *Container) Upgrade(ctx context.Context) error { return c.db.Upgrade(ctx) } -func (c *StoreContainer) scanDevice(row dbutil.Scannable) (*Device, error) { +func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { var device Device var aciIdentityKeyPair, pniIdentityKeyPair []byte @@ -65,26 +65,25 @@ func (c *StoreContainer) scanDevice(row dbutil.Scannable) (*Device, error) { return nil, fmt.Errorf("failed to deserialize PNI identity key pair: %w", err) } - innerStore := newSQLStore(c, device.ACI) - // Assign innerStore to all the interfaces - device.PreKeyStore = innerStore - device.PreKeyStoreExtras = innerStore - device.SignedPreKeyStore = innerStore - device.KyberPreKeyStore = innerStore - device.IdentityStore = innerStore - device.SessionStore = innerStore - device.SessionStoreExtras = innerStore - device.ProfileKeyStore = innerStore - device.SenderKeyStore = innerStore - device.GroupStore = innerStore - device.ContactStore = innerStore - device.DeviceStore = innerStore + baseStore := &sqlStore{Container: c, AccountID: device.ACI} + aciStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.ACIServiceID()} + pniStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.PNIServiceID()} + device.ACIPreKeyStore = aciStore + device.PNIPreKeyStore = pniStore + device.ACISessionStore = aciStore + device.PNISessionStore = pniStore + device.IdentityStore = baseStore + device.ProfileKeyStore = baseStore + device.SenderKeyStore = baseStore + device.GroupStore = baseStore + device.ContactStore = baseStore + device.DeviceStore = baseStore return &device, nil } // GetAllDevices finds all the devices in the database. -func (c *StoreContainer) GetAllDevices(ctx context.Context) ([]*Device, error) { +func (c *Container) GetAllDevices(ctx context.Context) ([]*Device, error) { rows, err := c.db.Query(ctx, getAllDevicesQuery) if err != nil { return nil, fmt.Errorf("failed to query sessions: %w", err) @@ -103,7 +102,7 @@ func (c *StoreContainer) GetAllDevices(ctx context.Context) ([]*Device, error) { // GetDevice finds the device with the specified ACI UUID in the database. // If the device is not found, nil is returned instead. -func (c *StoreContainer) DeviceByACI(ctx context.Context, aci uuid.UUID) (*Device, error) { +func (c *Container) DeviceByACI(ctx context.Context, aci uuid.UUID) (*Device, error) { sess, err := c.scanDevice(c.db.QueryRow(ctx, getDeviceQuery, aci)) if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -136,7 +135,7 @@ const ( var ErrDeviceIDMustBeSet = errors.New("device aci_uuid must be known before accessing database") // PutDevice stores the given device in this database. -func (c *StoreContainer) PutDevice(ctx context.Context, device *DeviceData) error { +func (c *Container) PutDevice(ctx context.Context, device *DeviceData) error { if device.ACI == uuid.Nil { return ErrDeviceIDMustBeSet } @@ -162,7 +161,7 @@ func (c *StoreContainer) PutDevice(ctx context.Context, device *DeviceData) erro } // DeleteDevice deletes the given device from this database -func (c *StoreContainer) DeleteDevice(ctx context.Context, device *DeviceData) error { +func (c *Container) DeleteDevice(ctx context.Context, device *DeviceData) error { if device.ACI == uuid.Nil { return ErrDeviceIDMustBeSet } diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index 6a10b4b..96f112b 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -10,18 +10,15 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -// SQLStore is basically a StoreContainer with an ACI UUID attached to it, -// reperesenting a store for a single user -type SQLStore struct { - *StoreContainer - ACI uuid.UUID +type sqlStore struct { + *Container + AccountID uuid.UUID } -func newSQLStore(container *StoreContainer, aci uuid.UUID) *SQLStore { - return &SQLStore{ - StoreContainer: container, - ACI: aci, - } +type scopedSQLStore struct { + *Container + AccountID uuid.UUID + ServiceID libsignalgo.ServiceID } type DeviceData struct { @@ -40,6 +37,10 @@ func (d *DeviceData) ACIServiceID() libsignalgo.ServiceID { return libsignalgo.NewACIServiceID(d.ACI) } +func (d *DeviceData) PNIServiceID() libsignalgo.ServiceID { + return libsignalgo.NewPNIServiceID(d.PNI) +} + func (d *DeviceData) BasicAuthCreds() (string, string) { username := fmt.Sprintf("%s.%d", d.ACI, d.DeviceID) password := d.Password @@ -55,20 +56,17 @@ type Device struct { // (search for "innerStore" further down in this file) // libsignalgo store interfaces - PreKeyStore libsignalgo.PreKeyStore - SignedPreKeyStore libsignalgo.SignedPreKeyStore - KyberPreKeyStore libsignalgo.KyberPreKeyStore - IdentityStore libsignalgo.IdentityKeyStore - SessionStore libsignalgo.SessionStore - SenderKeyStore libsignalgo.SenderKeyStore + ACIPreKeyStore PreKeyStore + PNIPreKeyStore PreKeyStore + ACISessionStore SessionStore + PNISessionStore SessionStore + IdentityStore libsignalgo.IdentityKeyStore + SenderKeyStore libsignalgo.SenderKeyStore - // internal store interfaces - PreKeyStoreExtras PreKeyStoreExtras - SessionStoreExtras SessionStoreExtras - ProfileKeyStore ProfileKeyStore - GroupStore GroupStore - ContactStore ContactStore - DeviceStore DeviceStore + ProfileKeyStore ProfileKeyStore + GroupStore GroupStore + ContactStore ContactStore + DeviceStore DeviceStore } func (d *Device) ClearDeviceKeys(ctx context.Context) error { @@ -77,11 +75,11 @@ func (d *Device) ClearDeviceKeys(ctx context.Context) error { zerolog.Ctx(ctx).Warn().Msg("ClearDeviceKeys called with nil device") return nil } - err := d.PreKeyStoreExtras.DeleteAllPreKeys(ctx) + err := d.ACIPreKeyStore.DeleteAllPreKeys(ctx) if err != nil { return err } - err = d.SessionStoreExtras.RemoveAllSessions(ctx) + err = d.ACISessionStore.RemoveAllSessions(ctx) return err } @@ -96,3 +94,21 @@ func (d *Device) ClearPassword(ctx context.Context) error { d.Password = "" return d.DeviceStore.PutDevice(ctx, &d.DeviceData) } + +func (d *Device) PreKeyStore(serviceID libsignalgo.ServiceID) PreKeyStore { + if serviceID == d.ACIServiceID() { + return d.ACIPreKeyStore + } else if serviceID == d.PNIServiceID() { + return d.PNIPreKeyStore + } + return nil +} + +func (d *Device) SessionStore(serviceID libsignalgo.ServiceID) SessionStore { + if serviceID == d.ACIServiceID() { + return d.ACISessionStore + } else if serviceID == d.PNIServiceID() { + return d.PNISessionStore + } + return nil +} diff --git a/pkg/signalmeow/store/group_store.go b/pkg/signalmeow/store/group_store.go index 5ee356e..83a5473 100644 --- a/pkg/signalmeow/store/group_store.go +++ b/pkg/signalmeow/store/group_store.go @@ -26,7 +26,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -var _ GroupStore = (*SQLStore)(nil) +var _ GroupStore = (*sqlStore)(nil) type dbGroup struct { OurAciUuid string @@ -60,8 +60,8 @@ func scanGroup(row dbutil.Scannable) (*dbGroup, error) { return &g, nil } -func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (types.SerializedGroupMasterKey, error) { - g, err := scanGroup(s.db.QueryRow(ctx, getGroupByIDQuery, s.ACI, groupID)) +func (s *sqlStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID types.GroupIdentifier) (types.SerializedGroupMasterKey, error) { + g, err := scanGroup(s.db.QueryRow(ctx, getGroupByIDQuery, s.AccountID, groupID)) if g == nil { return "", err } else { @@ -69,7 +69,7 @@ func (s *SQLStore) MasterKeyFromGroupIdentifier(ctx context.Context, groupID typ } } -func (s *SQLStore) StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key types.SerializedGroupMasterKey) error { - _, err := s.db.Exec(ctx, upsertGroupMasterKeyQuery, s.ACI, groupID, key) +func (s *sqlStore) StoreMasterKey(ctx context.Context, groupID types.GroupIdentifier, key types.SerializedGroupMasterKey) error { + _, err := s.db.Exec(ctx, upsertGroupMasterKeyQuery, s.AccountID, groupID, key) return err } diff --git a/pkg/signalmeow/store/identity_store.go b/pkg/signalmeow/store/identity_store.go index 73cb2ce..1004daf 100644 --- a/pkg/signalmeow/store/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -27,7 +27,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -var _ libsignalgo.IdentityKeyStore = (*SQLStore)(nil) +var _ libsignalgo.IdentityKeyStore = (*sqlStore)(nil) const ( getIdentityKeyPairQuery = `SELECT aci_identity_key_pair FROM signalmeow_device WHERE aci_uuid=$1` @@ -70,20 +70,20 @@ func scanIdentityKey(row dbutil.Scannable) (*libsignalgo.IdentityKey, error) { return libsignalgo.DeserializeIdentityKey(key) } -func (s *SQLStore) GetIdentityKeyPair(ctx context.Context) (*libsignalgo.IdentityKeyPair, error) { - return scanIdentityKeyPair(s.db.QueryRow(ctx, getIdentityKeyPairQuery, s.ACI)) +func (s *sqlStore) GetIdentityKeyPair(ctx context.Context) (*libsignalgo.IdentityKeyPair, error) { + return scanIdentityKeyPair(s.db.QueryRow(ctx, getIdentityKeyPairQuery, s.AccountID)) } -func (s *SQLStore) GetLocalRegistrationID(ctx context.Context) (uint32, error) { +func (s *sqlStore) GetLocalRegistrationID(ctx context.Context) (uint32, error) { var regID sql.NullInt64 - err := s.db.QueryRow(ctx, getRegistrationLocalIDQuery, s.ACI).Scan(®ID) + err := s.db.QueryRow(ctx, getRegistrationLocalIDQuery, s.AccountID).Scan(®ID) if err != nil { return 0, fmt.Errorf("failed to get local registration ID: %w", err) } return uint32(regID.Int64), nil } -func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey) (bool, error) { +func (s *sqlStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey) (bool, error) { trustLevel := "TRUSTED_UNVERIFIED" // TODO: this should be hard coded here serialized, err := identityKey.Serialize() if err != nil { @@ -97,7 +97,7 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add if err != nil { return false, fmt.Errorf("failed to get device ID: %w", err) } - oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirServiceID, deviceID)) + oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.AccountID, theirServiceID, deviceID)) if err != nil { return false, fmt.Errorf("failed to get old identity key: %w", err) } @@ -110,14 +110,14 @@ func (s *SQLStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add // We are replacing the old key if the old key exists, and it is not equal to the new key replacing = !equal } - _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.ACI, theirServiceID, deviceID, serialized, trustLevel) + _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.AccountID, theirServiceID, deviceID, serialized, trustLevel) if err != nil { return replacing, fmt.Errorf("failed to insert new identity key: %w", err) } return replacing, err } -func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { +func (s *sqlStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { // TODO: this should check direction, and probably some other stuff (though whisperfish is pretty basic) theirServiceID, err := address.Name() if err != nil { @@ -128,7 +128,7 @@ func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.A return false, fmt.Errorf("failed to get device ID: %w", err) } var trustLevel string - err = s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.ACI, theirServiceID, deviceID).Scan(&trustLevel) + err = s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.AccountID, theirServiceID, deviceID).Scan(&trustLevel) if errors.Is(err, sql.ErrNoRows) { // If no rows, they are a new identity, so trust by default return true, nil @@ -139,7 +139,7 @@ func (s *SQLStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.A return trusted, nil } -func (s *SQLStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.IdentityKey, error) { +func (s *sqlStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.IdentityKey, error) { theirServiceID, err := address.Name() if err != nil { return nil, fmt.Errorf("failed to get their service ID: %w", err) @@ -148,7 +148,7 @@ func (s *SQLStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Addr if err != nil { return nil, fmt.Errorf("failed to get device ID: %w", err) } - key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.ACI, theirServiceID, deviceID)) + key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.AccountID, theirServiceID, deviceID)) if err != nil { return nil, fmt.Errorf("failed to get identity key from database: %w", err) } diff --git a/pkg/signalmeow/store/prekey_store.go b/pkg/signalmeow/store/prekey_store.go index 4963491..03d03bd 100644 --- a/pkg/signalmeow/store/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -25,281 +25,206 @@ import ( "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -var _ libsignalgo.PreKeyStore = (*SQLStore)(nil) -var _ libsignalgo.SignedPreKeyStore = (*SQLStore)(nil) -var _ libsignalgo.KyberPreKeyStore = (*SQLStore)(nil) -var _ PreKeyStoreExtras = (*SQLStore)(nil) +var _ PreKeyStore = (*scopedSQLStore)(nil) -// TODO: figure out how best to handle ACI vs PNI UUIDs +type PreKeyStore interface { + libsignalgo.PreKeyStore + libsignalgo.SignedPreKeyStore + libsignalgo.KyberPreKeyStore -type PreKeyStoreExtras interface { - PreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) - SignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) - KyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) - SavePreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error - SaveSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.SignedPreKeyRecord, markUploaded bool) error - SaveKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.KyberPreKeyRecord, lastResort bool) error - DeletePreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error - DeleteSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error - DeleteKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error - GetNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) - GetSignedNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) - GetNextKyberPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) - MarkPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error - MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error - IsKyberPreKeyLastResort(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (bool, error) - AllPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.PreKeyRecord, error) - AllNormalKyberPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.KyberPreKeyRecord, error) + GetServiceID() libsignalgo.ServiceID + + StoreLastResortKyberPreKey(ctx context.Context, preKeyID uint32, record *libsignalgo.KyberPreKeyRecord) error + RemoveSignedPreKey(ctx context.Context, preKeyID uint32) error + RemoveKyberPreKey(ctx context.Context, preKeyID uint32) error + GetNextPreKeyID(ctx context.Context) (uint32, error) + GetNextKyberPreKeyID(ctx context.Context) (uint32, error) + IsKyberPreKeyLastResort(ctx context.Context, preKeyID uint32) (bool, error) + AllPreKeys(ctx context.Context) ([]*libsignalgo.PreKeyRecord, error) + AllNormalKyberPreKeys(ctx context.Context) ([]*libsignalgo.KyberPreKeyRecord, error) DeleteAllPreKeys(ctx context.Context) error } -// libsignalgo.PreKeyStore implementation - -func (s *SQLStore) LoadPreKey(ctx context.Context, id uint32) (*libsignalgo.PreKeyRecord, error) { - return s.PreKey(ctx, types.UUIDKindACI, int(id)) -} -func (s *SQLStore) StorePreKey(ctx context.Context, id uint32, preKeyRecord *libsignalgo.PreKeyRecord) error { - return s.SavePreKey(ctx, types.UUIDKindACI, preKeyRecord, false) -} -func (s *SQLStore) RemovePreKey(ctx context.Context, id uint32) error { - return s.DeletePreKey(ctx, types.UUIDKindACI, int(id)) -} - -// libsignalgo.SignedPreKeyStore implementation - -func (s *SQLStore) LoadSignedPreKey(ctx context.Context, id uint32) (*libsignalgo.SignedPreKeyRecord, error) { - return s.SignedPreKey(ctx, types.UUIDKindACI, int(id)) -} -func (s *SQLStore) StoreSignedPreKey(ctx context.Context, id uint32, signedPreKeyRecord *libsignalgo.SignedPreKeyRecord) error { - return s.SaveSignedPreKey(ctx, types.UUIDKindACI, signedPreKeyRecord, false) -} -func (s *SQLStore) RemoveSignedPreKey(ctx context.Context, id uint32) error { - return s.DeleteSignedPreKey(ctx, types.UUIDKindACI, int(id)) -} - -// libsignalgo.KyberPreKeyStore implementation - -func (s *SQLStore) LoadKyberPreKey(ctx context.Context, id uint32) (*libsignalgo.KyberPreKeyRecord, error) { - return s.KyberPreKey(ctx, types.UUIDKindACI, int(id)) -} -func (s *SQLStore) StoreKyberPreKey(ctx context.Context, id uint32, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord) error { - return s.SaveKyberPreKey(ctx, types.UUIDKindACI, kyberPreKeyRecord, false) -} -func (s *SQLStore) MarkKyberPreKeyUsed(ctx context.Context, id uint32) error { - isLastResort, err := s.IsKyberPreKeyLastResort(ctx, types.UUIDKindACI, int(id)) - if err != nil { - return err - } - if !isLastResort { - return s.DeleteKyberPreKey(ctx, types.UUIDKindACI, int(id)) - } - return nil -} - const ( - getKyberPreKeyQuery = `SELECT key_pair, is_last_resort FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND key_id=$2 AND uuid_kind=$3` - insertKyberPreKeyQuery = `INSERT INTO signalmeow_kyber_pre_keys (aci_uuid, key_id, uuid_kind, key_pair, is_last_resort) VALUES ($1, $2, $3, $4, $5)` - deleteKyberPreKeyQuery = `DELETE FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND key_id=$2 AND uuid_kind=$3` - getLastKyberPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2` - isLastResortQuery = `SELECT is_last_resort FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND key_id=$2 AND uuid_kind=$3` + getAllPreKeysQuery = `SELECT key_pair FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_signed=$3` + getPreKeyQuery = `SELECT key_pair FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3 AND is_signed=$4` + insertPreKeyQuery = `INSERT INTO signalmeow_pre_keys (account_id, service_id, key_id, is_signed, key_pair) VALUES ($1, $2, $3, $4, $5)` + deletePreKeyQuery = `DELETE FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3 AND is_signed=$4` + getLastPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_signed=$3` + + getAllKyberPreKeysQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_last_resort=false` + getKyberPreKeyQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$2` + insertKyberPreKeyQuery = `INSERT INTO signalmeow_kyber_pre_keys (account_id, service_id, key_id, key_pair, is_last_resort) VALUES ($1, $2, $3, $4, $5)` + deleteKyberPreKeyQuery = `DELETE FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` + getLastKyberPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2` + isLastResortQuery = `SELECT is_last_resort FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` ) -func (s *SQLStore) KyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.KyberPreKeyRecord, error) { - var record []byte - var isLastResort bool - err := s.db.QueryRow(ctx, getKyberPreKeyQuery, s.ACI, preKeyID, uuidKind).Scan(&record, &isLastResort) +func scanRecord[T any](row dbutil.Scannable, deserializer func([]byte) (*T, error)) (*T, error) { + record, err := dbutil.ScanSingleColumn[[]byte](row) if errors.Is(err, sql.ErrNoRows) { return nil, nil - } - if err != nil { + } else if err != nil { return nil, err } - return libsignalgo.DeserializeKyberPreKeyRecord(record) + return deserializer(record) } -func (s *SQLStore) SaveKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord, lastResort bool) error { +func scanPreKey(row dbutil.Scannable) (*libsignalgo.PreKeyRecord, error) { + return scanRecord(row, libsignalgo.DeserializePreKeyRecord) +} + +func scanSignedPreKey(row dbutil.Scannable) (*libsignalgo.SignedPreKeyRecord, error) { + return scanRecord(row, libsignalgo.DeserializeSignedPreKeyRecord) +} + +func scanKyberPreKey(row dbutil.Scannable) (*libsignalgo.KyberPreKeyRecord, error) { + return scanRecord(row, libsignalgo.DeserializeKyberPreKeyRecord) +} + +func (s *scopedSQLStore) GetServiceID() libsignalgo.ServiceID { + return s.ServiceID +} + +func (s *scopedSQLStore) LoadPreKey(ctx context.Context, preKeyID uint32) (*libsignalgo.PreKeyRecord, error) { + return scanPreKey(s.db.QueryRow(ctx, getPreKeyQuery, s.AccountID, s.ServiceID, preKeyID, false)) +} + +func (s *scopedSQLStore) LoadSignedPreKey(ctx context.Context, preKeyID uint32) (*libsignalgo.SignedPreKeyRecord, error) { + return scanSignedPreKey(s.db.QueryRow(ctx, getPreKeyQuery, s.AccountID, s.ServiceID, preKeyID, true)) +} + +func (s *scopedSQLStore) LoadKyberPreKey(ctx context.Context, preKeyID uint32) (*libsignalgo.KyberPreKeyRecord, error) { + return scanKyberPreKey(s.db.QueryRow(ctx, getKyberPreKeyQuery, s.AccountID, s.ServiceID, preKeyID)) +} + +func (s *scopedSQLStore) StorePreKey(ctx context.Context, preKeyID uint32, preKey *libsignalgo.PreKeyRecord) error { + id, err := preKey.GetID() + if err != nil { + return fmt.Errorf("failed to get prekey ID: %w", err) + } else if preKeyID > 0 && id != preKeyID { + return fmt.Errorf("prekey ID mismatch: expected %d, got %d", preKeyID, id) + } + serialized, err := preKey.Serialize() + if err != nil { + return fmt.Errorf("failed to serialize prekey: %w", err) + } + _, err = s.db.Exec(ctx, insertPreKeyQuery, s.AccountID, s.ServiceID, id, false, serialized) + return err +} + +func (s *scopedSQLStore) StoreSignedPreKey(ctx context.Context, preKeyID uint32, preKey *libsignalgo.SignedPreKeyRecord) error { + id, err := preKey.GetID() + if err != nil { + return fmt.Errorf("failed to get signed prekey ID: %w", err) + } else if preKeyID > 0 && id != preKeyID { + return fmt.Errorf("prekey ID mismatch: expected %d, got %d", preKeyID, id) + } + serialized, err := preKey.Serialize() + if err != nil { + return fmt.Errorf("failed to serialize signed prekey: %w", err) + } + _, err = s.db.Exec(ctx, insertPreKeyQuery, s.AccountID, s.ServiceID, id, true, serialized) + return err +} + +func (s *scopedSQLStore) StoreKyberPreKey(ctx context.Context, preKeyID uint32, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord) error { + return s.storeKyberPreKey(ctx, preKeyID, kyberPreKeyRecord, false) +} + +func (s *scopedSQLStore) StoreLastResortKyberPreKey(ctx context.Context, preKeyID uint32, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord) error { + return s.storeKyberPreKey(ctx, preKeyID, kyberPreKeyRecord, true) +} + +func (s *scopedSQLStore) storeKyberPreKey(ctx context.Context, preKeyID uint32, kyberPreKeyRecord *libsignalgo.KyberPreKeyRecord, lastResort bool) error { id, err := kyberPreKeyRecord.GetID() if err != nil { return fmt.Errorf("failed to get kyber prekey record ID: %w", err) + } else if preKeyID > 0 && id != preKeyID { + return fmt.Errorf("prekey ID mismatch: expected %d, got %d", preKeyID, id) } serialized, err := kyberPreKeyRecord.Serialize() if err != nil { return fmt.Errorf("failed to serialize kyber prekey record: %w", err) } - _, err = s.db.Exec(ctx, insertKyberPreKeyQuery, s.ACI, id, uuidKind, serialized, lastResort) + _, err = s.db.Exec(ctx, insertKyberPreKeyQuery, s.AccountID, s.ServiceID, id, serialized, lastResort) return err } -func (s *SQLStore) DeleteKyberPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { - _, err := s.db.Exec(ctx, deleteKyberPreKeyQuery, s.ACI, preKeyID, uuidKind) +func (s *scopedSQLStore) RemovePreKey(ctx context.Context, preKeyID uint32) error { + _, err := s.db.Exec(ctx, deletePreKeyQuery, s.AccountID, s.ServiceID, preKeyID, false) return err } -func (s *SQLStore) GetNextKyberPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { +func (s *scopedSQLStore) RemoveSignedPreKey(ctx context.Context, preKeyID uint32) error { + _, err := s.db.Exec(ctx, deletePreKeyQuery, s.AccountID, s.ServiceID, preKeyID, true) + return err +} + +func (s *scopedSQLStore) RemoveKyberPreKey(ctx context.Context, preKeyID uint32) error { + _, err := s.db.Exec(ctx, deleteKyberPreKeyQuery, s.AccountID, s.ServiceID, preKeyID) + return err +} + +func (s *scopedSQLStore) MarkKyberPreKeyUsed(ctx context.Context, id uint32) error { + isLastResort, err := s.IsKyberPreKeyLastResort(ctx, id) + if err != nil { + return err + } + if !isLastResort { + return s.RemoveKyberPreKey(ctx, id) + } + return nil +} + +func (s *scopedSQLStore) GetNextPreKeyID(ctx context.Context) (uint32, error) { var lastKeyID sql.NullInt64 - err := s.db.QueryRow(ctx, getLastKyberPreKeyIDQuery, s.ACI, uuidKind).Scan(&lastKeyID) + err := s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.AccountID, s.ServiceID, false).Scan(&lastKeyID) + if err != nil { + return 0, fmt.Errorf("failed to query next prekey ID: %w", err) + } + return uint32(lastKeyID.Int64) + 1, nil +} + +func (s *scopedSQLStore) GetNextKyberPreKeyID(ctx context.Context) (uint32, error) { + var lastKeyID sql.NullInt64 + err := s.db.QueryRow(ctx, getLastKyberPreKeyIDQuery, s.AccountID, s.ServiceID).Scan(&lastKeyID) if err != nil { return 0, fmt.Errorf("failed to query next kyber prekey ID: %w", err) } - return uint(lastKeyID.Int64) + 1, nil + return uint32(lastKeyID.Int64) + 1, nil } -func (s *SQLStore) IsKyberPreKeyLastResort(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (bool, error) { +func (s *scopedSQLStore) IsKyberPreKeyLastResort(ctx context.Context, preKeyID uint32) (bool, error) { var isLastResort bool - err := s.db.QueryRow(ctx, isLastResortQuery, s.ACI, preKeyID, uuidKind).Scan(&isLastResort) + err := s.db.QueryRow(ctx, isLastResortQuery, s.AccountID, s.ServiceID, preKeyID).Scan(&isLastResort) if err != nil { return false, err } return isLastResort, nil } -const ( - getPreKeyQuery = `SELECT key_id, key_pair FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND key_id=$2 AND uuid_kind=$3 and is_signed=$4` - insertPreKeyQuery = `INSERT INTO signalmeow_pre_keys (aci_uuid, key_id, uuid_kind, is_signed, key_pair, uploaded) VALUES ($1, $2, $3, $4, $5, $6)` - deletePreKeyQuery = `DELETE FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND key_id=$2 AND uuid_kind=$3 AND is_signed=$4` - getLastPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_signed=$3` - markPreKeysAsUploadedQuery = `UPDATE signalmeow_pre_keys SET uploaded=true WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_signed=$3 AND key_id<=$4` - getUnuploadedPreKeysQuery = `SELECT key_id, key_pair FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_signed=$3 AND uploaded=false ORDER BY key_id` - getUploadedPreKeyCountQuery = `SELECT COUNT(*) FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_signed=$3 AND uploaded=true` -) - -func scanPreKey(row dbutil.Scannable) (*libsignalgo.PreKeyRecord, error) { - var id uint - var record []byte - err := row.Scan(&id, &record) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - return libsignalgo.DeserializePreKeyRecord(record) -} - -func scanSignedPreKey(row dbutil.Scannable) (*libsignalgo.SignedPreKeyRecord, error) { - var id uint - var record []byte - err := row.Scan(&id, &record) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - return libsignalgo.DeserializeSignedPreKeyRecord(record) -} - -func (s *SQLStore) PreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.PreKeyRecord, error) { - return scanPreKey(s.db.QueryRow(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, false)) -} - -func (s *SQLStore) SignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) (*libsignalgo.SignedPreKeyRecord, error) { - return scanSignedPreKey(s.db.QueryRow(ctx, getPreKeyQuery, s.ACI, preKeyID, uuidKind, true)) -} - -func (s *SQLStore) SavePreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.PreKeyRecord, markUploaded bool) error { - id, err := preKey.GetID() - if err != nil { - return fmt.Errorf("failed to get prekey ID: %w", err) - } - serialized, err := preKey.Serialize() - if err != nil { - return fmt.Errorf("failed to serialize prekey: %w", err) - } - _, err = s.db.Exec(ctx, insertPreKeyQuery, s.ACI, id, uuidKind, false, serialized, markUploaded) - return err -} - -func (s *SQLStore) SaveSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKey *libsignalgo.SignedPreKeyRecord, markUploaded bool) error { - id, err := preKey.GetID() - if err != nil { - return fmt.Errorf("failed to get signed prekey ID: %w", err) - } - serialized, err := preKey.Serialize() - if err != nil { - return fmt.Errorf("failed to serialize signed prekey: %w", err) - } - _, err = s.db.Exec(ctx, insertPreKeyQuery, s.ACI, id, uuidKind, true, serialized, markUploaded) - return err -} - -func (s *SQLStore) DeletePreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { - _, err := s.db.Exec(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, false) - return err -} - -func (s *SQLStore) DeleteSignedPreKey(ctx context.Context, uuidKind types.UUIDKind, preKeyID int) error { - _, err := s.db.Exec(ctx, deletePreKeyQuery, s.ACI, preKeyID, uuidKind, true) - return err -} - -func (s *SQLStore) GetNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { - var lastKeyID sql.NullInt64 - err := s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, false).Scan(&lastKeyID) - if err != nil { - return 0, fmt.Errorf("failed to query next prekey ID: %w", err) - } - return uint(lastKeyID.Int64) + 1, nil -} - -func (s *SQLStore) GetSignedNextPreKeyID(ctx context.Context, uuidKind types.UUIDKind) (uint, error) { - var lastKeyID sql.NullInt64 - err := s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.ACI, uuidKind, true).Scan(&lastKeyID) - if err != nil { - return 0, fmt.Errorf("failed to query next signed prekey ID: %w", err) - } - return uint(lastKeyID.Int64) + 1, nil -} - -func (s *SQLStore) MarkPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error { - _, err := s.db.Exec(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, false, upToID) - return err -} - -func (s *SQLStore) MarkSignedPreKeysAsUploaded(ctx context.Context, uuidKind types.UUIDKind, upToID uint) error { - _, err := s.db.Exec(ctx, markPreKeysAsUploadedQuery, s.ACI, uuidKind, true, upToID) - return err -} - -func (s *SQLStore) DeleteAllPreKeys(ctx context.Context) error { +func (s *scopedSQLStore) DeleteAllPreKeys(ctx context.Context) error { return s.db.DoTxn(ctx, nil, func(ctx context.Context) error { - _, err := s.db.Exec(ctx, "DELETE FROM signalmeow_pre_keys WHERE aci_uuid=$1", s.ACI) + _, err := s.db.Exec(ctx, "DELETE FROM signalmeow_pre_keys WHERE account_id=$1", s.AccountID) if err != nil { return err } - _, err = s.db.Exec(ctx, "DELETE FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1", s.ACI) + _, err = s.db.Exec(ctx, "DELETE FROM signalmeow_kyber_pre_keys WHERE account_id=$1", s.AccountID) return err }) } -func (s *SQLStore) AllPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.PreKeyRecord, error) { - queryString := "SELECT key_id, key_pair FROM signalmeow_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_signed=$3" - rows, err := s.db.Query(ctx, queryString, s.ACI, uuidKind, false) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } - if err != nil { - return nil, err - } - return dbutil.NewRowIter(rows, scanPreKey).AsList() +func (s *scopedSQLStore) AllPreKeys(ctx context.Context) ([]*libsignalgo.PreKeyRecord, error) { + return dbutil.ConvertRowFn[*libsignalgo.PreKeyRecord](scanPreKey). + NewRowIter(s.db.Query(ctx, getAllPreKeysQuery, s.AccountID, s.ServiceID, false)). + AsList() } -func (s *SQLStore) AllNormalKyberPreKeys(ctx context.Context, uuidKind types.UUIDKind) ([]*libsignalgo.KyberPreKeyRecord, error) { - queryString := "SELECT key_id, key_pair FROM signalmeow_kyber_pre_keys WHERE aci_uuid=$1 AND uuid_kind=$2 AND is_last_resort=false" - rows, err := s.db.Query(ctx, queryString, s.ACI, uuidKind) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - return dbutil.NewRowIter(rows, func(row dbutil.Scannable) (*libsignalgo.KyberPreKeyRecord, error) { - var id uint - var record []byte - err := row.Scan(&id, &record) - if err != nil { - return nil, err - } - return libsignalgo.DeserializeKyberPreKeyRecord(record) - }).AsList() +func (s *scopedSQLStore) AllNormalKyberPreKeys(ctx context.Context) ([]*libsignalgo.KyberPreKeyRecord, error) { + return dbutil.ConvertRowFn[*libsignalgo.KyberPreKeyRecord](scanKyberPreKey). + NewRowIter(s.db.Query(ctx, getAllKyberPreKeysQuery, s.AccountID, s.ServiceID)). + AsList() } diff --git a/pkg/signalmeow/store/profile_key_store.go b/pkg/signalmeow/store/profile_key_store.go index c384f4f..aaeaccf 100644 --- a/pkg/signalmeow/store/profile_key_store.go +++ b/pkg/signalmeow/store/profile_key_store.go @@ -27,7 +27,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -var _ ProfileKeyStore = (*SQLStore)(nil) +var _ ProfileKeyStore = (*sqlStore)(nil) type ProfileKeyStore interface { // LoadProfileKey loads the profile key for the given address. @@ -54,15 +54,15 @@ func scanProfileKey(row dbutil.Scannable) (*libsignalgo.ProfileKey, error) { return &profileKey, err } -func (s *SQLStore) LoadProfileKey(ctx context.Context, theirACI uuid.UUID) (*libsignalgo.ProfileKey, error) { - return scanProfileKey(s.db.QueryRow(ctx, loadProfileKeyQuery, s.ACI, theirACI)) +func (s *sqlStore) LoadProfileKey(ctx context.Context, theirACI uuid.UUID) (*libsignalgo.ProfileKey, error) { + return scanProfileKey(s.db.QueryRow(ctx, loadProfileKeyQuery, s.AccountID, theirACI)) } -func (s *SQLStore) MyProfileKey(ctx context.Context) (*libsignalgo.ProfileKey, error) { - return scanProfileKey(s.db.QueryRow(ctx, loadProfileKeyQuery, s.ACI, s.ACI)) +func (s *sqlStore) MyProfileKey(ctx context.Context) (*libsignalgo.ProfileKey, error) { + return scanProfileKey(s.db.QueryRow(ctx, loadProfileKeyQuery, s.AccountID, s.AccountID)) } -func (s *SQLStore) StoreProfileKey(ctx context.Context, theirACI uuid.UUID, key libsignalgo.ProfileKey) error { - _, err := s.db.Exec(ctx, storeProfileKeyQuery, s.ACI, theirACI, key.Slice()) +func (s *sqlStore) StoreProfileKey(ctx context.Context, theirACI uuid.UUID, key libsignalgo.ProfileKey) error { + _, err := s.db.Exec(ctx, storeProfileKeyQuery, s.AccountID, theirACI, key.Slice()) return err } diff --git a/pkg/signalmeow/store/sender_key_store.go b/pkg/signalmeow/store/sender_key_store.go index e9ffea2..cd8dcb9 100644 --- a/pkg/signalmeow/store/sender_key_store.go +++ b/pkg/signalmeow/store/sender_key_store.go @@ -28,7 +28,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -var _ libsignalgo.SenderKeyStore = (*SQLStore)(nil) +var _ libsignalgo.SenderKeyStore = (*sqlStore)(nil) const ( loadSenderKeyQuery = `SELECT key_record FROM signalmeow_sender_keys WHERE our_aci_uuid=$1 AND sender_uuid=$2 AND sender_device_id=$3 AND distribution_id=$4` @@ -46,7 +46,7 @@ func scanSenderKey(row dbutil.Scannable) (*libsignalgo.SenderKeyRecord, error) { return libsignalgo.DeserializeSenderKeyRecord(key) } -func (s *SQLStore) LoadSenderKey(ctx context.Context, sender *libsignalgo.Address, distributionID uuid.UUID) (*libsignalgo.SenderKeyRecord, error) { +func (s *sqlStore) LoadSenderKey(ctx context.Context, sender *libsignalgo.Address, distributionID uuid.UUID) (*libsignalgo.SenderKeyRecord, error) { senderUUID, err := sender.Name() if err != nil { return nil, fmt.Errorf("failed to get sender UUID: %w", err) @@ -55,10 +55,10 @@ func (s *SQLStore) LoadSenderKey(ctx context.Context, sender *libsignalgo.Addres if err != nil { return nil, fmt.Errorf("failed to get sender device ID: %w", err) } - return scanSenderKey(s.db.QueryRow(ctx, loadSenderKeyQuery, s.ACI, senderUUID, deviceID, distributionID)) + return scanSenderKey(s.db.QueryRow(ctx, loadSenderKeyQuery, s.AccountID, senderUUID, deviceID, distributionID)) } -func (s *SQLStore) StoreSenderKey(ctx context.Context, sender *libsignalgo.Address, distributionID uuid.UUID, record *libsignalgo.SenderKeyRecord) error { +func (s *sqlStore) StoreSenderKey(ctx context.Context, sender *libsignalgo.Address, distributionID uuid.UUID, record *libsignalgo.SenderKeyRecord) error { senderUUID, err := sender.Name() if err != nil { return fmt.Errorf("failed to get sender UUID: %w", err) @@ -71,6 +71,6 @@ func (s *SQLStore) StoreSenderKey(ctx context.Context, sender *libsignalgo.Addre if err != nil { return fmt.Errorf("failed to serialize sender key: %w", err) } - _, err = s.db.Exec(ctx, storeSenderKeyQuery, s.ACI, senderUUID, deviceID, distributionID, serialized) + _, err = s.db.Exec(ctx, storeSenderKeyQuery, s.AccountID, senderUUID, deviceID, distributionID, serialized) return err } diff --git a/pkg/signalmeow/store/session_store.go b/pkg/signalmeow/store/session_store.go index bb6f18a..a2090e9 100644 --- a/pkg/signalmeow/store/session_store.go +++ b/pkg/signalmeow/store/session_store.go @@ -27,21 +27,22 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -var _ libsignalgo.SessionStore = (*SQLStore)(nil) -var _ SessionStoreExtras = (*SQLStore)(nil) +var _ SessionStore = (*scopedSQLStore)(nil) const ( - loadSessionQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3` + loadSessionQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3 AND their_device_id=$4` storeSessionQuery = ` - INSERT INTO signalmeow_sessions (our_aci_uuid, their_service_id, their_device_id, record) - VALUES ($1, $2, $3, $4) - ON CONFLICT (our_aci_uuid, their_service_id, their_device_id) DO UPDATE SET record=excluded.record + INSERT INTO signalmeow_sessions (account_id, service_id, their_service_id, their_device_id, record) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (account_id, service_id, their_service_id, their_device_id) DO UPDATE SET record=excluded.record ` - allSessionsQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_service_id=$2` - removeSessionQuery = `DELETE FROM signalmeow_sessions WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3` + allSessionsQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3` + removeSessionQuery = `DELETE FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3 AND their_device_id=$4` + deleteAllSessionsQuery = "DELETE FROM signalmeow_sessions WHERE account_id=$1" ) -type SessionStoreExtras interface { +type SessionStore interface { + libsignalgo.SessionStore // AllSessionsForServiceID returns all sessions for the given service ID. AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) // RemoveSession removes the session for the given address. @@ -50,20 +51,20 @@ type SessionStoreExtras interface { RemoveAllSessions(ctx context.Context) error } -func scanRecord(row dbutil.Scannable) (int, *libsignalgo.SessionRecord, error) { +func scanSessionRecord(row dbutil.Scannable) (int, *libsignalgo.SessionRecord, error) { var record []byte - var deviceId int - err := row.Scan(&deviceId, &record) + var deviceID int + err := row.Scan(&deviceID, &record) if errors.Is(err, sql.ErrNoRows) { return 0, nil, nil } else if err != nil { return 0, nil, err } sessionRecord, err := libsignalgo.DeserializeSessionRecord(record) - return deviceId, sessionRecord, err + return deviceID, sessionRecord, err } -func (s *SQLStore) RemoveSession(ctx context.Context, address *libsignalgo.Address) error { +func (s *scopedSQLStore) RemoveSession(ctx context.Context, address *libsignalgo.Address) error { theirServiceID, err := address.Name() if err != nil { return fmt.Errorf("failed to get their service ID: %w", err) @@ -72,12 +73,12 @@ func (s *SQLStore) RemoveSession(ctx context.Context, address *libsignalgo.Addre if err != nil { return fmt.Errorf("failed to get their device ID: %w", err) } - _, err = s.db.Exec(ctx, removeSessionQuery, s.ACI, theirServiceID, deviceID) + _, err = s.db.Exec(ctx, removeSessionQuery, s.AccountID, s.ServiceID, theirServiceID, deviceID) return err } -func (s *SQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) { - rows, err := s.db.Query(ctx, allSessionsQuery, s.ACI, theirID.String()) +func (s *scopedSQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) { + rows, err := s.db.Query(ctx, allSessionsQuery, s.AccountID, s.ServiceID, theirID) if err != nil { return nil, nil, err } @@ -85,7 +86,7 @@ func (s *SQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsigna var records []*libsignalgo.SessionRecord var addresses []*libsignalgo.Address for rows.Next() { - deviceID, record, err := scanRecord(rows) + deviceID, record, err := scanSessionRecord(rows) if err != nil { return nil, nil, err } @@ -99,7 +100,7 @@ func (s *SQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsigna return addresses, records, rows.Err() } -func (s *SQLStore) LoadSession(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.SessionRecord, error) { +func (s *scopedSQLStore) LoadSession(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.SessionRecord, error) { theirServiceID, err := address.Name() if err != nil { return nil, fmt.Errorf("failed to get their service ID: %w", err) @@ -108,11 +109,11 @@ func (s *SQLStore) LoadSession(ctx context.Context, address *libsignalgo.Address if err != nil { return nil, fmt.Errorf("failed to get their device ID: %w", err) } - _, record, err := scanRecord(s.db.QueryRow(ctx, loadSessionQuery, s.ACI, theirServiceID, deviceID)) + _, record, err := scanSessionRecord(s.db.QueryRow(ctx, loadSessionQuery, s.AccountID, s.ServiceID, theirServiceID, deviceID)) return record, err } -func (s *SQLStore) StoreSession(ctx context.Context, address *libsignalgo.Address, record *libsignalgo.SessionRecord) error { +func (s *scopedSQLStore) StoreSession(ctx context.Context, address *libsignalgo.Address, record *libsignalgo.SessionRecord) error { theirServiceID, err := address.Name() if err != nil { return fmt.Errorf("failed to get their service ID: %w", err) @@ -125,11 +126,11 @@ func (s *SQLStore) StoreSession(ctx context.Context, address *libsignalgo.Addres if err != nil { return fmt.Errorf("failed to serialize session record: %w", err) } - _, err = s.db.Exec(ctx, storeSessionQuery, s.ACI, theirServiceID, deviceID, serialized) + _, err = s.db.Exec(ctx, storeSessionQuery, s.AccountID, s.ServiceID, theirServiceID, deviceID, serialized) return err } -func (s *SQLStore) RemoveAllSessions(ctx context.Context) error { - _, err := s.db.Exec(ctx, "DELETE FROM signalmeow_sessions WHERE our_aci_uuid=$1", s.ACI) +func (s *scopedSQLStore) RemoveAllSessions(ctx context.Context) error { + _, err := s.db.Exec(ctx, deleteAllSessionsQuery, s.AccountID) return err } diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index f4cdeac..65b4eb3 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v9: Latest revision +-- v0 -> v10: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -15,17 +15,29 @@ CREATE TABLE signalmeow_device ( ); CREATE TABLE signalmeow_pre_keys ( - aci_uuid TEXT NOT NULL, - key_id INTEGER NOT NULL, - uuid_kind TEXT NOT NULL, - is_signed BOOLEAN NOT NULL, - key_pair bytea NOT NULL, - uploaded BOOLEAN NOT NULL, + account_id TEXT NOT NULL, + service_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + is_signed BOOLEAN NOT NULL, + key_pair bytea NOT NULL, - PRIMARY KEY (aci_uuid, uuid_kind, is_signed, key_id), - FOREIGN KEY (aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + PRIMARY KEY (account_id, service_id, key_id, is_signed), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); +CREATE TABLE signalmeow_kyber_pre_keys ( + account_id TEXT NOT NULL, + service_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + key_pair bytea NOT NULL, + is_last_resort BOOLEAN NOT NULL, + + PRIMARY KEY (account_id, service_id, key_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); + +-- TODO rename our_aci_uuid to account_id in all tables for consistency + CREATE TABLE signalmeow_identity_keys ( our_aci_uuid TEXT NOT NULL, their_service_id TEXT NOT NULL, @@ -38,13 +50,14 @@ CREATE TABLE signalmeow_identity_keys ( ); CREATE TABLE signalmeow_sessions ( - our_aci_uuid TEXT NOT NULL, + account_id TEXT NOT NULL, + service_id TEXT NOT NULL, their_service_id TEXT NOT NULL, their_device_id INTEGER NOT NULL, record bytea NOT NULL, - PRIMARY KEY (our_aci_uuid, their_service_id, their_device_id), - FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + PRIMARY KEY (account_id, service_id, their_service_id, their_device_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_profile_keys ( @@ -58,7 +71,7 @@ CREATE TABLE signalmeow_profile_keys ( CREATE TABLE signalmeow_sender_keys ( our_aci_uuid TEXT NOT NULL, - sender_uuid TEXT NOT NULL, + sender_uuid TEXT NOT NULL, -- note: this may actually be a service id sender_device_id INTEGER NOT NULL, distribution_id TEXT NOT NULL, key_record bytea NOT NULL, @@ -91,14 +104,3 @@ CREATE TABLE signalmeow_contacts ( PRIMARY KEY (our_aci_uuid, aci_uuid), FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); - -CREATE TABLE signalmeow_kyber_pre_keys ( - aci_uuid TEXT NOT NULL, - key_id INTEGER NOT NULL, - uuid_kind TEXT NOT NULL, - key_pair bytea NOT NULL, - is_last_resort BOOLEAN NOT NULL, - - PRIMARY KEY (aci_uuid, uuid_kind, key_id), - FOREIGN KEY (aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE -); diff --git a/pkg/signalmeow/store/upgrades/10-prekey-store-service-id.postgres.sql b/pkg/signalmeow/store/upgrades/10-prekey-store-service-id.postgres.sql new file mode 100644 index 0000000..c4d913d --- /dev/null +++ b/pkg/signalmeow/store/upgrades/10-prekey-store-service-id.postgres.sql @@ -0,0 +1,31 @@ +-- v10: Change prekey store to use service IDs instead of UUID kind column +ALTER TABLE signalmeow_pre_keys ADD COLUMN service_id TEXT; +UPDATE signalmeow_pre_keys SET service_id=aci_uuid WHERE uuid_kind='aci'; +UPDATE signalmeow_pre_keys SET service_id='PNI:' || ( + SELECT pni_uuid FROM signalmeow_device WHERE signalmeow_device.aci_uuid=signalmeow_pre_keys.aci_uuid +) WHERE uuid_kind='pni'; +ALTER TABLE signalmeow_pre_keys ALTER COLUMN service_id SET NOT NULL; +ALTER TABLE signalmeow_pre_keys DROP CONSTRAINT signalmeow_pre_keys_pkey; +ALTER TABLE signalmeow_pre_keys DROP COLUMN uuid_kind; +ALTER TABLE signalmeow_pre_keys RENAME COLUMN aci_uuid TO account_id; +ALTER TABLE signalmeow_pre_keys ADD PRIMARY KEY (account_id, service_id, is_signed, key_id); + +ALTER TABLE signalmeow_pre_keys DROP COLUMN uploaded; + +ALTER TABLE signalmeow_kyber_pre_keys ADD COLUMN service_id TEXT; +UPDATE signalmeow_kyber_pre_keys SET service_id=aci_uuid WHERE uuid_kind='aci'; +UPDATE signalmeow_kyber_pre_keys SET service_id='PNI:' || ( + SELECT pni_uuid FROM signalmeow_device WHERE signalmeow_device.aci_uuid=signalmeow_kyber_pre_keys.aci_uuid +) WHERE uuid_kind='pni'; +ALTER TABLE signalmeow_kyber_pre_keys ALTER COLUMN service_id SET NOT NULL; +ALTER TABLE signalmeow_kyber_pre_keys DROP CONSTRAINT signalmeow_kyber_pre_keys_pkey; +ALTER TABLE signalmeow_kyber_pre_keys DROP COLUMN uuid_kind; +ALTER TABLE signalmeow_kyber_pre_keys RENAME COLUMN aci_uuid TO account_id; +ALTER TABLE signalmeow_kyber_pre_keys ADD PRIMARY KEY (account_id, service_id, key_id); + +ALTER TABLE signalmeow_sessions ADD COLUMN service_id TEXT; +UPDATE signalmeow_sessions SET service_id=our_aci_uuid; -- there are no PNI sessions yet +ALTER TABLE signalmeow_sessions ALTER COLUMN service_id SET NOT NULL; +ALTER TABLE signalmeow_sessions DROP CONSTRAINT signalmeow_sessions_pkey; +ALTER TABLE signalmeow_sessions RENAME COLUMN our_aci_uuid TO account_id; +ALTER TABLE signalmeow_sessions ADD PRIMARY KEY (account_id, service_id, their_service_id, their_device_id); diff --git a/pkg/signalmeow/store/upgrades/10-prekey-store-service-id.sqlite.sql b/pkg/signalmeow/store/upgrades/10-prekey-store-service-id.sqlite.sql new file mode 100644 index 0000000..25b2824 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/10-prekey-store-service-id.sqlite.sql @@ -0,0 +1,59 @@ +-- v10: Change prekey store to use service IDs instead of UUID kind column +CREATE TABLE new_signalmeow_pre_keys ( + account_id TEXT NOT NULL, + service_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + is_signed BOOLEAN NOT NULL, + key_pair bytea NOT NULL, + + PRIMARY KEY (account_id, service_id, is_signed, key_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); + +INSERT INTO new_signalmeow_pre_keys (account_id, service_id, key_id, is_signed, key_pair) +SELECT aci_uuid, CASE WHEN uuid_kind='pni' THEN 'PNI:'||( + SELECT pni_uuid FROM signalmeow_device WHERE signalmeow_device.aci_uuid=signalmeow_pre_keys.aci_uuid +) ELSE aci_uuid END, key_id, is_signed, key_pair +FROM signalmeow_pre_keys; + +DROP TABLE signalmeow_pre_keys; +ALTER TABLE new_signalmeow_pre_keys RENAME TO signalmeow_pre_keys; + + +CREATE TABLE new_signalmeow_kyber_pre_keys ( + account_id TEXT NOT NULL, + service_id TEXT NOT NULL, + key_id INTEGER NOT NULL, + key_pair bytea NOT NULL, + is_last_resort BOOLEAN NOT NULL, + + PRIMARY KEY (account_id, service_id, key_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); + +INSERT INTO new_signalmeow_kyber_pre_keys (account_id, service_id, key_id, key_pair, is_last_resort) +SELECT aci_uuid, CASE WHEN uuid_kind='pni' THEN 'PNI:'||( + SELECT pni_uuid FROM signalmeow_device WHERE signalmeow_device.aci_uuid=signalmeow_kyber_pre_keys.aci_uuid +) ELSE aci_uuid END, key_id, key_pair, is_last_resort +FROM signalmeow_kyber_pre_keys; + +DROP TABLE signalmeow_kyber_pre_keys; +ALTER TABLE new_signalmeow_kyber_pre_keys RENAME TO signalmeow_kyber_pre_keys; + + +CREATE TABLE new_signalmeow_sessions ( + account_id TEXT NOT NULL, + service_id TEXT NOT NULL, + their_service_id TEXT NOT NULL, + their_device_id INTEGER NOT NULL, + record bytea NOT NULL, + + PRIMARY KEY (account_id, service_id, their_service_id, their_device_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +INSERT INTO new_signalmeow_sessions (account_id, service_id, their_service_id, their_device_id, record) +SELECT our_aci_uuid, our_aci_uuid, their_service_id, their_device_id, record +FROM signalmeow_sessions; + +DROP TABLE signalmeow_sessions; +ALTER TABLE new_signalmeow_sessions RENAME TO signalmeow_sessions; From 0d98e3560b6a0d263a2675d5e56d2cf815e86cb7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 19 Mar 2024 19:18:56 +0200 Subject: [PATCH 112/718] Rename our_aci_uuid columns to account_id --- pkg/signalmeow/store/contact_store.go | 14 ++++---- pkg/signalmeow/store/group_store.go | 6 ++-- pkg/signalmeow/store/identity_store.go | 8 ++--- pkg/signalmeow/store/profile_key_store.go | 4 +-- pkg/signalmeow/store/sender_key_store.go | 4 +-- pkg/signalmeow/store/upgrades/00-latest.sql | 32 +++++++++---------- .../store/upgrades/11-aci-to-account-id.sql | 6 ++++ 7 files changed, 39 insertions(+), 35 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/11-aci-to-account-id.sql diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go index 9e2017b..fa079e9 100644 --- a/pkg/signalmeow/store/contact_store.go +++ b/pkg/signalmeow/store/contact_store.go @@ -54,12 +54,12 @@ const ( profile_fetched_at FROM signalmeow_contacts ` - getAllContactsOfUserQuery = getAllContactsQuery + `WHERE our_aci_uuid = $1` - getContactByUUIDQuery = getAllContactsQuery + `WHERE our_aci_uuid = $1 AND aci_uuid = $2` - getContactByPhoneQuery = getAllContactsQuery + `WHERE our_aci_uuid = $1 AND e164_number = $2` + getAllContactsOfUserQuery = getAllContactsQuery + `WHERE account_id = $1` + getContactByUUIDQuery = getAllContactsQuery + `WHERE account_id = $1 AND aci_uuid = $2` + getContactByPhoneQuery = getAllContactsQuery + `WHERE account_id = $1 AND e164_number = $2` upsertContactQuery = ` INSERT INTO signalmeow_contacts ( - our_aci_uuid, + account_id, aci_uuid, e164_number, contact_name, @@ -72,7 +72,7 @@ const ( profile_fetched_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) - ON CONFLICT (our_aci_uuid, aci_uuid) DO UPDATE SET + ON CONFLICT (account_id, aci_uuid) DO UPDATE SET e164_number = excluded.e164_number, contact_name = excluded.contact_name, contact_avatar_hash = excluded.contact_avatar_hash, @@ -85,7 +85,7 @@ const ( ` upsertContactPhoneQuery = ` INSERT INTO signalmeow_contacts ( - our_aci_uuid, + account_id, aci_uuid, e164_number, contact_name, @@ -98,7 +98,7 @@ const ( profile_fetched_at ) VALUES ($1, $2, $3, '', '', NULL, '', '', '', '', NULL) - ON CONFLICT (our_aci_uuid, aci_uuid) DO UPDATE + ON CONFLICT (account_id, aci_uuid) DO UPDATE SET e164_number = excluded.e164_number ` ) diff --git a/pkg/signalmeow/store/group_store.go b/pkg/signalmeow/store/group_store.go index 83a5473..39b4684 100644 --- a/pkg/signalmeow/store/group_store.go +++ b/pkg/signalmeow/store/group_store.go @@ -40,11 +40,11 @@ type GroupStore interface { } const ( - getGroupByIDQuery = `SELECT our_aci_uuid, group_identifier, master_key FROM signalmeow_groups WHERE our_aci_uuid=$1 AND group_identifier=$2` + getGroupByIDQuery = `SELECT account_id, group_identifier, master_key FROM signalmeow_groups WHERE account_id=$1 AND group_identifier=$2` upsertGroupMasterKeyQuery = ` - INSERT INTO signalmeow_groups (our_aci_uuid, group_identifier, master_key) + INSERT INTO signalmeow_groups (account_id, group_identifier, master_key) VALUES ($1, $2, $3) - ON CONFLICT (our_aci_uuid, group_identifier) DO UPDATE + ON CONFLICT (account_id, group_identifier) DO UPDATE SET master_key = excluded.master_key; ` ) diff --git a/pkg/signalmeow/store/identity_store.go b/pkg/signalmeow/store/identity_store.go index 1004daf..dbed8f2 100644 --- a/pkg/signalmeow/store/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -33,18 +33,18 @@ const ( getIdentityKeyPairQuery = `SELECT aci_identity_key_pair FROM signalmeow_device WHERE aci_uuid=$1` getRegistrationLocalIDQuery = `SELECT registration_id FROM signalmeow_device WHERE aci_uuid=$1` insertIdentityKeyQuery = ` - INSERT INTO signalmeow_identity_keys (our_aci_uuid, their_service_id, their_device_id, key, trust_level) + INSERT INTO signalmeow_identity_keys (account_id, their_service_id, their_device_id, key, trust_level) VALUES ($1, $2, $3, $4, $5) - ON CONFLICT (our_aci_uuid, their_service_id, their_device_id) DO UPDATE + ON CONFLICT (account_id, their_service_id, their_device_id) DO UPDATE SET key=excluded.key, trust_level=excluded.trust_level ` getIdentityKeyTrustLevelQuery = ` SELECT trust_level FROM signalmeow_identity_keys - WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3 + WHERE account_id=$1 AND their_service_id=$2 AND their_device_id=$3 ` getIdentityKeyQuery = ` SELECT key FROM signalmeow_identity_keys - WHERE our_aci_uuid=$1 AND their_service_id=$2 AND their_device_id=$3 + WHERE account_id=$1 AND their_service_id=$2 AND their_device_id=$3 ` ) diff --git a/pkg/signalmeow/store/profile_key_store.go b/pkg/signalmeow/store/profile_key_store.go index aaeaccf..2c22f57 100644 --- a/pkg/signalmeow/store/profile_key_store.go +++ b/pkg/signalmeow/store/profile_key_store.go @@ -38,8 +38,8 @@ type ProfileKeyStore interface { } const ( - loadProfileKeyQuery = `SELECT key FROM signalmeow_profile_keys WHERE our_aci_uuid=$1 AND their_aci_uuid=$2` - storeProfileKeyQuery = `INSERT INTO signalmeow_profile_keys (our_aci_uuid, their_aci_uuid, key) VALUES ($1, $2, $3) ON CONFLICT (our_aci_uuid, their_aci_uuid) DO UPDATE SET key=excluded.key` + loadProfileKeyQuery = `SELECT key FROM signalmeow_profile_keys WHERE account_id=$1 AND their_aci_uuid=$2` + storeProfileKeyQuery = `INSERT INTO signalmeow_profile_keys (account_id, their_aci_uuid, key) VALUES ($1, $2, $3) ON CONFLICT (account_id, their_aci_uuid) DO UPDATE SET key=excluded.key` ) func scanProfileKey(row dbutil.Scannable) (*libsignalgo.ProfileKey, error) { diff --git a/pkg/signalmeow/store/sender_key_store.go b/pkg/signalmeow/store/sender_key_store.go index cd8dcb9..092bcdd 100644 --- a/pkg/signalmeow/store/sender_key_store.go +++ b/pkg/signalmeow/store/sender_key_store.go @@ -31,8 +31,8 @@ import ( var _ libsignalgo.SenderKeyStore = (*sqlStore)(nil) const ( - loadSenderKeyQuery = `SELECT key_record FROM signalmeow_sender_keys WHERE our_aci_uuid=$1 AND sender_uuid=$2 AND sender_device_id=$3 AND distribution_id=$4` - storeSenderKeyQuery = `INSERT INTO signalmeow_sender_keys (our_aci_uuid, sender_uuid, sender_device_id, distribution_id, key_record) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (our_aci_uuid, sender_uuid, sender_device_id, distribution_id) DO UPDATE SET key_record=excluded.key_record` + loadSenderKeyQuery = `SELECT key_record FROM signalmeow_sender_keys WHERE account_id=$1 AND sender_uuid=$2 AND sender_device_id=$3 AND distribution_id=$4` + storeSenderKeyQuery = `INSERT INTO signalmeow_sender_keys (account_id, sender_uuid, sender_device_id, distribution_id, key_record) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (account_id, sender_uuid, sender_device_id, distribution_id) DO UPDATE SET key_record=excluded.key_record` ) func scanSenderKey(row dbutil.Scannable) (*libsignalgo.SenderKeyRecord, error) { diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 65b4eb3..3acc5fc 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v10: Latest revision +-- v0 -> v11: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -36,17 +36,15 @@ CREATE TABLE signalmeow_kyber_pre_keys ( FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); --- TODO rename our_aci_uuid to account_id in all tables for consistency - CREATE TABLE signalmeow_identity_keys ( - our_aci_uuid TEXT NOT NULL, + account_id TEXT NOT NULL, their_service_id TEXT NOT NULL, their_device_id INTEGER NOT NULL, key bytea NOT NULL, trust_level TEXT NOT NULL, - PRIMARY KEY (our_aci_uuid, their_service_id, their_device_id), - FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + PRIMARY KEY (account_id, their_service_id, their_device_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_sessions ( @@ -61,35 +59,35 @@ CREATE TABLE signalmeow_sessions ( ); CREATE TABLE signalmeow_profile_keys ( - our_aci_uuid TEXT NOT NULL, + account_id TEXT NOT NULL, their_aci_uuid TEXT NOT NULL, key bytea NOT NULL, - PRIMARY KEY (our_aci_uuid, their_aci_uuid), - FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + PRIMARY KEY (account_id, their_aci_uuid), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_sender_keys ( - our_aci_uuid TEXT NOT NULL, + account_id TEXT NOT NULL, sender_uuid TEXT NOT NULL, -- note: this may actually be a service id sender_device_id INTEGER NOT NULL, distribution_id TEXT NOT NULL, key_record bytea NOT NULL, - PRIMARY KEY (our_aci_uuid, sender_uuid, sender_device_id, distribution_id), - FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + PRIMARY KEY (account_id, sender_uuid, sender_device_id, distribution_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_groups ( - our_aci_uuid TEXT NOT NULL, + account_id TEXT NOT NULL, group_identifier TEXT NOT NULL, master_key TEXT NOT NULL, - PRIMARY KEY (our_aci_uuid, group_identifier) + PRIMARY KEY (account_id, group_identifier) ); CREATE TABLE signalmeow_contacts ( - our_aci_uuid TEXT NOT NULL, + account_id TEXT NOT NULL, aci_uuid TEXT NOT NULL, e164_number TEXT NOT NULL, contact_name TEXT NOT NULL, @@ -101,6 +99,6 @@ CREATE TABLE signalmeow_contacts ( profile_avatar_path TEXT NOT NULL, profile_fetched_at BIGINT, - PRIMARY KEY (our_aci_uuid, aci_uuid), - FOREIGN KEY (our_aci_uuid) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + PRIMARY KEY (account_id, aci_uuid), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); diff --git a/pkg/signalmeow/store/upgrades/11-aci-to-account-id.sql b/pkg/signalmeow/store/upgrades/11-aci-to-account-id.sql new file mode 100644 index 0000000..88974a6 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/11-aci-to-account-id.sql @@ -0,0 +1,6 @@ +-- v11: Rename our_aci_uuid columns to account_id +ALTER TABLE signalmeow_identity_keys RENAME COLUMN our_aci_uuid TO account_id; +ALTER TABLE signalmeow_profile_keys RENAME COLUMN our_aci_uuid TO account_id; +ALTER TABLE signalmeow_sender_keys RENAME COLUMN our_aci_uuid TO account_id; +ALTER TABLE signalmeow_groups RENAME COLUMN our_aci_uuid TO account_id; +ALTER TABLE signalmeow_contacts RENAME COLUMN our_aci_uuid TO account_id; From 869033d077841f98accdca336177439c1a1f3da6 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Wed, 20 Mar 2024 10:41:26 -0400 Subject: [PATCH 113/718] Fix setting portal expiry on new DMs (#486) --- portal.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/portal.go b/portal.go index 357a14b..06ec381 100644 --- a/portal.go +++ b/portal.go @@ -30,6 +30,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/exfmt" "go.mau.fi/util/jsontime" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" @@ -1311,6 +1312,14 @@ func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet portal.storeMessageInDB(ctx, resp.EventID, sender.SignalID, converted.Timestamp, i) if converted.DisappearIn != 0 { portal.addDisappearingMessage(ctx, resp.EventID, converted.DisappearIn, sender.SignalID == source.SignalID) + // Ensure portal expiration timer is correct in DMs + if portal.implicitlyUpdateExpirationTimer(ctx, converted.DisappearIn) { + log.Info().Uint32("new_time", converted.DisappearIn).Msg("Implicitly updated expiration timer") + err := portal.Update(ctx) + if err != nil { + log.Err(err).Msg("Failed to save portal in database after implicitly updating group info") + } + } } } } @@ -1981,6 +1990,22 @@ func (portal *Portal) updateExpirationTimer(ctx context.Context, newExpirationTi return true } +func (portal *Portal) implicitlyUpdateExpirationTimer(ctx context.Context, newExpirationTimer uint32) bool { + if portal.ExpirationTime == newExpirationTimer { + return false + } + portal.ExpirationTime = newExpirationTimer + if portal.MXID != "" { + msg := portal.MsgConv.ConvertDisappearingTimerChangeToMatrix(ctx, newExpirationTimer, false) + msg.Content.Body = fmt.Sprintf("Automatically enabled disappearing message timer (%s) because incoming message is disappearing", exfmt.Duration(time.Duration(newExpirationTimer)*time.Second)) + _, err := portal.sendMainIntentMessage(ctx, msg.Content) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to send notice about disappearing message timer changing implicitly") + } + } + return true +} + func (portal *Portal) updateName(ctx context.Context, newName string, sender *Puppet) bool { if portal.Name == newName && (portal.NameSet || portal.MXID == "") { return false From 20acd100daf99588578106698f52280ef25c93a6 Mon Sep 17 00:00:00 2001 From: Malte E Date: Thu, 29 Feb 2024 20:12:10 +0100 Subject: [PATCH 114/718] bridge matrix -> signal group actions (except pendingMember stuff) --- ROADMAP.md | 15 +- config/bridge.go | 1 + config/upgrade.go | 1 + example-config.yaml | 3 +- pkg/libsignalgo/groupsecretparams.go | 85 +++++ pkg/libsignalgo/profilekey.go | 28 +- pkg/libsignalgo/serversecretparams.go | 77 +++++ pkg/libsignalgo/verifysignature.go | 2 +- pkg/signalmeow/attachments.go | 79 +++++ pkg/signalmeow/groups.go | 464 +++++++++++++++++++++++++- pkg/signalmeow/profile.go | 55 ++- pkg/signalmeow/sending.go | 31 +- pkg/signalmeow/types/contact.go | 1 + portal.go | 345 ++++++++++++++++++- 14 files changed, 1163 insertions(+), 24 deletions(-) create mode 100644 pkg/libsignalgo/serversecretparams.go diff --git a/ROADMAP.md b/ROADMAP.md index a060c0d..85c7494 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -16,15 +16,16 @@ * [x] Message edits * [x] Message reactions * [x] Message redactions - * [ ] Group info changes - * [ ] Name - * [ ] Avatar - * [ ] Topic + * [x] Group info changes + * [x] Name + * [x] Avatar + * [x] Topic * [ ] Membership actions * [ ] Join (accepting invites) - * [ ] Invite - * [ ] Leave - * [ ] Kick/Ban/Unban + * [x] Invite + * [x] Leave + * [x] Kick/Ban/Unban + * [x] Group permissions * [x] Typing notifications * [x] Read receipts * [x] Delivery receipts (sent after message is bridged) diff --git a/config/bridge.go b/config/bridge.go index 088d286..3b7967c 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -52,6 +52,7 @@ type BridgeConfig struct { PublicPortals bool `yaml:"public_portals"` CaptionInMessage bool `yaml:"caption_in_message"` FederateRooms bool `yaml:"federate_rooms"` + BridgeMatrixLeave bool `yaml:"bridge_matrix_leave"` DoublePuppetConfig bridgeconfig.DoublePuppetConfig `yaml:",inline"` diff --git a/config/upgrade.go b/config/upgrade.go index cb0ab06..0d943d6 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -125,6 +125,7 @@ func DoUpgrade(helper *up.Helper) { helper.Copy(up.Int, "bridge", "encryption", "rotation", "milliseconds") helper.Copy(up.Int, "bridge", "encryption", "rotation", "messages") helper.Copy(up.Bool, "bridge", "encryption", "rotation", "disable_device_change_key_rotation") + helper.Copy(up.Bool, "bridge", "bridge_matrix_leave") helper.Copy(up.Str, "bridge", "provisioning", "prefix") if secret, ok := helper.Get(up.Str, "bridge", "provisioning", "shared_secret"); !ok || secret == "generate" { diff --git a/example-config.yaml b/example-config.yaml index a509a0c..b61c355 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -255,7 +255,8 @@ bridge: # Disable rotating keys when a user's devices change? # You should not enable this option unless you understand all the implications. disable_device_change_key_rotation: false - + # Should leaving the room on Matrix make the user leave on Signal? + bridge_matrix_leave: true # Settings for provisioning API provisioning: # Prefix for the provisioning API paths. diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 4861868..5d526fc 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -116,6 +116,26 @@ func (gsp *GroupSecretParams) DecryptBlobWithPadding(blob []byte) ([]byte, error return CopySignalOwnedBufferToBytes(plaintext), nil } +func (gsp *GroupSecretParams) EncryptBlobWithPaddingDeterministic(randomness Randomness, plaintext []byte, padding_len uint32) ([]byte, error) { + var ciphertext C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + 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)), + borrowedPlaintext, + (C.uint32_t)(padding_len), + ) + runtime.KeepAlive(randomness) + runtime.KeepAlive(gsp) + runtime.KeepAlive(plaintext) + runtime.KeepAlive(padding_len) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(ciphertext), nil +} + func (gsp *GroupSecretParams) DecryptUUID(ciphertextUUID UUIDCiphertext) (uuid.UUID, error) { u := C.SignalServiceIdFixedWidthBinaryBytes{} signalFfiError := C.signal_group_secret_params_decrypt_service_id( @@ -136,6 +156,27 @@ func (gsp *GroupSecretParams) DecryptUUID(ciphertextUUID UUIDCiphertext) (uuid.U return result, nil } +func (gsp *GroupSecretParams) EncryptUUID(uuid uuid.UUID) (*UUIDCiphertext, error) { + var cipherTextUUID [C.SignalUUID_CIPHERTEXT_LEN]C.uchar + serviceId, err := SignalServiceIDFromUUID(uuid) + if err != nil { + return nil, err + } + signalFfiError := C.signal_group_secret_params_encrypt_service_id( + &cipherTextUUID, + (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)), + serviceId, + ) + runtime.KeepAlive(gsp) + runtime.KeepAlive(serviceId) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + var result UUIDCiphertext + copy(result[:], C.GoBytes(unsafe.Pointer(&cipherTextUUID), C.int(C.SignalUUID_CIPHERTEXT_LEN))) + return &result, nil +} + func (gsp *GroupSecretParams) DecryptProfileKey(ciphertextProfileKey ProfileKeyCiphertext, u uuid.UUID) (*ProfileKey, error) { profileKey := [C.SignalPROFILE_KEY_LEN]C.uchar{} serviceId, err := SignalServiceIDFromUUID(u) @@ -157,3 +198,47 @@ func (gsp *GroupSecretParams) DecryptProfileKey(ciphertextProfileKey ProfileKeyC copy(result[:], C.GoBytes(unsafe.Pointer(&profileKey), C.int(C.SignalPROFILE_KEY_LEN))) return &result, nil } + +func (gsp *GroupSecretParams) EncryptProfileKey(profileKey ProfileKey, u uuid.UUID) (*ProfileKeyCiphertext, error) { + ciphertextProfileKey := [C.SignalPROFILE_KEY_CIPHERTEXT_LEN]C.uchar{} + serviceId, err := SignalServiceIDFromUUID(u) + if err != nil { + return nil, err + } + 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)), + serviceId, + ) + 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 +} + +func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp ServerPublicParams, credential ExpiringProfileKeyCredential) (*ProfileKeyCredentialPresentation, error) { + var out C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + randomness := GenerateRandomness() + signalFfiError := C.signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic( + &out, + (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&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)), + ) + runtime.KeepAlive(gsp) + runtime.KeepAlive(spp) + runtime.KeepAlive(credential) + runtime.KeepAlive(randomness) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + presentationBytes := CopySignalOwnedBufferToBytes(out) + presentation := ProfileKeyCredentialPresentation(presentationBytes) + return &presentation, nil +} diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index ba43a60..1b8836e 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -130,6 +130,8 @@ type ProfileKeyCredentialRequest [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN]byt type ProfileKeyCredentialResponse []byte type ProfileKeyCredentialPresentation []byte type ServerPublicParams [C.SignalSERVER_PUBLIC_PARAMS_LEN]byte +type ExpiringProfileKeyCredential [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]byte +type ExpiringProfileKeyCredentialResponse [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]byte func CreateProfileKeyCredentialRequestContext(serverPublicParams ServerPublicParams, u uuid.UUID, profileKey ProfileKey) (*ProfileKeyCredentialRequestContext, error) { c_result := [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]C.uchar{} @@ -176,14 +178,36 @@ func (p *ProfileKeyCredentialRequestContext) ProfileKeyCredentialRequestContextG return &result, nil } -func NewProfileKeyCredentialResponse(b []byte) (ProfileKeyCredentialResponse, error) { +func NewExpiringProfileKeyCredentialResponse(b []byte) (*ExpiringProfileKeyCredentialResponse, error) { borrowedBuffer := BytesToBuffer(b) signalFfiError := C.signal_expiring_profile_key_credential_response_check_valid_contents(borrowedBuffer) runtime.KeepAlive(b) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return ProfileKeyCredentialResponse(b), nil + response := ExpiringProfileKeyCredentialResponse(b) + return &response, nil +} + +func ReceiveExpiringProfileKeyCredential(spp ServerPublicParams, requestContext *ProfileKeyCredentialRequestContext, response *ExpiringProfileKeyCredentialResponse, currentTimeInSeconds uint64) (*ExpiringProfileKeyCredential, error) { + c_credential := [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]C.uchar{} + signalFfiError := C.signal_server_public_params_receive_expiring_profile_key_credential( + &c_credential, + (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&spp[0])), + (*[C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]C.uchar)(unsafe.Pointer(requestContext)), + (*[C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]C.uchar)(unsafe.Pointer(response)), + (C.uint64_t)(currentTimeInSeconds), + ) + runtime.KeepAlive(spp) + runtime.KeepAlive(requestContext) + runtime.KeepAlive(response) + runtime.KeepAlive(currentTimeInSeconds) + 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 } //func NewProfileKeyCredentialPresentation(b []byte) (ProfileKeyCredentialPresentation, error) { diff --git a/pkg/libsignalgo/serversecretparams.go b/pkg/libsignalgo/serversecretparams.go new file mode 100644 index 0000000..6692173 --- /dev/null +++ b/pkg/libsignalgo/serversecretparams.go @@ -0,0 +1,77 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Malte Eggers +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#cgo LDFLAGS: -lsignal_ffi -ldl -lm +#include "./libsignal-ffi.h" +*/ +import "C" +import ( + "runtime" + "unsafe" + + "github.com/google/uuid" +) + +type ServerSecretParams [C.SignalSERVER_SECRET_PARAMS_LEN]byte + +func GenerateServerSecretParams() (ServerSecretParams, error) { + return GenerateServerSecretParamsWithRandomness(GenerateRandomness()) +} + +func GenerateServerSecretParamsWithRandomness(randomness Randomness) (ServerSecretParams, error) { + var params [C.SignalSERVER_SECRET_PARAMS_LEN]C.uchar + signalFfiError := C.signal_server_secret_params_generate_deterministic(¶ms, (*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness))) + runtime.KeepAlive(randomness) + if signalFfiError != nil { + return ServerSecretParams{}, wrapError(signalFfiError) + } + var serverSecretParams ServerSecretParams + copy(serverSecretParams[:], C.GoBytes(unsafe.Pointer(¶ms), C.int(C.SignalSERVER_SECRET_PARAMS_LEN))) + return serverSecretParams, nil +} + +func (ssp *ServerSecretParams) IssueExpiringProfileKeyCredential(request ProfileKeyCredentialRequest, uuid uuid.UUID, commitment ProfileKeyCommitment, expiration uint64) (*ExpiringProfileKeyCredentialResponse, error) { + var response [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]C.uchar + randomness := GenerateRandomness() + serviceID, err := SignalServiceIDFromUUID(uuid) + if err != nil { + return nil, err + } + signalFfiError := C.signal_server_secret_params_issue_expiring_profile_key_credential_deterministic( + &response, + (*[C.SignalSERVER_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(ssp)), + (*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness)), + (*[C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN]C.uchar)(unsafe.Pointer(&request)), + serviceID, + (*[C.SignalPROFILE_KEY_COMMITMENT_LEN]C.uchar)(unsafe.Pointer(&commitment)), + (C.uint64_t)(expiration), + ) + runtime.KeepAlive(ssp) + runtime.KeepAlive(randomness) + runtime.KeepAlive(request) + runtime.KeepAlive(serviceID) + runtime.KeepAlive(commitment) + runtime.KeepAlive(expiration) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + var result *ExpiringProfileKeyCredentialResponse + copy(result[:], C.GoBytes(unsafe.Pointer(&response), C.int(C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN))) + return result, nil +} diff --git a/pkg/libsignalgo/verifysignature.go b/pkg/libsignalgo/verifysignature.go index 69d354e..08fbab7 100644 --- a/pkg/libsignalgo/verifysignature.go +++ b/pkg/libsignalgo/verifysignature.go @@ -1,5 +1,5 @@ // mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber +// Copyright (C) 2024 Malte Eggers // // 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 diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 2095d1e..5fb0635 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -27,12 +27,17 @@ import ( "fmt" "io" "math" + "mime/multipart" "net/http" "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "go.mau.fi/util/random" + "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/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -200,6 +205,80 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb return attachmentPointer, nil } +func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier) (*string, error) { + groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) + if err != nil { + log.Err(err).Msg("Could not get master key from group id") + return nil, err + } + groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyToBytes(groupMasterKey)) + if err != nil { + log.Err(err).Msg("Failed to get Authorization for today") + return nil, err + } + groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) + if err != nil { + log.Err(err).Msg("Could not get groupSecretParams from master key") + return nil, err + } + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Avatar{Avatar: avatarBytes}} + encryptedAvatar, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) + if err != nil { + log.Err(err).Msg("Could not encrypt avatar into Group Property") + return nil, err + } + + // Get upload form from Signal server + formPath := "/v1/groups/avatar/form" + opts := &web.HTTPReqOpt{Username: &groupAuth.Username, Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, Host: web.StorageHostname} + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, formPath, opts) + if err != nil { + log.Err(err).Msg("Error sending request fetching avatar upload form") + return nil, err + } + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Err(err).Msg("Error decoding response body fetching upload attributes") + return nil, err + } + uploadForm := signalpb.AvatarUploadAttributes{} + err = proto.Unmarshal(body, &uploadForm) + if err != nil { + log.Err(err).Msg("failed to unmarshal group avatar upload form") + return nil, err + } + requestBody := &bytes.Buffer{} + w := multipart.NewWriter(requestBody) + w.WriteField("key", uploadForm.Key) + w.WriteField("x-amz-credential", uploadForm.Credential) + w.WriteField("acl", uploadForm.Acl) + w.WriteField("x-amz-algorithm", uploadForm.Algorithm) + w.WriteField("x-amz-date", uploadForm.Date) + w.WriteField("policy", uploadForm.Policy) + w.WriteField("x-amz-signature", uploadForm.Signature) + w.WriteField("Content-Type", "application/octet-stream") + filewriter, _ := w.CreateFormFile("file", "file") + filewriter.Write(*encryptedAvatar) + w.Close() + + // Upload avatar to CDN + resp, err = web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ + Body: requestBody.Bytes(), + ContentType: web.ContentType(w.FormDataContentType()), + Host: web.CDN1Hostname, + }) + if err != nil { + log.Err(err).Msg("Error sending request uploading attachment") + return nil, err + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + log.Error().Int("status_code", resp.StatusCode).Msg("Error uploading attachment") + return nil, fmt.Errorf("error uploading attachment: %s", resp.Status) + } + + return &uploadForm.Key, nil +} + func verifyMAC(key, body, mac []byte) bool { m := hmac.New(sha256.New, key) m.Write(body) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index ed9ed1d..c75a0d0 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -1,5 +1,5 @@ // mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber +// Copyright (C) 2023 Scott Weber, Malte Eggers // // 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 @@ -21,6 +21,7 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -171,6 +172,108 @@ type GroupChange struct { // ModifyInviteLinkPassword []byte } +func (groupChange *GroupChange) isEmptpy() bool { + return len(groupChange.AddMembers) == 0 && + len(groupChange.DeleteMembers) == 0 && + len(groupChange.ModifyMemberRoles) == 0 && + len(groupChange.ModifyMemberProfileKeys) == 0 && + len(groupChange.AddPendingMembers) == 0 && + len(groupChange.PromotePendingMembers) == 0 && + groupChange.ModifyTitle == nil && + groupChange.ModifyAvatar == nil && + groupChange.ModifyDisappearingMessagesDuration == nil && + groupChange.ModifyAttributesAccess == nil && + groupChange.ModifyMemberAccess == nil && + groupChange.ModifyAddFromInviteLinkAccess == nil && + len(groupChange.AddRequestingMembers) == 0 && + len(groupChange.DeleteRequestingMembers) == 0 && + len(groupChange.PromoteRequestingMembers) == 0 && + groupChange.ModifyDescription == nil && + groupChange.ModifyAnnouncementsOnly == nil && + len(groupChange.AddBannedMembers) == 0 && + len(groupChange.DeleteMembers) == 0 +} + +func (groupChange *GroupChange) resolveConflict(group *Group) { + if *groupChange.ModifyTitle == group.Title { + groupChange.ModifyTitle = nil + } + if *groupChange.ModifyDescription == group.Description { + groupChange.ModifyDescription = nil + } + if *groupChange.ModifyAvatar == group.AvatarPath { + groupChange.ModifyAvatar = nil + } + if *groupChange.ModifyDisappearingMessagesDuration == group.DisappearingMessagesDuration { + groupChange.ModifyDisappearingMessagesDuration = nil + } + if *groupChange.ModifyAttributesAccess == group.AccessControl.Attributes { + groupChange.ModifyAttributesAccess = nil + } + if *groupChange.ModifyMemberAccess == group.AccessControl.Members { + groupChange.ModifyAttributesAccess = nil + } + if *groupChange.ModifyAddFromInviteLinkAccess == group.AccessControl.AddFromInviteLink { + groupChange.ModifyAddFromInviteLinkAccess = nil + } + if *groupChange.ModifyAnnouncementsOnly == group.AnnouncementsOnly { + groupChange.ModifyAnnouncementsOnly = nil + } + members := make(map[uuid.UUID]bool) + for _, member := range group.Members { + members[member.UserID] = true + } + pendingMembers := make(map[uuid.UUID]bool) + for _, pendingMember := range group.PendingMembers { + pendingMembers[pendingMember.UserID] = true + } + requestingMembers := make(map[uuid.UUID]bool) + for _, requestingMember := range group.RequestingMembers { + requestingMembers[requestingMember.UserID] = true + } + for i, member := range groupChange.AddMembers { + if members[member.GroupMember.UserID] { + groupChange.AddMembers = append(groupChange.AddMembers[:i], groupChange.AddMembers[i+1:]...) + } + } + for i, promotePendingMember := range groupChange.PromotePendingMembers { + if members[promotePendingMember.UserID] { + groupChange.PromotePendingMembers = append(groupChange.PromotePendingMembers[:i], groupChange.PromotePendingMembers[i+1:]...) + } + } + for i, promoteRequestingMember := range groupChange.PromotePendingMembers { + if members[promoteRequestingMember.UserID] { + groupChange.PromoteRequestingMembers = append(groupChange.PromoteRequestingMembers[:i], groupChange.PromoteRequestingMembers[i+1:]...) + } + } + for i, pendingMember := range groupChange.AddPendingMembers { + if pendingMembers[pendingMember.GroupMember.UserID] { + groupChange.AddPendingMembers = append(groupChange.AddPendingMembers[:i], groupChange.AddPendingMembers[i+1:]...) + } + } + for i, requestingMember := range groupChange.AddRequestingMembers { + if pendingMembers[requestingMember.UserID] { + groupChange.AddRequestingMembers = append(groupChange.AddRequestingMembers[:i], groupChange.AddRequestingMembers[i+1:]...) + } + } + for i, deletePendingMember := range groupChange.DeletePendingMembers { + if !pendingMembers[*deletePendingMember] { + groupChange.DeletePendingMembers = append(groupChange.DeletePendingMembers[:i], groupChange.DeletePendingMembers[i+1:]...) + } + } + for i, deleteRequestingMember := range groupChange.DeleteRequestingMembers { + if !pendingMembers[*deleteRequestingMember] { + groupChange.DeleteRequestingMembers = append(groupChange.DeleteRequestingMembers[:i], groupChange.DeleteRequestingMembers[i+1:]...) + } + } + for i, deleteMember := range groupChange.DeleteMembers { + if !members[*deleteMember] { + groupChange.DeleteMembers = append(groupChange.DeleteMembers[:i], groupChange.DeleteMembers[i+1:]...) + } + } + // TODO: Membership/role actions +} + func (groupChange *GroupChange) getGroupMasterKey() types.SerializedGroupMasterKey { return groupChange.groupMasterKey } @@ -449,6 +552,18 @@ func decryptGroupPropertyIntoBlob(groupSecretParams libsignalgo.GroupSecretParam return &propertyBlob, nil } +func encryptBlobIntoGroupProperty(groupSecretParams libsignalgo.GroupSecretParams, attributeBlob *signalpb.GroupAttributeBlob) (*[]byte, error) { + decryptedProperty, err := proto.Marshal(attributeBlob) + if err != nil { + return nil, fmt.Errorf("error marshalling groupProperty: %w", err) + } + encryptedProperty, err := groupSecretParams.EncryptBlobWithPaddingDeterministic(libsignalgo.GenerateRandomness(), decryptedProperty, 0) + if err != nil { + return nil, fmt.Errorf("error encrypting blob with padding: %w", err) + } + return &encryptedProperty, nil +} + func cleanupStringProperty(property string) string { // strip non-printable characters from the string property = strings.Map(cleanupStringMapping, property) @@ -979,7 +1094,7 @@ func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretPara ProfileKey: *profileKey, Role: GroupMemberRole(member.Role), JoinedAtRevision: member.JoinedAtRevision, - }, err + }, nil } func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMember, groupSecretParams libsignalgo.GroupSecretParams) (*PendingMember, error) { @@ -1028,3 +1143,348 @@ func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.Req Timestamp: requestingMember.Timestamp, }, nil } + +func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroupChange *GroupChange, gid types.GroupIdentifier) (*signalpb.GroupChange, error) { + log := zerolog.Ctx(ctx).With().Str("action", "EncryptGroupChange").Logger() + groupMasterKey := decryptedGroupChange.groupMasterKey + masterKeyBytes := masterKeyToBytes(groupMasterKey) + groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyBytes) + if err != nil { + log.Err(err).Msg("Could not get groupSecretParams from master key") + return nil, err + } + groupChangeActions := &signalpb.GroupChange_Actions{Revision: decryptedGroupChange.Revision} + if decryptedGroupChange.ModifyTitle != nil { + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Title{Title: *decryptedGroupChange.ModifyTitle}} + encryptedTitle, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) + if err != nil { + log.Err(err).Msg("Could not get encrypt Title") + return nil, err + } + groupChangeActions.ModifyTitle = &signalpb.GroupChange_Actions_ModifyTitleAction{Title: *encryptedTitle} + } + if decryptedGroupChange.ModifyDescription != nil { + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Description{Description: *decryptedGroupChange.ModifyDescription}} + encryptedDescription, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) + if err != nil { + log.Err(err).Msg("Could not get encrypt Title") + return nil, err + } + groupChangeActions.ModifyDescription = &signalpb.GroupChange_Actions_ModifyDescriptionAction{Description: *encryptedDescription} + } + if decryptedGroupChange.ModifyAvatar != nil { + groupChangeActions.ModifyAvatar = &signalpb.GroupChange_Actions_ModifyAvatarAction{Avatar: *decryptedGroupChange.ModifyAvatar} + } + for _, addMember := range decryptedGroupChange.AddMembers { + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addMember.UserID) + if err != nil { + log.Err(err).Msg("failed getting expiring profile key credential for addMember") + return nil, err + } + presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( + prodServerPublicParams, + *expiringProfileKeyCredential, + ) + if err != nil { + log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") + return nil, err + } + groupChangeActions.AddMembers = append(groupChangeActions.AddMembers, &signalpb.GroupChange_Actions_AddMemberAction{ + Added: &signalpb.Member{ + Presentation: *presentation, + Role: signalpb.Member_Role(addMember.Role), + }, + JoinFromInviteLink: addMember.JoinFromInviteLink, + }) + } + for _, deleteMember := range decryptedGroupChange.DeleteMembers { + encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteMember) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for deleteMember") + return nil, err + } + groupChangeActions.DeleteMembers = append(groupChangeActions.DeleteMembers, &signalpb.GroupChange_Actions_DeleteMemberAction{ + DeletedUserId: encryptedUserID[:], + }) + } + for _, modifyMemberRoles := range decryptedGroupChange.ModifyMemberRoles { + encryptedUserID, err := groupSecretParams.EncryptUUID(modifyMemberRoles.UserID) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for modifyMemberRoles") + return nil, err + } + groupChangeActions.ModifyMemberRoles = append(groupChangeActions.ModifyMemberRoles, &signalpb.GroupChange_Actions_ModifyMemberRoleAction{ + UserId: encryptedUserID[:], + Role: signalpb.Member_Role(modifyMemberRoles.Role), + }) + } + // for _, addPendingMember := range decryptedGroupChange.AddPendingMembers { + // } + for _, deletePendingMember := range decryptedGroupChange.DeletePendingMembers { + encryptedUserID, err := groupSecretParams.EncryptUUID(*deletePendingMember) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for deletePendingMember") + return nil, err + } + groupChangeActions.DeletePendingMembers = append(groupChangeActions.DeletePendingMembers, &signalpb.GroupChange_Actions_DeletePendingMemberAction{ + DeletedUserId: encryptedUserID[:], + }) + } + for _, promotePendingMember := range decryptedGroupChange.PromotePendingMembers { + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, promotePendingMember.UserID) + if err != nil { + log.Err(err).Msg("failed getting expiring profile key credential for addMember") + return nil, err + } + presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( + prodServerPublicParams, + *expiringProfileKeyCredential, + ) + if err != nil { + log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") + return nil, err + } + groupChangeActions.PromotePendingMembers = append(groupChangeActions.PromotePendingMembers, &signalpb.GroupChange_Actions_PromotePendingMemberAction{ + Presentation: *presentation, + }) + } + for _, addRequestingMember := range decryptedGroupChange.AddRequestingMembers { + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addRequestingMember.UserID) + if err != nil { + log.Err(err).Msg("failed getting expiring profile key credential for addMember") + return nil, err + } + presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( + prodServerPublicParams, + *expiringProfileKeyCredential, + ) + if err != nil { + log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") + return nil, err + } + groupChangeActions.AddRequestingMembers = append(groupChangeActions.AddRequestingMembers, &signalpb.GroupChange_Actions_AddRequestingMemberAction{ + Added: &signalpb.RequestingMember{ + Presentation: *presentation, + }, + }) + } + for _, deleteRequestingMember := range decryptedGroupChange.DeleteRequestingMembers { + encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteRequestingMember) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for promotePendingMember") + return nil, err + } + groupChangeActions.DeleteRequestingMembers = append(groupChangeActions.DeleteRequestingMembers, &signalpb.GroupChange_Actions_DeleteRequestingMemberAction{ + DeletedUserId: encryptedUserID[:], + }) + } + for _, promoteRequestingMember := range decryptedGroupChange.PromoteRequestingMembers { + encryptedUserID, err := groupSecretParams.EncryptUUID(promoteRequestingMember.UserID) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") + return nil, err + } + + groupChangeActions.PromoteRequestingMembers = append(groupChangeActions.PromoteRequestingMembers, &signalpb.GroupChange_Actions_PromoteRequestingMemberAction{ + UserId: encryptedUserID[:], + Role: signalpb.Member_Role(promoteRequestingMember.Role), + }) + } + for _, addBannedMember := range decryptedGroupChange.AddBannedMembers { + encryptedUserID, err := groupSecretParams.EncryptUUID(addBannedMember.UserID) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") + return nil, err + } + groupChangeActions.AddBannedMembers = append(groupChangeActions.AddBannedMembers, &signalpb.GroupChange_Actions_AddBannedMemberAction{ + Added: &signalpb.BannedMember{ + UserId: encryptedUserID[:], + Timestamp: addBannedMember.Timestamp, + }, + }) + } + for _, deleteBannedMember := range decryptedGroupChange.DeleteBannedMembers { + encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteBannedMember) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") + return nil, err + } + groupChangeActions.DeleteBannedMembers = append(groupChangeActions.DeleteBannedMembers, &signalpb.GroupChange_Actions_DeleteBannedMemberAction{ + DeletedUserId: encryptedUserID[:], + }) + } + if decryptedGroupChange.ModifyAnnouncementsOnly != nil { + groupChangeActions.ModifyAnnouncementsOnly = &signalpb.GroupChange_Actions_ModifyAnnouncementsOnlyAction{ + AnnouncementsOnly: *decryptedGroupChange.ModifyAnnouncementsOnly, + } + } + if decryptedGroupChange.ModifyAttributesAccess != nil { + groupChangeActions.ModifyAttributesAccess = &signalpb.GroupChange_Actions_ModifyAttributesAccessControlAction{ + AttributesAccess: signalpb.AccessControl_AccessRequired(*decryptedGroupChange.ModifyAttributesAccess), + } + } + if decryptedGroupChange.ModifyMemberAccess != nil { + groupChangeActions.ModifyMemberAccess = &signalpb.GroupChange_Actions_ModifyMembersAccessControlAction{ + MembersAccess: signalpb.AccessControl_AccessRequired(*decryptedGroupChange.ModifyMemberAccess), + } + } + if decryptedGroupChange.ModifyAddFromInviteLinkAccess != nil { + groupChangeActions.ModifyAddFromInviteLinkAccess = &signalpb.GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction{ + AddFromInviteLinkAccess: signalpb.AccessControl_AccessRequired(*decryptedGroupChange.ModifyAddFromInviteLinkAccess), + } + } + if decryptedGroupChange.ModifyDisappearingMessagesDuration != nil { + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_DisappearingMessagesDuration{DisappearingMessagesDuration: *decryptedGroupChange.ModifyDisappearingMessagesDuration}} + encryptedTimer, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) + if err != nil { + log.Err(err).Msg("Could not get encrypt Title") + return nil, err + } + groupChangeActions.ModifyDisappearingMessagesTimer = &signalpb.GroupChange_Actions_ModifyDisappearingMessagesTimerAction{Timer: *encryptedTimer} + } + + return cli.patchGroup(ctx, groupChangeActions, groupMasterKey, nil) +} + +var ( + NoContentError = RespError{Err: "NoContentError"} + GroupPatchNotAcceptedError = RespError{Err: "GroupPatchNotAcceptedError"} + ConflictError = RespError{Err: "ConflictError"} + AuthorizationFailedError = RespError{Err: "AuthorizationFailedError"} + NotFoundError = RespError{Err: "NotFoundError"} + ContactManifestMismatchError = RespError{Err: "ContactManifestMismatchError"} + RateLimitError = RespError{Err: "RateLimitError"} + DeprecatedVersionError = RespError{Err: "DeprecatedVersionError"} +) + +type RespError struct { + Err string +} + +func (e RespError) Error() string { + return e.Err +} + +func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupChange_Actions, groupMasterKey types.SerializedGroupMasterKey, groupLinkPassword []byte) (*signalpb.GroupChange, error) { + log := zerolog.Ctx(ctx).With().Str("action", "patchGroup").Logger() + groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyToBytes(groupMasterKey)) + if err != nil { + log.Err(err).Msg("Failed to get Authorization for today") + return nil, err + } + var path string + if groupLinkPassword == nil { + path = "/v1/groups/" + } else { + path = fmt.Sprintf("/v1/groups/?inviteLinkPassword=%s", base64.StdEncoding.EncodeToString(groupLinkPassword)) + } + requestBody, err := proto.Marshal(groupChange) + if err != nil { + log.Err(err).Msg("Failed to marshal request") + return nil, err + } + opts := &web.HTTPReqOpt{ + Username: &groupAuth.Username, + Password: &groupAuth.Password, + ContentType: web.ContentTypeProtobuf, + Body: requestBody, + Host: web.StorageHostname, + } + resp, err := web.SendHTTPRequest(ctx, http.MethodPatch, path, opts) + if err != nil { + return nil, fmt.Errorf("SendRequest error: %w", err) + } + switch resp.StatusCode { + case http.StatusNoContent: + return nil, NoContentError + case http.StatusBadRequest: + return nil, GroupPatchNotAcceptedError + case http.StatusForbidden: + return nil, AuthorizationFailedError + case http.StatusNotFound: + return nil, NotFoundError + case http.StatusConflict: + if resp.Body != nil { + return nil, ContactManifestMismatchError + } else { + return nil, ConflictError + } + case http.StatusTooManyRequests: + return nil, RateLimitError + case 499: + return nil, DeprecatedVersionError + } + if resp.Body == nil { + return nil, errors.New("no response body") + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read storage manifest response: %w", err) + } + signedGroupChange := signalpb.GroupChange{} + err = proto.Unmarshal(body, &signedGroupChange) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal signed groupChange: %w", err) + } + return &signedGroupChange, nil +} + +func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) error { + log := zerolog.Ctx(ctx).With().Str("action", "commitChangeWithConflictResolution").Logger() + groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) + if err != nil { + log.Err(err).Msg("Could not get master key from group id") + return err + } + groupChange.groupMasterKey = groupMasterKey + masterKeyBytes := masterKeyToBytes(groupMasterKey) + var refetchedAddMemberCredentials bool + var signedGroupChange *signalpb.GroupChange + group, err := cli.RetrieveGroupByID(ctx, gid, 0) + if err != nil { + log.Err(err).Msg("Failed to retrieve Group") + } + groupChange.Revision = group.Revision + 1 + for attempt := 0; attempt < 5; attempt++ { + signedGroupChange, err = cli.EncryptAndSignGroupChange(ctx, groupChange, gid) + if errors.Is(err, GroupPatchNotAcceptedError) { + log.Warn().Str("Error applying GroupChange, retrying...", err.Error()) + if len(groupChange.AddMembers) > 0 && !refetchedAddMemberCredentials { + refetchedAddMemberCredentials = true + // change = refetchAddMemberCredentials(change); TODO + } else { + return fmt.Errorf("Group Change Failed: %w", err) + } + } else if errors.Is(err, ConflictError) { + delete(cli.GroupCache.groups, gid) + delete(cli.GroupCache.lastFetched, gid) + delete(cli.GroupCache.activeCalls, gid) + group, err = cli.RetrieveGroupByID(ctx, gid, 0) + groupChange.resolveConflict(group) + if groupChange.isEmptpy() { + log.Debug().Msg("Change is empty after conflict resolution") + } + groupChange.Revision = group.Revision + 1 + } else { + break + } + } + if err != nil { + log.Err(err).Msg("couldn't patch group on server") + return err + } + delete(cli.GroupCache.groups, gid) + delete(cli.GroupCache.lastFetched, gid) + delete(cli.GroupCache.activeCalls, gid) + groupChangeBytes, err := proto.Marshal(signedGroupChange) + if err != nil { + log.Err(err).Msg("Error marshalling signed GroupChange") + return err + } + groupContext := &signalpb.GroupContextV2{Revision: &groupChange.Revision, GroupChange: groupChangeBytes, MasterKey: masterKeyBytes[:]} + _, err = cli.SendGroupChange(ctx, group, groupContext, groupChange) + if err != nil { + log.Err(err).Msg("Error sending GroupChange to group members") + } + return nil +} diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index f27db40..ba160c7 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -154,7 +154,6 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) } func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*types.Profile, error) { - log := zerolog.Ctx(ctx) profileKey, err := cli.ProfileKeyForSignalID(ctx, signalID) if err != nil { return nil, fmt.Errorf("error getting profile key: %w", err) @@ -162,6 +161,15 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*t return nil, errProfileKeyNotFound } + credentialRequest, err := cli.ProfileKeyCredentialRequest(ctx, signalID) + if err != nil { + return nil, fmt.Errorf("error getting profile key credential request: %w", err) + } + return cli.fetchProfileWithRequestAndKey(ctx, signalID, credentialRequest, profileKey) +} + +func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID uuid.UUID, credentialRequest []byte, profileKey *libsignalgo.ProfileKey) (*types.Profile, error) { + log := zerolog.Ctx(ctx) profileKeyVersion, err := profileKey.GetProfileKeyVersion(signalID) if err != nil { return nil, fmt.Errorf("error getting profile key version: %w", err) @@ -172,12 +180,6 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*t return nil, fmt.Errorf("error deriving access key: %w", err) } base64AccessKey := base64.StdEncoding.EncodeToString(accessKey[:]) - - credentialRequest, err := cli.ProfileKeyCredentialRequest(ctx, signalID) - if err != nil { - return nil, fmt.Errorf("error getting profile key credential request: %w", err) - } - path := "/v1/profile/" + signalID.String() useUnidentified := profileKeyVersion != nil && accessKey != nil if useUnidentified { @@ -241,6 +243,7 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*t } // TODO store other metadata fields? profile.AvatarPath = profileResponse.Avatar + profile.Credential = profileResponse.Credential profile.Key = *profileKey return &profile, nil @@ -344,3 +347,41 @@ func AesgcmEncrypt(key, nonce, plaintext []byte) ([]byte, error) { } return aesgcm.Seal(nil, nonce, plaintext, nil), nil } + +func (cli *Client) FetchExpiringProfileKeyCredentialById(ctx context.Context, signalACI uuid.UUID) (*libsignalgo.ExpiringProfileKeyCredential, error) { + profileKey, err := cli.ProfileKeyForSignalID(ctx, signalACI) + if err != nil { + return nil, fmt.Errorf("error getting profile key for ACI: %w", err) + } + requestContext, err := libsignalgo.CreateProfileKeyCredentialRequestContext( + prodServerPublicParams, + signalACI, + *profileKey, + ) + if err != nil { + return nil, fmt.Errorf("error creating profile key credential request context: %w", err) + } + + request, err := requestContext.ProfileKeyCredentialRequestContextGetRequest() + if err != nil { + return nil, fmt.Errorf("error getting profile key credential request: %w", err) + } + + // convert request bytes to hexidecimal representation + hexRequest := hex.EncodeToString(request[:]) + credentialRequest := []byte(hexRequest) + + profile, err := cli.fetchProfileWithRequestAndKey(ctx, signalACI, credentialRequest, profileKey) + if err != nil { + return nil, fmt.Errorf("failed to fetch profile: %w", err) + } + response, err := libsignalgo.NewExpiringProfileKeyCredentialResponse(profile.Credential) + if err != nil { + return nil, fmt.Errorf("failed to get expiring profile key credential response: %w", err) + } + epkc, err := libsignalgo.ReceiveExpiringProfileKeyCredential(prodServerPublicParams, requestContext, response, uint64(time.Now().Unix())) + if err != nil { + return nil, fmt.Errorf("failed to receive expiring profile key credential: %w", err) + } + return epkc, nil +} diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 33cd93f..a36bca4 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -29,6 +29,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "go.mau.fi/util/exfmt" "google.golang.org/protobuf/proto" @@ -511,6 +512,31 @@ func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { } } +func (cli *Client) SendGroupChange(ctx context.Context, group *Group, groupContext *signalpb.GroupContextV2, groupChange *GroupChange) (*GroupMessageSendResult, error) { + log := zerolog.Ctx(ctx).With(). + Str("action", "send group change message"). + Stringer("group_id", group.GroupIdentifier). + Logger() + ctx = log.WithContext(ctx) + timestamp := currentMessageTimestamp() + dm := &signalpb.DataMessage{ + Timestamp: ×tamp, + GroupV2: groupContext, + } + content := wrapDataMessageInContent(dm) + recipients := group.Members + for _, member := range group.PendingMembers { + recipients = append(recipients, &member.GroupMember) + } + for _, member := range groupChange.AddPendingMembers { + recipients = append(recipients, &member.GroupMember) + } + for _, member := range groupChange.AddMembers { + recipients = append(recipients, &member.GroupMember) + } + return cli.sendToGroup(ctx, recipients, content, timestamp) +} + func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { log := zerolog.Ctx(ctx).With(). Str("action", "send group message"). @@ -530,13 +556,16 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi messageTimestamp = content.EditMessage.DataMessage.GetTimestamp() content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) } + return cli.sendToGroup(ctx, group.Members, content, messageTimestamp) +} +func (cli *Client) sendToGroup(ctx context.Context, recipients []*GroupMember, content *signalpb.Content, messageTimestamp uint64) (*GroupMessageSendResult, error) { // Send to each member of the group result := &GroupMessageSendResult{ SuccessfullySentTo: []SuccessfulSendResult{}, FailedToSendTo: []FailedSendResult{}, } - for _, member := range group.Members { + for _, member := range recipients { if member.UserID == cli.Store.ACI { // Don't send normal DataMessages to ourselves continue diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index f00c89b..a9fdbd3 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -31,6 +31,7 @@ type Profile struct { AvatarPath string Key libsignalgo.ProfileKey FetchedAt time.Time + Credential []byte } func (p *Profile) Equals(other *Profile) bool { diff --git a/portal.go b/portal.go index 06ec381..46004ce 100644 --- a/portal.go +++ b/portal.go @@ -1074,9 +1074,7 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou if *groupChange.ModifyAttributesAccess == signalmeow.AccessControl_ADMINISTRATOR { level = 50 } - levels.EnsureEventLevel(event.StateRoomName, level) - levels.EnsureEventLevel(event.StateTopic, level) - levels.EnsureEventLevel(event.StateRoomAvatar, level) + levels.StateDefaultPtr = &level } if groupChange.ModifyMemberAccess != nil { level := 0 @@ -2440,3 +2438,344 @@ func (br *SignalBridge) CleanupRoom(ctx context.Context, log *zerolog.Logger, in log.Err(err).Msg("Failed to leave room while cleaning up portal") } } + +func (portal *Portal) HandleMatrixLeave(brSender bridge.User, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix leave"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + if portal.IsPrivateChat() { + log.Info().Msg("User left private chat portal, cleaning up and deleting...") + portal.Delete() + portal.Cleanup(ctx, false) + return + } else if portal.bridge.Config.Bridge.BridgeMatrixLeave { + portal.deleteMember(sender, sender.SignalID, evt) + } + // TODO: delete portal if empty +} +func (portal *Portal) HandleMatrixKick(brSender bridge.User, ghost bridge.Ghost, evt *event.Event) { + portal.deleteMember(brSender.(*User), ghost.(*Puppet).SignalID, evt) +} +func (portal *Portal) deleteMember(sender *User, target uuid.UUID, evt *event.Event) error { + log := portal.log.With(). + Str("action", "handle matrix kick/leave"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + groupChange := &signalmeow.GroupChange{DeleteMembers: []*uuid.UUID{&target}} + err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error deleting Member from Signal") + return err + } + return nil +} +func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix invite"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + puppet := brGhost.(*Puppet) + role := signalmeow.GroupMember_DEFAULT + levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) + if err != nil { + log.Err(err).Msg("Couldn't get power levels") + if levels.GetUserLevel(puppet.IntentFor(portal).UserID) >= 50 { + role = signalmeow.GroupMember_ADMINISTRATOR + } + } + groupChange := &signalmeow.GroupChange{AddMembers: []*signalmeow.AddMember{{ + GroupMember: signalmeow.GroupMember{ + UserID: puppet.SignalID, + Role: role, + }, + }}} + err = sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error inviting user on Signal") + } + puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) +} + +func (portal *Portal) HandleMatrixAcceptKnock(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix accept knock"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + puppet := brGhost.(*Puppet) + role := signalmeow.GroupMember_DEFAULT + levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) + if err != nil { + log.Err(err).Msg("Couldn't get power levels") + if levels.GetUserLevel(puppet.IntentFor(portal).UserID) >= 50 { + role = signalmeow.GroupMember_ADMINISTRATOR + } + } + groupChange := &signalmeow.GroupChange{PromoteRequestingMembers: []*signalmeow.RoleMember{{ + UserID: puppet.SignalID, + Role: role, + }}} + err = sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error accepting join request on Signal") + } +} + +func (portal *Portal) HandleMatrixRejectKnock(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { + portal.removeRequestingMember(brSender.(*User), brGhost.(*Puppet).SignalID, evt) +} + +func (portal *Portal) HandleMatrixRetractKnock(brSender bridge.User, evt *event.Event) { + portal.removeRequestingMember(brSender.(*User), brSender.(*User).SignalID, evt) +} + +func (portal *Portal) removeRequestingMember(sender *User, target uuid.UUID, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix knock -> leave"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + groupChange := &signalmeow.GroupChange{DeleteRequestingMembers: []*uuid.UUID{&target}} + err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error removing requesting member") + } +} + +func (portal *Portal) HandleMatrixKnock(brSender bridge.User, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix knock"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + log.Debug().Msg("Knocks aren't implemented yet :(") +} + +func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix ban"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + puppet := brGhost.(*Puppet) + groupChange := &signalmeow.GroupChange{AddBannedMembers: []*signalmeow.BannedMember{{ + UserID: puppet.SignalID, + Timestamp: uint64(time.Now().UnixMilli()), + }}} + switch prevMembership := evt.Unsigned.PrevContent.AsMember().Membership; prevMembership { + case event.MembershipJoin: + groupChange.DeleteMembers = []*uuid.UUID{&puppet.SignalID} + case event.MembershipKnock: + groupChange.DeleteRequestingMembers = []*uuid.UUID{&puppet.SignalID} + case event.MembershipInvite: + groupChange.DeletePendingMembers = []*uuid.UUID{&puppet.SignalID} + } + err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error banning on Signal") + } +} + +func (portal *Portal) HandleMatrixUnban(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix unban"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + puppet := brGhost.(*Puppet) + groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*uuid.UUID{&puppet.SignalID}} + err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error unbanning on Signal") + } +} + +func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix power levels"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + if !sender.IsLoggedIn() { + log.Warn().Msg("Can't change power levels: user is not logged in") + return + } + evt.Content.ParseRaw(event.StatePowerLevels) + levels := evt.Content.AsPowerLevels() + var prevLevels *event.PowerLevelsEventContent + if evt.Unsigned.PrevContent != nil { + evt.Unsigned.PrevContent.ParseRaw(event.StatePowerLevels) + prevLevels = evt.Unsigned.PrevContent.AsPowerLevels() + } else { + prevLevels = &event.PowerLevelsEventContent{} + } + groupChange := &signalmeow.GroupChange{} + var role signalmeow.GroupMemberRole + for user, level := range levels.Users { + prevLevel := prevLevels.GetUserLevel(user) + if (level >= 50 && prevLevel < 50) || (level < 50 && prevLevel >= 50) { + puppet := portal.bridge.GetPuppetByMXID(user) + if puppet == nil { + log.Warn().Stringer("mxid", user).Msg("Couldn't get puppet for power level change") + continue + } + role = signalmeow.GroupMember_DEFAULT + if level > 50 { + role = signalmeow.GroupMember_ADMINISTRATOR + } + groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles, &signalmeow.RoleMember{ + UserID: puppet.SignalID, + Role: role, + }) + } + } + if levels.EventsDefault >= 50 && prevLevels.EventsDefault < 50 { + announcementsOnly := true + groupChange.ModifyAnnouncementsOnly = &announcementsOnly + } else if levels.EventsDefault < 50 && prevLevels.EventsDefault >= 50 { + announcementsOnly := false + groupChange.ModifyAnnouncementsOnly = &announcementsOnly + } + if levels.StateDefault() >= 50 && prevLevels.StateDefault() < 50 { + attributesAccess := signalmeow.AccessControl_ADMINISTRATOR + groupChange.ModifyAttributesAccess = &attributesAccess + } else if levels.StateDefault() < 50 && prevLevels.StateDefault() >= 50 { + attributesAccess := signalmeow.AccessControl_MEMBER + groupChange.ModifyAttributesAccess = &attributesAccess + } + if levels.Invite() >= 50 && prevLevels.Invite() < 50 { + memberAccess := signalmeow.AccessControl_ADMINISTRATOR + groupChange.ModifyMemberAccess = &memberAccess + } else if levels.Invite() < 50 && prevLevels.Invite() >= 50 { + memberAccess := signalmeow.AccessControl_MEMBER + groupChange.ModifyMemberAccess = &memberAccess + } + err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error changing group access control") + return + } +} + +func (portal *Portal) HandleMatrixJoinRule(brSender bridge.User, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix join rule"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + if !sender.IsLoggedIn() { + log.Warn().Msg("Can't change join rule: user is not logged in") + return + } + evt.Content.ParseRaw(event.StateJoinRules) + joinRule := evt.Content.AsJoinRules().JoinRule + groupChange := &signalmeow.GroupChange{} + addFromInviteLinkAccess := signalmeow.AccessControl_UNSATISFIABLE + if joinRule == event.JoinRuleKnock { + addFromInviteLinkAccess = signalmeow.AccessControl_ADMINISTRATOR + } else if joinRule == event.JoinRulePublic { + addFromInviteLinkAccess = signalmeow.AccessControl_ANY + } + groupChange.ModifyAddFromInviteLinkAccess = &addFromInviteLinkAccess + err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error updating group access control") + return + } +} + +func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { + log := portal.log.With(). + Str("action", "handle matrix meta"). + Stringer("event_id", evt.ID). + Str("event_type", evt.Type.String()). + Logger() + ctx := log.WithContext(context.TODO()) + sender := brSender.(*User) + if !sender.IsLoggedIn() { + log.Warn().Msg("Can't change room info: user is not logged in") + return + } + + var err error + groupChange := &signalmeow.GroupChange{Revision: portal.Revision + 1} + var avatarPath *string + var avatarHash string + var avatarURL id.ContentURI + var avatarChanged bool + switch content := evt.Content.Parsed.(type) { + case *event.RoomNameEventContent: + if content.Name == portal.Name { + return + } + portal.Name = content.Name + groupChange.ModifyTitle = &content.Name + case *event.TopicEventContent: + if content.Topic == portal.Topic { + return + } + portal.Topic = content.Topic + groupChange.ModifyDescription = &content.Topic + case *event.RoomAvatarEventContent: + if content.URL == portal.AvatarURL { + return + } + var data []byte + if !content.URL.IsEmpty() { + data, err = portal.MainIntent().DownloadBytes(ctx, content.URL) + if err != nil { + log.Err(err).Stringer("Failed to download updated avatar %s", content.URL) + return + } + log.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{sender.MXID, content.URL}) + } else { + log.Debug().Stringer("%s removed the group avatar", sender.MXID) + } + avatarPath, err = sender.Client.UploadGroupAvatar(ctx, data, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Failed to upload group avatar") + return + } + groupChange.ModifyAvatar = avatarPath + hash := sha256.Sum256(data) + avatarHash = hex.EncodeToString(hash[:]) + avatarChanged = true + avatarURL = content.URL + } + err = sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error updating group attributes") + return + } + if avatarChanged { + log.Debug().Msg("Successfully updated group avatar") + portal.AvatarSet = true + portal.AvatarPath = *avatarPath + portal.AvatarHash = avatarHash + portal.AvatarURL = avatarURL + portal.UpdateBridgeInfo(ctx) + portal.Update(ctx) + } + portal.Revision = portal.Revision + 1 + log.Info().Msg("finished updating group") +} From 3e0aae5bd23a9707e67f7ffdabc8047487f16a3e Mon Sep 17 00:00:00 2001 From: Malte E Date: Fri, 15 Mar 2024 22:02:03 +0100 Subject: [PATCH 115/718] fixes & cleanup --- pkg/libsignalgo/serversecretparams.go | 77 ------------------------- pkg/signalmeow/groups.go | 76 +++++++++++++++++++------ pkg/signalmeow/types/identifer.go | 1 + portal.go | 81 +++++++++++++++++++++------ 4 files changed, 124 insertions(+), 111 deletions(-) delete mode 100644 pkg/libsignalgo/serversecretparams.go diff --git a/pkg/libsignalgo/serversecretparams.go b/pkg/libsignalgo/serversecretparams.go deleted file mode 100644 index 6692173..0000000 --- a/pkg/libsignalgo/serversecretparams.go +++ /dev/null @@ -1,77 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2024 Malte Eggers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package libsignalgo - -/* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm -#include "./libsignal-ffi.h" -*/ -import "C" -import ( - "runtime" - "unsafe" - - "github.com/google/uuid" -) - -type ServerSecretParams [C.SignalSERVER_SECRET_PARAMS_LEN]byte - -func GenerateServerSecretParams() (ServerSecretParams, error) { - return GenerateServerSecretParamsWithRandomness(GenerateRandomness()) -} - -func GenerateServerSecretParamsWithRandomness(randomness Randomness) (ServerSecretParams, error) { - var params [C.SignalSERVER_SECRET_PARAMS_LEN]C.uchar - signalFfiError := C.signal_server_secret_params_generate_deterministic(¶ms, (*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness))) - runtime.KeepAlive(randomness) - if signalFfiError != nil { - return ServerSecretParams{}, wrapError(signalFfiError) - } - var serverSecretParams ServerSecretParams - copy(serverSecretParams[:], C.GoBytes(unsafe.Pointer(¶ms), C.int(C.SignalSERVER_SECRET_PARAMS_LEN))) - return serverSecretParams, nil -} - -func (ssp *ServerSecretParams) IssueExpiringProfileKeyCredential(request ProfileKeyCredentialRequest, uuid uuid.UUID, commitment ProfileKeyCommitment, expiration uint64) (*ExpiringProfileKeyCredentialResponse, error) { - var response [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]C.uchar - randomness := GenerateRandomness() - serviceID, err := SignalServiceIDFromUUID(uuid) - if err != nil { - return nil, err - } - signalFfiError := C.signal_server_secret_params_issue_expiring_profile_key_credential_deterministic( - &response, - (*[C.SignalSERVER_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(ssp)), - (*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness)), - (*[C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN]C.uchar)(unsafe.Pointer(&request)), - serviceID, - (*[C.SignalPROFILE_KEY_COMMITMENT_LEN]C.uchar)(unsafe.Pointer(&commitment)), - (C.uint64_t)(expiration), - ) - runtime.KeepAlive(ssp) - runtime.KeepAlive(randomness) - runtime.KeepAlive(request) - runtime.KeepAlive(serviceID) - runtime.KeepAlive(commitment) - runtime.KeepAlive(expiration) - if signalFfiError != nil { - return nil, wrapError(signalFfiError) - } - var result *ExpiringProfileKeyCredentialResponse - copy(result[:], C.GoBytes(unsafe.Pointer(&response), C.int(C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN))) - return result, nil -} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index c75a0d0..d60dbd4 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -18,6 +18,7 @@ package signalmeow import ( "context" + "crypto/rand" "encoding/base64" "encoding/hex" "encoding/json" @@ -86,8 +87,8 @@ type Group struct { PendingMembers []*PendingMember RequestingMembers []*RequestingMember BannedMembers []*BannedMember + InviteLinkPassword *types.SerializedInviteLinkPassword //PublicKey *libsignalgo.PublicKey - //InviteLinkPassword []byte } type GroupAccessControl struct { @@ -169,7 +170,7 @@ type GroupChange struct { AddBannedMembers []*BannedMember DeleteBannedMembers []*uuid.UUID PromotePendingPniAciMembers []*ProfileKeyMember - // ModifyInviteLinkPassword []byte + ModifyInviteLinkPassword *types.SerializedInviteLinkPassword } func (groupChange *GroupChange) isEmptpy() bool { @@ -219,9 +220,9 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { if *groupChange.ModifyAnnouncementsOnly == group.AnnouncementsOnly { groupChange.ModifyAnnouncementsOnly = nil } - members := make(map[uuid.UUID]bool) + members := make(map[uuid.UUID]GroupMemberRole) for _, member := range group.Members { - members[member.UserID] = true + members[member.UserID] = member.Role } pendingMembers := make(map[uuid.UUID]bool) for _, pendingMember := range group.PendingMembers { @@ -232,17 +233,17 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { requestingMembers[requestingMember.UserID] = true } for i, member := range groupChange.AddMembers { - if members[member.GroupMember.UserID] { + if _, ok := members[member.GroupMember.UserID]; ok { groupChange.AddMembers = append(groupChange.AddMembers[:i], groupChange.AddMembers[i+1:]...) } } for i, promotePendingMember := range groupChange.PromotePendingMembers { - if members[promotePendingMember.UserID] { + if _, ok := members[promotePendingMember.UserID]; ok { groupChange.PromotePendingMembers = append(groupChange.PromotePendingMembers[:i], groupChange.PromotePendingMembers[i+1:]...) } } for i, promoteRequestingMember := range groupChange.PromotePendingMembers { - if members[promoteRequestingMember.UserID] { + if _, ok := members[promoteRequestingMember.UserID]; ok { groupChange.PromoteRequestingMembers = append(groupChange.PromoteRequestingMembers[:i], groupChange.PromoteRequestingMembers[i+1:]...) } } @@ -267,11 +268,15 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } } for i, deleteMember := range groupChange.DeleteMembers { - if !members[*deleteMember] { + if _, ok := members[*deleteMember]; !ok { groupChange.DeleteMembers = append(groupChange.DeleteMembers[:i], groupChange.DeleteMembers[i+1:]...) } } - // TODO: Membership/role actions + for i, modifyMemberRole := range groupChange.ModifyMemberRoles { + if members[modifyMemberRole.UserID] == modifyMemberRole.Role { + groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles[:i], groupChange.ModifyMemberRoles[i+1:]...) + } + } } func (groupChange *GroupChange) getGroupMasterKey() types.SerializedGroupMasterKey { @@ -415,6 +420,18 @@ func masterKeyFromBytes(masterKey libsignalgo.GroupMasterKey) types.SerializedGr return types.SerializedGroupMasterKey(base64.StdEncoding.EncodeToString(masterKey[:])) } +func inviteLinkPasswordToBytes(inviteLinkPassword types.SerializedInviteLinkPassword) ([]byte, error) { + inviteLinkPasswordBytes, err := base64.StdEncoding.DecodeString((string(inviteLinkPassword))) + if err != nil { + return nil, err + } + return inviteLinkPasswordBytes, nil +} + +func inviteLinkPasswordFromBytes(inviteLinkPassword []byte) types.SerializedInviteLinkPassword { + return types.SerializedInviteLinkPassword(base64.StdEncoding.EncodeToString(inviteLinkPassword)) +} + func groupIdentifierFromMasterKey(masterKey types.SerializedGroupMasterKey) (types.GroupIdentifier, error) { groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(masterKey)) if err != nil { @@ -536,6 +553,10 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast AddFromInviteLink: (AccessControl)(encryptedGroup.AccessControl.AddFromInviteLink), } } + if len(encryptedGroup.InviteLinkPassword) > 0 { + inviteLinkPassword := inviteLinkPasswordFromBytes(encryptedGroup.InviteLinkPassword) + decryptedGroup.InviteLinkPassword = &inviteLinkPassword + } return decryptedGroup, nil } @@ -1071,6 +1092,10 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp newDisappaeringMessagesDuration := timerBlob.GetDisappearingMessagesDuration() decryptedGroupChange.ModifyDisappearingMessagesDuration = &newDisappaeringMessagesDuration } + if encryptedActions.ModifyInviteLinkPassword != nil { + inviteLinkPassword := inviteLinkPasswordFromBytes(encryptedActions.ModifyInviteLinkPassword.InviteLinkPassword) + decryptedGroupChange.ModifyInviteLinkPassword = &inviteLinkPassword + } return decryptedGroupChange, nil } @@ -1342,6 +1367,15 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup } groupChangeActions.ModifyDisappearingMessagesTimer = &signalpb.GroupChange_Actions_ModifyDisappearingMessagesTimerAction{Timer: *encryptedTimer} } + if decryptedGroupChange.ModifyInviteLinkPassword != nil { + inviteLinkPasswordBytes, err := inviteLinkPasswordToBytes(*decryptedGroupChange.ModifyInviteLinkPassword) + if err != nil { + log.Err(err).Msg("Failed to decode invite link password") + } + groupChangeActions.ModifyInviteLinkPassword = &signalpb.GroupChange_Actions_ModifyInviteLinkPasswordAction{ + InviteLinkPassword: inviteLinkPasswordBytes, + } + } return cli.patchGroup(ctx, groupChangeActions, groupMasterKey, nil) } @@ -1429,12 +1463,12 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh return &signedGroupChange, nil } -func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) error { +func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) (uint32, error) { log := zerolog.Ctx(ctx).With().Str("action", "commitChangeWithConflictResolution").Logger() groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { log.Err(err).Msg("Could not get master key from group id") - return err + return 0, err } groupChange.groupMasterKey = groupMasterKey masterKeyBytes := masterKeyToBytes(groupMasterKey) @@ -1444,6 +1478,12 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi if err != nil { log.Err(err).Msg("Failed to retrieve Group") } + if group.InviteLinkPassword == nil && groupChange.ModifyAddFromInviteLinkAccess != nil && groupChange.ModifyInviteLinkPassword != nil { + inviteLinkPasswordBytes := make([]byte, 16) + rand.Read(inviteLinkPasswordBytes) + inviteLinkPassword := inviteLinkPasswordFromBytes(inviteLinkPasswordBytes) + groupChange.ModifyInviteLinkPassword = &inviteLinkPassword + } groupChange.Revision = group.Revision + 1 for attempt := 0; attempt < 5; attempt++ { signedGroupChange, err = cli.EncryptAndSignGroupChange(ctx, groupChange, gid) @@ -1453,7 +1493,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi refetchedAddMemberCredentials = true // change = refetchAddMemberCredentials(change); TODO } else { - return fmt.Errorf("Group Change Failed: %w", err) + return 0, fmt.Errorf("Group Change Failed: %w", err) } } else if errors.Is(err, ConflictError) { delete(cli.GroupCache.groups, gid) @@ -1469,22 +1509,22 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi break } } - if err != nil { - log.Err(err).Msg("couldn't patch group on server") - return err - } delete(cli.GroupCache.groups, gid) delete(cli.GroupCache.lastFetched, gid) delete(cli.GroupCache.activeCalls, gid) + if err != nil { + log.Err(err).Msg("couldn't patch group on server") + return 0, err + } groupChangeBytes, err := proto.Marshal(signedGroupChange) if err != nil { log.Err(err).Msg("Error marshalling signed GroupChange") - return err + return 0, err } groupContext := &signalpb.GroupContextV2{Revision: &groupChange.Revision, GroupChange: groupChangeBytes, MasterKey: masterKeyBytes[:]} _, err = cli.SendGroupChange(ctx, group, groupContext, groupChange) if err != nil { log.Err(err).Msg("Error sending GroupChange to group members") } - return nil + return groupChange.Revision, nil } diff --git a/pkg/signalmeow/types/identifer.go b/pkg/signalmeow/types/identifer.go index 334e9bb..c11238c 100644 --- a/pkg/signalmeow/types/identifer.go +++ b/pkg/signalmeow/types/identifer.go @@ -44,3 +44,4 @@ func (gid GroupIdentifier) Bytes() (raw libsignalgo.GroupIdentifier, err error) // This is just base64 encoded group master key type SerializedGroupMasterKey string +type SerializedInviteLinkPassword string diff --git a/portal.go b/portal.go index 46004ce..7a8a4bd 100644 --- a/portal.go +++ b/portal.go @@ -1112,6 +1112,7 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou log.Err(err).Msg("Failed to save portal in database after processing group change") } portal.UpdateBridgeInfo(ctx) + portal.CleanupIfEmpty(ctx) } func (portal *Portal) sendMembershipForPuppetAndUser(ctx context.Context, sender *Puppet, target uuid.UUID, membership event.Membership, action string) (puppet *Puppet, err error) { @@ -2309,6 +2310,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } } } + portal.CleanupIfEmpty(ctx) return userIDs } @@ -2455,12 +2457,12 @@ func (portal *Portal) HandleMatrixLeave(brSender bridge.User, evt *event.Event) } else if portal.bridge.Config.Bridge.BridgeMatrixLeave { portal.deleteMember(sender, sender.SignalID, evt) } - // TODO: delete portal if empty + portal.CleanupIfEmpty(ctx) } func (portal *Portal) HandleMatrixKick(brSender bridge.User, ghost bridge.Ghost, evt *event.Event) { portal.deleteMember(brSender.(*User), ghost.(*Puppet).SignalID, evt) } -func (portal *Portal) deleteMember(sender *User, target uuid.UUID, evt *event.Event) error { +func (portal *Portal) deleteMember(sender *User, target uuid.UUID, evt *event.Event) { log := portal.log.With(). Str("action", "handle matrix kick/leave"). Stringer("event_id", evt.ID). @@ -2468,12 +2470,13 @@ func (portal *Portal) deleteMember(sender *User, target uuid.UUID, evt *event.Ev Logger() ctx := log.WithContext(context.TODO()) groupChange := &signalmeow.GroupChange{DeleteMembers: []*uuid.UUID{&target}} - err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error deleting Member from Signal") - return err + return } - return nil + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { log := portal.log.With(). @@ -2498,11 +2501,13 @@ func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brGhost bridge.Gh Role: role, }, }}} - err = sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error inviting user on Signal") } puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixAcceptKnock(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { @@ -2526,10 +2531,12 @@ func (portal *Portal) HandleMatrixAcceptKnock(brSender bridge.User, brGhost brid UserID: puppet.SignalID, Role: role, }}} - err = sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error accepting join request on Signal") } + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixRejectKnock(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { @@ -2548,10 +2555,12 @@ func (portal *Portal) removeRequestingMember(sender *User, target uuid.UUID, evt Logger() ctx := log.WithContext(context.TODO()) groupChange := &signalmeow.GroupChange{DeleteRequestingMembers: []*uuid.UUID{&target}} - err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error removing requesting member") } + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixKnock(brSender bridge.User, evt *event.Event) { @@ -2584,10 +2593,12 @@ func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost case event.MembershipInvite: groupChange.DeletePendingMembers = []*uuid.UUID{&puppet.SignalID} } - err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error banning on Signal") } + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixUnban(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { @@ -2600,10 +2611,12 @@ func (portal *Portal) HandleMatrixUnban(brSender bridge.User, brGhost bridge.Gho sender := brSender.(*User) puppet := brGhost.(*Puppet) groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*uuid.UUID{&puppet.SignalID}} - err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error unbanning on Signal") } + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.Event) { @@ -2638,7 +2651,7 @@ func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.E continue } role = signalmeow.GroupMember_DEFAULT - if level > 50 { + if level >= 50 { role = signalmeow.GroupMember_ADMINISTRATOR } groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles, &signalmeow.RoleMember{ @@ -2668,11 +2681,13 @@ func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.E memberAccess := signalmeow.AccessControl_MEMBER groupChange.ModifyMemberAccess = &memberAccess } - err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error changing group access control") return } + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixJoinRule(brSender bridge.User, evt *event.Event) { @@ -2697,11 +2712,13 @@ func (portal *Portal) HandleMatrixJoinRule(brSender bridge.User, evt *event.Even addFromInviteLinkAccess = signalmeow.AccessControl_ANY } groupChange.ModifyAddFromInviteLinkAccess = &addFromInviteLinkAccess - err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error updating group access control") return } + portal.Revision = revision + portal.Update(ctx) } func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { @@ -2762,7 +2779,7 @@ func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { avatarChanged = true avatarURL = content.URL } - err = sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error updating group attributes") return @@ -2774,8 +2791,40 @@ func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { portal.AvatarHash = avatarHash portal.AvatarURL = avatarURL portal.UpdateBridgeInfo(ctx) - portal.Update(ctx) } - portal.Revision = portal.Revision + 1 + portal.Revision = revision + portal.Update(ctx) log.Info().Msg("finished updating group") } + +func (portal *Portal) CleanupIfEmpty(ctx context.Context) { + log := portal.log.With(). + Str("action", "Clean up if empty"). + Logger() + users, err := portal.GetMatrixUsers(ctx) + if err != nil { + log.Err(err).Msg("Failed to get Matrix user list to determine if portal needs to be cleaned up") + return + } + + if len(users) == 0 { + log.Info().Msg("Room seems to be empty, cleaning up...") + portal.Delete() + portal.Cleanup(ctx, false) + } +} + +func (portal *Portal) GetMatrixUsers(ctx context.Context) ([]id.UserID, error) { + members, err := portal.MainIntent().JoinedMembers(ctx, portal.MXID) + if err != nil { + return nil, fmt.Errorf("failed to get member list: %w", err) + } + var users []id.UserID + for userID := range members.Joined { + _, isPuppet := portal.bridge.ParsePuppetMXID(userID) + if !isPuppet && userID != portal.bridge.Bot.UserID { + users = append(users, userID) + } + } + return users, nil +} From 791e89dec4151b4848834f203d6ccc1ebf366ad5 Mon Sep 17 00:00:00 2001 From: Malte E Date: Sun, 17 Mar 2024 09:12:38 +0100 Subject: [PATCH 116/718] add commands for getting and setting invite link password --- commands.go | 60 ++++++++++++++++++++++++++++++++++++++++ pkg/signalmeow/groups.go | 32 ++++++++++++++++++--- portal.go | 36 ++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/commands.go b/commands.go index 3f3c80d..9449d65 100644 --- a/commands.go +++ b/commands.go @@ -62,6 +62,8 @@ func (br *SignalBridge) RegisterCommands() { cmdDeletePortal, cmdDeleteAllPortals, cmdCleanupLostPortals, + cmdInviteLink, + cmdResetInviteLink, ) } @@ -642,3 +644,61 @@ func fnCleanupLostPortals(ce *WrappedCommandEvent) { } ce.Reply("Finished cleaning up portals") } + +var cmdInviteLink = &commands.FullHandler{ + Func: wrapCommand(fnInviteLink), + Name: "invite-link", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "Get the invite link for the corresponding Signal Group", + }, + RequiresLogin: true, +} + +func fnInviteLink(ce *WrappedCommandEvent) { + if ce.Portal == nil { + ce.Reply("This is not a portal room") + return + } + if ce.Portal.IsPrivateChat() { + ce.Reply("Invite Links are not available for private chats") + return + } + inviteLinkPassword, err := ce.Portal.GetInviteLink(ce.Ctx, ce.User) + if err != nil { + ce.Reply("Error getting invite link %w", err) + return + } + ce.Reply(inviteLinkPassword) +} + +var cmdResetInviteLink = &commands.FullHandler{ + Func: wrapCommand(fnResetInviteLink), + Name: "reset-invite-link", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "Generate a new invite link password", + }, + RequiresLogin: true, +} + +func fnResetInviteLink(ce *WrappedCommandEvent) { + if ce.Portal == nil { + ce.Reply("This is not a portal room") + return + } + if ce.Portal.IsPrivateChat() { + ce.Reply("Invite Links are not available for private chats") + return + } + err := ce.Portal.ResetInviteLink(ce.Ctx, ce.User) + if err != nil { + ce.Reply("Error setting new invite link %w", err) + } + inviteLink, err := ce.Portal.GetInviteLink(ce.Ctx, ce.User) + if err != nil { + ce.Reply("Error getting new invite link %w", err) + return + } + ce.Reply(inviteLink) +} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index d60dbd4..66971fd 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -91,6 +91,30 @@ type Group struct { //PublicKey *libsignalgo.PublicKey } +func (group *Group) GetInviteLink() (string, error) { + if group.InviteLinkPassword == nil { + return "", fmt.Errorf("no invite link password set") + } + masterKeyBytes := masterKeyToBytes(group.groupMasterKey) + inviteLinkPasswordBytes, err := inviteLinkPasswordToBytes(*group.InviteLinkPassword) + if err != nil { + return "", fmt.Errorf("couldn't decode invite link password") + } + inviteLinkContents := signalpb.GroupInviteLink_V1Contents{ + V1Contents: &signalpb.GroupInviteLink_GroupInviteLinkContentsV1{ + GroupMasterKey: masterKeyBytes[:], + InviteLinkPassword: inviteLinkPasswordBytes, + }, + } + inviteLink := signalpb.GroupInviteLink{Contents: &inviteLinkContents} + inviteLinkEncoded, err := proto.Marshal(&inviteLink) + if err != nil { + return "", fmt.Errorf("failed to marshal invite link") + } + inviteLinkPath := base64.URLEncoding.EncodeToString(inviteLinkEncoded) + return "https://signal.group/#" + inviteLinkPath, nil +} + type GroupAccessControl struct { Members AccessControl AddFromInviteLink AccessControl @@ -428,7 +452,7 @@ func inviteLinkPasswordToBytes(inviteLinkPassword types.SerializedInviteLinkPass return inviteLinkPasswordBytes, nil } -func inviteLinkPasswordFromBytes(inviteLinkPassword []byte) types.SerializedInviteLinkPassword { +func InviteLinkPasswordFromBytes(inviteLinkPassword []byte) types.SerializedInviteLinkPassword { return types.SerializedInviteLinkPassword(base64.StdEncoding.EncodeToString(inviteLinkPassword)) } @@ -554,7 +578,7 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast } } if len(encryptedGroup.InviteLinkPassword) > 0 { - inviteLinkPassword := inviteLinkPasswordFromBytes(encryptedGroup.InviteLinkPassword) + inviteLinkPassword := InviteLinkPasswordFromBytes(encryptedGroup.InviteLinkPassword) decryptedGroup.InviteLinkPassword = &inviteLinkPassword } return decryptedGroup, nil @@ -1093,7 +1117,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp decryptedGroupChange.ModifyDisappearingMessagesDuration = &newDisappaeringMessagesDuration } if encryptedActions.ModifyInviteLinkPassword != nil { - inviteLinkPassword := inviteLinkPasswordFromBytes(encryptedActions.ModifyInviteLinkPassword.InviteLinkPassword) + inviteLinkPassword := InviteLinkPasswordFromBytes(encryptedActions.ModifyInviteLinkPassword.InviteLinkPassword) decryptedGroupChange.ModifyInviteLinkPassword = &inviteLinkPassword } @@ -1481,7 +1505,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi if group.InviteLinkPassword == nil && groupChange.ModifyAddFromInviteLinkAccess != nil && groupChange.ModifyInviteLinkPassword != nil { inviteLinkPasswordBytes := make([]byte, 16) rand.Read(inviteLinkPasswordBytes) - inviteLinkPassword := inviteLinkPasswordFromBytes(inviteLinkPasswordBytes) + inviteLinkPassword := InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) groupChange.ModifyInviteLinkPassword = &inviteLinkPassword } groupChange.Revision = group.Revision + 1 diff --git a/portal.go b/portal.go index 7a8a4bd..14c7d6d 100644 --- a/portal.go +++ b/portal.go @@ -18,6 +18,7 @@ package main import ( "context" + "crypto/rand" "crypto/sha256" "encoding/hex" "errors" @@ -30,7 +31,11 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" +<<<<<<< HEAD "go.mau.fi/util/exfmt" +======= + "github.com/rs/zerolog/log" +>>>>>>> c756473 (add commands for getting and setting invite link password) "go.mau.fi/util/jsontime" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" @@ -2828,3 +2833,34 @@ func (portal *Portal) GetMatrixUsers(ctx context.Context) ([]id.UserID, error) { } return users, nil } + +func (portal *Portal) GetInviteLink(ctx context.Context, source *User) (string, error) { + info, err := source.Client.RetrieveGroupByID(ctx, portal.GroupID(), portal.Revision) + if err != nil { + log.Err(err). + Stringer("source_user_id", source.MXID). + Msg("Failed to fetch group info") + return "", err + } + inviteLinkPassword, err := info.GetInviteLink() + if err != nil { + log.Err(err).Msg("Failed to get invite link") + } + return inviteLinkPassword, nil +} + +func (portal *Portal) ResetInviteLink(ctx context.Context, source *User) error { + var inviteLinkPassword types.SerializedInviteLinkPassword + inviteLinkPasswordBytes := make([]byte, 16) + rand.Read(inviteLinkPasswordBytes) + inviteLinkPassword = signalmeow.InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) + groupChange := &signalmeow.GroupChange{ModifyInviteLinkPassword: &inviteLinkPassword} + revision, err := source.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) + if err != nil { + log.Err(err).Msg("Error setting invite link password") + return err + } + portal.Revision = revision + portal.Update(ctx) + return nil +} From 407dbfd3468638e6692941b95b2fd3b6ceb4c9a3 Mon Sep 17 00:00:00 2001 From: Malte E Date: Wed, 20 Mar 2024 22:49:03 +0100 Subject: [PATCH 117/718] add create command --- commands.go | 210 +++++++++++++++++++++++++++ pkg/libsignalgo/groupsecretparams.go | 15 ++ pkg/signalmeow/groups.go | 186 +++++++++++++++++++++--- portal.go | 20 +-- 4 files changed, 405 insertions(+), 26 deletions(-) diff --git a/commands.go b/commands.go index 9449d65..e3b0c04 100644 --- a/commands.go +++ b/commands.go @@ -18,11 +18,16 @@ package main import ( "context" + "crypto/sha256" + "encoding/hex" + "errors" "fmt" "strconv" "strings" "github.com/google/uuid" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/skip2/go-qrcode" "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridge/commands" @@ -30,6 +35,7 @@ import ( "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) var ( @@ -64,6 +70,7 @@ func (br *SignalBridge) RegisterCommands() { cmdCleanupLostPortals, cmdInviteLink, cmdResetInviteLink, + cmdCreate, ) } @@ -702,3 +709,206 @@ func fnResetInviteLink(ce *WrappedCommandEvent) { } ce.Reply(inviteLink) } + +var cmdCreate = &commands.FullHandler{ + Func: wrapCommand(fnCreate), + Name: "create", + Help: commands.HelpMeta{ + Section: HelpSectionCreatingPortals, + Description: "Create a Signal group chat for the current Matrix room.", + }, + RequiresLogin: true, +} + +func fnCreate(ce *WrappedCommandEvent) { + if ce.Portal != nil { + ce.Reply("This is already a portal room") + return + } + + roomState, err := ce.Bot.State(ce.Ctx, ce.RoomID) + if err != nil { + ce.Reply("Failed to get room state: %w", err) + return + } + members := roomState[event.StateMember] + powerLevelsRaw, ok := roomState[event.StatePowerLevels][""] + if !ok { + ce.Reply("Failed to get room power levels") + return + } + powerLevelsRaw.Content.ParseRaw(event.StatePowerLevels) + powerLevels := powerLevelsRaw.Content.AsPowerLevels() + joinRulesRaw, ok := roomState[event.StateJoinRules][""] + if !ok { + ce.Reply("Failed to get join rules") + return + } + joinRulesRaw.Content.ParseRaw(event.StateJoinRules) + joinRule := joinRulesRaw.Content.AsJoinRules().JoinRule + roomNameEventRaw, ok := roomState[event.StateRoomName][""] + if !ok { + ce.Reply("Failed to get room name") + return + } + roomNameEventRaw.Content.ParseRaw(event.StateRoomName) + roomName := roomNameEventRaw.Content.AsRoomName().Name + if len(roomName) == 0 { + ce.Reply("Please set a name for the room first") + return + } + roomTopic := "" + roomTopicEvent, ok := roomState[event.StateTopic][""] + if ok { + roomTopicEvent.Content.ParseRaw(event.StateTopic) + roomTopic = roomTopicEvent.Content.AsTopic().Topic + } + roomAvatarEvent, ok := roomState[event.StateRoomAvatar][""] + var avatarHash string + var avatarURL id.ContentURI + var avatarBytes []byte + if ok { + roomAvatarEvent.Content.ParseRaw(event.StateRoomAvatar) + avatarURL = roomAvatarEvent.Content.AsRoomAvatar().URL + if !avatarURL.IsEmpty() { + avatarBytes, err = ce.Bot.DownloadBytes(ce.Ctx, avatarURL) + if err != nil { + ce.ZLog.Err(err).Stringer("Failed to download updated avatar %s", avatarURL) + return + } + hash := sha256.Sum256(avatarBytes) + avatarHash = hex.EncodeToString(hash[:]) + log.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{ce.User.MXID, avatarURL}) + } + } + var encryptionEvent *event.EncryptionEventContent + encryptionEventContent, ok := roomState[event.StateEncryption][""] + if ok { + encryptionEventContent.Content.ParseRaw(event.StateEncryption) + encryptionEvent = encryptionEventContent.Content.AsEncryption() + } + var participants []*signalmeow.GroupMember + var bannedMembers []*signalmeow.BannedMember + participantDedup := make(map[uuid.UUID]bool) + participantDedup[uuid.Nil] = true + for key, member := range members { + mxid := id.UserID(key) + member.Content.ParseRaw(event.StateMember) + content := member.Content.AsMember() + membership := content.Membership + var uuid uuid.UUID + puppet := ce.Bridge.GetPuppetByMXID(mxid) + if puppet != nil { + uuid = puppet.SignalID + } else { + user := ce.Bridge.GetUserByMXID(mxid) + if user != nil && user.IsLoggedIn() { + uuid = user.SignalID + } + } + role := signalmeow.GroupMember_DEFAULT + if powerLevels.GetUserLevel(mxid) >= 50 { + role = signalmeow.GroupMember_ADMINISTRATOR + } + if !participantDedup[uuid] { + participantDedup[uuid] = true + // invites should be added on signal and then auto-joined + // joined members that need to be pending-Members should have their signal invite auto-accepted + if membership == event.MembershipJoin || membership == event.MembershipInvite { + participants = append(participants, &signalmeow.GroupMember{ + UserID: uuid, + Role: role, + }) + } else if membership == event.MembershipBan { + bannedMembers = append(bannedMembers, &signalmeow.BannedMember{ + UserID: uuid, + }) + } + } + } + addFromInviteLinkAccess := signalmeow.AccessControl_UNSATISFIABLE + if joinRule == event.JoinRulePublic { + addFromInviteLinkAccess = signalmeow.AccessControl_ANY + } else if joinRule == event.JoinRuleKnock { + addFromInviteLinkAccess = signalmeow.AccessControl_ADMINISTRATOR + } + var inviteLinkPassword types.SerializedInviteLinkPassword + if addFromInviteLinkAccess != signalmeow.AccessControl_UNSATISFIABLE { + inviteLinkPassword = signalmeow.GenerateInviteLinkPassword() + } + membersAccess := signalmeow.AccessControl_MEMBER + if powerLevels.Invite() >= 50 { + membersAccess = signalmeow.AccessControl_ADMINISTRATOR + } + attributesAccess := signalmeow.AccessControl_MEMBER + if powerLevels.StateDefault() >= 50 { + attributesAccess = signalmeow.AccessControl_ADMINISTRATOR + } + announcementsOnly := false + if powerLevels.EventsDefault >= 50 { + announcementsOnly = true + } + ce.ZLog.Info(). + Str("room_name", roomName). + Any("participants", participants). + Msg("Creating Signal group for Matrix room") + group, err := ce.User.Client.CreateGroupOnServer(ce.Ctx, &signalmeow.Group{ + Title: roomName, + Description: roomTopic, + Members: participants, + AccessControl: &signalmeow.GroupAccessControl{ + Members: membersAccess, + Attributes: attributesAccess, + AddFromInviteLink: addFromInviteLinkAccess, + }, + InviteLinkPassword: &inviteLinkPassword, + BannedMembers: bannedMembers, + AnnouncementsOnly: announcementsOnly, + }, avatarBytes) + if err != nil { + ce.Reply("Failed to create group: %v", err) + return + } + gid := group.GroupIdentifier + ce.ZLog.UpdateContext(func(c zerolog.Context) zerolog.Context { + return c.Stringer("group_id", gid) + }) + portal := ce.User.GetPortalByChatID(gid.String()) + portal.roomCreateLock.Lock() + defer portal.roomCreateLock.Unlock() + if len(portal.MXID) != 0 { + ce.ZLog.Warn().Msg("Detected race condition in room creation") + // TODO race condition, clean up the old room + } + portal.MXID = ce.RoomID + portal.Name = roomName + portal.Encrypted = encryptionEvent.Algorithm == id.AlgorithmMegolmV1 + if !portal.Encrypted && ce.Bridge.Config.Bridge.Encryption.Default { + _, err = portal.MainIntent().SendStateEvent(ce.Ctx, portal.MXID, event.StateEncryption, "", portal.GetEncryptionEventContent()) + if err != nil { + ce.ZLog.Err(err).Msg("Failed to enable encryption in room") + if errors.Is(err, mautrix.MForbidden) { + ce.Reply("I don't seem to have permission to enable encryption in this room.") + } else { + ce.Reply("Failed to enable encryption in room: %v", err) + } + } + portal.Encrypted = true + } + revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &signalmeow.GroupChange{}, gid) + if err != nil { + ce.Reply("Failed to update Group") + return + } + portal.Revision = revision + portal.AvatarHash = avatarHash + portal.AvatarURL = avatarURL + portal.AvatarPath = group.AvatarPath + portal.AvatarSet = true + err = portal.Update(ce.Ctx) + if err != nil { + ce.ZLog.Err(err).Msg("Failed to save portal after creating group") + } + portal.UpdateBridgeInfo(ce.Ctx) + ce.Reply("Successfully created Signal group %s", gid.String()) +} diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 5d526fc..c4af165 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -242,3 +242,18 @@ func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp presentation := ProfileKeyCredentialPresentation(presentationBytes) return &presentation, nil } + +func (gsp *GroupSecretParams) GetMasterKey() (*GroupMasterKey, error) { + masterKeyBytes := [C.SignalGROUP_MASTER_KEY_LEN]C.uchar{} + signalFfiError := C.signal_group_secret_params_get_master_key( + &masterKeyBytes, + (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar)(unsafe.Pointer(gsp)), + ) + 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 +} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 66971fd..080516e 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -32,6 +32,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -655,6 +656,9 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier if groupMasterKey == "" { return nil, fmt.Errorf("No group master key found for group identifier %s", gid) } + return cli.fetchGroupWithMasterKey(ctx, groupMasterKey) +} +func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { masterKeyBytes := masterKeyToBytes(groupMasterKey) groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) if err != nil { @@ -1216,7 +1220,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Description{Description: *decryptedGroupChange.ModifyDescription}} encryptedDescription, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) if err != nil { - log.Err(err).Msg("Could not get encrypt Title") + log.Err(err).Msg("Could not get encrypt description") return nil, err } groupChangeActions.ModifyDescription = &signalpb.GroupChange_Actions_ModifyDescriptionAction{Description: *encryptedDescription} @@ -1225,24 +1229,12 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup groupChangeActions.ModifyAvatar = &signalpb.GroupChange_Actions_ModifyAvatarAction{Avatar: *decryptedGroupChange.ModifyAvatar} } for _, addMember := range decryptedGroupChange.AddMembers { - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addMember.UserID) + encryptedMember, err := cli.encryptMember(ctx, &addMember.GroupMember, &groupSecretParams) if err != nil { - log.Err(err).Msg("failed getting expiring profile key credential for addMember") - return nil, err - } - presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( - prodServerPublicParams, - *expiringProfileKeyCredential, - ) - if err != nil { - log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") - return nil, err + log.Err(err).Msg("Failed to encrypt GroupMember") } groupChangeActions.AddMembers = append(groupChangeActions.AddMembers, &signalpb.GroupChange_Actions_AddMemberAction{ - Added: &signalpb.Member{ - Presentation: *presentation, - Role: signalpb.Member_Role(addMember.Role), - }, + Added: encryptedMember, JoinFromInviteLink: addMember.JoinFromInviteLink, }) } @@ -1404,6 +1396,28 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup return cli.patchGroup(ctx, groupChangeActions, groupMasterKey, nil) } +func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, error) { + log := zerolog.Ctx(ctx) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, member.UserID) + if err != nil { + log.Err(err).Msg("failed getting expiring profile key credential for addMember") + return nil, err + } + presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( + prodServerPublicParams, + *expiringProfileKeyCredential, + ) + if err != nil { + log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") + return nil, err + } + encryptedMember := signalpb.Member{ + Presentation: *presentation, + Role: signalpb.Member_Role(member.Role), + } + return &encryptedMember, nil +} + var ( NoContentError = RespError{Err: "NoContentError"} GroupPatchNotAcceptedError = RespError{Err: "GroupPatchNotAcceptedError"} @@ -1413,6 +1427,7 @@ var ( ContactManifestMismatchError = RespError{Err: "ContactManifestMismatchError"} RateLimitError = RespError{Err: "RateLimitError"} DeprecatedVersionError = RespError{Err: "DeprecatedVersionError"} + GroupExistsError = RespError{Err: "GroupExistsError"} ) type RespError struct { @@ -1488,7 +1503,7 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh } func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) (uint32, error) { - log := zerolog.Ctx(ctx).With().Str("action", "commitChangeWithConflictResolution").Logger() + log := zerolog.Ctx(ctx).With().Str("action", "UpdateGroup").Logger() groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { log.Err(err).Msg("Could not get master key from group id") @@ -1552,3 +1567,140 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi } return groupChange.Revision, nil } + +func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, groupSecretParams libsignalgo.GroupSecretParams) (*signalpb.Group, error) { + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Title{Title: decryptedGroup.Title}} + encryptedTitle, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) + if err != nil { + log.Err(err).Msg("Could not get encrypt Title") + return nil, err + } + groupPublicParams, err := groupSecretParams.GetPublicParams() + if err != nil { + log.Err(err).Msg("Couldn't get public params from GroupSecretParams") + return nil, err + } + encryptedGroup := &signalpb.Group{ + PublicKey: groupPublicParams[:], + Title: *encryptedTitle, + Avatar: decryptedGroup.AvatarPath, + AnnouncementsOnly: decryptedGroup.AnnouncementsOnly, + Revision: 0, + } + if decryptedGroup.Description != "" { + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Description{Description: decryptedGroup.Description}} + encryptedDescription, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) + if err != nil { + log.Err(err).Msg("Could not get encrypt Description") + return nil, err + } + encryptedGroup.Description = *encryptedDescription + } + if decryptedGroup.AccessControl != nil { + encryptedGroup.AccessControl = &signalpb.AccessControl{ + Members: signalpb.AccessControl_AccessRequired(decryptedGroup.AccessControl.Members), + Attributes: signalpb.AccessControl_AccessRequired(decryptedGroup.AccessControl.Attributes), + AddFromInviteLink: signalpb.AccessControl_AccessRequired(decryptedGroup.AccessControl.AddFromInviteLink), + } + if decryptedGroup.AccessControl.AddFromInviteLink != AccessControl_UNSATISFIABLE { + inviteLinkPasswordBytes := make([]byte, 16) + rand.Read(inviteLinkPasswordBytes) + encryptedGroup.InviteLinkPassword = inviteLinkPasswordBytes + } + } + for _, member := range decryptedGroup.Members { + encryptedMember, err := cli.encryptMember(ctx, member, &groupSecretParams) + if err != nil { + log.Err(err).Msg("Failed to encrypt GroupMember") + } + encryptedGroup.Members = append(encryptedGroup.Members, encryptedMember) + } + return encryptedGroup, nil +} + +func (cli *Client) CreateGroupOnServer(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { + log := zerolog.Ctx(ctx).With().Str("action", "CreateGroupOnServer").Logger() + masterKeyByteArray := make([]byte, 32) + rand.Read(masterKeyByteArray) + masterKeyBytes := libsignalgo.GroupMasterKey(masterKeyByteArray) + groupMasterKey := masterKeyFromBytes(masterKeyBytes) + groupId, err := groupIdentifierFromMasterKey(groupMasterKey) + if err != nil { + log.Err(err).Msg("Couldn't get gid from masterkey") + return nil, err + } + err = cli.Store.GroupStore.StoreMasterKey(ctx, groupId, groupMasterKey) + if err != nil { + return nil, fmt.Errorf("StoreMasterKey error: %w", err) + } + log.Debug().Msg(string(groupMasterKey)) + groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyBytes) + if err != nil { + log.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") + return nil, err + } + if len(avatarBytes) > 0 { + avatarPath, err := cli.UploadGroupAvatar(ctx, avatarBytes, groupId) + if err != nil { + log.Err(err).Msg("Failed to upload group avatar") + return nil, err + } + decryptedGroup.AvatarPath = *avatarPath + } + encryptedGroup, err := cli.EncryptGroup(ctx, decryptedGroup, groupSecretParams) + if err != nil { + log.Err(err).Msg("Failed to encrypt group") + return nil, err + } + log.Debug().Stringer("groupID", groupId) + groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) + if err != nil { + log.Err(err).Msg("Failed to get Authorization for today") + return nil, err + } + path := "/v1/groups/" + requestBody, err := proto.Marshal(encryptedGroup) + if err != nil { + log.Err(err).Msg("Failed to marshal request") + return nil, err + } + opts := &web.HTTPReqOpt{ + Username: &groupAuth.Username, + Password: &groupAuth.Password, + ContentType: web.ContentTypeProtobuf, + Body: requestBody, + Host: web.StorageHostname, + } + resp, err := web.SendHTTPRequest(ctx, http.MethodPut, path, opts) + if err != nil { + return nil, fmt.Errorf("SendRequest error: %w", err) + } + switch resp.StatusCode { + case http.StatusNoContent: + return nil, NoContentError + case http.StatusForbidden: + return nil, AuthorizationFailedError + case http.StatusNotFound: + return nil, NotFoundError + case http.StatusConflict: + return nil, GroupExistsError + case http.StatusTooManyRequests: + return nil, RateLimitError + case 499: + return nil, DeprecatedVersionError + case http.StatusBadRequest: + return nil, fmt.Errorf("failed to put new group: bad request") + } + group, err := cli.fetchGroupWithMasterKey(ctx, groupMasterKey) + if err != nil { + return nil, fmt.Errorf("failed to get new group: %w", err) + } + log.Debug().Stringer("group id", group.GroupIdentifier).Msg("new group created") + return group, nil +} + +func GenerateInviteLinkPassword() types.SerializedInviteLinkPassword { + inviteLinkPasswordBytes := make([]byte, 16) + rand.Read(inviteLinkPasswordBytes) + return InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) +} diff --git a/portal.go b/portal.go index 14c7d6d..31d6659 100644 --- a/portal.go +++ b/portal.go @@ -18,7 +18,6 @@ package main import ( "context" - "crypto/rand" "crypto/sha256" "encoding/hex" "errors" @@ -31,11 +30,8 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" -<<<<<<< HEAD - "go.mau.fi/util/exfmt" -======= "github.com/rs/zerolog/log" ->>>>>>> c756473 (add commands for getting and setting invite link password) + "go.mau.fi/util/exfmt" "go.mau.fi/util/jsontime" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" @@ -2850,10 +2846,7 @@ func (portal *Portal) GetInviteLink(ctx context.Context, source *User) (string, } func (portal *Portal) ResetInviteLink(ctx context.Context, source *User) error { - var inviteLinkPassword types.SerializedInviteLinkPassword - inviteLinkPasswordBytes := make([]byte, 16) - rand.Read(inviteLinkPasswordBytes) - inviteLinkPassword = signalmeow.InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) + inviteLinkPassword := signalmeow.GenerateInviteLinkPassword() groupChange := &signalmeow.GroupChange{ModifyInviteLinkPassword: &inviteLinkPassword} revision, err := source.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { @@ -2864,3 +2857,12 @@ func (portal *Portal) ResetInviteLink(ctx context.Context, source *User) error { portal.Update(ctx) return nil } + +func (portal *Portal) GetEncryptionEventContent() (evt *event.EncryptionEventContent) { + evt = &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1} + if rot := portal.bridge.Config.Bridge.Encryption.Rotation; rot.EnableCustom { + evt.RotationPeriodMillis = rot.Milliseconds + evt.RotationPeriodMessages = rot.Messages + } + return +} From a93dd0eec56b5245257d2d78368f668e22b8671b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 20 Mar 2024 18:43:32 +0200 Subject: [PATCH 118/718] Support PNIs for sync messages and refactor some things --- pkg/libsignalgo/serviceid.go | 6 +++ pkg/signalmeow/receiving.go | 58 ++++++++++++++------------- pkg/signalmeow/store/prekey_store.go | 7 +++- pkg/signalmeow/store/session_store.go | 2 + pkg/signalmeow/types/uuid.go | 10 ----- 5 files changed, 43 insertions(+), 40 deletions(-) delete mode 100644 pkg/signalmeow/types/uuid.go diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index 0214f65..a0d7471 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -29,6 +29,7 @@ import ( "unsafe" "github.com/google/uuid" + "github.com/rs/zerolog" ) func init() { @@ -104,6 +105,11 @@ func (s ServiceID) GoString() string { return fmt.Sprintf(`libsignalgo.ServiceID{Type: %#v, UUID: uuid.MustParse("%s")}`, s.Type, s.UUID) } +func (s ServiceID) MarshalZerologObject(e *zerolog.Event) { + e.Stringer("type", s.Type) + e.Stringer("uuid", s.UUID) +} + type ServiceIDFixedBytes [17]byte func (s ServiceID) FixedBytes() *ServiceIDFixedBytes { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 14fb688..8f81d9b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -294,15 +294,23 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. return nil, err } var result *DecryptionResult + log.Trace(). + Uint64("timestamp", envelope.GetTimestamp()). + Str("destination_service_id", envelope.GetDestinationServiceId()). + Str("source_service_id", envelope.GetSourceServiceId()). + Uint32("source_device_id", envelope.GetSourceDevice()). + Object("parsed_destination_service_id", destinationServiceID). + Int32("envelope_type_id", int32(envelope.GetType())). + Str("envelope_type", signalpb.Envelope_Type_name[int32(envelope.GetType())]). + Msg("Received envelope") switch *envelope.Type { case signalpb.Envelope_UNIDENTIFIED_SENDER: if destinationServiceID != cli.Store.ACIServiceID() { log.Warn().Stringer("destination_service_id", destinationServiceID). - Msg("Received envelope type UNIDENTIFIED_SENDER for non-ACI destination") + Msg("Received UNIDENTIFIED_SENDER envelope for non-ACI destination") break } - log.Trace().Msg("Received envelope type UNIDENTIFIED_SENDER") usmc, err := libsignalgo.SealedSenderDecryptToUSMC( ctx, envelope.GetContent(), @@ -481,7 +489,6 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case signalpb.Envelope_PREKEY_BUNDLE: - log.Debug().Msg("Received envelope type PREKEY_BUNDLE") sender, err := libsignalgo.NewUUIDAddressFromString( *envelope.SourceServiceId, uint(*envelope.SourceDevice), @@ -501,10 +508,8 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case signalpb.Envelope_PLAINTEXT_CONTENT: - log.Debug().Msg("Received envelope type PLAINTEXT_CONTENT") case signalpb.Envelope_CIPHERTEXT: - log.Debug().Msg("Received envelope type CIPHERTEXT") message, err := libsignalgo.DeserializeMessage(envelope.Content) if err != nil { log.Err(err).Msg("DeserializeMessage error") @@ -550,15 +555,12 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case signalpb.Envelope_RECEIPT: - log.Debug().Msg("Received envelope type RECEIPT") // TODO: handle receipt case signalpb.Envelope_KEY_EXCHANGE: - log.Debug().Msg("Received envelope type KEY_EXCHANGE") responseCode = 400 case signalpb.Envelope_UNKNOWN: - log.Warn().Msg("Received envelope type UNKNOWN") responseCode = 400 default: @@ -576,6 +578,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log = log.With(). Str("sender_name", name). Uint("sender_device_id", deviceId). + Str("destination_service_id", destinationServiceID.String()). Logger() ctx = log.WithContext(ctx) log.Debug().Msg("Decrypted message") @@ -611,16 +614,15 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. Status: responseCode, }, nil } - theirUUID := theirServiceID.UUID // TODO: handle more sync messages if content.SyncMessage != nil { syncSent := content.SyncMessage.GetSent() if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { destination := syncSent.DestinationServiceId - var destinationUUID uuid.UUID + var syncDestinationServiceID libsignalgo.ServiceID if destination != nil { - destinationUUID, err = uuid.Parse(*destination) + syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) if err != nil { log.Err(err).Msg("Sync message destination parse error") return nil, err @@ -630,9 +632,9 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Warn().Msg("sync message sent destination is nil") } else if content.SyncMessage.Sent.Message != nil { // TODO handle expiration start ts, and maybe the sync message ts? - cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, destinationUUID) + cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, syncDestinationServiceID) } else if content.SyncMessage.Sent.EditMessage != nil { - cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, destinationUUID) + cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID) } } if content.SyncMessage.Contacts != nil { @@ -679,13 +681,13 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. var sendDeliveryReceipt bool if content.DataMessage != nil { - sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirUUID, theirUUID) + sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID) } else if content.EditMessage != nil { - sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirUUID, theirUUID) + sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID) } if sendDeliveryReceipt { // TODO send delivery receipts after actually bridging instead of here - err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirUUID) + err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) if err != nil { log.Err(err).Msg("sendDeliveryReceipts error") } @@ -699,8 +701,8 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ - Sender: theirUUID, - ChatID: groupOrUserID(groupID, theirUUID), + Sender: theirServiceID.UUID, + ChatID: groupOrUserID(groupID, theirServiceID), }, Event: content.TypingMessage, }) @@ -710,8 +712,8 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { cli.handleEvent(&events.Call{ Info: events.MessageInfo{ - Sender: theirUUID, - ChatID: theirUUID.String(), + Sender: theirServiceID.UUID, + ChatID: theirServiceID.String(), }, IsRinging: content.CallMessage.Offer != nil, }) @@ -719,14 +721,14 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. // Read and delivery receipts if content.ReceiptMessage != nil { - if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirUUID == cli.Store.ACI { + if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() { // Ignore delivery receipts from other own devices return &web.SimpleResponse{ Status: responseCode, }, nil } cli.handleEvent(&events.Receipt{ - Sender: theirUUID, + Sender: theirServiceID.UUID, Content: content.ReceiptMessage, }) } @@ -787,14 +789,14 @@ func contentFieldsString(c *signalpb.Content) string { return builder.String() } -func groupOrUserID(groupID types.GroupIdentifier, userID uuid.UUID) string { +func groupOrUserID(groupID types.GroupIdentifier, userID libsignalgo.ServiceID) string { if groupID == "" { return userID.String() } return string(groupID) } -func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSender, chatRecipient uuid.UUID) bool { +func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID) bool { // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier var groupRevision uint32 @@ -812,7 +814,7 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp } cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ - Sender: messageSender, + Sender: messageSenderACI, ChatID: groupOrUserID(groupID, chatRecipient), GroupRevision: groupRevision, }, @@ -821,11 +823,11 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp return true } -func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSender, chatRecipient uuid.UUID) bool { +func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID) bool { // If there's a profile key, save it if dataMessage.ProfileKey != nil { profileKey := libsignalgo.ProfileKey(dataMessage.ProfileKey) - err := cli.Store.ProfileKeyStore.StoreProfileKey(ctx, messageSender, profileKey) + err := cli.Store.ProfileKeyStore.StoreProfileKey(ctx, messageSenderACI, profileKey) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("StoreProfileKey error") return false @@ -849,7 +851,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp } evtInfo := events.MessageInfo{ - Sender: messageSender, + Sender: messageSenderACI, ChatID: groupOrUserID(groupID, chatRecipient), GroupRevision: groupRevision, } diff --git a/pkg/signalmeow/store/prekey_store.go b/pkg/signalmeow/store/prekey_store.go index 03d03bd..59a3373 100644 --- a/pkg/signalmeow/store/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -29,12 +29,15 @@ import ( var _ PreKeyStore = (*scopedSQLStore)(nil) +type ServiceScopedStore interface { + GetServiceID() libsignalgo.ServiceID +} + type PreKeyStore interface { libsignalgo.PreKeyStore libsignalgo.SignedPreKeyStore libsignalgo.KyberPreKeyStore - - GetServiceID() libsignalgo.ServiceID + ServiceScopedStore StoreLastResortKyberPreKey(ctx context.Context, preKeyID uint32, record *libsignalgo.KyberPreKeyRecord) error RemoveSignedPreKey(ctx context.Context, preKeyID uint32) error diff --git a/pkg/signalmeow/store/session_store.go b/pkg/signalmeow/store/session_store.go index a2090e9..5fe6cba 100644 --- a/pkg/signalmeow/store/session_store.go +++ b/pkg/signalmeow/store/session_store.go @@ -43,6 +43,8 @@ const ( type SessionStore interface { libsignalgo.SessionStore + ServiceScopedStore + // AllSessionsForServiceID returns all sessions for the given service ID. AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) // RemoveSession removes the session for the given address. diff --git a/pkg/signalmeow/types/uuid.go b/pkg/signalmeow/types/uuid.go deleted file mode 100644 index 86271dd..0000000 --- a/pkg/signalmeow/types/uuid.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -const ( - // UUIDKindACI is the UUID kind for account identifiers. - UUIDKindACI UUIDKind = "aci" - // UUIDKindPNI is the UUID kind for phone number identifiers. - UUIDKindPNI UUIDKind = "pni" -) - -type UUIDKind string From a99d36a2846747853e36a905cd055053e85c0ef9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 21 Mar 2024 16:24:03 +0200 Subject: [PATCH 119/718] Drop their_device_id column in signalmeow_identity_keys table --- pkg/libsignalgo/address.go | 5 -- pkg/libsignalgo/address_test.go | 7 +- pkg/libsignalgo/groupcipher_test.go | 2 +- pkg/libsignalgo/identitykeystore.go | 27 ++++++-- pkg/libsignalgo/inmemorystore_test.go | 44 +++---------- pkg/libsignalgo/session_test.go | 17 +++-- pkg/signalmeow/provisioning.go | 6 +- pkg/signalmeow/store/identity_store.go | 66 ++++--------------- pkg/signalmeow/store/upgrades/00-latest.sql | 5 +- ...2-drop-identity-key-device-id.postgres.sql | 5 ++ .../12-drop-identity-key-device-id.sqlite.sql | 19 ++++++ 11 files changed, 91 insertions(+), 112 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.postgres.sql create mode 100644 pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.sqlite.sql diff --git a/pkg/libsignalgo/address.go b/pkg/libsignalgo/address.go index e1aa64e..9afacc0 100644 --- a/pkg/libsignalgo/address.go +++ b/pkg/libsignalgo/address.go @@ -44,11 +44,6 @@ func NewUUIDAddressFromString(uuidStr string, deviceID uint) (*Address, error) { return serviceID.Address(deviceID) } -// Deprecated: phone addresses are not used anymore -func NewPhoneAddress(phone string, deviceID uint) (*Address, error) { - return newAddress(phone, deviceID) -} - func newAddress(name string, deviceID uint) (*Address, error) { var pa *C.SignalProtocolAddress signalFfiError := C.signal_address_new(&pa, C.CString(name), C.uint(deviceID)) diff --git a/pkg/libsignalgo/address_test.go b/pkg/libsignalgo/address_test.go index 4026cb5..b72eb2f 100644 --- a/pkg/libsignalgo/address_test.go +++ b/pkg/libsignalgo/address_test.go @@ -19,6 +19,7 @@ package libsignalgo_test import ( "testing" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -28,12 +29,14 @@ import ( func TestAddress(t *testing.T) { setupLogging() - addr, err := libsignalgo.NewPhoneAddress("addr1", 5) + testUUID := uuid.New() + + addr, err := libsignalgo.NewPNIServiceID(testUUID).Address(5) assert.NoError(t, err) name, err := addr.Name() assert.NoError(t, err) - assert.Equal(t, "addr1", name) + assert.Equal(t, "PNI:"+testUUID.String(), name) deviceID, err := addr.DeviceID() assert.NoError(t, err) diff --git a/pkg/libsignalgo/groupcipher_test.go b/pkg/libsignalgo/groupcipher_test.go index f862705..eda4fdf 100644 --- a/pkg/libsignalgo/groupcipher_test.go +++ b/pkg/libsignalgo/groupcipher_test.go @@ -30,7 +30,7 @@ import ( func TestGroupCipher(t *testing.T) { ctx := context.TODO() - sender, err := libsignalgo.NewPhoneAddress("+14159999111", 4) + sender, err := libsignalgo.NewACIServiceID(uuid.New()).Address(4) assert.NoError(t, err) distributionID, err := uuid.Parse("d1d1d1d1-7000-11eb-b32a-33b8a8a487a6") diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index 58c3cdf..19c6520 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -45,9 +45,9 @@ const ( type IdentityKeyStore interface { GetIdentityKeyPair(ctx context.Context) (*IdentityKeyPair, error) GetLocalRegistrationID(ctx context.Context) (uint32, error) - SaveIdentityKey(ctx context.Context, address *Address, identityKey *IdentityKey) (bool, error) - GetIdentityKey(ctx context.Context, address *Address) (*IdentityKey, error) - IsTrustedIdentity(ctx context.Context, address *Address, identityKey *IdentityKey, direction SignalDirection) (bool, error) + SaveIdentityKey(ctx context.Context, theirServiceID ServiceID, identityKey *IdentityKey) (bool, error) + GetIdentityKey(ctx context.Context, theirServiceID ServiceID) (*IdentityKey, error) + IsTrustedIdentity(ctx context.Context, theirServiceID ServiceID, identityKey *IdentityKey, direction SignalDirection) (bool, error) } //export signal_get_identity_key_pair_callback @@ -90,9 +90,14 @@ func signal_save_identity_key_callback(storeCtx unsafe.Pointer, address *C.const if err != nil { return -1, err } + addr := &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))} + theirServiceID, err := addr.NameServiceID() + if err != nil { + return -1, err + } replaced, err := store.SaveIdentityKey( ctx, - &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, + theirServiceID, &IdentityKey{cloned}, ) if err != nil { @@ -109,7 +114,12 @@ func signal_save_identity_key_callback(storeCtx unsafe.Pointer, address *C.const //export signal_get_identity_key_callback func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp **C.SignalPublicKey, address *C.const_address) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { - key, err := store.GetIdentityKey(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}) + addr := &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))} + theirServiceID, err := addr.NameServiceID() + if err != nil { + return err + } + key, err := store.GetIdentityKey(ctx, theirServiceID) if err == nil && key != nil { key.publicKey.CancelFinalizer() *public_keyp = key.publicKey.ptr @@ -121,7 +131,12 @@ func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp **C.S //export signal_is_trusted_identity_callback func signal_is_trusted_identity_callback(storeCtx unsafe.Pointer, address *C.const_address, public_key *C.const_public_key, direction C.uint) C.int { return wrapStoreCallbackCustomReturn(storeCtx, func(store IdentityKeyStore, ctx context.Context) (int, error) { - trusted, err := store.IsTrustedIdentity(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, &IdentityKey{&PublicKey{ptr: (*C.SignalPublicKey)(unsafe.Pointer(public_key))}}, SignalDirection(direction)) + addr := &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))} + theirServiceID, err := addr.NameServiceID() + if err != nil { + return -1, err + } + trusted, err := store.IsTrustedIdentity(ctx, theirServiceID, &IdentityKey{&PublicKey{ptr: (*C.SignalPublicKey)(unsafe.Pointer(public_key))}}, SignalDirection(direction)) if err != nil { return -1, err } diff --git a/pkg/libsignalgo/inmemorystore_test.go b/pkg/libsignalgo/inmemorystore_test.go index e73c201..1c95ae9 100644 --- a/pkg/libsignalgo/inmemorystore_test.go +++ b/pkg/libsignalgo/inmemorystore_test.go @@ -44,7 +44,7 @@ type InMemorySignalProtocolStore struct { identityKeyPair *libsignalgo.IdentityKeyPair registrationID uint32 - identityKeyMap map[AddressKey][]byte + identityKeyMap map[libsignalgo.ServiceID][]byte preKeyMap map[uint32]*libsignalgo.PreKeyRecord senderKeyMap map[SenderKeyName]*libsignalgo.SenderKeyRecord sessionMap map[AddressKey]*libsignalgo.SessionRecord @@ -67,7 +67,7 @@ func NewInMemorySignalProtocolStore() *InMemorySignalProtocolStore { identityKeyPair: identityKeyPair, registrationID: uint32(registrationID.Uint64()), - identityKeyMap: make(map[AddressKey][]byte), + identityKeyMap: make(map[libsignalgo.ServiceID][]byte), preKeyMap: make(map[uint32]*libsignalgo.PreKeyRecord), senderKeyMap: make(map[SenderKeyName]*libsignalgo.SenderKeyRecord), sessionMap: make(map[AddressKey]*libsignalgo.SessionRecord), @@ -147,18 +147,10 @@ func (ps *InMemorySignalProtocolStore) GetLocalRegistrationID(ctx context.Contex return ps.registrationID, nil } -func (ps *InMemorySignalProtocolStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey) (bool, error) { +func (ps *InMemorySignalProtocolStore) SaveIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey) (bool, error) { log.Debug().Msg("SaveIdentityKey called") - name, err := address.Name() - if err != nil { - return false, err - } - deviceID, err := address.DeviceID() - if err != nil { - return false, err - } replacing := false - oldKeySerialized, ok := ps.identityKeyMap[AddressKey{name, deviceID}] + oldKeySerialized, ok := ps.identityKeyMap[theirServiceID] if ok { oldKey, err := libsignalgo.DeserializeIdentityKey(oldKeySerialized) if err != nil { @@ -180,40 +172,22 @@ func (ps *InMemorySignalProtocolStore) SaveIdentityKey(ctx context.Context, addr hexIdentityKey := hex.EncodeToString(serializedIdentityKey) log.Debug().Str("hexIdentityKey", hexIdentityKey).Msg("SaveIdentityKey") - ps.identityKeyMap[AddressKey{name, deviceID}] = serializedIdentityKey + ps.identityKeyMap[theirServiceID] = serializedIdentityKey return replacing, nil } -func (ps *InMemorySignalProtocolStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.IdentityKey, error) { +func (ps *InMemorySignalProtocolStore) GetIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID) (*libsignalgo.IdentityKey, error) { log.Debug().Msg("GetIdentityKey called") - name, err := address.Name() - if err != nil { - return nil, err - } - deviceID, err := address.DeviceID() - if err != nil { - return nil, err - } - serializedIdentityKey, ok := ps.identityKeyMap[AddressKey{name, deviceID}] + serializedIdentityKey, ok := ps.identityKeyMap[theirServiceID] if !ok { return nil, nil } return libsignalgo.DeserializeIdentityKey(serializedIdentityKey) } -func (ps *InMemorySignalProtocolStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { +func (ps *InMemorySignalProtocolStore) IsTrustedIdentity(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { log.Debug().Msg("IsTrustedIdentity called") - name, err := address.Name() - if err != nil { - log.Error().Err(err).Msg("Error getting name") - return false, err - } - deviceID, err := address.DeviceID() - if err != nil { - log.Error().Err(err).Msg("Error getting deviceID") - return false, err - } - if existingSerialized, ok := ps.identityKeyMap[AddressKey{name, deviceID}]; ok { + if existingSerialized, ok := ps.identityKeyMap[theirServiceID]; ok { existingKey, err := libsignalgo.DeserializeIdentityKey(existingSerialized) if err != nil { log.Error().Err(err).Interface("existingKey", existingKey).Msg("Error deserializing existing identity key") diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index b557dfa..17ea8c9 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -121,10 +121,12 @@ func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtoc // From SessionTests.swift:testSessionCipher func TestSessionCipher(t *testing.T) { ctx := context.TODO() + aliceACI := uuid.New() + bobACI := uuid.New() - aliceAddress, err := libsignalgo.NewPhoneAddress("+14151111111", 1) + aliceAddress, err := libsignalgo.NewACIServiceID(aliceACI).Address(1) assert.NoError(t, err) - bobAddress, err := libsignalgo.NewPhoneAddress("+14151111112", 1) + bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1) assert.NoError(t, err) aliceStore := NewInMemorySignalProtocolStore() @@ -170,9 +172,12 @@ func TestSessionCipher(t *testing.T) { func TestSessionCipherWithBadStore(t *testing.T) { ctx := context.TODO() - aliceAddress, err := libsignalgo.NewPhoneAddress("+14151111111", 1) + aliceACI := uuid.New() + bobACI := uuid.New() + + aliceAddress, err := libsignalgo.NewACIServiceID(aliceACI).Address(1) assert.NoError(t, err) - bobAddress, err := libsignalgo.NewPhoneAddress("+14151111112", 1) + bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1) assert.NoError(t, err) aliceStore := NewInMemorySignalProtocolStore() @@ -337,7 +342,9 @@ func TestArchiveSession(t *testing.T) { ctx := context.TODO() setupLogging() - bobAddress, err := libsignalgo.NewPhoneAddress("+14151111112", 1) + bobACI := uuid.New() + + bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1) assert.NoError(t, err) aliceStore := NewInMemorySignalProtocolStore() diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 576e6c1..8d6f3d1 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -184,15 +184,15 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev device.ClearDeviceKeys(ctx) // Store identity keys? - address, err := libsignalgo.NewACIServiceID(device.ACI).Address(uint(device.DeviceID)) + _, err = device.IdentityStore.SaveIdentityKey(ctx, device.ACIServiceID(), device.ACIIdentityKeyPair.GetIdentityKey()) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, - Err: fmt.Errorf("error creating new address: %w", err), + Err: fmt.Errorf("error saving identity key: %w", err), } return } - _, err = device.IdentityStore.SaveIdentityKey(ctx, address, device.ACIIdentityKeyPair.GetIdentityKey()) + _, err = device.IdentityStore.SaveIdentityKey(ctx, device.PNIServiceID(), device.PNIIdentityKeyPair.GetIdentityKey()) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, diff --git a/pkg/signalmeow/store/identity_store.go b/pkg/signalmeow/store/identity_store.go index dbed8f2..a64af0a 100644 --- a/pkg/signalmeow/store/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -33,41 +33,27 @@ const ( getIdentityKeyPairQuery = `SELECT aci_identity_key_pair FROM signalmeow_device WHERE aci_uuid=$1` getRegistrationLocalIDQuery = `SELECT registration_id FROM signalmeow_device WHERE aci_uuid=$1` insertIdentityKeyQuery = ` - INSERT INTO signalmeow_identity_keys (account_id, their_service_id, their_device_id, key, trust_level) - VALUES ($1, $2, $3, $4, $5) - ON CONFLICT (account_id, their_service_id, their_device_id) DO UPDATE + INSERT INTO signalmeow_identity_keys (account_id, their_service_id, key, trust_level) + VALUES ($1, $2, $3, $4) + ON CONFLICT (account_id, their_service_id) DO UPDATE SET key=excluded.key, trust_level=excluded.trust_level ` getIdentityKeyTrustLevelQuery = ` SELECT trust_level FROM signalmeow_identity_keys - WHERE account_id=$1 AND their_service_id=$2 AND their_device_id=$3 + WHERE account_id=$1 AND their_service_id=$2 ` getIdentityKeyQuery = ` SELECT key FROM signalmeow_identity_keys - WHERE account_id=$1 AND their_service_id=$2 AND their_device_id=$3 + WHERE account_id=$1 AND their_service_id=$2 ` ) func scanIdentityKeyPair(row dbutil.Scannable) (*libsignalgo.IdentityKeyPair, error) { - var keyPair []byte - err := row.Scan(&keyPair) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - return libsignalgo.DeserializeIdentityKeyPair(keyPair) + return scanRecord(row, libsignalgo.DeserializeIdentityKeyPair) } func scanIdentityKey(row dbutil.Scannable) (*libsignalgo.IdentityKey, error) { - var key []byte - err := row.Scan(&key) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - return libsignalgo.DeserializeIdentityKey(key) + return scanRecord(row, libsignalgo.DeserializeIdentityKey) } func (s *sqlStore) GetIdentityKeyPair(ctx context.Context) (*libsignalgo.IdentityKeyPair, error) { @@ -83,21 +69,13 @@ func (s *sqlStore) GetLocalRegistrationID(ctx context.Context) (uint32, error) { return uint32(regID.Int64), nil } -func (s *sqlStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey) (bool, error) { +func (s *sqlStore) SaveIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey) (bool, error) { trustLevel := "TRUSTED_UNVERIFIED" // TODO: this should be hard coded here serialized, err := identityKey.Serialize() if err != nil { return false, fmt.Errorf("failed to serialize identity key: %w", err) } - theirServiceID, err := address.Name() - if err != nil { - return false, fmt.Errorf("failed to get their service ID: %w", err) - } - deviceID, err := address.DeviceID() - if err != nil { - return false, fmt.Errorf("failed to get device ID: %w", err) - } - oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.AccountID, theirServiceID, deviceID)) + oldKey, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.AccountID, theirServiceID)) if err != nil { return false, fmt.Errorf("failed to get old identity key: %w", err) } @@ -110,25 +88,17 @@ func (s *sqlStore) SaveIdentityKey(ctx context.Context, address *libsignalgo.Add // We are replacing the old key if the old key exists, and it is not equal to the new key replacing = !equal } - _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.AccountID, theirServiceID, deviceID, serialized, trustLevel) + _, err = s.db.Exec(ctx, insertIdentityKeyQuery, s.AccountID, theirServiceID, serialized, trustLevel) if err != nil { return replacing, fmt.Errorf("failed to insert new identity key: %w", err) } return replacing, err } -func (s *sqlStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.Address, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { +func (s *sqlStore) IsTrustedIdentity(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) { // TODO: this should check direction, and probably some other stuff (though whisperfish is pretty basic) - theirServiceID, err := address.Name() - if err != nil { - return false, fmt.Errorf("failed to get their service ID: %w", err) - } - deviceID, err := address.DeviceID() - if err != nil { - return false, fmt.Errorf("failed to get device ID: %w", err) - } var trustLevel string - err = s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.AccountID, theirServiceID, deviceID).Scan(&trustLevel) + err := s.db.QueryRow(ctx, getIdentityKeyTrustLevelQuery, s.AccountID, theirServiceID).Scan(&trustLevel) if errors.Is(err, sql.ErrNoRows) { // If no rows, they are a new identity, so trust by default return true, nil @@ -139,16 +109,8 @@ func (s *sqlStore) IsTrustedIdentity(ctx context.Context, address *libsignalgo.A return trusted, nil } -func (s *sqlStore) GetIdentityKey(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.IdentityKey, error) { - theirServiceID, err := address.Name() - if err != nil { - return nil, fmt.Errorf("failed to get their service ID: %w", err) - } - deviceID, err := address.DeviceID() - if err != nil { - return nil, fmt.Errorf("failed to get device ID: %w", err) - } - key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.AccountID, theirServiceID, deviceID)) +func (s *sqlStore) GetIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID) (*libsignalgo.IdentityKey, error) { + key, err := scanIdentityKey(s.db.QueryRow(ctx, getIdentityKeyQuery, s.AccountID, theirServiceID)) if err != nil { return nil, fmt.Errorf("failed to get identity key from database: %w", err) } diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 3acc5fc..b36e4a9 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v11: Latest revision +-- v0 -> v12: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -39,11 +39,10 @@ CREATE TABLE signalmeow_kyber_pre_keys ( CREATE TABLE signalmeow_identity_keys ( account_id TEXT NOT NULL, their_service_id TEXT NOT NULL, - their_device_id INTEGER NOT NULL, key bytea NOT NULL, trust_level TEXT NOT NULL, - PRIMARY KEY (account_id, their_service_id, their_device_id), + PRIMARY KEY (account_id, their_service_id), FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); diff --git a/pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.postgres.sql b/pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.postgres.sql new file mode 100644 index 0000000..8625f12 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.postgres.sql @@ -0,0 +1,5 @@ +-- v12: Drop their_device_id column in signalmeow_identity_keys table +DELETE FROM signalmeow_identity_keys WHERE their_device_id<>1; +ALTER TABLE signalmeow_identity_keys DROP CONSTRAINT signalmeow_identity_keys_pkey; +ALTER TABLE signalmeow_identity_keys DROP COLUMN their_device_id; +ALTER TABLE signalmeow_identity_keys ADD PRIMARY KEY (account_id, their_service_id); diff --git a/pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.sqlite.sql b/pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.sqlite.sql new file mode 100644 index 0000000..396862f --- /dev/null +++ b/pkg/signalmeow/store/upgrades/12-drop-identity-key-device-id.sqlite.sql @@ -0,0 +1,19 @@ +-- v12: Drop their_device_id column in signalmeow_identity_keys table +CREATE TABLE new_signalmeow_identity_keys ( + account_id TEXT NOT NULL, + their_service_id TEXT NOT NULL, + key bytea NOT NULL, + trust_level TEXT NOT NULL, + + PRIMARY KEY (account_id, their_service_id), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); + +INSERT INTO new_signalmeow_identity_keys (account_id, their_service_id, key, trust_level) +SELECT account_id, their_service_id, key, trust_level +FROM signalmeow_identity_keys +WHERE their_device_id=1; + +DROP TABLE signalmeow_identity_keys; + +ALTER TABLE new_signalmeow_identity_keys RENAME TO signalmeow_identity_keys; From 5bb2db43c031286a3c4546f90cf0f49f07fc4247 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 15:37:21 +0200 Subject: [PATCH 120/718] Add support for PNI portals --- database/portal.go | 10 +++- msgconv/msgconv.go | 3 +- pkg/libsignalgo/serviceid.go | 12 +++- pkg/signalmeow/events/message.go | 7 +++ pkg/signalmeow/receiving.go | 47 ++++++++++++++++ portal.go | 68 +++++++++++++++++------ puppet.go | 2 +- user.go | 94 ++++++++++++++++++++++++++++++-- 8 files changed, 214 insertions(+), 29 deletions(-) diff --git a/database/portal.go b/database/portal.go index 31132c6..786f084 100644 --- a/database/portal.go +++ b/database/portal.go @@ -24,6 +24,7 @@ import ( "go.mau.fi/util/dbutil" "maunium.net/go/mautrix/id" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -56,6 +57,7 @@ const ( WHERE chat_id=$1 AND receiver=$2 ` deletePortalQuery = `DELETE FROM portal WHERE chat_id=$1 AND receiver=$2` + reIDPortalQuery = `UPDATE portal SET chat_id=$2 WHERE chat_id=$1 AND receiver=$3` ) type PortalQuery struct { @@ -67,8 +69,8 @@ type PortalKey struct { Receiver uuid.UUID } -func (pk *PortalKey) UserID() uuid.UUID { - parsed, _ := uuid.Parse(pk.ChatID) +func (pk *PortalKey) UserID() libsignalgo.ServiceID { + parsed, _ := libsignalgo.ServiceIDFromString(pk.ChatID) return parsed } @@ -198,3 +200,7 @@ func (p *Portal) Update(ctx context.Context) error { func (p *Portal) Delete(ctx context.Context) error { return p.qh.Exec(ctx, deletePortalQuery, p.ChatID, p.Receiver) } + +func (p *Portal) ReID(ctx context.Context, newID string) error { + return p.qh.Exec(ctx, reIDPortalQuery, p.ChatID, newID, p.Receiver) +} diff --git a/msgconv/msgconv.go b/msgconv/msgconv.go index 4e926ed..b7f9771 100644 --- a/msgconv/msgconv.go +++ b/msgconv/msgconv.go @@ -19,7 +19,6 @@ package msgconv import ( "context" - "github.com/google/uuid" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -58,5 +57,5 @@ type MessageConverter struct { } func (mc *MessageConverter) IsPrivateChat(ctx context.Context) bool { - return mc.GetData(ctx).UserID() != uuid.Nil + return !mc.GetData(ctx).UserID().IsEmpty() } diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index a0d7471..cd08f4d 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -65,6 +65,8 @@ type ServiceID struct { UUID uuid.UUID } +var EmptyServiceID ServiceID + func NewPNIServiceID(uuid uuid.UUID) ServiceID { return ServiceID{ Type: ServiceIDTypePNI, @@ -79,6 +81,10 @@ func NewACIServiceID(uuid uuid.UUID) ServiceID { } } +func (s ServiceID) IsEmpty() bool { + return s.UUID == uuid.Nil +} + func (s ServiceID) Address(deviceID uint) (*Address, error) { return newAddress(s.String(), deviceID) } @@ -121,18 +127,18 @@ func (s ServiceID) FixedBytes() *ServiceIDFixedBytes { func ServiceIDFromString(val string) (ServiceID, error) { if len(val) < 36 { - return ServiceID{}, fmt.Errorf("invalid UUID string: %s", val) + return EmptyServiceID, fmt.Errorf("invalid UUID string: %s", val) } if strings.ToUpper(val[:4]) == "PNI:" { parsed, err := uuid.Parse(val[4:]) if err != nil { - return ServiceID{}, err + return EmptyServiceID, err } return NewPNIServiceID(parsed), nil } else { parsed, err := uuid.Parse(val) if err != nil { - return ServiceID{}, err + return EmptyServiceID, err } return NewACIServiceID(parsed), nil } diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 6fa73fb..f4c6514 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -19,6 +19,7 @@ package events 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/types" ) @@ -32,6 +33,7 @@ func (*Receipt) isSignalEvent() {} func (*ReadSelf) isSignalEvent() {} func (*Call) isSignalEvent() {} func (*ContactList) isSignalEvent() {} +func (*ACIFound) isSignalEvent() {} type MessageInfo struct { Sender uuid.UUID @@ -63,3 +65,8 @@ type Call struct { type ContactList struct { Contacts []*types.Contact } + +type ACIFound struct { + PNI libsignalgo.ServiceID + ACI libsignalgo.ServiceID +} diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 8f81d9b..a7eb904 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -615,6 +615,17 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. }, nil } + if content.GetPniSignatureMessage() != nil { + log.Debug().Msg("Content includes PNI signature message") + err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.GetPniSignatureMessage()) + if err != nil { + log.Err(err). + Hex("pni_raw", content.GetPniSignatureMessage().GetPni()). + Stringer("aci", theirServiceID.UUID). + Msg("Failed to verify ACI-PNI mapping") + } + } + // TODO: handle more sync messages if content.SyncMessage != nil { syncSent := content.SyncMessage.GetSent() @@ -796,6 +807,42 @@ func groupOrUserID(groupID types.GroupIdentifier, userID libsignalgo.ServiceID) return string(groupID) } +func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsignalgo.ServiceID, msg *signalpb.PniSignatureMessage) error { + if sender.Type != libsignalgo.ServiceIDTypeACI { + return fmt.Errorf("PNI signature message sender is not an ACI") + } + pniBytes := msg.GetPni() + if len(pniBytes) != 16 { + return fmt.Errorf("unexpected PNI length %d (expected 16)", len(pniBytes)) + } + pni := uuid.UUID(pniBytes) + pniServiceID := libsignalgo.NewPNIServiceID(pni) + pniIdentity, err := cli.Store.IdentityStore.GetIdentityKey(ctx, pniServiceID) + if err != nil { + return fmt.Errorf("failed to get identity for PNI %s: %w", pni, err) + } else if pniIdentity == nil { + return fmt.Errorf("identity not found for PNI %s", pni) + } + aciIdentity, err := cli.Store.IdentityStore.GetIdentityKey(ctx, sender) + if err != nil { + return fmt.Errorf("failed to get identity for ACI %s: %w", sender, err) + } else if aciIdentity == nil { + return fmt.Errorf("identity not found for ACI %s", sender) + } + if ok, err := pniIdentity.VerifyAlternateIdentity(aciIdentity, msg.GetSignature()); err != nil { + return fmt.Errorf("signature validation failed: %w", err) + } else if !ok { + return fmt.Errorf("signature is invalid") + } + zerolog.Ctx(ctx).Debug(). + Stringer("aci", sender.UUID). + Stringer("pni", pni). + Msg("Verified ACI-PNI mapping") + // TODO save mapping somewhere + cli.handleEvent(&events.ACIFound{ACI: sender, PNI: pniServiceID}) + return nil +} + func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID) bool { // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier diff --git a/portal.go b/portal.go index 98a27cd..9c2049e 100644 --- a/portal.go +++ b/portal.go @@ -30,6 +30,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "go.mau.fi/util/jsontime" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" @@ -72,8 +73,18 @@ func (br *SignalBridge) GetPortalByMXID(mxid id.RoomID) *Portal { func (br *SignalBridge) GetPortalByChatID(key database.PortalKey) *Portal { br.portalsLock.Lock() defer br.portalsLock.Unlock() + return br.unlockedGetPortalByChatID(key, true) +} + +func (br *SignalBridge) GetPortalByChatIDIfExists(key database.PortalKey) *Portal { + br.portalsLock.Lock() + defer br.portalsLock.Unlock() + return br.unlockedGetPortalByChatID(key, false) +} + +func (br *SignalBridge) unlockedGetPortalByChatID(key database.PortalKey, createIfNotExists bool) *Portal { // If this PortalKey is for a group, Receiver should be empty - if key.UserID() == uuid.Nil { + if key.UserID().IsEmpty() { key.Receiver = uuid.Nil } portal, ok := br.portalsByID[key] @@ -83,7 +94,11 @@ func (br *SignalBridge) GetPortalByChatID(key database.PortalKey) *Portal { br.ZLog.Err(err).Msg("Failed to get portal from database") return nil } - return br.loadPortal(context.TODO(), dbPortal, &key) + keyIfNotExists := &key + if !createIfNotExists { + keyIfNotExists = nil + } + return br.loadPortal(context.TODO(), dbPortal, keyIfNotExists) } return portal } @@ -269,17 +284,18 @@ func (portal *Portal) GetRelayUser() *User { } func (portal *Portal) IsPrivateChat() bool { - return portal.UserID() != uuid.Nil + return !portal.UserID().IsEmpty() } func (portal *Portal) IsNoteToSelf() bool { userID := portal.UserID() - return userID != uuid.Nil && userID == portal.Receiver + return !userID.IsEmpty() && userID.UUID == portal.Receiver } func (portal *Portal) MainIntent() *appservice.IntentAPI { - if portal.IsPrivateChat() { - return portal.bridge.GetPuppetBySignalID(portal.UserID()).DefaultIntent() + dmPuppet := portal.GetDMPuppet() + if dmPuppet != nil { + return dmPuppet.DefaultIntent() } return portal.bridge.Bot @@ -681,7 +697,7 @@ func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Conte // Check to see if portal.ChatID is a standard UUID (with dashes) if portal.IsPrivateChat() { // this is a 1:1 chat - result := sender.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(portal.UserID()), msg) + result := sender.Client.SendMessage(ctx, portal.UserID(), msg) if !result.WasSuccessful { return result.Error } @@ -880,7 +896,7 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg // If this message is a group change, don't handle it here, it's handled below. if msg.GetGroupV2().GetGroupChange() == nil && portal.Revision < msg.GetGroupV2().GetRevision() { portal.UpdateInfo(genericCtx, source, nil, msg.GetGroupV2().GetRevision()) - } else if portal.IsPrivateChat() && portal.UserID() == portal.Receiver && portal.Name != NoteToSelfName { + } else if portal.IsPrivateChat() && portal.UserID().UUID == portal.Receiver && portal.Name != NoteToSelfName { // Slightly hacky way to make note to self names backfill portal.UpdateDMInfo(genericCtx, false) } @@ -1489,12 +1505,13 @@ func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { // Check to see if portal.ChatID is a standard UUID (with dashes) // Note: not handling sending to a group right now, since that will // require SenderKey sending to not be terrible - if portal.IsPrivateChat() { + dmUserID := portal.UserID() + if !dmUserID.IsEmpty() && dmUserID.Type == libsignalgo.ServiceIDTypeACI { // this is a 1:1 chat portal.log.Debug().Msg("Sending Typing event to Signal") ctx := context.TODO() typingMessage := signalmeow.TypingMessage(isTyping) - result := user.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(portal.UserID()), typingMessage) + result := user.Client.SendMessage(ctx, portal.UserID(), typingMessage) if !result.WasSuccessful { portal.log.Err(result.FailedSendResult.Error).Msg("Error sending event to Signal") } @@ -1719,8 +1736,12 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev var groupInfo *signalmeow.Group if portal.IsPrivateChat() { dmPuppet = portal.GetDMPuppet() - dmPuppet.UpdateInfo(ctx, user) - portal.UpdateDMInfo(ctx, false) + if dmPuppet != nil { + dmPuppet.UpdateInfo(ctx, user) + portal.UpdateDMInfo(ctx, false) + } else { + portal.UpdatePNIDMInfo(ctx, user) + } } else { groupInfo = portal.UpdateGroupInfo(ctx, user, nil, groupRevision, true) if groupInfo == nil { @@ -1779,7 +1800,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev user.syncChatDoublePuppetDetails(portal, true) go portal.addToPersonalSpace(portal.log.WithContext(context.TODO()), user) - if portal.IsPrivateChat() { + if dmPuppet != nil { user.UpdateDirectChats(ctx, map[id.UserID][]id.RoomID{ dmPuppet.MXID: {portal.MXID}, }) @@ -1789,10 +1810,11 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev } func (portal *Portal) GetDMPuppet() *Puppet { - if !portal.IsPrivateChat() { + userID := portal.UserID() + if userID.IsEmpty() || userID.Type != libsignalgo.ServiceIDTypeACI { return nil } - return portal.bridge.GetPuppetBySignalID(portal.UserID()) + return portal.bridge.GetPuppetBySignalID(userID.UUID) } func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *signalmeow.Group, revision uint32) { @@ -1819,7 +1841,7 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { puppet := portal.GetDMPuppet() update := forceSave - if portal.UserID() == portal.Receiver { + if portal.UserID().UUID == portal.Receiver { noteToSelfAvatar := portal.bridge.Config.Bridge.NoteToSelfAvatar.ParseOrIgnore() avatarHash := sha256.Sum256([]byte(noteToSelfAvatar.String())) @@ -1843,6 +1865,20 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { } } +func (portal *Portal) UpdatePNIDMInfo(ctx context.Context, user *User) { + // TODO find phone number and set room name/topic accurately + update := false + topic := fmt.Sprintf("%s with %s", PrivateChatTopic, portal.ChatID) + update = portal.updateTopic(ctx, topic, nil) || update + if update { + err := portal.Update(ctx) + if err != nil { + log.Err(err).Msg("Failed to save portal in database after updating group info") + } + portal.UpdateBridgeInfo(ctx) + } +} + func (portal *Portal) updatePowerLevelsAndJoinRule(ctx context.Context, info *signalmeow.Group, members map[id.UserID]int) { log := zerolog.Ctx(ctx).With(). Str("function", "updatePowerLevelsAndJoinRule"). diff --git a/puppet.go b/puppet.go index 1ecc240..5a7929c 100644 --- a/puppet.go +++ b/puppet.go @@ -216,7 +216,7 @@ func (puppet *Puppet) CustomIntent() *appservice.IntentAPI { func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI { if puppet != nil { - if puppet.customIntent == nil || portal.UserID() == puppet.SignalID { + if puppet.customIntent == nil || portal.UserID().UUID == puppet.SignalID { return puppet.DefaultIntent() } return puppet.customIntent diff --git a/user.go b/user.go index ab36113..2ece26c 100644 --- a/user.go +++ b/user.go @@ -19,6 +19,7 @@ package main import ( "context" "errors" + "fmt" "net/http" "strings" "sync" @@ -36,6 +37,7 @@ import ( "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/database" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -754,6 +756,79 @@ func (user *User) handleContactList(evt *events.ContactList) { } } +func (user *User) handleACIFound(evt *events.ACIFound) { + log := user.log.With(). + Str("action", "handle aci found"). + Stringer("aci", evt.ACI.UUID). + Stringer("pni", evt.PNI.UUID). + Logger() + ctx := log.WithContext(context.TODO()) + user.bridge.portalsLock.Lock() + defer user.bridge.portalsLock.Unlock() + pniPortal := user.bridge.unlockedGetPortalByChatID(database.PortalKey{ + ChatID: evt.PNI.String(), + Receiver: user.SignalID, + }, false) + pniPortal.roomCreateLock.Lock() + defer pniPortal.roomCreateLock.Unlock() + if pniPortal == nil { + log.Debug().Msg("PNI portal doesn't exist, ignoring event") + return + } else if pniPortal.MXID == "" { + log.Debug().Msg("PNI portal doesn't have Matrix room, deleting row") + pniPortal.Delete() + return + } + log.UpdateContext(func(c zerolog.Context) zerolog.Context { + return c.Stringer("pni_portal_mxid", pniPortal.MXID) + }) + aciPortal := user.bridge.unlockedGetPortalByChatID(database.PortalKey{ + ChatID: evt.ACI.String(), + Receiver: user.SignalID, + }, false) + aciPortal.roomCreateLock.Lock() + defer aciPortal.roomCreateLock.Unlock() + if aciPortal == nil { + log.Debug().Msg("ACI portal doesn't exist, re-ID'ing PNI portal") + err := pniPortal.unlockedReID(ctx, evt.ACI.String()) + if err != nil { + log.Err(err).Msg("Failed to re-ID PNI portal") + } + } else if aciPortal.MXID == "" { + log.Debug().Msg("ACI portal row exists, but doesn't have a Matrix room. Deleting ACI portal row and re-ID'ing PNI portal") + aciPortal.Delete() + err := pniPortal.unlockedReID(ctx, evt.ACI.String()) + if err != nil { + log.Err(err).Msg("Failed to re-ID PNI portal") + } + } else { + log.UpdateContext(func(c zerolog.Context) zerolog.Context { + return c.Stringer("aci_portal_mxid", aciPortal.MXID) + }) + log.Debug().Msg("Both ACI and PNI portal have Matrix room, tombstoning PNI portal") + _, err := pniPortal.MainIntent().SendStateEvent(ctx, pniPortal.MXID, event.StateTombstone, "", &event.TombstoneEventContent{ + Body: fmt.Sprintf("This room has been merged"), + ReplacementRoom: aciPortal.MXID, + }) + if err != nil { + log.Err(err).Msg("Failed to send tombstone to PNI portal") + } + pniPortal.Delete() + pniPortal.Cleanup(ctx, err == nil) + } +} + +func (portal *Portal) unlockedReID(ctx context.Context, newID string) error { + err := portal.Portal.ReID(ctx, newID) + if err != nil { + return err + } + delete(portal.bridge.portalsByID, portal.PortalKey) + portal.PortalKey.ChatID = newID + portal.bridge.portalsByID[portal.PortalKey] = portal + return nil +} + func (user *User) eventHandler(rawEvt events.SignalEvent) { switch evt := rawEvt.(type) { case *events.ChatEvent: @@ -781,17 +856,25 @@ func (user *User) eventHandler(rawEvt events.SignalEvent) { portal.sendMainIntentMessage(context.TODO(), content) case *events.ContactList: user.handleContactList(evt) + case *events.ACIFound: + user.handleACIFound(evt) default: user.log.Warn().Type("event_type", evt).Msg("Unrecognized event type from signalmeow") } } func (user *User) GetPortalByChatID(signalID string) *Portal { - pk := database.PortalKey{ + return user.bridge.GetPortalByChatID(database.PortalKey{ ChatID: signalID, Receiver: user.SignalID, - } - return user.bridge.GetPortalByChatID(pk) + }) +} + +func (user *User) GetPortalByChatIDIfExists(signalID string) *Portal { + return user.bridge.GetPortalByChatIDIfExists(database.PortalKey{ + ChatID: signalID, + Receiver: user.SignalID, + }) } func (user *User) disconnectNoLock() (*signalmeow.Client, error) { @@ -892,8 +975,9 @@ func (user *User) getDirectChats() map[id.UserID][]id.RoomID { return chats } for _, portal := range privateChats { - if portal.MXID != "" { - puppetMXID := user.bridge.FormatPuppetMXID(portal.UserID()) + portalUserID := portal.UserID() + if portal.MXID != "" && portalUserID.Type == libsignalgo.ServiceIDTypeACI { + puppetMXID := user.bridge.FormatPuppetMXID(portalUserID.UUID) chats[puppetMXID] = []id.RoomID{portal.MXID} } From fabded7ba38f57e3d0c24a6f3d6785c5af848a30 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 15:45:20 +0200 Subject: [PATCH 121/718] Allow creating PNI portals with pm command --- commands.go | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/commands.go b/commands.go index 3f3c80d..b21304e 100644 --- a/commands.go +++ b/commands.go @@ -29,6 +29,7 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" ) @@ -212,39 +213,46 @@ func fnPM(ce *WrappedCommandEvent) { } user := ce.User - var targetUUID uuid.UUID + var aci, pni uuid.UUID if contact, err := user.Client.ContactByE164(ce.Ctx, fmt.Sprintf("+%d", number)); err != nil { ce.Reply("Error looking up number in local contact list: %v", err) return } else if contact != nil { - targetUUID = contact.UUID + aci = contact.UUID } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") ce.Reply("Error looking up number on server: %v", err) return - } else if resp[number].ACI == uuid.Nil { - if resp[number].PNI == uuid.Nil { - ce.Reply("+%d doesn't seem to be on Signal", number) - } else { - ce.Reply("Server only returned PNI (%s) for +%d, but the bridge doesn't know what to do with it", resp[number].PNI, number) - } - return } else { - targetUUID = resp[number].ACI - err = user.Client.Store.ContactStore.UpdatePhone(ce.Ctx, targetUUID, fmt.Sprintf("+%d", number)) + aci = resp[number].ACI + pni = resp[number].PNI + } + if aci == uuid.Nil && pni == uuid.Nil { + ce.Reply("+%d doesn't seem to be on Signal", number) + return + } + if aci != uuid.Nil { + err = user.Client.Store.ContactStore.UpdatePhone(ce.Ctx, aci, fmt.Sprintf("+%d", number)) if err != nil { ce.ZLog.Warn().Err(err).Msg("Failed to update phone number in user's contact store") } } ce.ZLog.Debug(). Uint64("e164", number). - Stringer("uuid", targetUUID). + Stringer("aci", aci). + Stringer("pni", pni). Msg("Found DM target user") - portal := user.GetPortalByChatID(targetUUID.String()) + var targetServiceID libsignalgo.ServiceID + if aci != uuid.Nil { + targetServiceID = libsignalgo.NewACIServiceID(aci) + } else { + targetServiceID = libsignalgo.NewPNIServiceID(pni) + } + portal := user.GetPortalByChatID(targetServiceID.String()) if portal == nil { - ce.Reply("Couldn't get portal with %s/+%d", targetUUID, number) + ce.Reply("Couldn't get portal with %s/+%d", targetServiceID, number) return } else if portal.MXID != "" { ok := portal.ensureUserInvited(ce.Ctx, ce.User) From 782782b0d0ad7fe338aaa94d313c1686fc7e292f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 21:26:52 +0200 Subject: [PATCH 122/718] Fix a bunch of bad loggers --- commands.go | 3 +-- pkg/signalmeow/attachments.go | 2 +- pkg/signalmeow/groups.go | 2 +- pkg/signalmeow/sending.go | 5 ++--- portal.go | 3 +-- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/commands.go b/commands.go index 6d92591..66daa54 100644 --- a/commands.go +++ b/commands.go @@ -27,7 +27,6 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "github.com/skip2/go-qrcode" "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridge/commands" @@ -786,7 +785,7 @@ func fnCreate(ce *WrappedCommandEvent) { } hash := sha256.Sum256(avatarBytes) avatarHash = hex.EncodeToString(hash[:]) - log.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{ce.User.MXID, avatarURL}) + ce.ZLog.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{ce.User.MXID, avatarURL}) } } var encryptionEvent *event.EncryptionEventContent diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 5fb0635..64054dd 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -31,7 +31,6 @@ import ( "net/http" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "go.mau.fi/util/random" "google.golang.org/protobuf/proto" @@ -206,6 +205,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb } func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier) (*string, error) { + log := zerolog.Ctx(ctx) groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { log.Err(err).Msg("Could not get master key from group id") diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 0d71b07..90c987e 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -32,7 +32,6 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -1573,6 +1572,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi } func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, groupSecretParams libsignalgo.GroupSecretParams) (*signalpb.Group, error) { + log := zerolog.Ctx(ctx) attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Title{Title: decryptedGroup.Title}} encryptedTitle, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) if err != nil { diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 1822660..3663ce2 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -29,7 +29,6 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "go.mau.fi/util/exfmt" "google.golang.org/protobuf/proto" @@ -575,7 +574,7 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*GroupMember, c // Don't send normal DataMessages to ourselves continue } - log := log.With().Stringer("member", member.UserID).Logger() + log := zerolog.Ctx(ctx).With().Stringer("member", member.UserID).Logger() ctx := log.WithContext(ctx) sentUnidentified, err := cli.sendContent(ctx, member.UserServiceID(), messageTimestamp, content, 0, true) if err != nil { @@ -603,7 +602,7 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*GroupMember, c } _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true) if selfSendErr != nil { - log.Err(selfSendErr).Msg("Failed to send sync message to myself") + zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } } diff --git a/portal.go b/portal.go index 13a23e9..94af0a3 100644 --- a/portal.go +++ b/portal.go @@ -30,7 +30,6 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "go.mau.fi/util/exfmt" "go.mau.fi/util/jsontime" "go.mau.fi/util/variationselector" @@ -2876,7 +2875,7 @@ func (portal *Portal) GetInviteLink(ctx context.Context, source *User) (string, } inviteLinkPassword, err := info.GetInviteLink() if err != nil { - log.Err(err).Msg("Failed to get invite link") + zerolog.Ctx(ctx).Err(err).Msg("Failed to get invite link") } return inviteLinkPassword, nil } From 2eb41b5e83bf3609b98f3ef05b84a3ec00536fbd Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 21:24:30 +0200 Subject: [PATCH 123/718] Refactor recipient storage --- commands.go | 33 +- config/bridge.go | 8 +- pkg/libsignalgo/groupsecretparams.go | 2 + pkg/libsignalgo/profilekey.go | 17 +- pkg/signalmeow/contact.go | 153 +++------ pkg/signalmeow/events/message.go | 2 +- pkg/signalmeow/groups.go | 16 +- pkg/signalmeow/profile.go | 2 +- pkg/signalmeow/provisioning.go | 10 +- pkg/signalmeow/receiving.go | 15 +- pkg/signalmeow/store/contact_store.go | 180 ---------- pkg/signalmeow/store/container.go | 3 +- pkg/signalmeow/store/device.go | 10 +- pkg/signalmeow/store/profile_key_store.go | 32 +- pkg/signalmeow/store/recipient_store.go | 318 ++++++++++++++++++ pkg/signalmeow/store/upgrades/00-latest.sql | 29 +- .../upgrades/13-recipients-table.postgres.sql | 22 ++ .../upgrades/13-recipients-table.sqlite.sql | 37 ++ pkg/signalmeow/types/contact.go | 9 +- portal.go | 48 ++- provisioning.go | 55 +-- puppet.go | 12 +- user.go | 7 +- 23 files changed, 608 insertions(+), 412 deletions(-) delete mode 100644 pkg/signalmeow/store/contact_store.go create mode 100644 pkg/signalmeow/store/recipient_store.go create mode 100644 pkg/signalmeow/store/upgrades/13-recipients-table.postgres.sql create mode 100644 pkg/signalmeow/store/upgrades/13-recipients-table.sqlite.sql diff --git a/commands.go b/commands.go index 66daa54..68a0f9f 100644 --- a/commands.go +++ b/commands.go @@ -222,12 +222,16 @@ func fnPM(ce *WrappedCommandEvent) { user := ce.User var aci, pni uuid.UUID + e164 := fmt.Sprintf("+%d", number) + var recipient *types.Recipient - if contact, err := user.Client.ContactByE164(ce.Ctx, fmt.Sprintf("+%d", number)); err != nil { + if recipient, err = user.Client.ContactByE164(ce.Ctx, e164); err != nil { ce.Reply("Error looking up number in local contact list: %v", err) return - } else if contact != nil { - aci = contact.UUID + } else if recipient != nil && (recipient.ACI != uuid.Nil || recipient.PNI != uuid.Nil) { + // TODO maybe lookup PNI if there's only ACI and E164 stored? + aci = recipient.ACI + pni = recipient.PNI } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") ce.Reply("Error looking up number on server: %v", err) @@ -235,16 +239,15 @@ func fnPM(ce *WrappedCommandEvent) { } else { aci = resp[number].ACI pni = resp[number].PNI - } - if aci == uuid.Nil && pni == uuid.Nil { - ce.Reply("+%d doesn't seem to be on Signal", number) - return - } - if aci != uuid.Nil { - err = user.Client.Store.ContactStore.UpdatePhone(ce.Ctx, aci, fmt.Sprintf("+%d", number)) - if err != nil { - ce.ZLog.Warn().Err(err).Msg("Failed to update phone number in user's contact store") + if aci == uuid.Nil && pni == uuid.Nil { + ce.Reply("+%d doesn't seem to be on Signal", number) + return } + recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ce.Ctx, aci, pni, e164) + if err != nil { + ce.ZLog.Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI } ce.ZLog.Debug(). Uint64("e164", number). @@ -311,12 +314,6 @@ func fnResolvePhone(ce *WrappedCommandEvent) { result, found := resp[phone] if found { _, _ = fmt.Fprintf(&out, "+%d: %s / %s\n", phone, result.ACI, result.PNI) - if result.ACI != uuid.Nil { - err = ce.User.Client.Store.ContactStore.UpdatePhone(ce.Ctx, result.ACI, fmt.Sprintf("+%d", phone)) - if err != nil { - ce.ZLog.Warn().Err(err).Msg("Failed to update phone number in user's contact store") - } - } } else { _, _ = fmt.Fprintf(&out, "+%d: not found\n", phone) } diff --git a/config/bridge.go b/config/bridge.go index 3b7967c..2ce4bb9 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -165,17 +165,21 @@ type DisplaynameParams struct { Username string PhoneNumber string UUID string + ACI string + PNI string AboutEmoji string } -func (bc BridgeConfig) FormatDisplayname(contact *types.Contact) string { +func (bc BridgeConfig) FormatDisplayname(contact *types.Recipient) string { var buffer strings.Builder _ = bc.displaynameTemplate.Execute(&buffer, DisplaynameParams{ ProfileName: contact.Profile.Name, ContactName: contact.ContactName, //Username: contact.Username, PhoneNumber: contact.E164, - UUID: contact.UUID.String(), + UUID: contact.ACI.String(), + ACI: contact.ACI.String(), + PNI: contact.PNI.String(), AboutEmoji: contact.Profile.AboutEmoji, }) return buffer.String() diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index cd79cd9..90b8a56 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -138,6 +138,8 @@ func (gsp *GroupSecretParams) EncryptBlobWithPaddingDeterministic(randomness Ran } func (gsp *GroupSecretParams) DecryptUUID(ciphertextUUID UUIDCiphertext) (uuid.UUID, error) { + // TODO this should probably be DecryptServiceID + u := C.SignalServiceIdFixedWidthBinaryBytes{} signalFfiError := C.signal_group_secret_params_decrypt_service_id( &u, diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index aadecf9..8d4ba8f 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -23,6 +23,7 @@ package libsignalgo */ import "C" import ( + "errors" "runtime" "unsafe" @@ -30,11 +31,23 @@ import ( "go.mau.fi/util/random" ) -type ProfileKey [C.SignalPROFILE_KEY_LEN]byte +const ProfileKeyLength = C.SignalPROFILE_KEY_LEN + +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 +func DeserializeProfileKey(bytes []byte) (*ProfileKey, error) { + if len(bytes) == 0 { + return nil, nil + } else if len(bytes) != ProfileKeyLength { + return nil, errors.New("invalid profile key length") + } + key := ProfileKey(bytes) + return &key, nil +} + var blankProfileKey ProfileKey func (pk *ProfileKey) IsEmpty() bool { @@ -50,7 +63,7 @@ func (pv *ProfileKeyVersion) String() string { } func (pk *ProfileKey) Slice() []byte { - if pk == nil { + if pk.IsEmpty() { return nil } return pk[:] diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index c4eacf2..546b02d 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -36,83 +36,49 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDetails *signalpb.ContactDetails, avatar *[]byte) (*types.Contact, error) { +func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDetails *signalpb.ContactDetails, avatar *[]byte) (*types.Recipient, error) { parsedUUID, err := uuid.Parse(contactDetails.GetAci()) if err != nil { return nil, err } - log := zerolog.Ctx(ctx).With(). + ctx = zerolog.Ctx(ctx).With(). Str("action", "store contact details as contact"). Stringer("uuid", parsedUUID). - Logger() - existingContact, err := cli.Store.ContactStore.LoadContact(ctx, parsedUUID) - if err != nil { - log.Err(err).Msg("Failed to load contact from database") - return nil, err - } - if existingContact == nil { - existingContact = &types.Contact{ - UUID: parsedUUID, + Logger().WithContext(ctx) + return cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, parsedUUID, uuid.Nil, func(recipient *types.Recipient) (bool, error) { + recipient.E164 = contactDetails.GetNumber() + recipient.ContactName = contactDetails.GetName() + if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { + profileKey := libsignalgo.ProfileKey(profileKeyString) + recipient.Profile.Key = profileKey } - } - - existingContact.E164 = contactDetails.GetNumber() - existingContact.ContactName = contactDetails.GetName() - if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { - profileKey := libsignalgo.ProfileKey(profileKeyString) - existingContact.Profile.Key = profileKey - err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, existingContact.UUID, profileKey) - if err != nil { - log.Err(err).Msg("Failed to store profile key from contact") + if avatar != nil && *avatar != nil && len(*avatar) > 0 { + rawHash := sha256.Sum256(*avatar) + avatarHash := hex.EncodeToString(rawHash[:]) + var contentType string + if avatarDetails := contactDetails.GetAvatar(); avatarDetails != nil && !strings.HasSuffix(avatarDetails.GetContentType(), "/*") { + contentType = *avatarDetails.ContentType + } else { + contentType = http.DetectContentType(*avatar) + } + recipient.ContactAvatar = types.ContactAvatar{ + Image: *avatar, + ContentType: contentType, + Hash: avatarHash, + } } - } - - if avatar != nil && *avatar != nil && len(*avatar) > 0 { - rawHash := sha256.Sum256(*avatar) - avatarHash := hex.EncodeToString(rawHash[:]) - var contentType string - if avatarDetails := contactDetails.GetAvatar(); avatarDetails != nil && !strings.HasSuffix(avatarDetails.GetContentType(), "/*") { - contentType = *avatarDetails.ContentType - } else { - contentType = http.DetectContentType(*avatar) - } - existingContact.ContactAvatar = types.ContactAvatar{ - Image: *avatar, - ContentType: contentType, - Hash: avatarHash, - } - } - - storeErr := cli.Store.ContactStore.StoreContact(ctx, *existingContact) - if storeErr != nil { - log.Err(storeErr).Msg("Failed to save contact") - return existingContact, storeErr - } - return existingContact, nil + return true, nil + }) } -func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, profileUUID uuid.UUID) (*types.Contact, error) { +func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, aci uuid.UUID) (*types.Recipient, error) { log := zerolog.Ctx(ctx).With(). Str("action", "fetch contact then try and update with profile"). - Stringer("profile_uuid", profileUUID). + Stringer("profile_aci", aci). Logger() - contactChanged := false + ctx = log.WithContext(ctx) - existingContact, err := cli.Store.ContactStore.LoadContact(ctx, profileUUID) - if err != nil { - log.Err(err).Msg("Failed to load contact from database") - return nil, err - } - if existingContact == nil { - log.Debug().Msg("creating new contact") - existingContact = &types.Contact{ - UUID: profileUUID, - } - contactChanged = true - } else { - log.Debug().Msg("updating existing contact") - } - profile, err := cli.RetrieveProfileByID(ctx, profileUUID) + profile, err := cli.RetrieveProfileByID(ctx, aci) if err != nil { logLevel := zerolog.ErrorLevel if errors.Is(err, errProfileKeyNotFound) { @@ -121,55 +87,24 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, log.WithLevel(logLevel).Err(err).Msg("Failed to fetch profile") // Continue to return contact without profile } - - if profile != nil { - // Don't bother saving every fetched timestamp to the database, but save if anything else changed - if !existingContact.Profile.Equals(profile) || existingContact.Profile.FetchedAt.IsZero() { - contactChanged = true + return cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { + if profile != nil { + // Don't bother saving every fetched timestamp to the database, but save if anything else changed + if !recipient.Profile.Equals(profile) || recipient.Profile.FetchedAt.IsZero() { + changed = true + } + recipient.Profile = *profile } - existingContact.Profile = *profile - } - - if contactChanged { - err = cli.Store.ContactStore.StoreContact(ctx, *existingContact) - if err != nil { - log.Err(err).Msg("Failed to save contact") - return nil, err - } - } - return existingContact, nil + return + }) } -func (cli *Client) UpdateContactE164(ctx context.Context, uuid uuid.UUID, e164 string) error { - log := zerolog.Ctx(ctx).With(). - Str("action", "update contact e164"). - Stringer("uuid", uuid). - Str("e164", e164). - Logger() - existingContact, err := cli.Store.ContactStore.LoadContact(ctx, uuid) - if err != nil { - log.Err(err).Msg("Failed to load contact from database") - return err - } - if existingContact == nil { - existingContact = &types.Contact{ - UUID: uuid, - } - } - if existingContact.E164 == e164 { - return nil - } - log.Debug().Msg("Contact phone number changed") - existingContact.E164 = e164 - return cli.Store.ContactStore.StoreContact(ctx, *existingContact) +func (cli *Client) ContactByACI(ctx context.Context, aci uuid.UUID) (*types.Recipient, error) { + return cli.fetchContactThenTryAndUpdateWithProfile(ctx, aci) } -func (cli *Client) ContactByID(ctx context.Context, uuid uuid.UUID) (*types.Contact, error) { - return cli.fetchContactThenTryAndUpdateWithProfile(ctx, uuid) -} - -func (cli *Client) ContactByE164(ctx context.Context, e164 string) (*types.Contact, error) { - contact, err := cli.Store.ContactStore.LoadContactByE164(ctx, e164) +func (cli *Client) ContactByE164(ctx context.Context, e164 string) (*types.Recipient, error) { + contact, err := cli.Store.RecipientStore.LoadRecipientByE164(ctx, e164) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("ContactByE164 error loading contact") return nil, err @@ -177,7 +112,9 @@ func (cli *Client) ContactByE164(ctx context.Context, e164 string) (*types.Conta if contact == nil { return nil, nil } - contact, err = cli.fetchContactThenTryAndUpdateWithProfile(ctx, contact.UUID) + if contact.ACI != uuid.Nil { + contact, err = cli.fetchContactThenTryAndUpdateWithProfile(ctx, contact.ACI) + } return contact, err } diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index f4c6514..e8ba1cb 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -63,7 +63,7 @@ type Call struct { } type ContactList struct { - Contacts []*types.Contact + Contacts []*types.Recipient } type ACIFound struct { diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 90c987e..38cd290 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -697,19 +697,19 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t // Store the profile keys in case they're new for _, member := range group.Members { - err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } } for _, pendingMember := range group.PendingMembers { - err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, pendingMember.UserID, pendingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, pendingMember.UserID, pendingMember.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } } for _, requestingMember := range group.RequestingMembers { - err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, requestingMember.UserID, requestingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, requestingMember.UserID, requestingMember.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } @@ -884,7 +884,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp GroupMember: *decryptedMember, JoinFromInviteLink: addMember.JoinFromInviteLink, }) - err = cli.Store.ProfileKeyStore.StoreProfileKey(ctx, decryptedMember.UserID, decryptedMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedMember.UserID, decryptedMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -937,7 +937,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp UserID: userID, ProfileKey: *profileKey, }) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -990,7 +990,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp UserID: userID, ProfileKey: *profileKey, }) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1018,7 +1018,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp UserID: userID, ProfileKey: *profileKey, }) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1034,7 +1034,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp return nil, err } decryptedGroupChange.AddRequestingMembers = append(decryptedGroupChange.AddRequestingMembers, decryptedRequestingMember) - cli.Store.ProfileKeyStore.StoreProfileKey(ctx, decryptedRequestingMember.UserID, decryptedRequestingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedRequestingMember.UserID, decryptedRequestingMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index ba160c7..81a6c86 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -102,7 +102,7 @@ func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uu } func (cli *Client) ProfileKeyForSignalID(ctx context.Context, signalACI uuid.UUID) (*libsignalgo.ProfileKey, error) { - profileKey, err := cli.Store.ProfileKeyStore.LoadProfileKey(ctx, signalACI) + profileKey, err := cli.Store.RecipientStore.LoadProfileKey(ctx, signalACI) if err != nil { return nil, fmt.Errorf("error getting profile key: %w", err) } diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 8d6f3d1..3fe1988 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -36,6 +36,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" "go.mau.fi/mautrix-signal/pkg/signalmeow/wspb" ) @@ -208,7 +209,14 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev device.PNIPreKeyStore.StoreLastResortKyberPreKey(ctx, 1, pniPQLastResortPreKey) // Store our profile key - err = device.ProfileKeyStore.StoreProfileKey(ctx, data.ACI, profileKey) + err = device.RecipientStore.StoreRecipient(ctx, &types.Recipient{ + ACI: data.ACI, + PNI: data.PNI, + E164: data.Number, + Profile: types.Profile{ + Key: profileKey, + }, + }) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index a7eb904..4d9989f 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -360,10 +360,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. ctx = log.WithContext(ctx) log.Trace().Msg("Received SealedSender message") - err = cli.UpdateContactE164(ctx, senderUUID, senderE164) - if err != nil { - log.Err(err).Msg("UpdateContactE164 error") - } + cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: @@ -662,9 +659,10 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") } log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") - convertedContacts := make([]*types.Contact, 0, len(contacts)) + convertedContacts := make([]*types.Recipient, 0, len(contacts)) for i, signalContact := range contacts { if signalContact.Aci == nil || *signalContact.Aci == "" { + // TODO lookup PNI via CDSI and store that when ACI is missing? log.Info(). Any("contact", signalContact). Msg("Signal Contact UUID is nil, skipping") @@ -838,7 +836,10 @@ func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsign Stringer("aci", sender.UUID). Stringer("pni", pni). Msg("Verified ACI-PNI mapping") - // TODO save mapping somewhere + _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, sender.UUID, pni, nil) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update aci/pni mapping in store") + } cli.handleEvent(&events.ACIFound{ACI: sender, PNI: pniServiceID}) return nil } @@ -874,7 +875,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp // If there's a profile key, save it if dataMessage.ProfileKey != nil { profileKey := libsignalgo.ProfileKey(dataMessage.ProfileKey) - err := cli.Store.ProfileKeyStore.StoreProfileKey(ctx, messageSenderACI, profileKey) + err := cli.Store.RecipientStore.StoreProfileKey(ctx, messageSenderACI, profileKey) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("StoreProfileKey error") return false diff --git a/pkg/signalmeow/store/contact_store.go b/pkg/signalmeow/store/contact_store.go deleted file mode 100644 index fa079e9..0000000 --- a/pkg/signalmeow/store/contact_store.go +++ /dev/null @@ -1,180 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package store - -import ( - "context" - "database/sql" - "errors" - "time" - - "github.com/google/uuid" - "go.mau.fi/util/dbutil" - - "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" -) - -type ContactStore interface { - LoadContact(ctx context.Context, theirUUID uuid.UUID) (*types.Contact, error) - LoadContactByE164(ctx context.Context, e164 string) (*types.Contact, error) - StoreContact(ctx context.Context, contact types.Contact) error - AllContacts(ctx context.Context) ([]*types.Contact, error) - UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error -} - -var _ ContactStore = (*sqlStore)(nil) - -const ( - getAllContactsQuery = ` - SELECT - aci_uuid, - e164_number, - contact_name, - contact_avatar_hash, - profile_key, - profile_name, - profile_about, - profile_about_emoji, - profile_avatar_path, - profile_fetched_at - FROM signalmeow_contacts - ` - getAllContactsOfUserQuery = getAllContactsQuery + `WHERE account_id = $1` - getContactByUUIDQuery = getAllContactsQuery + `WHERE account_id = $1 AND aci_uuid = $2` - getContactByPhoneQuery = getAllContactsQuery + `WHERE account_id = $1 AND e164_number = $2` - upsertContactQuery = ` - INSERT INTO signalmeow_contacts ( - account_id, - aci_uuid, - e164_number, - contact_name, - contact_avatar_hash, - profile_key, - profile_name, - profile_about, - profile_about_emoji, - profile_avatar_path, - profile_fetched_at - ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) - ON CONFLICT (account_id, aci_uuid) DO UPDATE SET - e164_number = excluded.e164_number, - contact_name = excluded.contact_name, - contact_avatar_hash = excluded.contact_avatar_hash, - profile_key = excluded.profile_key, - profile_name = excluded.profile_name, - profile_about = excluded.profile_about, - profile_about_emoji = excluded.profile_about_emoji, - profile_avatar_path = excluded.profile_avatar_path, - profile_fetched_at = excluded.profile_fetched_at - ` - upsertContactPhoneQuery = ` - INSERT INTO signalmeow_contacts ( - account_id, - aci_uuid, - e164_number, - contact_name, - contact_avatar_hash, - profile_key, - profile_name, - profile_about, - profile_about_emoji, - profile_avatar_path, - profile_fetched_at - ) - VALUES ($1, $2, $3, '', '', NULL, '', '', '', '', NULL) - ON CONFLICT (account_id, aci_uuid) DO UPDATE - SET e164_number = excluded.e164_number - ` -) - -func scanContact(row dbutil.Scannable) (*types.Contact, error) { - var contact types.Contact - var profileKey []byte - var profileFetchedAt sql.NullInt64 - err := row.Scan( - &contact.UUID, - &contact.E164, - &contact.ContactName, - &contact.ContactAvatar.Hash, - &profileKey, - &contact.Profile.Name, - &contact.Profile.About, - &contact.Profile.AboutEmoji, - &contact.Profile.AvatarPath, - &profileFetchedAt, - ) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - if profileFetchedAt.Valid { - contact.Profile.FetchedAt = time.UnixMilli(profileFetchedAt.Int64) - } - if len(profileKey) != 0 { - contact.Profile.Key = libsignalgo.ProfileKey(profileKey) - } - return &contact, err -} - -func (s *sqlStore) LoadContact(ctx context.Context, theirUUID uuid.UUID) (*types.Contact, error) { - return scanContact(s.db.QueryRow(ctx, getContactByUUIDQuery, s.AccountID, theirUUID)) -} - -func (s *sqlStore) LoadContactByE164(ctx context.Context, e164 string) (*types.Contact, error) { - return scanContact(s.db.QueryRow(ctx, getContactByPhoneQuery, s.AccountID, e164)) -} - -func (s *sqlStore) AllContacts(ctx context.Context) ([]*types.Contact, error) { - rows, err := s.db.Query(ctx, getAllContactsOfUserQuery, s.AccountID) - if err != nil { - return nil, err - } - return dbutil.NewRowIter(rows, scanContact).AsList() -} - -func (s *sqlStore) StoreContact(ctx context.Context, contact types.Contact) error { - var profileKey []byte - if contact.Profile.Key.IsEmpty() { - profileKey = contact.Profile.Key[:] - } - _, err := s.db.Exec( - ctx, - upsertContactQuery, - s.AccountID, - contact.UUID, - contact.E164, - contact.ContactName, - contact.ContactAvatar.Hash, - profileKey, - contact.Profile.Name, - contact.Profile.About, - contact.Profile.AboutEmoji, - contact.Profile.AvatarPath, - dbutil.UnixMilliPtr(contact.Profile.FetchedAt), - ) - return err -} - -func (s *sqlStore) UpdatePhone(ctx context.Context, theirUUID uuid.UUID, newE164 string) error { - _, err := s.db.Exec( - ctx, upsertContactPhoneQuery, s.AccountID, theirUUID, newE164, - ) - return err -} diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 626c77e..3b28a8c 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -73,10 +73,9 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.ACISessionStore = aciStore device.PNISessionStore = pniStore device.IdentityStore = baseStore - device.ProfileKeyStore = baseStore device.SenderKeyStore = baseStore device.GroupStore = baseStore - device.ContactStore = baseStore + device.RecipientStore = baseStore device.DeviceStore = baseStore return &device, nil diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index 96f112b..a8c1ed1 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -3,6 +3,7 @@ package store import ( "context" "fmt" + "sync" "github.com/google/uuid" "github.com/rs/zerolog" @@ -13,6 +14,8 @@ import ( type sqlStore struct { *Container AccountID uuid.UUID + + contactLock sync.Mutex } type scopedSQLStore struct { @@ -63,10 +66,9 @@ type Device struct { IdentityStore libsignalgo.IdentityKeyStore SenderKeyStore libsignalgo.SenderKeyStore - ProfileKeyStore ProfileKeyStore - GroupStore GroupStore - ContactStore ContactStore - DeviceStore DeviceStore + GroupStore GroupStore + RecipientStore RecipientStore + DeviceStore DeviceStore } func (d *Device) ClearDeviceKeys(ctx context.Context) error { diff --git a/pkg/signalmeow/store/profile_key_store.go b/pkg/signalmeow/store/profile_key_store.go index 2c22f57..02fd3e6 100644 --- a/pkg/signalmeow/store/profile_key_store.go +++ b/pkg/signalmeow/store/profile_key_store.go @@ -1,5 +1,5 @@ // mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber +// Copyright (C) 2024 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 @@ -18,8 +18,6 @@ package store import ( "context" - "database/sql" - "errors" "github.com/google/uuid" "go.mau.fi/util/dbutil" @@ -27,31 +25,17 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -var _ ProfileKeyStore = (*sqlStore)(nil) - -type ProfileKeyStore interface { - // LoadProfileKey loads the profile key for the given address. - // If the address is not found, nil is returned. - LoadProfileKey(ctx context.Context, theirACI uuid.UUID) (*libsignalgo.ProfileKey, error) - StoreProfileKey(ctx context.Context, theirACI uuid.UUID, key libsignalgo.ProfileKey) error - MyProfileKey(ctx context.Context) (*libsignalgo.ProfileKey, error) -} - const ( - loadProfileKeyQuery = `SELECT key FROM signalmeow_profile_keys WHERE account_id=$1 AND their_aci_uuid=$2` - storeProfileKeyQuery = `INSERT INTO signalmeow_profile_keys (account_id, their_aci_uuid, key) VALUES ($1, $2, $3) ON CONFLICT (account_id, their_aci_uuid) DO UPDATE SET key=excluded.key` + loadProfileKeyQuery = `SELECT profile_key FROM signalmeow_recipients WHERE account_id=$1 AND aci_uuid=$2` + storeProfileKeyQuery = ` + INSERT INTO signalmeow_recipients (account_id, aci_uuid, profile_key) + VALUES ($1, $2, $3) + ON CONFLICT (account_id, aci_uuid) DO UPDATE SET profile_key=excluded.profile_key + ` ) func scanProfileKey(row dbutil.Scannable) (*libsignalgo.ProfileKey, error) { - var record []byte - err := row.Scan(&record) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } else if err != nil { - return nil, err - } - profileKey := libsignalgo.ProfileKey(record) - return &profileKey, err + return scanRecord(row, libsignalgo.DeserializeProfileKey) } func (s *sqlStore) LoadProfileKey(ctx context.Context, theirACI uuid.UUID) (*libsignalgo.ProfileKey, error) { diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go new file mode 100644 index 0000000..b507dda --- /dev/null +++ b/pkg/signalmeow/store/recipient_store.go @@ -0,0 +1,318 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2023 Scott Weber +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package store + +import ( + "context" + "database/sql" + "errors" + "fmt" + "time" + + "github.com/google/uuid" + "go.mau.fi/util/dbutil" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +type RecipientStore interface { + LoadProfileKey(ctx context.Context, theirACI uuid.UUID) (*libsignalgo.ProfileKey, error) + StoreProfileKey(ctx context.Context, theirACI uuid.UUID, key libsignalgo.ProfileKey) error + MyProfileKey(ctx context.Context) (*libsignalgo.ProfileKey, error) + + LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUID, updater RecipientUpdaterFunc) (*types.Recipient, error) + LoadRecipientByE164(ctx context.Context, e164 string) (*types.Recipient, error) + StoreRecipient(ctx context.Context, recipient *types.Recipient) error + UpdateRecipientE164(ctx context.Context, aci, pni uuid.UUID, e164 string) (*types.Recipient, error) +} + +var _ RecipientStore = (*sqlStore)(nil) + +const ( + getAllRecipientsQuery = ` + SELECT + aci_uuid, + pni_uuid, + e164_number, + contact_name, + contact_avatar_hash, + profile_key, + profile_name, + profile_about, + profile_about_emoji, + profile_avatar_path, + profile_fetched_at + FROM signalmeow_recipients + WHERE account_id = $1 + ` + getRecipientByACIQuery = getAllRecipientsQuery + `AND aci_uuid = $2` + getRecipientByPNIQuery = getAllRecipientsQuery + `AND pni_uuid = $2` + getRecipientByACIOrPNIQuery = getAllRecipientsQuery + `AND (($2<>'00000000-0000-0000-0000-000000000000' AND aci_uuid = $2) OR ($3<>'00000000-0000-0000-0000-000000000000' AND pni_uuid = $3))` + getRecipientByPhoneQuery = getAllRecipientsQuery + `AND e164_number = $2` + deleteRecipientByPNIQuery = `DELETE FROM signalmeow_recipients WHERE account_id = $1 AND pni_uuid = $2` + upsertACIRecipientQuery = ` + INSERT INTO signalmeow_recipients ( + account_id, + aci_uuid, + pni_uuid, + e164_number, + contact_name, + contact_avatar_hash, + profile_key, + profile_name, + profile_about, + profile_about_emoji, + profile_avatar_path, + profile_fetched_at + ) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + ON CONFLICT (account_id, aci_uuid) DO UPDATE SET + pni_uuid = excluded.pni_uuid, + e164_number = excluded.e164_number, + contact_name = excluded.contact_name, + contact_avatar_hash = excluded.contact_avatar_hash, + profile_key = excluded.profile_key, + profile_name = excluded.profile_name, + profile_about = excluded.profile_about, + profile_about_emoji = excluded.profile_about_emoji, + profile_avatar_path = excluded.profile_avatar_path, + profile_fetched_at = excluded.profile_fetched_at + ` + upsertPNIRecipientQuery = ` + INSERT INTO signalmeow_recipients ( + account_id, + pni_uuid, + e164_number, + contact_name, + contact_avatar_hash + ) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (account_id, pni_uuid) DO UPDATE SET + e164_number = excluded.e164_number, + contact_name = excluded.contact_name, + contact_avatar_hash = excluded.contact_avatar_hash + ` +) + +func scanRecipient(row dbutil.Scannable) (*types.Recipient, error) { + var recipient types.Recipient + var aci, pni uuid.NullUUID + var profileKey []byte + var profileFetchedAt sql.NullInt64 + err := row.Scan( + &aci, + &pni, + &recipient.E164, + &recipient.ContactName, + &recipient.ContactAvatar.Hash, + &profileKey, + &recipient.Profile.Name, + &recipient.Profile.About, + &recipient.Profile.AboutEmoji, + &recipient.Profile.AvatarPath, + &profileFetchedAt, + ) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } else if err != nil { + return nil, err + } + recipient.ACI = aci.UUID + recipient.PNI = pni.UUID + if profileFetchedAt.Valid { + recipient.Profile.FetchedAt = time.UnixMilli(profileFetchedAt.Int64) + } + if len(profileKey) == libsignalgo.ProfileKeyLength { + recipient.Profile.Key = libsignalgo.ProfileKey(profileKey) + } + return &recipient, err +} + +func (s *sqlStore) LoadRecipientByACI(ctx context.Context, theirUUID uuid.UUID) (*types.Recipient, error) { + return scanRecipient(s.db.QueryRow(ctx, getRecipientByACIQuery, s.AccountID, theirUUID)) +} + +func (s *sqlStore) LoadRecipientByPNI(ctx context.Context, theirUUID uuid.UUID) (*types.Recipient, error) { + return scanRecipient(s.db.QueryRow(ctx, getRecipientByPNIQuery, s.AccountID, theirUUID)) +} + +type RecipientUpdaterFunc func(recipient *types.Recipient) (changed bool, err error) + +func (s *sqlStore) mergeRecipients(ctx context.Context, first, second *types.Recipient, updater RecipientUpdaterFunc) (*types.Recipient, error) { + if first.ACI == uuid.Nil { + first, second = second, first + } + first.PNI = second.PNI + if second.E164 != "" { + first.E164 = second.E164 + } + if first.ContactName == "" { + first.ContactName = second.ContactName + } + if first.ContactAvatar.Hash == "" { + first.ContactAvatar = second.ContactAvatar + } + _, err := updater(first) + if err != nil { + return first, fmt.Errorf("failed to run updater function: %w", err) + } + err = s.DeleteRecipientByPNI(ctx, first.PNI) + if err != nil { + return first, fmt.Errorf("failed to delete duplicate PNI row: %w", err) + } + err = s.StoreRecipient(ctx, first) + if err != nil { + return first, fmt.Errorf("failed to store merged row: %w", err) + } + return first, nil +} + +func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUID, updater RecipientUpdaterFunc) (outRecipient *types.Recipient, outErr error) { + if aci == uuid.Nil && pni == uuid.Nil { + return nil, fmt.Errorf("no ACI or PNI provided in LoadAndUpdateRecipient call") + } + if updater == nil { + updater = func(recipient *types.Recipient) (bool, error) { + return false, nil + } + } + s.contactLock.Lock() + defer s.contactLock.Unlock() + outErr = s.db.DoTxn(ctx, nil, func(ctx context.Context) error { + var entries []*types.Recipient + var err error + if aci != uuid.Nil && pni != uuid.Nil { + query := getRecipientByACIOrPNIQuery + if s.db.Dialect == dbutil.Postgres { + query += " FOR UPDATE" + } + entries, err = dbutil.ConvertRowFn[*types.Recipient](scanRecipient). + NewRowIter(s.db.Query(ctx, query, s.AccountID, aci, pni)). + AsList() + } else if aci != uuid.Nil { + var entry *types.Recipient + entry, err = s.LoadRecipientByACI(ctx, aci) + if entry != nil { + entries = []*types.Recipient{entry} + } + } else if pni != uuid.Nil { + var entry *types.Recipient + entry, err = s.LoadRecipientByPNI(ctx, pni) + if entry != nil { + entries = []*types.Recipient{entry} + } + } else { + panic("impossible case") + } + if err != nil { + return err + } else if len(entries) > 2 { + return fmt.Errorf("got more than two recipient rows for ACI %s and PNI %s", aci, pni) + } else if len(entries) < 2 { + if len(entries) == 0 { + outRecipient = &types.Recipient{ + ACI: aci, + PNI: pni, + } + } else { + outRecipient = entries[0] + } + changed, err := updater(outRecipient) + if err != nil { + return fmt.Errorf("failed to run updater function: %w", err) + } + if outRecipient.PNI == uuid.Nil && pni != uuid.Nil { + outRecipient.PNI = pni + changed = true + } + if outRecipient.ACI == uuid.Nil && aci != uuid.Nil { + outRecipient.ACI = aci + changed = true + } + if changed || len(entries) == 0 { + err = s.StoreRecipient(ctx, outRecipient) + if err != nil { + return fmt.Errorf("failed to store updated recipient row: %w", err) + } + } + return nil + } else if outRecipient, err = s.mergeRecipients(ctx, entries[0], entries[1], updater); err != nil { + return fmt.Errorf("failed to merge recipient rows for ACI %s and PNI %s: %w", aci, pni, err) + } else { + return nil + } + }) + return +} + +func (s *sqlStore) UpdateRecipientE164(ctx context.Context, aci, pni uuid.UUID, e164 string) (*types.Recipient, error) { + return s.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (bool, error) { + if recipient.E164 != e164 { + recipient.E164 = e164 + return true, nil + } + return false, nil + }) +} +func (s *sqlStore) LoadRecipientByE164(ctx context.Context, e164 string) (*types.Recipient, error) { + return scanRecipient(s.db.QueryRow(ctx, getRecipientByPhoneQuery, s.AccountID, e164)) +} + +func (s *sqlStore) DeleteRecipientByPNI(ctx context.Context, pni uuid.UUID) error { + _, err := s.db.Exec(ctx, deleteRecipientByPNIQuery, s.AccountID, pni) + return err +} + +func nullableUUID(u uuid.UUID) uuid.NullUUID { + return uuid.NullUUID{UUID: u, Valid: u != uuid.Nil} +} + +func (s *sqlStore) StoreRecipient(ctx context.Context, recipient *types.Recipient) (err error) { + if recipient.ACI != uuid.Nil { + _, err = s.db.Exec( + ctx, + upsertACIRecipientQuery, + s.AccountID, + recipient.ACI, + nullableUUID(recipient.PNI), + recipient.E164, + recipient.ContactName, + recipient.ContactAvatar.Hash, + recipient.Profile.Key.Slice(), + recipient.Profile.Name, + recipient.Profile.About, + recipient.Profile.AboutEmoji, + recipient.Profile.AvatarPath, + dbutil.UnixMilliPtr(recipient.Profile.FetchedAt), + ) + } else if recipient.PNI != uuid.Nil { + _, err = s.db.Exec( + ctx, + upsertPNIRecipientQuery, + s.AccountID, + recipient.PNI, + recipient.E164, + recipient.ContactName, + recipient.ContactAvatar.Hash, + ) + } else { + err = fmt.Errorf("no ACI or PNI provided in StoreRecipient call") + } + return +} diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index b36e4a9..4bf27bc 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v12: Latest revision +-- v0 -> v13: Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -85,19 +85,22 @@ CREATE TABLE signalmeow_groups ( PRIMARY KEY (account_id, group_identifier) ); -CREATE TABLE signalmeow_contacts ( - account_id TEXT NOT NULL, - aci_uuid TEXT NOT NULL, - e164_number TEXT NOT NULL, - contact_name TEXT NOT NULL, - contact_avatar_hash TEXT NOT NULL, +CREATE TABLE signalmeow_recipients ( + account_id TEXT NOT NULL, + aci_uuid TEXT, + pni_uuid TEXT, + e164_number TEXT NOT NULL DEFAULT '', + contact_name TEXT NOT NULL DEFAULT '', + contact_avatar_hash TEXT NOT NULL DEFAULT '', profile_key bytea, - profile_name TEXT NOT NULL, - profile_about TEXT NOT NULL, - profile_about_emoji TEXT NOT NULL, - profile_avatar_path TEXT NOT NULL, + profile_name TEXT NOT NULL DEFAULT '', + profile_about TEXT NOT NULL DEFAULT '', + profile_about_emoji TEXT NOT NULL DEFAULT '', + profile_avatar_path TEXT NOT NULL DEFAULT '', profile_fetched_at BIGINT, - PRIMARY KEY (account_id, aci_uuid), - FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE + CONSTRAINT signalmeow_contacts_account_id_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) + ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_contacts_aci_unique UNIQUE (account_id, aci_uuid), + CONSTRAINT signalmeow_contacts_pni_unique UNIQUE (account_id, pni_uuid) ); diff --git a/pkg/signalmeow/store/upgrades/13-recipients-table.postgres.sql b/pkg/signalmeow/store/upgrades/13-recipients-table.postgres.sql new file mode 100644 index 0000000..181807c --- /dev/null +++ b/pkg/signalmeow/store/upgrades/13-recipients-table.postgres.sql @@ -0,0 +1,22 @@ +-- v13: Add PNIs to recipient table and merge profile keys +ALTER TABLE signalmeow_contacts DROP CONSTRAINT signalmeow_contacts_pkey; +ALTER TABLE signalmeow_contacts RENAME TO signalmeow_recipients; +ALTER TABLE signalmeow_recipients ADD COLUMN pni_uuid TEXT; +ALTER TABLE signalmeow_recipients ALTER COLUMN aci_uuid DROP NOT NULL; +ALTER TABLE signalmeow_recipients ADD CONSTRAINT signalmeow_contacts_aci_unique UNIQUE (account_id, aci_uuid); +ALTER TABLE signalmeow_recipients ADD CONSTRAINT signalmeow_contacts_pni_unique UNIQUE (account_id, pni_uuid); + +ALTER TABLE signalmeow_recipients ALTER COLUMN e164_number SET DEFAULT ''; +ALTER TABLE signalmeow_recipients ALTER COLUMN contact_name SET DEFAULT ''; +ALTER TABLE signalmeow_recipients ALTER COLUMN contact_avatar_hash SET DEFAULT ''; +ALTER TABLE signalmeow_recipients ALTER COLUMN profile_name SET DEFAULT ''; +ALTER TABLE signalmeow_recipients ALTER COLUMN profile_about SET DEFAULT ''; +ALTER TABLE signalmeow_recipients ALTER COLUMN profile_about_emoji SET DEFAULT ''; +ALTER TABLE signalmeow_recipients ALTER COLUMN profile_avatar_path SET DEFAULT ''; + +INSERT INTO signalmeow_recipients (account_id, aci_uuid, profile_key) +SELECT account_id, their_aci_uuid, key +FROM signalmeow_profile_keys +ON CONFLICT (account_id, aci_uuid) DO UPDATE SET profile_key=excluded.profile_key; + +DROP TABLE signalmeow_profile_keys; diff --git a/pkg/signalmeow/store/upgrades/13-recipients-table.sqlite.sql b/pkg/signalmeow/store/upgrades/13-recipients-table.sqlite.sql new file mode 100644 index 0000000..4060685 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/13-recipients-table.sqlite.sql @@ -0,0 +1,37 @@ +-- v13: Add PNIs to recipient table and merge profile keys +CREATE TABLE signalmeow_recipients ( + account_id TEXT NOT NULL, + aci_uuid TEXT, + pni_uuid TEXT, + e164_number TEXT NOT NULL DEFAULT '', + contact_name TEXT NOT NULL DEFAULT '', + contact_avatar_hash TEXT NOT NULL DEFAULT '', + profile_key bytea, + profile_name TEXT NOT NULL DEFAULT '', + profile_about TEXT NOT NULL DEFAULT '', + profile_about_emoji TEXT NOT NULL DEFAULT '', + profile_avatar_path TEXT NOT NULL DEFAULT '', + profile_fetched_at BIGINT, + + CONSTRAINT signalmeow_contacts_account_id_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) + ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_contacts_aci_unique UNIQUE (account_id, aci_uuid), + CONSTRAINT signalmeow_contacts_pni_unique UNIQUE (account_id, pni_uuid) +); + +INSERT INTO signalmeow_recipients ( + account_id, aci_uuid, e164_number, contact_name, contact_avatar_hash, profile_key, profile_name, + profile_about, profile_about_emoji, profile_avatar_path, profile_fetched_at +) +SELECT account_id, aci_uuid, e164_number, contact_name, contact_avatar_hash, profile_key, profile_name, + profile_about, profile_about_emoji, profile_avatar_path, profile_fetched_at +FROM signalmeow_contacts; + +INSERT INTO signalmeow_recipients (account_id, aci_uuid, profile_key) +SELECT account_id, their_aci_uuid, key +FROM signalmeow_profile_keys +WHERE true -- https://sqlite.org/lang_upsert.html#parsing_ambiguity +ON CONFLICT (account_id, aci_uuid) DO UPDATE SET profile_key=excluded.profile_key; + +DROP TABLE signalmeow_contacts; +DROP TABLE signalmeow_profile_keys; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index a9fdbd3..29cf8c0 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -42,13 +42,12 @@ func (p *Profile) Equals(other *Profile) bool { p.Key == other.Key } -// The Contact struct combines information from two sources: +// The Recipient struct combines information from two sources: // - A Signal "contact": contact info harvested from our user's phone's contact list // - A Signal "profile": contact info entered by the target user when registering for Signal -// Users of this Contact struct should prioritize "contact" information, but fall back -// to "profile" information if the contact information is not available. -type Contact struct { - UUID uuid.UUID +type Recipient struct { + ACI uuid.UUID + PNI uuid.UUID E164 string ContactName string ContactAvatar ContactAvatar diff --git a/portal.go b/portal.go index 94af0a3..6dcb3b3 100644 --- a/portal.go +++ b/portal.go @@ -1734,7 +1734,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev }) portal.Encrypted = true - if portal.IsPrivateChat() { + if portal.IsPrivateChat() && portal.MainIntent() != portal.bridge.Bot { invite = append(invite, portal.bridge.Bot.UserID) } } @@ -1857,6 +1857,19 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { } else if portal.shouldSetDMRoomMetadata() { update = portal.updateName(ctx, puppet.Name, nil) || update update = portal.updateAvatarWithMXC(ctx, puppet.AvatarPath, puppet.AvatarHash, puppet.AvatarURL) || update + } else { + // Clear name/avatar if they're set in a DM that shouldn't have them set + if portal.Name != "" && portal.NameSet { + update = portal.updateName(ctx, "", nil) || update + } + // Avatar is currently never set in PNI portals + //if !portal.AvatarURL.IsEmpty() && portal.AvatarSet { + // update = true + // portal.AvatarURL = id.ContentURI{} + // portal.AvatarHash = "" + // portal.AvatarPath = "" + // portal.updateAvatarInRoom(ctx, nil) + //} } topic := PrivateChatTopic if portal.bridge.Config.Bridge.NumberInTopic && puppet.Number != "" { @@ -1873,12 +1886,32 @@ func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { } func (portal *Portal) UpdatePNIDMInfo(ctx context.Context, user *User) { - // TODO find phone number and set room name/topic accurately + portalUserID := portal.UserID() + if portalUserID.Type != libsignalgo.ServiceIDTypePNI { + return + } + log := zerolog.Ctx(ctx) update := false - topic := fmt.Sprintf("%s with %s", PrivateChatTopic, portal.ChatID) + recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, uuid.Nil, portalUserID.UUID, nil) + if err != nil { + log.Err(err).Msg("Failed to get PNI DM recipient entry") + } + if recipient == nil { + recipient = &types.Recipient{PNI: portalUserID.UUID} + } + topic := PrivateChatTopic + name := portalUserID.UUID.String() + if recipient.E164 != "" { + topic = fmt.Sprintf("%s with %s", topic, recipient.E164) + name = recipient.E164 + } + if recipient.ContactName != "" { + name = recipient.ContactName + } update = portal.updateTopic(ctx, topic, nil) || update + update = portal.updateName(ctx, name, nil) || update if update { - err := portal.Update(ctx) + err = portal.Update(ctx) if err != nil { log.Err(err).Msg("Failed to save portal in database after updating group info") } @@ -2868,7 +2901,7 @@ func (portal *Portal) GetMatrixUsers(ctx context.Context) ([]id.UserID, error) { func (portal *Portal) GetInviteLink(ctx context.Context, source *User) (string, error) { info, err := source.Client.RetrieveGroupByID(ctx, portal.GroupID(), portal.Revision) if err != nil { - log.Err(err). + zerolog.Ctx(ctx).Err(err). Stringer("source_user_id", source.MXID). Msg("Failed to fetch group info") return "", err @@ -2885,12 +2918,11 @@ func (portal *Portal) ResetInviteLink(ctx context.Context, source *User) error { groupChange := &signalmeow.GroupChange{ModifyInviteLinkPassword: &inviteLinkPassword} revision, err := source.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { - log.Err(err).Msg("Error setting invite link password") + zerolog.Ctx(ctx).Err(err).Msg("Error setting invite link password") return err } portal.Revision = revision - portal.Update(ctx) - return nil + return portal.Update(ctx) } func (portal *Portal) GetEncryptionEventContent() (evt *event.EncryptionEventContent) { diff --git a/provisioning.go b/provisioning.go index 117fa1b..ac38b99 100644 --- a/provisioning.go +++ b/provisioning.go @@ -36,6 +36,7 @@ import ( "maunium.net/go/mautrix" "maunium.net/go/mautrix/id" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" ) @@ -143,10 +144,10 @@ type WhoAmIResponseSignal struct { } type ResolveIdentifierResponse struct { - RoomID id.RoomID `json:"room_id"` - ChatID ResolveIdentifierResponseChatID `json:"chat_id"` - JustCreated bool `json:"just_created"` - OtherUser ResolveIdentifierResponseOtherUser `json:"other_user"` + RoomID id.RoomID `json:"room_id"` + ChatID ResolveIdentifierResponseChatID `json:"chat_id"` + JustCreated bool `json:"just_created"` + OtherUser *ResolveIdentifierResponseOtherUser `json:"other_user,omitempty"` } type ResolveIdentifierResponseChatID struct { @@ -169,37 +170,51 @@ func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, return http.StatusBadRequest, nil, fmt.Errorf("error parsing phone number: %w", err) } e164String := fmt.Sprintf("+%d", e164Number) - var targetUUID uuid.UUID + var aci, pni uuid.UUID if contact, err := user.Client.ContactByE164(ctx, e164String); err != nil { return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number in local contact list: %w", err) } else if contact != nil { - targetUUID = contact.UUID + aci = contact.ACI + pni = contact.PNI } else if resp, err := user.Client.LookupPhone(ctx, e164Number); err != nil { return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number on server: %w", err) - } else if resp[e164Number].ACI != uuid.Nil { - targetUUID = resp[e164Number].ACI - err = user.Client.Store.ContactStore.UpdatePhone(ctx, targetUUID, e164String) - if err != nil { - zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to update phone number in user's contact store") - } } else { + aci = resp[e164Number].ACI + pni = resp[e164Number].PNI + user.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) + } + if aci == uuid.Nil && pni == uuid.Nil { return http.StatusNotFound, nil, errors.New("user not found on Signal") } + zerolog.Ctx(ctx).Debug(). + Uint64("e164", e164Number). + Stringer("aci", aci). + Stringer("pni", pni). + Msg("Found DM target user") - portal := user.GetPortalByChatID(targetUUID.String()) - puppet := prov.bridge.GetPuppetBySignalID(targetUUID) + var targetServiceID libsignalgo.ServiceID + var otherUserInfo *ResolveIdentifierResponseOtherUser + if aci != uuid.Nil { + targetServiceID = libsignalgo.NewACIServiceID(aci) + puppet := prov.bridge.GetPuppetBySignalID(aci) + otherUserInfo = &ResolveIdentifierResponseOtherUser{ + MXID: puppet.MXID.String(), + DisplayName: puppet.Name, + AvatarURL: puppet.AvatarURL.String(), + } + } else { + targetServiceID = libsignalgo.NewPNIServiceID(pni) + // TODO fill other user displayname/avatar if there's a contact entry? + } + portal := user.GetPortalByChatID(targetServiceID.String()) return http.StatusOK, &ResolveIdentifierResponse{ RoomID: portal.MXID, ChatID: ResolveIdentifierResponseChatID{ - UUID: targetUUID.String(), + UUID: targetServiceID.String(), Number: e164String, }, - OtherUser: ResolveIdentifierResponseOtherUser{ - MXID: puppet.MXID.String(), - DisplayName: puppet.Name, - AvatarURL: puppet.AvatarURL.String(), - }, + OtherUser: otherUserInfo, }, nil } diff --git a/puppet.go b/puppet.go index 5a7929c..f58befa 100644 --- a/puppet.go +++ b/puppet.go @@ -53,14 +53,14 @@ func (br *SignalBridge) GetPuppetBySignalIDString(id string) *Puppet { } func (br *SignalBridge) GetPuppetBySignalID(id uuid.UUID) *Puppet { - br.puppetsLock.Lock() - defer br.puppetsLock.Unlock() - if id == uuid.Nil { br.ZLog.Warn().Msg("Trying to get puppet with empty signal_user_id") return nil } + br.puppetsLock.Lock() + defer br.puppetsLock.Unlock() + puppet, ok := br.puppets[id] if !ok { dbPuppet, err := br.DB.Puppet.GetBySignalID(context.TODO(), id) @@ -240,7 +240,7 @@ func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { ctx = log.WithContext(ctx) var err error log.Debug().Msg("Fetching contact info to update puppet") - info, err := source.Client.ContactByID(ctx, puppet.SignalID) + info, err := source.Client.ContactByACI(ctx, puppet.SignalID) if err != nil { log.Err(err).Msg("Failed to fetch contact info") return @@ -311,7 +311,7 @@ func (puppet *Puppet) updatePortalMeta(ctx context.Context) { } } -func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *types.Contact) bool { +func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *types.Recipient) bool { var avatarData []byte var avatarContentType string log := zerolog.Ctx(ctx) @@ -390,7 +390,7 @@ func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *type return true } -func (puppet *Puppet) updateName(ctx context.Context, contact *types.Contact) bool { +func (puppet *Puppet) updateName(ctx context.Context, contact *types.Recipient) bool { // TODO set name quality newName := puppet.bridge.Config.Bridge.FormatDisplayname(contact) if puppet.NameSet && puppet.Name == newName { diff --git a/user.go b/user.go index 2ece26c..624a121 100644 --- a/user.go +++ b/user.go @@ -748,9 +748,12 @@ func (user *User) handleReadSelf(evt *events.ReadSelf) { func (user *User) handleContactList(evt *events.ContactList) { ctx := user.log.With().Str("action", "handle contact list").Logger().WithContext(context.TODO()) for _, contact := range evt.Contacts { - puppet := user.bridge.GetPuppetBySignalID(contact.UUID) + if contact.ACI == uuid.Nil { + continue + } + puppet := user.bridge.GetPuppetBySignalID(contact.ACI) if puppet == nil { - return + continue } puppet.UpdateInfo(ctx, user) } From 68cb547ef969b007314756ae24fac774cded2c59 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 21:50:26 +0200 Subject: [PATCH 124/718] Request and save master key for storage service --- pkg/signalmeow/receiving.go | 16 ++++++++ pkg/signalmeow/sending.go | 41 +++++++++++++------ pkg/signalmeow/storageservice.go | 5 +++ pkg/signalmeow/store/container.go | 13 +++--- pkg/signalmeow/store/device.go | 1 + pkg/signalmeow/store/upgrades/00-latest.sql | 6 ++- .../upgrades/14-save-storage-master-key.sql | 2 + 7 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/14-save-storage-master-key.sql diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 4d9989f..5e74a39 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -189,6 +189,9 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection log.Info().Msg("Both websockets connected, sending contacts sync request") // TODO hacky cli.SendContactSyncRequest(ctx) + if cli.Store.MasterKey == nil { + cli.SendStorageMasterKeyRequest(ctx) + } return } } @@ -625,6 +628,19 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. // TODO: handle more sync messages if content.SyncMessage != nil { + if content.SyncMessage.Keys != nil { + cli.Store.MasterKey = content.SyncMessage.Keys.GetMaster() + err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + if err != nil { + log.Err(err).Msg("Failed to save device after receiving master key") + } else { + log.Info().Msg("Received master key") + go cli.SyncStorage(ctx) + } + } else if content.SyncMessage.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { + log.Debug().Msg("Received storage manifest fetch latest notice") + go cli.SyncStorage(ctx) + } syncSent := content.SyncMessage.GetSent() if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { destination := syncSent.DestinationServiceId diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 3663ce2..68e311d 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -381,16 +381,6 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su } } -func syncMessageForContactRequest() *signalpb.Content { - return &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ - Request: &signalpb.SyncMessage_Request{ - Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), - }, - }, - } -} - func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender libsignalgo.ServiceID) *signalpb.Content { if *receiptMessage.Type != signalpb.ReceiptMessage_READ { zerolog.Ctx(ctx).Warn(). @@ -435,8 +425,13 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { return nil } - groupRequest := syncMessageForContactRequest() - _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(currentUnixTime), groupRequest, 0, true) + _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(currentUnixTime), &signalpb.Content{ + SyncMessage: &signalpb.SyncMessage{ + Request: &signalpb.SyncMessage_Request{ + Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), + }, + }, + }, 0, false) if err != nil { log.Err(err).Msg("Failed to send contact sync request message to myself") return err @@ -445,6 +440,28 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { return nil } +func (cli *Client) SendStorageMasterKeyRequest(ctx context.Context) error { + log := zerolog.Ctx(ctx).With(). + Str("action", "send key sync request"). + Logger() + ctx = log.WithContext(ctx) + + _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), &signalpb.Content{ + SyncMessage: &signalpb.SyncMessage{ + Request: &signalpb.SyncMessage_Request{ + Type: signalpb.SyncMessage_Request_KEYS.Enum(), + }, + }, + }, 0, false) + if err != nil { + log.Err(err).Msg("Failed to send key sync request message to myself") + return err + } else { + log.Info().Msg("Sent key sync request to self") + } + return nil +} + func TypingMessage(isTyping bool) *signalpb.Content { // Note: not handling sending to a group ATM since that will require // SenderKey sending to not be terrible diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 9e2e93c..4ba481d 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -34,6 +34,11 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) +func (cli *Client) SyncStorage(ctx context.Context) { + //log := zerolog.Ctx(ctx).With().Str("action", "sync storage").Logger() + // TODO implement +} + type StorageUpdate struct { Version uint64 NewRecords []*DecryptedStorageRecord diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 3b28a8c..4f6efff 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -34,7 +34,7 @@ const getAllDevicesQuery = ` SELECT aci_uuid, aci_identity_key_pair, registration_id, pni_uuid, pni_identity_key_pair, pni_registration_id, - device_id, number, password + device_id, number, password, master_key FROM signalmeow_device ` @@ -51,7 +51,7 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { err := row.Scan( &device.ACI, &aciIdentityKeyPair, &device.RegistrationID, &device.PNI, &pniIdentityKeyPair, &device.PNIRegistrationID, - &device.DeviceID, &device.Number, &device.Password, + &device.DeviceID, &device.Number, &device.Password, &device.MasterKey, ) if err != nil { return nil, fmt.Errorf("failed to scan session: %w", err) @@ -114,9 +114,9 @@ const ( INSERT INTO signalmeow_device ( aci_uuid, aci_identity_key_pair, registration_id, pni_uuid, pni_identity_key_pair, pni_registration_id, - device_id, number, password + device_id, number, password, master_key ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (aci_uuid) DO UPDATE SET aci_identity_key_pair=excluded.aci_identity_key_pair, registration_id=excluded.registration_id, @@ -125,7 +125,8 @@ const ( pni_registration_id=excluded.pni_registration_id, device_id=excluded.device_id, number=excluded.number, - password=excluded.password + password=excluded.password, + master_key=excluded.master_key ` deleteDeviceQuery = `DELETE FROM signalmeow_device WHERE aci_uuid=$1` ) @@ -151,7 +152,7 @@ func (c *Container) PutDevice(ctx context.Context, device *DeviceData) error { _, err = c.db.Exec(ctx, insertDeviceQuery, device.ACI, aciIdentityKeyPair, device.RegistrationID, device.PNI, pniIdentityKeyPair, device.PNIRegistrationID, - device.DeviceID, device.Number, device.Password, + device.DeviceID, device.Number, device.Password, device.MasterKey, ) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("failed to insert device") diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index a8c1ed1..e07feb5 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -34,6 +34,7 @@ type DeviceData struct { DeviceID int Number string Password string + MasterKey []byte } func (d *DeviceData) ACIServiceID() libsignalgo.ServiceID { diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 4bf27bc..9dff754 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v13: Latest revision +-- v0 -> v14 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -11,7 +11,9 @@ CREATE TABLE signalmeow_device ( device_id INTEGER NOT NULL, number TEXT NOT NULL DEFAULT '', - password TEXT NOT NULL DEFAULT '' + password TEXT NOT NULL DEFAULT '', + + master_key bytea ); CREATE TABLE signalmeow_pre_keys ( diff --git a/pkg/signalmeow/store/upgrades/14-save-storage-master-key.sql b/pkg/signalmeow/store/upgrades/14-save-storage-master-key.sql new file mode 100644 index 0000000..6c75ed1 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/14-save-storage-master-key.sql @@ -0,0 +1,2 @@ +-- v14 (compatible with v13+): Save storage master key for devices +ALTER TABLE signalmeow_device ADD COLUMN master_key bytea; From d1ac878312e75d1a7485970739570554d8182195 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 22:11:43 +0200 Subject: [PATCH 125/718] Sync contacts and groups from storage service --- pkg/libsignalgo/groupsecretparams.go | 4 +- pkg/signalmeow/storageservice.go | 76 +++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 90b8a56..fed5477 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -41,7 +41,9 @@ func GenerateRandomness() Randomness { return randomness } -type GroupMasterKey [C.SignalGROUP_MASTER_KEY_LEN]byte +const GroupMasterKeyLength = C.SignalGROUP_MASTER_KEY_LEN + +type GroupMasterKey [GroupMasterKeyLength]byte type GroupSecretParams [C.SignalGROUP_SECRET_PARAMS_LEN]byte type GroupPublicParams [C.SignalGROUP_PUBLIC_PARAMS_LEN]byte type GroupIdentifier [C.SignalGROUP_IDENTIFIER_LEN]byte diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 4ba481d..a78f964 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -24,19 +24,91 @@ import ( "fmt" "io" "net/http" + "strings" + "github.com/google/uuid" + "github.com/rs/zerolog" "go.mau.fi/util/exerrors" "golang.org/x/exp/maps" "golang.org/x/exp/slices" "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/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) func (cli *Client) SyncStorage(ctx context.Context) { - //log := zerolog.Ctx(ctx).With().Str("action", "sync storage").Logger() - // TODO implement + log := zerolog.Ctx(ctx).With().Str("action", "sync storage").Logger() + // TODO only fetch changed entries + update, err := cli.FetchStorage(ctx, cli.Store.MasterKey, 0, nil) + if err != nil { + log.Err(err).Msg("Failed to fetch storage") + return + } + for _, record := range update.NewRecords { + switch data := record.StorageRecord.GetRecord().(type) { + case *signalpb.StorageRecord_Contact: + log.Trace().Any("contact_record", data.Contact).Msg("Handling contact record") + aci, _ := uuid.Parse(data.Contact.Aci) + pni, _ := uuid.Parse(data.Contact.Pni) + if aci == uuid.Nil && pni == uuid.Nil { + log.Warn(). + Str("raw_aci", data.Contact.Aci). + Str("raw_pni", data.Contact.Pni). + Str("raw_e164", data.Contact.E164). + Msg("Storage service has contact record with no ACI or PNI") + continue + } + contact := data.Contact + _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (changed bool, err error) { + if len(contact.ProfileKey) == libsignalgo.ProfileKeyLength { + newProfileKey := libsignalgo.ProfileKey(contact.ProfileKey) + changed = changed || recipient.Profile.Key != newProfileKey + recipient.Profile.Key = newProfileKey + } + if recipient.Profile.Name == "" && (contact.GivenName != "" || contact.FamilyName != "") { + changed = true + recipient.Profile.Name = strings.TrimSpace(fmt.Sprintf("%s %s", contact.GivenName, contact.FamilyName)) + } + if contact.SystemGivenName != "" || contact.SystemFamilyName != "" { + changed = true + recipient.ContactName = strings.TrimSpace(fmt.Sprintf("%s %s", contact.SystemGivenName, contact.SystemFamilyName)) + } + if contact.E164 != "" { + changed = changed || recipient.E164 != contact.E164 + recipient.E164 = contact.E164 + } + return + }) + if err != nil { + log.Err(err). + Stringer("aci", aci). + Stringer("pni", pni). + Msg("Failed to update contact") + } + case *signalpb.StorageRecord_GroupV2: + if len(data.GroupV2.MasterKey) != libsignalgo.GroupMasterKeyLength { + log.Warn().Msg("Invalid group master key length") + continue + } + masterKey := libsignalgo.GroupMasterKey(data.GroupV2.MasterKey) + groupID, err := cli.StoreMasterKey(ctx, masterKeyFromBytes(masterKey)) + if err != nil { + log.Err(err).Msg("Failed to store group master key from storage service") + } else { + log.Debug().Stringer("group_id", groupID).Msg("Stored group master key from storage service") + } + case *signalpb.StorageRecord_Account: + log.Trace().Any("account_record", data.Account).Msg("Found account record") + // There's probably some useful data here + case *signalpb.StorageRecord_GroupV1, *signalpb.StorageRecord_StoryDistributionList: + // irrelevant data + default: + log.Warn().Str("type", fmt.Sprintf("%T", data)).Msg("Unknown storage record type") + } + } } type StorageUpdate struct { From 71a164501f8f7a68baa5d06604ed0208f855dad4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 22:40:01 +0200 Subject: [PATCH 126/718] Fix typo in query --- pkg/signalmeow/store/prekey_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/store/prekey_store.go b/pkg/signalmeow/store/prekey_store.go index 59a3373..9999aad 100644 --- a/pkg/signalmeow/store/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -58,7 +58,7 @@ const ( getLastPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_signed=$3` getAllKyberPreKeysQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_last_resort=false` - getKyberPreKeyQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$2` + getKyberPreKeyQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` insertKyberPreKeyQuery = `INSERT INTO signalmeow_kyber_pre_keys (account_id, service_id, key_id, key_pair, is_last_resort) VALUES ($1, $2, $3, $4, $5)` deleteKyberPreKeyQuery = `DELETE FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` getLastKyberPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2` From 5fe7d54a6ac3f942c988cb8b92bb826cea775ad9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 22:42:07 +0200 Subject: [PATCH 127/718] Fix bugs in portal re-id'ing --- user.go | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/user.go b/user.go index 624a121..7a622af 100644 --- a/user.go +++ b/user.go @@ -765,6 +765,7 @@ func (user *User) handleACIFound(evt *events.ACIFound) { Stringer("aci", evt.ACI.UUID). Stringer("pni", evt.PNI.UUID). Logger() + log.Debug().Msg("Handling ACI found event") ctx := log.WithContext(context.TODO()) user.bridge.portalsLock.Lock() defer user.bridge.portalsLock.Unlock() @@ -772,13 +773,14 @@ func (user *User) handleACIFound(evt *events.ACIFound) { ChatID: evt.PNI.String(), Receiver: user.SignalID, }, false) - pniPortal.roomCreateLock.Lock() - defer pniPortal.roomCreateLock.Unlock() if pniPortal == nil { log.Debug().Msg("PNI portal doesn't exist, ignoring event") return - } else if pniPortal.MXID == "" { - log.Debug().Msg("PNI portal doesn't have Matrix room, deleting row") + } + pniPortal.roomCreateLock.Lock() + defer pniPortal.roomCreateLock.Unlock() + if pniPortal.MXID == "" { + log.Info().Msg("PNI portal doesn't have Matrix room, deleting row") pniPortal.Delete() return } @@ -789,26 +791,32 @@ func (user *User) handleACIFound(evt *events.ACIFound) { ChatID: evt.ACI.String(), Receiver: user.SignalID, }, false) - aciPortal.roomCreateLock.Lock() - defer aciPortal.roomCreateLock.Unlock() if aciPortal == nil { - log.Debug().Msg("ACI portal doesn't exist, re-ID'ing PNI portal") + log.Info().Msg("ACI portal doesn't exist, re-ID'ing PNI portal") err := pniPortal.unlockedReID(ctx, evt.ACI.String()) if err != nil { log.Err(err).Msg("Failed to re-ID PNI portal") + } else { + pniPortal.UpdateDMInfo(ctx, true) } - } else if aciPortal.MXID == "" { - log.Debug().Msg("ACI portal row exists, but doesn't have a Matrix room. Deleting ACI portal row and re-ID'ing PNI portal") + return + } + aciPortal.roomCreateLock.Lock() + defer aciPortal.roomCreateLock.Unlock() + if aciPortal.MXID == "" { + log.Info().Msg("ACI portal row exists, but doesn't have a Matrix room. Deleting ACI portal row and re-ID'ing PNI portal") aciPortal.Delete() err := pniPortal.unlockedReID(ctx, evt.ACI.String()) if err != nil { log.Err(err).Msg("Failed to re-ID PNI portal") + } else { + pniPortal.UpdateDMInfo(ctx, true) } } else { log.UpdateContext(func(c zerolog.Context) zerolog.Context { return c.Stringer("aci_portal_mxid", aciPortal.MXID) }) - log.Debug().Msg("Both ACI and PNI portal have Matrix room, tombstoning PNI portal") + log.Info().Msg("Both ACI and PNI portal have Matrix room, tombstoning PNI portal") _, err := pniPortal.MainIntent().SendStateEvent(ctx, pniPortal.MXID, event.StateTombstone, "", &event.TombstoneEventContent{ Body: fmt.Sprintf("This room has been merged"), ReplacementRoom: aciPortal.MXID, From b304be1510d3a0e4c69c319d5b32a8f25946b190 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Mar 2024 23:00:34 +0200 Subject: [PATCH 128/718] Fix more things --- pkg/signalmeow/contact.go | 4 +++- pkg/signalmeow/contactdiscovery.go | 2 -- portal.go | 12 ++++++++++++ user.go | 8 ++++++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index 546b02d..a8e8285 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -46,7 +46,9 @@ func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDeta Stringer("uuid", parsedUUID). Logger().WithContext(ctx) return cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, parsedUUID, uuid.Nil, func(recipient *types.Recipient) (bool, error) { - recipient.E164 = contactDetails.GetNumber() + if contactDetails.GetNumber() != "" { + recipient.E164 = contactDetails.GetNumber() + } recipient.ContactName = contactDetails.GetName() if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { profileKey := libsignalgo.ProfileKey(profileKeyString) diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index 5d5bce2..660439c 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -86,8 +86,6 @@ func (cli *Client) LookupPhone(ctx context.Context, e164s ...uint64) (ContactDis // (it's meant for old_e164s) //Token: cli.cdToken, NewE164S: requestData, - - ReturnAcisWithoutUaks: proto.Bool(true), }) if token != nil { cli.cdToken = token diff --git a/portal.go b/portal.go index 6dcb3b3..a1214b7 100644 --- a/portal.go +++ b/portal.go @@ -1839,6 +1839,18 @@ func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *s const PrivateChatTopic = "Signal private chat" const NoteToSelfName = "Signal Note to Self" +func (portal *Portal) PostReIDUpdate(ctx context.Context, user *User) { + _, err := portal.bridge.Bot.SetPowerLevel(ctx, portal.MXID, portal.MainIntent().UserID, 100) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update ghost power level after portal re-ID") + } + portal.GetDMPuppet().UpdateInfo(ctx, user) + portal.UpdateDMInfo(ctx, true) + if !portal.Encrypted { + _, _ = portal.bridge.Bot.LeaveRoom(ctx, portal.MXID) + } +} + func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { log := zerolog.Ctx(ctx).With(). Str("function", "UpdateDMInfo"). diff --git a/user.go b/user.go index 7a622af..064c896 100644 --- a/user.go +++ b/user.go @@ -797,7 +797,7 @@ func (user *User) handleACIFound(evt *events.ACIFound) { if err != nil { log.Err(err).Msg("Failed to re-ID PNI portal") } else { - pniPortal.UpdateDMInfo(ctx, true) + go pniPortal.PostReIDUpdate(ctx, user) } return } @@ -810,7 +810,7 @@ func (user *User) handleACIFound(evt *events.ACIFound) { if err != nil { log.Err(err).Msg("Failed to re-ID PNI portal") } else { - pniPortal.UpdateDMInfo(ctx, true) + go pniPortal.PostReIDUpdate(ctx, user) } } else { log.UpdateContext(func(c zerolog.Context) zerolog.Context { @@ -837,6 +837,10 @@ func (portal *Portal) unlockedReID(ctx context.Context, newID string) error { delete(portal.bridge.portalsByID, portal.PortalKey) portal.PortalKey.ChatID = newID portal.bridge.portalsByID[portal.PortalKey] = portal + err = portal.MainIntent().EnsureJoined(ctx, portal.MXID, appservice.EnsureJoinedParams{IgnoreCache: true}) + if err != nil { + return fmt.Errorf("failed to ensure ghost is joined to portal: %w", err) + } return nil } From 4fb5100f8db13216429730742388227f8d8e0bd4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 15:17:41 +0200 Subject: [PATCH 129/718] Fetch ACI from store after finding PNI in provisioning API too --- provisioning.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/provisioning.go b/provisioning.go index ac38b99..211bd46 100644 --- a/provisioning.go +++ b/provisioning.go @@ -38,6 +38,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) type provisioningContextKey int @@ -171,20 +172,25 @@ func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, } e164String := fmt.Sprintf("+%d", e164Number) var aci, pni uuid.UUID - if contact, err := user.Client.ContactByE164(ctx, e164String); err != nil { + var recipient *types.Recipient + if recipient, err = user.Client.ContactByE164(ctx, e164String); err != nil { return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number in local contact list: %w", err) - } else if contact != nil { - aci = contact.ACI - pni = contact.PNI + } else if recipient != nil { + aci = recipient.ACI + pni = recipient.PNI } else if resp, err := user.Client.LookupPhone(ctx, e164Number); err != nil { return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number on server: %w", err) } else { aci = resp[e164Number].ACI pni = resp[e164Number].PNI - user.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) - } - if aci == uuid.Nil && pni == uuid.Nil { - return http.StatusNotFound, nil, errors.New("user not found on Signal") + if aci == uuid.Nil && pni == uuid.Nil { + return http.StatusNotFound, nil, errors.New("user not found on Signal") + } + recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI } zerolog.Ctx(ctx).Debug(). Uint64("e164", e164Number). From e1cf5b76b0102a681b185ce95ba30b3ee079c64b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 15:18:25 +0200 Subject: [PATCH 130/718] Add PNI signature to next sent message after receiving to PNI --- pkg/signalmeow/receiving.go | 14 +++++++ pkg/signalmeow/sending.go | 38 ++++++++++++++++++- pkg/signalmeow/store/recipient_store.go | 13 +++++-- pkg/signalmeow/store/upgrades/00-latest.sql | 3 +- .../store/upgrades/15-needs-pni-signature.sql | 2 + pkg/signalmeow/types/contact.go | 2 + 6 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/15-needs-pni-signature.sql diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 5e74a39..23ccaf4 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -615,6 +615,20 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. }, nil } + if destinationServiceID == cli.Store.PNIServiceID() { + _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { + if !recipient.NeedsPNISignature { + log.Debug().Msg("Marking recipient as needing PNI signature") + recipient.NeedsPNISignature = true + return true, nil + } + return false, nil + }) + if err != nil { + log.Err(err).Msg("Failed to set needs_pni_signature flag after receiving message to PNI service ID") + } + } + if content.GetPniSignatureMessage() != nil { log.Debug().Msg("Content includes PNI signature message") err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.GetPniSignatureMessage()) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 68e311d..f60310f 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -168,8 +168,6 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg cli.encryptionLock.Lock() defer cli.encryptionLock.Unlock() - messages := []MyMessage{} - addresses, sessionRecords, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) if err == nil && (len(addresses) == 0 || len(sessionRecords) == 0) { // No sessions, make one with prekey @@ -184,6 +182,7 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg return nil, err } + messages := make([]MyMessage, 0, len(addresses)) for i, recipientAddress := range addresses { recipientDeviceID, err := recipientAddress.DeviceID() if err != nil { @@ -667,6 +666,41 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } else { messageTimestamp = currentMessageTimestamp() } + needsPNISignature := false + if recipientID.Type == libsignalgo.ServiceIDTypeACI { + _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, recipientID.UUID, uuid.Nil, func(recipientData *types.Recipient) (changed bool, err error) { + if recipientData.NeedsPNISignature { + needsPNISignature = true + zerolog.Ctx(ctx).Debug(). + Stringer("recipient", recipientID). + Msg("Including PNI identity in message") + sig, err := cli.Store.PNIIdentityKeyPair.SignAlternateIdentity(cli.Store.ACIIdentityKeyPair.GetIdentityKey()) + if err != nil { + return false, err + } + recipientData.NeedsPNISignature = false + content.PniSignatureMessage = &signalpb.PniSignatureMessage{ + Pni: cli.Store.PNI[:], + Signature: sig, + } + return true, nil + } + return false, nil + }) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to add PNI signature to message") + } + } + // Treat needs PNI signature as "this is a message request" and don't send receipts/typing + if needsPNISignature && (content.TypingMessage != nil || content.ReceiptMessage != nil) { + zerolog.Ctx(ctx).Debug().Msg("Not sending typing/receipt message to recipient as needs PNI signature flag is set") + res := &SuccessfulSendResult{Recipient: recipientID} + if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { + // Still send sync messages for read receipts + cli.sendSyncCopy(ctx, content, messageTimestamp, res) + } + return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} + } isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY if recipientID == cli.Store.ACIServiceID() && !isDeliveryReceipt { diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index b507dda..216dfc8 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -57,7 +57,8 @@ const ( profile_about, profile_about_emoji, profile_avatar_path, - profile_fetched_at + profile_fetched_at, + needs_pni_signature FROM signalmeow_recipients WHERE account_id = $1 ` @@ -79,9 +80,10 @@ const ( profile_about, profile_about_emoji, profile_avatar_path, - profile_fetched_at + profile_fetched_at, + needs_pni_signature ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) ON CONFLICT (account_id, aci_uuid) DO UPDATE SET pni_uuid = excluded.pni_uuid, e164_number = excluded.e164_number, @@ -92,7 +94,8 @@ const ( profile_about = excluded.profile_about, profile_about_emoji = excluded.profile_about_emoji, profile_avatar_path = excluded.profile_avatar_path, - profile_fetched_at = excluded.profile_fetched_at + profile_fetched_at = excluded.profile_fetched_at, + needs_pni_signature = excluded.needs_pni_signature ` upsertPNIRecipientQuery = ` INSERT INTO signalmeow_recipients ( @@ -127,6 +130,7 @@ func scanRecipient(row dbutil.Scannable) (*types.Recipient, error) { &recipient.Profile.AboutEmoji, &recipient.Profile.AvatarPath, &profileFetchedAt, + &recipient.NeedsPNISignature, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -300,6 +304,7 @@ func (s *sqlStore) StoreRecipient(ctx context.Context, recipient *types.Recipien recipient.Profile.AboutEmoji, recipient.Profile.AvatarPath, dbutil.UnixMilliPtr(recipient.Profile.FetchedAt), + recipient.NeedsPNISignature, ) } else if recipient.PNI != uuid.Nil { _, err = s.db.Exec( diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 9dff754..bd376bb 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v14 (compatible with v13+): Latest revision +-- v0 -> v15 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -100,6 +100,7 @@ CREATE TABLE signalmeow_recipients ( profile_about_emoji TEXT NOT NULL DEFAULT '', profile_avatar_path TEXT NOT NULL DEFAULT '', profile_fetched_at BIGINT, + needs_pni_signature BOOLEAN NOT NULL DEFAULT false, CONSTRAINT signalmeow_contacts_account_id_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE, diff --git a/pkg/signalmeow/store/upgrades/15-needs-pni-signature.sql b/pkg/signalmeow/store/upgrades/15-needs-pni-signature.sql new file mode 100644 index 0000000..26d854a --- /dev/null +++ b/pkg/signalmeow/store/upgrades/15-needs-pni-signature.sql @@ -0,0 +1,2 @@ +-- v15 (compatible with v13+): Store flag for recipients who need a PNI signature +ALTER TABLE signalmeow_recipients ADD COLUMN needs_pni_signature boolean DEFAULT false; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index 29cf8c0..fea6fa5 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -52,6 +52,8 @@ type Recipient struct { ContactName string ContactAvatar ContactAvatar Profile Profile + + NeedsPNISignature bool } type ContactAvatar struct { From f77a9a87175fa8a72d3c783c2a3893dc0c138d9e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 17:50:35 +0200 Subject: [PATCH 131/718] Partially fix time handling in SendContactSyncRequest --- pkg/signalmeow/client.go | 3 ++- pkg/signalmeow/sending.go | 14 ++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 6757316..f311e9a 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -21,6 +21,7 @@ import ( "errors" "net/url" "sync" + "time" "github.com/rs/zerolog" @@ -38,7 +39,7 @@ type Client struct { GroupCache *GroupCache ProfileCache *ProfileCache GroupCallCache *map[string]bool - LastContactRequestTime *int64 + LastContactRequestTime time.Time encryptionLock sync.Mutex diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index f60310f..30c2d44 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -407,24 +407,19 @@ func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *sign } func (cli *Client) SendContactSyncRequest(ctx context.Context) error { - if cli.LastContactRequestTime == nil { - cli.LastContactRequestTime = new(int64) - } - currentUnixTime := time.Now().Unix() log := zerolog.Ctx(ctx).With(). Str("action", "send contact sync request"). - Int64("current_unix_time", currentUnixTime). - Int64("last_request_time", *cli.LastContactRequestTime). - Int64("seconds_since_last_request", currentUnixTime-*cli.LastContactRequestTime). + Time("last_request_time", cli.LastContactRequestTime). Logger() ctx = log.WithContext(ctx) // If we've requested in the last minute, don't request again - if cli.LastContactRequestTime != nil && currentUnixTime-*cli.LastContactRequestTime < 60 { + if time.Since(cli.LastContactRequestTime) < 60*time.Second { log.Warn().Msg("Not sending contact sync request because we already requested it in the past minute") return nil } - _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(currentUnixTime), &signalpb.Content{ + cli.LastContactRequestTime = time.Now() + _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Request: &signalpb.SyncMessage_Request{ Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), @@ -435,7 +430,6 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { log.Err(err).Msg("Failed to send contact sync request message to myself") return err } - cli.LastContactRequestTime = ¤tUnixTime return nil } From 51617d3030780cf31b5f09e9a3099944a2163648 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 19:48:36 +0200 Subject: [PATCH 132/718] Don't clear keys on decryption errors --- pkg/signalmeow/receiving.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 23ccaf4..33887a7 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -244,24 +244,6 @@ func (cli *Client) ClearKeysAndDisconnect(ctx context.Context) error { return stopLoopErr } -// If a bridge can't decrypt prekeys, it's probably because the prekeys are broken so force re-registration -func (cli *Client) checkDecryptionErrorAndDisconnect(ctx context.Context, err error) { - if err == nil { - return - } - log := zerolog.Ctx(ctx).With().Str("action", "check decryption error and disconnect").Logger() - if strings.Contains(err.Error(), "70: invalid signed prekey identifier") { - log.Warn().Msg("Failed decrypting a SignedPreKey message, invalid signed prekey identifier") - } - if strings.Contains(err.Error(), "30: invalid PreKey message: decryption failed") { - log.Warn().Msg("Failed decrypting a PreKey message, probably our prekeys are broken, force re-registration") - disconnectErr := cli.ClearKeysAndDisconnect(ctx) - if disconnectErr != nil { - log.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") - } - } -} - func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { log := zerolog.Ctx(ctx).With(). Str("handler", "incoming request handler"). @@ -478,7 +460,6 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Debug().Msg("Message sent by us, ignoring") } else { log.Err(err).Msg("sealedSenderDecrypt error") - cli.checkDecryptionErrorAndDisconnect(ctx, err) } } else { log.Trace(). @@ -499,7 +480,6 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) if err != nil { log.Err(err).Msg("prekeyDecrypt error") - cli.checkDecryptionErrorAndDisconnect(ctx, err) } else { log.Trace(). Any("sender_address", result.SenderAddress). From b57710aa8f023927955c3ffdc9f8c1261b28fd9e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 20:55:46 +0200 Subject: [PATCH 133/718] Improve some log lines --- pkg/signalmeow/receiving.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 33887a7..0a7ea58 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -383,14 +383,14 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. log.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") result, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) if err != nil { - log.Err(err).Msg("prekeyDecrypt error") + log.Err(err).Msg("Sealed sender prekey ciphertext decryption error") } case libsignalgo.CiphertextMessageTypeWhisper: log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeWhisper") message, err := libsignalgo.DeserializeMessage(usmcContents) if err != nil { - log.Err(err).Msg("DeserializeMessage error") + log.Err(err).Msg("Sealed sender whisper deserialize error") } decryptedText, err := libsignalgo.Decrypt( ctx, @@ -400,7 +400,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. cli.Store.IdentityStore, ) if err != nil { - log.Err(err).Msg("Sealed sender Whisper Decryption error") + log.Err(err).Msg("Sealed sender whisper decryption error") } else { err = stripPadding(&decryptedText) if err != nil { @@ -479,12 +479,12 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) if err != nil { - log.Err(err).Msg("prekeyDecrypt error") + log.Err(err).Msg("Prekey bundle decryption error") } else { log.Trace(). Any("sender_address", result.SenderAddress). Any("content", result.Content). - Msg("prekey decrypt result") + Msg("Prekey bundle decryption result") } case signalpb.Envelope_PLAINTEXT_CONTENT: From 14a6adc5a27fc40a77cc0246472edca813141d49 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 21:25:00 +0200 Subject: [PATCH 134/718] Fix identity store being hardcoded to ACIs --- pkg/signalmeow/keys.go | 2 +- pkg/signalmeow/provisioning.go | 24 +++++++-------- pkg/signalmeow/receiving.go | 22 +++++++++----- pkg/signalmeow/sending.go | 4 +-- pkg/signalmeow/store/container.go | 16 ++++++++-- pkg/signalmeow/store/device.go | 25 +++++++++++----- pkg/signalmeow/store/identity_store.go | 41 ++++++++++++++------------ 7 files changed, 83 insertions(+), 51 deletions(-) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 645f02e..ac4a3b2 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -428,7 +428,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib preKeyBundle, address, cli.Store.ACISessionStore, - cli.Store.IdentityStore, + cli.Store.ACIIdentityStore, ) if err != nil { return fmt.Errorf("error processing prekey bundle: %w", err) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 3fe1988..95d0a77 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -123,8 +123,8 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev username := *provisioningMessage.Number password := random.String(22) code := provisioningMessage.ProvisioningCode - registrationId := mrand.Intn(16383) + 1 - pniRegistrationId := mrand.Intn(16383) + 1 + aciRegistrationID := mrand.Intn(16383) + 1 + pniRegistrationID := mrand.Intn(16383) + 1 aciSignedPreKey := GenerateSignedPreKey(1, aciIdentityKeyPair) pniSignedPreKey := GenerateSignedPreKey(1, pniIdentityKeyPair) aciPQLastResortPreKey := GenerateKyberPreKeys(1, 1, aciIdentityKeyPair)[0] @@ -134,8 +134,8 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev username, password, *code, - registrationId, - pniRegistrationId, + aciRegistrationID, + pniRegistrationID, aciSignedPreKey, pniSignedPreKey, aciPQLastResortPreKey, @@ -157,8 +157,8 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev data := &store.DeviceData{ ACIIdentityKeyPair: aciIdentityKeyPair, PNIIdentityKeyPair: pniIdentityKeyPair, - RegistrationID: registrationId, - PNIRegistrationID: pniRegistrationId, + ACIRegistrationID: aciRegistrationID, + PNIRegistrationID: pniRegistrationID, ACI: deviceResponse.ACI, PNI: deviceResponse.PNI, DeviceID: deviceId, @@ -185,7 +185,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev device.ClearDeviceKeys(ctx) // Store identity keys? - _, err = device.IdentityStore.SaveIdentityKey(ctx, device.ACIServiceID(), device.ACIIdentityKeyPair.GetIdentityKey()) + _, err = device.IdentityKeyStore.SaveIdentityKey(ctx, device.ACIServiceID(), device.ACIIdentityKeyPair.GetIdentityKey()) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, @@ -193,7 +193,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev } return } - _, err = device.IdentityStore.SaveIdentityKey(ctx, device.PNIServiceID(), device.PNIIdentityKeyPair.GetIdentityKey()) + _, err = device.IdentityKeyStore.SaveIdentityKey(ctx, device.PNIServiceID(), device.PNIIdentityKeyPair.GetIdentityKey()) if err != nil { c <- ProvisioningResponse{ State: StateProvisioningError, @@ -335,8 +335,8 @@ func confirmDevice( username string, password string, code string, - registrationId int, - pniRegistrationId int, + aciRegistrationID int, + pniRegistrationID int, aciSignedPreKey *libsignalgo.SignedPreKeyRecord, pniSignedPreKey *libsignalgo.SignedPreKeyRecord, aciPQLastResortPreKey *libsignalgo.KyberPreKeyRecord, @@ -369,8 +369,8 @@ func confirmDevice( "accountAttributes": map[string]any{ "fetchesMessages": true, "name": encryptedDeviceName, - "registrationId": registrationId, - "pniRegistrationId": pniRegistrationId, + "registrationId": aciRegistrationID, + "pniRegistrationId": pniRegistrationID, "capabilities": map[string]any{ "pni": true, }, diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 0a7ea58..55a44e8 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -299,7 +299,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. usmc, err := libsignalgo.SealedSenderDecryptToUSMC( ctx, envelope.GetContent(), - cli.Store.IdentityStore, + cli.Store.ACIIdentityStore, ) if err != nil || usmc == nil { if err == nil { @@ -397,7 +397,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. message, senderAddress, cli.Store.ACISessionStore, - cli.Store.IdentityStore, + cli.Store.ACIIdentityStore, ) if err != nil { log.Err(err).Msg("Sealed sender whisper decryption error") @@ -505,12 +505,16 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. if sessionStore == nil { return nil, fmt.Errorf("no session store for destination service ID %s", destinationServiceID) } + identityStore := cli.Store.IdentityStore(destinationServiceID) + if identityStore == nil { + return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) + } decryptedText, err := libsignalgo.Decrypt( ctx, message, senderAddress, sessionStore, - cli.Store.IdentityStore, + identityStore, ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { @@ -825,13 +829,13 @@ func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsign } pni := uuid.UUID(pniBytes) pniServiceID := libsignalgo.NewPNIServiceID(pni) - pniIdentity, err := cli.Store.IdentityStore.GetIdentityKey(ctx, pniServiceID) + pniIdentity, err := cli.Store.IdentityKeyStore.GetIdentityKey(ctx, pniServiceID) if err != nil { return fmt.Errorf("failed to get identity for PNI %s: %w", pni, err) } else if pniIdentity == nil { return fmt.Errorf("identity not found for PNI %s", pni) } - aciIdentity, err := cli.Store.IdentityStore.GetIdentityKey(ctx, sender) + aciIdentity, err := cli.Store.IdentityKeyStore.GetIdentityKey(ctx, sender) if err != nil { return fmt.Errorf("failed to get identity for ACI %s: %w", sender, err) } else if aciIdentity == nil { @@ -973,7 +977,7 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E prodServerTrustRootKey, timestamp, cli.Store.ACISessionStore, - cli.Store.IdentityStore, + cli.Store.ACIIdentityStore, cli.Store.ACIPreKeyStore, cli.Store.ACIPreKeyStore, ) @@ -1016,13 +1020,17 @@ func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.Se if ss == nil { return nil, fmt.Errorf("no session store found for %s", destination) } + is := cli.Store.IdentityStore(destination) + if is == nil { + return nil, fmt.Errorf("no identity store found for %s", destination) + } data, err := libsignalgo.DecryptPreKey( ctx, preKeyMessage, sender, ss, - cli.Store.IdentityStore, + is, pks, pks, pks, diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 30c2d44..2245cff 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -241,7 +241,7 @@ func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddres paddedMessage, recipientAddress, cli.Store.ACISessionStore, - cli.Store.IdentityStore, + cli.Store.ACIIdentityStore, ) if err != nil { return 0, nil, err @@ -274,7 +274,7 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l recipientAddress, cert, cli.Store.ACISessionStore, - cli.Store.IdentityStore, + cli.Store.ACIIdentityStore, ) if err != nil { return 0, nil, err diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 4f6efff..d649b92 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -49,7 +49,7 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { var aciIdentityKeyPair, pniIdentityKeyPair []byte err := row.Scan( - &device.ACI, &aciIdentityKeyPair, &device.RegistrationID, + &device.ACI, &aciIdentityKeyPair, &device.ACIRegistrationID, &device.PNI, &pniIdentityKeyPair, &device.PNIRegistrationID, &device.DeviceID, &device.Number, &device.Password, &device.MasterKey, ) @@ -72,7 +72,17 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.PNIPreKeyStore = pniStore device.ACISessionStore = aciStore device.PNISessionStore = pniStore - device.IdentityStore = baseStore + device.ACIIdentityStore = &sqlIdentityStore{ + sqlStore: baseStore, + OwnKeyPair: device.ACIIdentityKeyPair, + LocalRegistrationID: uint32(device.ACIRegistrationID), + } + device.PNIIdentityStore = &sqlIdentityStore{ + sqlStore: baseStore, + OwnKeyPair: device.PNIIdentityKeyPair, + LocalRegistrationID: uint32(device.PNIRegistrationID), + } + device.IdentityKeyStore = baseStore device.SenderKeyStore = baseStore device.GroupStore = baseStore device.RecipientStore = baseStore @@ -150,7 +160,7 @@ func (c *Container) PutDevice(ctx context.Context, device *DeviceData) error { return err } _, err = c.db.Exec(ctx, insertDeviceQuery, - device.ACI, aciIdentityKeyPair, device.RegistrationID, + device.ACI, aciIdentityKeyPair, device.ACIRegistrationID, device.PNI, pniIdentityKeyPair, device.PNIRegistrationID, device.DeviceID, device.Number, device.Password, device.MasterKey, ) diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index e07feb5..2c8d54a 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -27,7 +27,7 @@ type scopedSQLStore struct { type DeviceData struct { ACIIdentityKeyPair *libsignalgo.IdentityKeyPair PNIIdentityKeyPair *libsignalgo.IdentityKeyPair - RegistrationID int + ACIRegistrationID int PNIRegistrationID int ACI uuid.UUID PNI uuid.UUID @@ -60,12 +60,14 @@ type Device struct { // (search for "innerStore" further down in this file) // libsignalgo store interfaces - ACIPreKeyStore PreKeyStore - PNIPreKeyStore PreKeyStore - ACISessionStore SessionStore - PNISessionStore SessionStore - IdentityStore libsignalgo.IdentityKeyStore - SenderKeyStore libsignalgo.SenderKeyStore + ACIPreKeyStore PreKeyStore + PNIPreKeyStore PreKeyStore + ACISessionStore SessionStore + PNISessionStore SessionStore + ACIIdentityStore libsignalgo.IdentityKeyStore + PNIIdentityStore libsignalgo.IdentityKeyStore + IdentityKeyStore IdentityKeyStore + SenderKeyStore libsignalgo.SenderKeyStore GroupStore GroupStore RecipientStore RecipientStore @@ -115,3 +117,12 @@ func (d *Device) SessionStore(serviceID libsignalgo.ServiceID) SessionStore { } return nil } + +func (d *Device) IdentityStore(serviceID libsignalgo.ServiceID) libsignalgo.IdentityKeyStore { + if serviceID == d.ACIServiceID() { + return d.ACIIdentityStore + } else if serviceID == d.PNIServiceID() { + return d.PNIIdentityStore + } + return nil +} diff --git a/pkg/signalmeow/store/identity_store.go b/pkg/signalmeow/store/identity_store.go index a64af0a..3b2435d 100644 --- a/pkg/signalmeow/store/identity_store.go +++ b/pkg/signalmeow/store/identity_store.go @@ -27,12 +27,24 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -var _ libsignalgo.IdentityKeyStore = (*sqlStore)(nil) +type sqlIdentityStore struct { + *sqlStore + + OwnKeyPair *libsignalgo.IdentityKeyPair + LocalRegistrationID uint32 +} + +type IdentityKeyStore interface { + SaveIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey) (bool, error) + GetIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID) (*libsignalgo.IdentityKey, error) + IsTrustedIdentity(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey, direction libsignalgo.SignalDirection) (bool, error) +} + +var _ libsignalgo.IdentityKeyStore = (*sqlIdentityStore)(nil) +var _ IdentityKeyStore = (*sqlStore)(nil) const ( - getIdentityKeyPairQuery = `SELECT aci_identity_key_pair FROM signalmeow_device WHERE aci_uuid=$1` - getRegistrationLocalIDQuery = `SELECT registration_id FROM signalmeow_device WHERE aci_uuid=$1` - insertIdentityKeyQuery = ` + insertIdentityKeyQuery = ` INSERT INTO signalmeow_identity_keys (account_id, their_service_id, key, trust_level) VALUES ($1, $2, $3, $4) ON CONFLICT (account_id, their_service_id) DO UPDATE @@ -48,27 +60,18 @@ const ( ` ) -func scanIdentityKeyPair(row dbutil.Scannable) (*libsignalgo.IdentityKeyPair, error) { - return scanRecord(row, libsignalgo.DeserializeIdentityKeyPair) +func (s *sqlIdentityStore) GetIdentityKeyPair(ctx context.Context) (*libsignalgo.IdentityKeyPair, error) { + return s.OwnKeyPair, nil +} + +func (s *sqlIdentityStore) GetLocalRegistrationID(ctx context.Context) (uint32, error) { + return s.LocalRegistrationID, nil } func scanIdentityKey(row dbutil.Scannable) (*libsignalgo.IdentityKey, error) { return scanRecord(row, libsignalgo.DeserializeIdentityKey) } -func (s *sqlStore) GetIdentityKeyPair(ctx context.Context) (*libsignalgo.IdentityKeyPair, error) { - return scanIdentityKeyPair(s.db.QueryRow(ctx, getIdentityKeyPairQuery, s.AccountID)) -} - -func (s *sqlStore) GetLocalRegistrationID(ctx context.Context) (uint32, error) { - var regID sql.NullInt64 - err := s.db.QueryRow(ctx, getRegistrationLocalIDQuery, s.AccountID).Scan(®ID) - if err != nil { - return 0, fmt.Errorf("failed to get local registration ID: %w", err) - } - return uint32(regID.Int64), nil -} - func (s *sqlStore) SaveIdentityKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, identityKey *libsignalgo.IdentityKey) (bool, error) { trustLevel := "TRUSTED_UNVERIFIED" // TODO: this should be hard coded here serialized, err := identityKey.Serialize() From 120eca6dc0320566fd3861605d0be73da8f334b1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 21:27:48 +0200 Subject: [PATCH 135/718] Fix locking in ACI found handler --- portal.go | 14 +++++++++++++- user.go | 27 ++++++++++++++++----------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/portal.go b/portal.go index a1214b7..b5be7f3 100644 --- a/portal.go +++ b/portal.go @@ -2460,6 +2460,19 @@ func (portal *Portal) Delete() { portal.log.Err(err).Msg("Failed to delete portal from db") } portal.bridge.portalsLock.Lock() + portal.unlockedDeleteCache() + portal.bridge.portalsLock.Unlock() +} + +func (portal *Portal) unlockedDelete() { + err := portal.Portal.Delete(context.TODO()) + if err != nil { + portal.log.Err(err).Msg("Failed to delete portal from db") + } + portal.unlockedDeleteCache() +} + +func (portal *Portal) unlockedDeleteCache() { delete(portal.bridge.portalsByID, portal.PortalKey) if len(portal.MXID) > 0 { delete(portal.bridge.portalsByMXID, portal.MXID) @@ -2476,7 +2489,6 @@ func (portal *Portal) Delete() { user.RemoveInSpaceCache(portal.PortalKey) } } - portal.bridge.portalsLock.Unlock() } func (portal *Portal) Cleanup(ctx context.Context, puppetsOnly bool) { diff --git a/user.go b/user.go index 064c896..db5bd4c 100644 --- a/user.go +++ b/user.go @@ -766,6 +766,9 @@ func (user *User) handleACIFound(evt *events.ACIFound) { Stringer("pni", evt.PNI.UUID). Logger() log.Debug().Msg("Handling ACI found event") + defer func() { + log.Debug().Msg("Finished handling ACI found event") + }() ctx := log.WithContext(context.TODO()) user.bridge.portalsLock.Lock() defer user.bridge.portalsLock.Unlock() @@ -781,7 +784,7 @@ func (user *User) handleACIFound(evt *events.ACIFound) { defer pniPortal.roomCreateLock.Unlock() if pniPortal.MXID == "" { log.Info().Msg("PNI portal doesn't have Matrix room, deleting row") - pniPortal.Delete() + pniPortal.unlockedDelete() return } log.UpdateContext(func(c zerolog.Context) zerolog.Context { @@ -805,7 +808,7 @@ func (user *User) handleACIFound(evt *events.ACIFound) { defer aciPortal.roomCreateLock.Unlock() if aciPortal.MXID == "" { log.Info().Msg("ACI portal row exists, but doesn't have a Matrix room. Deleting ACI portal row and re-ID'ing PNI portal") - aciPortal.Delete() + aciPortal.unlockedDelete() err := pniPortal.unlockedReID(ctx, evt.ACI.String()) if err != nil { log.Err(err).Msg("Failed to re-ID PNI portal") @@ -817,15 +820,17 @@ func (user *User) handleACIFound(evt *events.ACIFound) { return c.Stringer("aci_portal_mxid", aciPortal.MXID) }) log.Info().Msg("Both ACI and PNI portal have Matrix room, tombstoning PNI portal") - _, err := pniPortal.MainIntent().SendStateEvent(ctx, pniPortal.MXID, event.StateTombstone, "", &event.TombstoneEventContent{ - Body: fmt.Sprintf("This room has been merged"), - ReplacementRoom: aciPortal.MXID, - }) - if err != nil { - log.Err(err).Msg("Failed to send tombstone to PNI portal") - } - pniPortal.Delete() - pniPortal.Cleanup(ctx, err == nil) + pniPortal.unlockedDelete() + go func() { + _, err := pniPortal.MainIntent().SendStateEvent(ctx, pniPortal.MXID, event.StateTombstone, "", &event.TombstoneEventContent{ + Body: fmt.Sprintf("This room has been merged"), + ReplacementRoom: aciPortal.MXID, + }) + if err != nil { + log.Err(err).Msg("Failed to send tombstone to PNI portal") + } + pniPortal.Cleanup(ctx, err == nil) + }() } } From 6755cf449e2f7e134259d7ac142e2df0bcda6a32 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Mar 2024 21:28:53 +0200 Subject: [PATCH 136/718] Update roadmap link in readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 4e644f5..82e9624 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,7 @@ Some quick links: * Basic usage: [Authentication](https://docs.mau.fi/bridges/go/signal/authentication.html) ### Features & Roadmap -[ROADMAP.md](https://github.com/mautrix/signal/blob/main/ROADMAP.md) -contains a general overview of what is supported by the bridge. +[ROADMAP.md](ROADMAP.md) contains a general overview of what is supported by the bridge. ## Discussion Matrix room: [`#signal:maunium.net`](https://matrix.to/#/#signal:maunium.net) From ee0ef89f3c2e363cd1d57f2bb78251ac6d037929 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 26 Mar 2024 17:36:18 +0200 Subject: [PATCH 137/718] Include E164 and identity key in PNI sync messages --- pkg/libsignalgo/identitykey.go | 11 +++++ pkg/signalmeow/sending.go | 73 ++++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/pkg/libsignalgo/identitykey.go b/pkg/libsignalgo/identitykey.go index 7ac9ec2..796e575 100644 --- a/pkg/libsignalgo/identitykey.go +++ b/pkg/libsignalgo/identitykey.go @@ -41,6 +41,17 @@ func NewIdentityKeyFromBytes(bytes []byte) (*IdentityKey, error) { return &IdentityKey{publicKey: publicKey}, nil } +func (i *IdentityKey) TrySerialize() []byte { + if i == nil { + return nil + } + serialized, err := i.Serialize() + if err != nil { + return nil + } + return serialized +} + func (i *IdentityKey) Serialize() ([]byte, error) { return i.publicKey.Serialize() } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 2245cff..ea1eeb4 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -285,8 +285,10 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l } type SuccessfulSendResult struct { - Recipient libsignalgo.ServiceID - Unidentified bool + Recipient libsignalgo.ServiceID + RecipientE164 *string + Unidentified bool + DestinationIdentityKey *libsignalgo.IdentityKey } type FailedSendResult struct { Recipient libsignalgo.ServiceID @@ -349,12 +351,14 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ Message: dataMessage, + DestinationE164: result.RecipientE164, DestinationServiceId: proto.String(result.Recipient.String()), Timestamp: dataMessage.Timestamp, UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), - Unidentified: &result.Unidentified, + DestinationServiceId: proto.String(result.Recipient.String()), + Unidentified: &result.Unidentified, + DestinationIdentityKey: result.DestinationIdentityKey.TrySerialize(), }, }, }, @@ -367,12 +371,14 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ EditMessage: editMessage, + DestinationE164: result.RecipientE164, DestinationServiceId: proto.String(result.Recipient.String()), Timestamp: editMessage.DataMessage.Timestamp, UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), - Unidentified: &result.Unidentified, + DestinationServiceId: proto.String(result.Recipient.String()), + Unidentified: &result.Unidentified, + DestinationIdentityKey: result.DestinationIdentityKey.TrySerialize(), }, }, }, @@ -661,29 +667,33 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv messageTimestamp = currentMessageTimestamp() } needsPNISignature := false + var aci, pni uuid.UUID if recipientID.Type == libsignalgo.ServiceIDTypeACI { - _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, recipientID.UUID, uuid.Nil, func(recipientData *types.Recipient) (changed bool, err error) { - if recipientData.NeedsPNISignature { - needsPNISignature = true - zerolog.Ctx(ctx).Debug(). - Stringer("recipient", recipientID). - Msg("Including PNI identity in message") - sig, err := cli.Store.PNIIdentityKeyPair.SignAlternateIdentity(cli.Store.ACIIdentityKeyPair.GetIdentityKey()) - if err != nil { - return false, err - } - recipientData.NeedsPNISignature = false - content.PniSignatureMessage = &signalpb.PniSignatureMessage{ - Pni: cli.Store.PNI[:], - Signature: sig, - } - return true, nil + aci = recipientID.UUID + } else if recipientID.Type == libsignalgo.ServiceIDTypePNI { + pni = recipientID.UUID + } + recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { + if recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature { + needsPNISignature = true + zerolog.Ctx(ctx).Debug(). + Stringer("recipient", recipientID). + Msg("Including PNI identity in message") + sig, err := cli.Store.PNIIdentityKeyPair.SignAlternateIdentity(cli.Store.ACIIdentityKeyPair.GetIdentityKey()) + if err != nil { + return false, err } - return false, nil - }) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to add PNI signature to message") + recipientData.NeedsPNISignature = false + content.PniSignatureMessage = &signalpb.PniSignatureMessage{ + Pni: cli.Store.PNI[:], + Signature: sig, + } + return true, nil } + return false, nil + }) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get message recipient data") } // Treat needs PNI signature as "this is a message request" and don't send receipts/typing if needsPNISignature && (content.TypingMessage != nil || content.ReceiptMessage != nil) { @@ -727,6 +737,17 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv Unidentified: sentUnidentified, }, } + if recipientID.Type == libsignalgo.ServiceIDTypePNI { + result.DestinationIdentityKey, err = cli.Store.IdentityKeyStore.GetIdentityKey(ctx, recipientID) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to add PNI destination identity key to sync message") + } + if recipientData != nil && recipientData.E164 != "" { + result.RecipientE164 = &recipientData.E164 + } else { + zerolog.Ctx(ctx).Warn().Msg("No E164 number found for PNI sync message") + } + } cli.sendSyncCopy(ctx, content, messageTimestamp, result.SuccessfulSendResult) From 00f58da3d54e5056082dba3cdc70d59f790a3194 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 26 Mar 2024 18:11:59 +0200 Subject: [PATCH 138/718] Move keepalive log to debug level. Fixes #473 --- pkg/signalmeow/web/signalwebsocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index c827657..40e43e4 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -297,7 +297,7 @@ func (s *SignalWebsocket) connectLoop( loopCancel(fmt.Errorf("error sending keepalive: %w", err)) return } - log.Info().Msg("Sent keepalive") + log.Debug().Msg("Sent keepalive") case <-loopCtx.Done(): return } From 62ff03a169f0f56c5b71b09aa1cb4438027af404 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Apr 2024 01:39:04 +0300 Subject: [PATCH 139/718] Prevent prekey overflows --- pkg/signalmeow/keys.go | 132 ++++++++++++------ pkg/signalmeow/store/prekey_store.go | 28 ++-- .../store/upgrades/16-remove-extra-prekeys.go | 81 +++++++++++ 3 files changed, 185 insertions(+), 56 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index ac4a3b2..219697f 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -42,11 +42,11 @@ type GeneratedPreKeys struct { } func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, pks store.PreKeyStore) error { - _, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, pks) + _, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, pks, 0) if err != nil { return fmt.Errorf("failed to generate and save next prekey batch: %w", err) } - _, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks) + _, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks, 0) if err != nil { return fmt.Errorf("failed to generate and save next kyber prekey batch: %w", err) } @@ -106,43 +106,98 @@ func (cli *Client) RegisterAllPreKeys(ctx context.Context, pks store.PreKeyStore return err } -func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, pks store.PreKeyStore) ([]*libsignalgo.PreKeyRecord, error) { - nextPreKeyID, err := pks.GetNextPreKeyID(ctx) +func (cli *Client) GenerateAndSaveNextPreKeyBatch(ctx context.Context, pks store.PreKeyStore, serverCount int) (bool, error) { + storeCount, nextPreKeyID, err := pks.GetNextPreKeyID(ctx) if err != nil { - return nil, fmt.Errorf("failed to get next prekey ID: %w", err) + return false, fmt.Errorf("failed to get next prekey ID: %w", err) } - preKeys := GeneratePreKeys(nextPreKeyID, PREKEY_BATCH_SIZE) - for _, preKey := range preKeys { - err = pks.StorePreKey(ctx, 0, preKey) - if err != nil { - return nil, fmt.Errorf("failed to save prekey: %w", err) + if serverCount < PREKEY_BATCH_SIZE/2 { + if storeCount >= PREKEY_BATCH_SIZE { + zerolog.Ctx(ctx).Warn(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Store is full, but server is not, reuploading EC prekeys without generating more") + } else { + zerolog.Ctx(ctx).Info(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Generating and uploading EC prekeys") + } + } else if uint32(serverCount) > storeCount { + zerolog.Ctx(ctx).Warn(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Server has more EC prekeys than store, reuploading") + } else { + zerolog.Ctx(ctx).Debug(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("EC prekey count is good") + return false, nil + } + if storeCount < PREKEY_BATCH_SIZE { + preKeys := GeneratePreKeys(nextPreKeyID, PREKEY_BATCH_SIZE-storeCount) + for _, preKey := range preKeys { + err = pks.StorePreKey(ctx, 0, preKey) + if err != nil { + return false, fmt.Errorf("failed to save prekey: %w", err) + } } } - return preKeys, nil + return true, nil } -func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, pks store.PreKeyStore) ([]*libsignalgo.KyberPreKeyRecord, error) { +func (cli *Client) GenerateAndSaveNextKyberPreKeyBatch(ctx context.Context, pks store.PreKeyStore, serverCount int) (bool, error) { var identityKeyPair *libsignalgo.IdentityKeyPair if pks.GetServiceID().Type == libsignalgo.ServiceIDTypePNI { identityKeyPair = cli.Store.PNIIdentityKeyPair } else { identityKeyPair = cli.Store.ACIIdentityKeyPair } - nextKyberPreKeyID, err := pks.GetNextKyberPreKeyID(ctx) + storeCount, nextKyberPreKeyID, err := pks.GetNextKyberPreKeyID(ctx) if err != nil { - return nil, fmt.Errorf("failed to get next kyber prekey ID: %w", err) + return false, fmt.Errorf("failed to get next kyber prekey ID: %w", err) } - kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, PREKEY_BATCH_SIZE, identityKeyPair) - for _, kyberPreKey := range kyberPreKeys { - err = pks.StoreKyberPreKey(ctx, 0, kyberPreKey) - if err != nil { - return nil, fmt.Errorf("failed to save kyber prekey: %w", err) + if serverCount < PREKEY_BATCH_SIZE/2 { + if storeCount >= PREKEY_BATCH_SIZE { + zerolog.Ctx(ctx).Warn(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Store is full, but server is not, reuploading kyber prekeys without generating more") + } else { + zerolog.Ctx(ctx).Info(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Generating and uploading kyber prekeys") + } + } else if uint32(serverCount) > storeCount { + zerolog.Ctx(ctx).Warn(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Server has more kyber prekeys than store, reuploading") + } else { + zerolog.Ctx(ctx).Debug(). + Int("server_count", serverCount). + Uint32("store_count", storeCount). + Msg("Kyber prekey count is good") + return false, nil + } + if storeCount < PREKEY_BATCH_SIZE { + kyberPreKeys := GenerateKyberPreKeys(nextKyberPreKeyID, PREKEY_BATCH_SIZE-storeCount, identityKeyPair) + for _, kyberPreKey := range kyberPreKeys { + err = pks.StoreKyberPreKey(ctx, 0, kyberPreKey) + if err != nil { + return false, fmt.Errorf("failed to save kyber prekey: %w", err) + } } } - return kyberPreKeys, nil + return true, nil } func GeneratePreKeys(startKeyID uint32, count uint32) []*libsignalgo.PreKeyRecord { + if count > PREKEY_BATCH_SIZE { + panic("count must be less than or equal to PREKEY_BATCH_SIZE") + } generatedPreKeys := make([]*libsignalgo.PreKeyRecord, 0, count) for keyID := startKeyID; keyID < startKeyID+count; keyID++ { privateKey, err := libsignalgo.GeneratePrivateKey() @@ -159,6 +214,9 @@ func GeneratePreKeys(startKeyID uint32, count uint32) []*libsignalgo.PreKeyRecor } func GenerateKyberPreKeys(startKeyID uint32, count uint32, identityKeyPair *libsignalgo.IdentityKeyPair) []*libsignalgo.KyberPreKeyRecord { + if count > PREKEY_BATCH_SIZE { + panic("count must be less than or equal to PREKEY_BATCH_SIZE") + } generatedKyberPreKeys := make([]*libsignalgo.KyberPreKeyRecord, 0, count) for keyID := startKeyID; keyID < startKeyID+count; keyID++ { kyberPreKeyPair, err := libsignalgo.KyberKeyPairGenerate() @@ -475,27 +533,17 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, pks store.PreKe log.Err(err).Msg("Error getting prekey counts") return err } - log.Debug().Int("preKeyCount", preKeyCount).Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Checking prekey counts") - - var preKeys []*libsignalgo.PreKeyRecord - var kyberPreKeys []*libsignalgo.KyberPreKeyRecord - if preKeyCount < 10 { - log.Info().Int("preKeyCount", preKeyCount).Msg("Generating and saving new prekeys") - preKeys, err = cli.GenerateAndSaveNextPreKeyBatch(ctx, pks) - if err != nil { - log.Err(err).Msg("Error generating and saving next prekey batch") - return err - } + doECUpload, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, pks, preKeyCount) + if err != nil { + log.Err(err).Msg("Error generating and saving next prekey batch") + return err } - if kyberPreKeyCount < 10 { - log.Info().Int("kyberPreKeyCount", kyberPreKeyCount).Msg("Generating and saving new kyber prekeys") - kyberPreKeys, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks) - if err != nil { - log.Err(err).Msg("Error generating and saving next kyber prekey batch") - return err - } + doKyberUpload, err := cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks, kyberPreKeyCount) + if err != nil { + log.Err(err).Msg("Error generating and saving next kyber prekey batch") + return err } - if len(preKeys) == 0 && len(kyberPreKeys) == 0 { + if !doECUpload && !doKyberUpload { log.Debug().Msg("No new prekeys to upload") return nil } @@ -510,9 +558,9 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, pks store.PreKe func (cli *Client) StartKeyCheckLoop(ctx context.Context) { log := zerolog.Ctx(ctx).With().Str("action", "start key check loop").Logger() go func() { - // Do the initial check within an hour of starting the loop - window_start := 0 - window_size := 1 + // Do the initial check in 5-10 minutes after starting the loop + window_start := 5 + window_size := 5 for { random_minutes_in_window := rand.Intn(window_size) + window_start check_time := time.Duration(random_minutes_in_window) * time.Minute diff --git a/pkg/signalmeow/store/prekey_store.go b/pkg/signalmeow/store/prekey_store.go index 9999aad..37bca7e 100644 --- a/pkg/signalmeow/store/prekey_store.go +++ b/pkg/signalmeow/store/prekey_store.go @@ -42,8 +42,8 @@ type PreKeyStore interface { StoreLastResortKyberPreKey(ctx context.Context, preKeyID uint32, record *libsignalgo.KyberPreKeyRecord) error RemoveSignedPreKey(ctx context.Context, preKeyID uint32) error RemoveKyberPreKey(ctx context.Context, preKeyID uint32) error - GetNextPreKeyID(ctx context.Context) (uint32, error) - GetNextKyberPreKeyID(ctx context.Context) (uint32, error) + GetNextPreKeyID(ctx context.Context) (count, max uint32, err error) + GetNextKyberPreKeyID(ctx context.Context) (count, max uint32, err error) IsKyberPreKeyLastResort(ctx context.Context, preKeyID uint32) (bool, error) AllPreKeys(ctx context.Context) ([]*libsignalgo.PreKeyRecord, error) AllNormalKyberPreKeys(ctx context.Context) ([]*libsignalgo.KyberPreKeyRecord, error) @@ -55,13 +55,13 @@ const ( getPreKeyQuery = `SELECT key_pair FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3 AND is_signed=$4` insertPreKeyQuery = `INSERT INTO signalmeow_pre_keys (account_id, service_id, key_id, is_signed, key_pair) VALUES ($1, $2, $3, $4, $5)` deletePreKeyQuery = `DELETE FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3 AND is_signed=$4` - getLastPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_signed=$3` + getLastPreKeyIDQuery = `SELECT COUNT(*), COALESCE(MAX(key_id), 0) FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_signed=$3` getAllKyberPreKeysQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_last_resort=false` getKyberPreKeyQuery = `SELECT key_pair FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` insertKyberPreKeyQuery = `INSERT INTO signalmeow_kyber_pre_keys (account_id, service_id, key_id, key_pair, is_last_resort) VALUES ($1, $2, $3, $4, $5)` deleteKyberPreKeyQuery = `DELETE FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` - getLastKyberPreKeyIDQuery = `SELECT MAX(key_id) FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2` + getLastKyberPreKeyIDQuery = `SELECT COUNT(*), COALESCE(MAX(key_id), 0) FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2` isLastResortQuery = `SELECT is_last_resort FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND key_id=$3` ) @@ -182,22 +182,22 @@ func (s *scopedSQLStore) MarkKyberPreKeyUsed(ctx context.Context, id uint32) err return nil } -func (s *scopedSQLStore) GetNextPreKeyID(ctx context.Context) (uint32, error) { - var lastKeyID sql.NullInt64 - err := s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.AccountID, s.ServiceID, false).Scan(&lastKeyID) +func (s *scopedSQLStore) GetNextPreKeyID(ctx context.Context) (count, next uint32, err error) { + err = s.db.QueryRow(ctx, getLastPreKeyIDQuery, s.AccountID, s.ServiceID, false).Scan(&count, &next) if err != nil { - return 0, fmt.Errorf("failed to query next prekey ID: %w", err) + err = fmt.Errorf("failed to query next prekey ID: %w", err) } - return uint32(lastKeyID.Int64) + 1, nil + next++ + return } -func (s *scopedSQLStore) GetNextKyberPreKeyID(ctx context.Context) (uint32, error) { - var lastKeyID sql.NullInt64 - err := s.db.QueryRow(ctx, getLastKyberPreKeyIDQuery, s.AccountID, s.ServiceID).Scan(&lastKeyID) +func (s *scopedSQLStore) GetNextKyberPreKeyID(ctx context.Context) (count, next uint32, err error) { + err = s.db.QueryRow(ctx, getLastKyberPreKeyIDQuery, s.AccountID, s.ServiceID).Scan(&count, &next) if err != nil { - return 0, fmt.Errorf("failed to query next kyber prekey ID: %w", err) + err = fmt.Errorf("failed to query next kyber prekey ID: %w", err) } - return uint32(lastKeyID.Int64) + 1, nil + next++ + return } func (s *scopedSQLStore) IsKyberPreKeyLastResort(ctx context.Context, preKeyID uint32) (bool, error) { diff --git a/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go b/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go new file mode 100644 index 0000000..9a5b011 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go @@ -0,0 +1,81 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package upgrades + +import ( + "context" + "fmt" + + "github.com/rs/zerolog" + "go.mau.fi/util/dbutil" +) + +type PreKeyCounts struct { + AccountID string + ServiceID string + Count int + MaxID int +} + +func scanPreKeyCounts(row dbutil.Scannable) (*PreKeyCounts, error) { + var pkc PreKeyCounts + return dbutil.ValueOrErr(&pkc, row.Scan(&pkc.AccountID, &pkc.ServiceID, &pkc.Count, &pkc.MaxID)) +} + +func deleteExtraPrekeys(ctx context.Context, db *dbutil.Database, selectQuery, deleteQuery string) error { + preKeys, err := dbutil.ConvertRowFn[*PreKeyCounts](scanPreKeyCounts).NewRowIter(db.Query(ctx, selectQuery)).AsList() + if err != nil { + return fmt.Errorf("failed to query prekey counts: %w", err) + } + for _, pkc := range preKeys { + if pkc.Count > 250 { + zerolog.Ctx(ctx).Debug(). + Str("account_id", pkc.AccountID). + Str("service_id", pkc.ServiceID). + Int("max_id", pkc.MaxID). + Int("count", pkc.Count). + Msg("Too many prekeys, deleting all") + _, err = db.Exec(ctx, deleteQuery, pkc.AccountID, pkc.ServiceID, pkc.MaxID-95) + if err != nil { + return fmt.Errorf("failed to delete extra prekeys for %s/%s: %w", pkc.AccountID, pkc.ServiceID, err) + } + } + } + return nil +} + +func init() { + Table.Register(-1, 16, 13, "Remove extra prekeys", true, func(ctx context.Context, db *dbutil.Database) error { + err := deleteExtraPrekeys(ctx, db, ` + SELECT account_id, service_id, COUNT(*), MAX(key_id) FROM signalmeow_pre_keys WHERE is_signed=false GROUP BY 1, 2 + `, ` + DELETE FROM signalmeow_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_signed=false AND key_id<$3 + `) + if err != nil { + return fmt.Errorf("failed to process EC: %w", err) + } + err = deleteExtraPrekeys(ctx, db, ` + SELECT account_id, service_id, COUNT(*), MAX(key_id) FROM signalmeow_kyber_pre_keys WHERE is_last_resort=false GROUP BY 1, 2 + `, ` + DELETE FROM signalmeow_kyber_pre_keys WHERE account_id=$1 AND service_id=$2 AND is_last_resort=false AND key_id<$3 + `) + if err != nil { + return fmt.Errorf("failed to process kyber: %w", err) + } + return nil + }) +} From 6ab46691b33c517ddf1e4158f0b65a2d66fae5e8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Apr 2024 02:15:31 +0300 Subject: [PATCH 140/718] Log errors when converting prekeys to JSON --- pkg/signalmeow/keys.go | 81 +++++++++++++++++++++++++--------- pkg/signalmeow/provisioning.go | 20 +++++++-- 2 files changed, 76 insertions(+), 25 deletions(-) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 219697f..9b87912 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -272,41 +272,74 @@ func GenerateSignedPreKey(startSignedKeyId uint32, identityKeyPair *libsignalgo. return signedPreKey } -func PreKeyToJSON(preKey *libsignalgo.PreKeyRecord) map[string]interface{} { - id, _ := preKey.GetID() - publicKey, _ := preKey.GetPublicKey() - serializedKey, _ := publicKey.Serialize() +func PreKeyToJSON(preKey *libsignalgo.PreKeyRecord) (map[string]interface{}, error) { + id, err := preKey.GetID() + if err != nil { + return nil, fmt.Errorf("failed to get ID: %w", err) + } + publicKey, err := preKey.GetPublicKey() + if err != nil { + return nil, fmt.Errorf("failed to get public key: %w", err) + } + serializedKey, err := publicKey.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to serialize public key: %w", err) + } preKeyJson := map[string]interface{}{ "keyId": id, "publicKey": base64.StdEncoding.EncodeToString(serializedKey), } - return preKeyJson + return preKeyJson, nil } -func SignedPreKeyToJSON(signedPreKey *libsignalgo.SignedPreKeyRecord) map[string]interface{} { - id, _ := signedPreKey.GetID() - publicKey, _ := signedPreKey.GetPublicKey() - serializedKey, _ := publicKey.Serialize() - signature, _ := signedPreKey.GetSignature() +func SignedPreKeyToJSON(signedPreKey *libsignalgo.SignedPreKeyRecord) (map[string]interface{}, error) { + id, err := signedPreKey.GetID() + if err != nil { + return nil, fmt.Errorf("failed to get ID: %w", err) + } + publicKey, err := signedPreKey.GetPublicKey() + if err != nil { + return nil, fmt.Errorf("failed to get public key: %w", err) + } + serializedKey, err := publicKey.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to serialize public key: %w", err) + } + signature, err := signedPreKey.GetSignature() + if err != nil { + return nil, fmt.Errorf("failed to get signature: %w", err) + } signedPreKeyJson := map[string]interface{}{ "keyId": id, "publicKey": base64.StdEncoding.EncodeToString(serializedKey), "signature": base64.StdEncoding.EncodeToString(signature), } - return signedPreKeyJson + return signedPreKeyJson, nil } -func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) map[string]interface{} { - id, _ := kyberPreKey.GetID() - publicKey, _ := kyberPreKey.GetPublicKey() - serializedKey, _ := publicKey.Serialize() - signature, _ := kyberPreKey.GetSignature() +func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) (map[string]interface{}, error) { + id, err := kyberPreKey.GetID() + if err != nil { + return nil, fmt.Errorf("failed to get ID: %w", err) + } + publicKey, err := kyberPreKey.GetPublicKey() + if err != nil { + return nil, fmt.Errorf("failed to get public key: %w", err) + } + serializedKey, err := publicKey.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to serialize public key: %w", err) + } + signature, err := kyberPreKey.GetSignature() + if err != nil { + return nil, fmt.Errorf("failed to get signature: %w", err) + } kyberPreKeyJson := map[string]interface{}{ "keyId": id, "publicKey": base64.StdEncoding.EncodeToString(serializedKey), "signature": base64.StdEncoding.EncodeToString(signature), } - return kyberPreKeyJson + return kyberPreKeyJson, nil } func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pni bool, username string, password string) error { @@ -315,11 +348,17 @@ func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pn preKeysJson := []map[string]interface{}{} kyberPreKeysJson := []map[string]interface{}{} for _, preKey := range generatedPreKeys.PreKeys { - preKeyJson := PreKeyToJSON(preKey) + preKeyJson, err := PreKeyToJSON(preKey) + if err != nil { + return fmt.Errorf("failed to convert prekey to JSON: %w", err) + } preKeysJson = append(preKeysJson, preKeyJson) } for _, kyberPreKey := range generatedPreKeys.KyberPreKeys { - kyberPreKeyJson := KyberPreKeyToJSON(kyberPreKey) + kyberPreKeyJson, err := KyberPreKeyToJSON(kyberPreKey) + if err != nil { + return fmt.Errorf("failed to convert kyber prekey to JSON: %w", err) + } kyberPreKeysJson = append(kyberPreKeysJson, kyberPreKeyJson) } @@ -559,8 +598,8 @@ func (cli *Client) StartKeyCheckLoop(ctx context.Context) { log := zerolog.Ctx(ctx).With().Str("action", "start key check loop").Logger() go func() { // Do the initial check in 5-10 minutes after starting the loop - window_start := 5 - window_size := 5 + window_start := 0 + window_size := 1 for { random_minutes_in_window := rand.Intn(window_size) + window_start check_time := time.Duration(random_minutes_in_window) * time.Minute diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 95d0a77..22a8b52 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -358,11 +358,23 @@ func confirmDevice( } defer ws.Close(websocket.StatusInternalError, "Websocket StatusInternalError") - aciSignedPreKeyJson := SignedPreKeyToJSON(aciSignedPreKey) - pniSignedPreKeyJson := SignedPreKeyToJSON(pniSignedPreKey) + aciSignedPreKeyJson, err := SignedPreKeyToJSON(aciSignedPreKey) + if err != nil { + return nil, fmt.Errorf("failed to convert signed ACI prekey to JSON: %w", err) + } + pniSignedPreKeyJson, err := SignedPreKeyToJSON(pniSignedPreKey) + if err != nil { + return nil, fmt.Errorf("failed to convert signed PNI prekey to JSON: %w", err) + } - aciPQLastResortPreKeyJson := KyberPreKeyToJSON(aciPQLastResortPreKey) - pniPQLastResortPreKeyJson := KyberPreKeyToJSON(pniPQLastResortPreKey) + aciPQLastResortPreKeyJson, err := KyberPreKeyToJSON(aciPQLastResortPreKey) + if err != nil { + return nil, fmt.Errorf("failed to convert ACI kyber last resort prekey to JSON: %w", err) + } + pniPQLastResortPreKeyJson, err := KyberPreKeyToJSON(pniPQLastResortPreKey) + if err != nil { + return nil, fmt.Errorf("failed to convert PNI kyber last resort prekey to JSON: %w", err) + } data := map[string]any{ "verificationCode": code, From 79d42dd1600f82026aeb111ea42048f7edfca702 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Apr 2024 02:39:25 +0300 Subject: [PATCH 141/718] Delete session if prekey upload returns 422 --- pkg/signalmeow/keys.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 9b87912..ad717ac 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -20,6 +20,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "math/rand" "net/http" @@ -342,6 +343,8 @@ func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) (map[string]i return kyberPreKeyJson, nil } +var errPrekeyUpload422 = errors.New("http 422 while registering prekeys") + func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pni bool, username string, password string) error { log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() // Convert generated prekeys to JSON @@ -383,7 +386,9 @@ func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pn } defer resp.Body.Close() // status code not 2xx - if resp.StatusCode < 200 || resp.StatusCode >= 300 { + if resp.StatusCode == 422 { + return errPrekeyUpload422 + } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { return fmt.Errorf("error registering prekeys: %v", resp.Status) } return err @@ -619,6 +624,14 @@ func (cli *Client) StartKeyCheckLoop(ctx context.Context) { } err = cli.CheckAndUploadNewPreKeys(ctx, cli.Store.PNIPreKeyStore) if err != nil { + if errors.Is(err, errPrekeyUpload422) { + log.Err(err).Msg("Got 422 error while uploading PNI prekeys, deleting session") + disconnectErr := cli.ClearKeysAndDisconnect(ctx) + if disconnectErr != nil { + log.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") + } + return + } log.Err(err).Msg("Error checking and uploading new prekeys for PNI identity") // Retry within half an hour window_start = 5 From f6e698281a7acff83cbae8c9d85141cea1da79eb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Apr 2024 13:23:37 +0300 Subject: [PATCH 142/718] Fix latest signalmeow db revision number --- pkg/signalmeow/store/upgrades/00-latest.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index bd376bb..40afbfb 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v15 (compatible with v13+): Latest revision +-- v0 -> v16 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, From efc22ef158e6b82632c24357f840f6a0937e32f0 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Tue, 2 Apr 2024 10:09:31 +0200 Subject: [PATCH 143/718] Send correct event to other users when creating group (#491) Use empty message with GroupV2Context instead of an empty group change --- commands.go | 13 +++++-------- pkg/signalmeow/groups.go | 21 +++++++++++++++++++-- pkg/signalmeow/sending.go | 14 ++++++++------ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/commands.go b/commands.go index 68a0f9f..8e605ba 100644 --- a/commands.go +++ b/commands.go @@ -771,6 +771,7 @@ func fnCreate(ce *WrappedCommandEvent) { var avatarHash string var avatarURL id.ContentURI var avatarBytes []byte + avatarSet := false if ok { roomAvatarEvent.Content.ParseRaw(event.StateRoomAvatar) avatarURL = roomAvatarEvent.Content.AsRoomAvatar().URL @@ -783,6 +784,7 @@ func fnCreate(ce *WrappedCommandEvent) { hash := sha256.Sum256(avatarBytes) avatarHash = hex.EncodeToString(hash[:]) ce.ZLog.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{ce.User.MXID, avatarURL}) + avatarSet = true } } var encryptionEvent *event.EncryptionEventContent @@ -856,7 +858,7 @@ func fnCreate(ce *WrappedCommandEvent) { Str("room_name", roomName). Any("participants", participants). Msg("Creating Signal group for Matrix room") - group, err := ce.User.Client.CreateGroupOnServer(ce.Ctx, &signalmeow.Group{ + group, err := ce.User.Client.CreateGroup(ce.Ctx, &signalmeow.Group{ Title: roomName, Description: roomTopic, Members: participants, @@ -899,16 +901,11 @@ func fnCreate(ce *WrappedCommandEvent) { } portal.Encrypted = true } - revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &signalmeow.GroupChange{}, gid) - if err != nil { - ce.Reply("Failed to update Group") - return - } - portal.Revision = revision + portal.Revision = group.Revision portal.AvatarHash = avatarHash portal.AvatarURL = avatarURL portal.AvatarPath = group.AvatarPath - portal.AvatarSet = true + portal.AvatarSet = avatarSet err = portal.Update(ce.Ctx) if err != nil { ce.ZLog.Err(err).Msg("Failed to save portal after creating group") diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 38cd290..e789ff4 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -1564,7 +1564,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi return 0, err } groupContext := &signalpb.GroupContextV2{Revision: &groupChange.Revision, GroupChange: groupChangeBytes, MasterKey: masterKeyBytes[:]} - _, err = cli.SendGroupChange(ctx, group, groupContext, groupChange) + _, err = cli.SendGroupUpdate(ctx, group, groupContext, groupChange) if err != nil { log.Err(err).Msg("Error sending GroupChange to group members") } @@ -1622,7 +1622,7 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou return encryptedGroup, nil } -func (cli *Client) CreateGroupOnServer(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { +func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { log := zerolog.Ctx(ctx).With().Str("action", "CreateGroupOnServer").Logger() masterKeyByteArray := make([]byte, 32) rand.Read(masterKeyByteArray) @@ -1708,3 +1708,20 @@ func GenerateInviteLinkPassword() types.SerializedInviteLinkPassword { rand.Read(inviteLinkPasswordBytes) return InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) } + +func (cli *Client) CreateGroup(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { + log := zerolog.Ctx(ctx).With().Str("action", "CreateGroup").Logger() + group, err := cli.createGroupOnServer(ctx, decryptedGroup, avatarBytes) + if err != nil { + log.Err(err).Msg("Error creating group on server") + return nil, err + } + masterKeyBytes := masterKeyToBytes(group.groupMasterKey) + groupContext := &signalpb.GroupContextV2{Revision: &group.Revision, MasterKey: masterKeyBytes[:]} + _, err = cli.SendGroupUpdate(ctx, group, groupContext, nil) + if err != nil { + log.Err(err).Msg("Error sending GroupUpdate to group members") + return nil, err + } + return group, nil +} diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index ea1eeb4..473dd3e 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -532,7 +532,7 @@ func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { } } -func (cli *Client) SendGroupChange(ctx context.Context, group *Group, groupContext *signalpb.GroupContextV2, groupChange *GroupChange) (*GroupMessageSendResult, error) { +func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupContext *signalpb.GroupContextV2, groupChange *GroupChange) (*GroupMessageSendResult, error) { log := zerolog.Ctx(ctx).With(). Str("action", "send group change message"). Stringer("group_id", group.GroupIdentifier). @@ -548,11 +548,13 @@ func (cli *Client) SendGroupChange(ctx context.Context, group *Group, groupConte for _, member := range group.PendingMembers { recipients = append(recipients, &member.GroupMember) } - for _, member := range groupChange.AddPendingMembers { - recipients = append(recipients, &member.GroupMember) - } - for _, member := range groupChange.AddMembers { - recipients = append(recipients, &member.GroupMember) + if groupChange != nil { + for _, member := range groupChange.AddPendingMembers { + recipients = append(recipients, &member.GroupMember) + } + for _, member := range groupChange.AddMembers { + recipients = append(recipients, &member.GroupMember) + } } return cli.sendToGroup(ctx, recipients, content, timestamp) } From f24a76186d64c15b3135c75b820adee584f8a171 Mon Sep 17 00:00:00 2001 From: Malte E Date: Mon, 1 Apr 2024 12:59:04 +0200 Subject: [PATCH 144/718] UUID->ACI & invite command --- commands.go | 83 +++++++- pkg/libsignalgo/groupsecretparams.go | 26 +-- pkg/signalmeow/groups.go | 297 +++++++++++++++++---------- pkg/signalmeow/sending.go | 34 +-- portal.go | 125 ++++++----- 5 files changed, 370 insertions(+), 195 deletions(-) diff --git a/commands.go b/commands.go index 8e605ba..1b4fbea 100644 --- a/commands.go +++ b/commands.go @@ -71,6 +71,7 @@ func (br *SignalBridge) RegisterCommands() { cmdInviteLink, cmdResetInviteLink, cmdCreate, + cmdInvite, ) } @@ -284,6 +285,82 @@ func fnPM(ce *WrappedCommandEvent) { } } +var cmdInvite = &commands.FullHandler{ + Func: wrapCommand(fnInvite), + Name: "invite", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "Invite a user by phone number.", + Args: "<_international phone number_>", + }, + RequiresLogin: true, + RequiresPortal: true, +} + +func fnInvite(ce *WrappedCommandEvent) { + if len(ce.Args) == 0 { + ce.Reply("**Usage:** `invite `") + return + } + number, err := strconv.ParseUint(numberCleaner.Replace(strings.Join(ce.Args, "")), 10, 64) + if err != nil { + ce.Reply("Failed to parse number") + return + } + + user := ce.User + var aci, pni uuid.UUID + e164 := fmt.Sprintf("+%d", number) + var recipient *types.Recipient + + if recipient, err = user.Client.ContactByE164(ce.Ctx, e164); err != nil { + ce.Reply("Error looking up number in local contact list: %v", err) + return + } else if recipient != nil && (recipient.ACI != uuid.Nil || recipient.PNI != uuid.Nil) { + // TODO maybe lookup PNI if there's only ACI and E164 stored? + aci = recipient.ACI + pni = recipient.PNI + } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { + ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") + ce.Reply("Error looking up number on server: %v", err) + return + } else { + aci = resp[number].ACI + pni = resp[number].PNI + if aci == uuid.Nil && pni == uuid.Nil { + ce.Reply("+%d doesn't seem to be on Signal", number) + return + } + recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ce.Ctx, aci, pni, e164) + if err != nil { + ce.ZLog.Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI + } + ce.ZLog.Debug(). + Uint64("e164", number). + Stringer("aci", aci). + Stringer("pni", pni). + Msg("Found Invite target user") + + var groupChange signalmeow.GroupChange + if aci != uuid.Nil { + groupChange.AddMembers = append(groupChange.AddMembers, &signalmeow.AddMember{ + GroupMember: signalmeow.GroupMember{ + ACI: aci, + Role: signalmeow.GroupMember_DEFAULT, + }, + }) + } else { + groupChange.AddPendingMembers = append(groupChange.AddPendingMembers, &signalmeow.PendingMember{ + ServiceID: libsignalgo.NewPNIServiceID(pni), + AddedByUserID: ce.User.SignalID, + Role: signalmeow.GroupMember_DEFAULT, + }) + } + ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) +} + var cmdResolvePhone = &commands.FullHandler{ Func: wrapCommand(fnResolvePhone), Name: "resolve-phone", @@ -822,12 +899,12 @@ func fnCreate(ce *WrappedCommandEvent) { // joined members that need to be pending-Members should have their signal invite auto-accepted if membership == event.MembershipJoin || membership == event.MembershipInvite { participants = append(participants, &signalmeow.GroupMember{ - UserID: uuid, - Role: role, + ACI: uuid, + Role: role, }) } else if membership == event.MembershipBan { bannedMembers = append(bannedMembers, &signalmeow.BannedMember{ - UserID: uuid, + ServiceID: libsignalgo.NewACIServiceID(uuid), }) } } diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index fed5477..76a28f7 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -23,7 +23,6 @@ package libsignalgo import "C" import ( "crypto/rand" - "fmt" "runtime" "unsafe" @@ -139,41 +138,36 @@ func (gsp *GroupSecretParams) EncryptBlobWithPaddingDeterministic(randomness Ran return CopySignalOwnedBufferToBytes(ciphertext), nil } -func (gsp *GroupSecretParams) DecryptUUID(ciphertextUUID UUIDCiphertext) (uuid.UUID, error) { - // TODO this should probably be DecryptServiceID - +func (gsp *GroupSecretParams) DecryptServiceID(ciphertextServiceID UUIDCiphertext) (ServiceID, error) { u := C.SignalServiceIdFixedWidthBinaryBytes{} 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(&ciphertextUUID)), + (*[C.SignalUUID_CIPHERTEXT_LEN]C.uint8_t)(unsafe.Pointer(&ciphertextServiceID)), ) runtime.KeepAlive(gsp) - runtime.KeepAlive(ciphertextUUID) + runtime.KeepAlive(ciphertextServiceID) if signalFfiError != nil { - return uuid.Nil, wrapError(signalFfiError) + return EmptyServiceID, wrapError(signalFfiError) } serviceID := ServiceIDFromCFixedBytes(&u) - if serviceID.Type != ServiceIDTypeACI { - return uuid.Nil, fmt.Errorf("unexpected service ID type %d", serviceID.Type) - } - return serviceID.UUID, nil + return serviceID, nil } -func (gsp *GroupSecretParams) EncryptUUID(uuid uuid.UUID) (*UUIDCiphertext, error) { - var cipherTextUUID [C.SignalUUID_CIPHERTEXT_LEN]C.uchar +func (gsp *GroupSecretParams) EncryptServiceID(serviceID ServiceID) (*UUIDCiphertext, error) { + var cipherTextServiceID [C.SignalUUID_CIPHERTEXT_LEN]C.uchar signalFfiError := C.signal_group_secret_params_encrypt_service_id( - &cipherTextUUID, + &cipherTextServiceID, (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)), - NewACIServiceID(uuid).CFixedBytes(), + serviceID.CFixedBytes(), ) runtime.KeepAlive(gsp) if signalFfiError != nil { return nil, wrapError(signalFfiError) } var result UUIDCiphertext - copy(result[:], C.GoBytes(unsafe.Pointer(&cipherTextUUID), C.int(C.SignalUUID_CIPHERTEXT_LEN))) + copy(result[:], C.GoBytes(unsafe.Pointer(&cipherTextServiceID), C.int(C.SignalUUID_CIPHERTEXT_LEN))) return &result, nil } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index e789ff4..0e647d0 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -65,15 +65,14 @@ const ( ) type GroupMember struct { - UserID uuid.UUID + ACI uuid.UUID Role GroupMemberRole ProfileKey libsignalgo.ProfileKey JoinedAtRevision uint32 - //Presentation []byte } func (gm *GroupMember) UserServiceID() libsignalgo.ServiceID { - return libsignalgo.NewACIServiceID(gm.UserID) + return libsignalgo.NewACIServiceID(gm.ACI) } type Group struct { @@ -138,38 +137,41 @@ type AddMember struct { } type PendingMember struct { - GroupMember + ServiceID libsignalgo.ServiceID + Role GroupMemberRole AddedByUserID uuid.UUID Timestamp uint64 } type ProfileKeyMember struct { - UserID uuid.UUID + ACI uuid.UUID ProfileKey libsignalgo.ProfileKey - //Presentation []byte } type RequestingMember struct { - UserID uuid.UUID + ACI uuid.UUID ProfileKey libsignalgo.ProfileKey Timestamp uint64 - //Presentation []byte } -// type PromotePniAciMember struct { -// UserID uuid.UUID -// ProfileKey libsignalgo.ProfileKey -// PNI uuid.UUID -// Presentation []byte -// } +type PromotePendingMembers struct { + ACI uuid.UUID + ProfileKey libsignalgo.ProfileKey +} + +type PromotePendingPniAciMember struct { + ACI uuid.UUID + ProfileKey libsignalgo.ProfileKey + PNI uuid.UUID +} type RoleMember struct { - UserID uuid.UUID - Role GroupMemberRole + ACI uuid.UUID + Role GroupMemberRole } type BannedMember struct { - UserID uuid.UUID + ServiceID libsignalgo.ServiceID Timestamp uint64 } @@ -182,8 +184,8 @@ type GroupChange struct { ModifyMemberRoles []*RoleMember ModifyMemberProfileKeys []*ProfileKeyMember AddPendingMembers []*PendingMember - DeletePendingMembers []*uuid.UUID - PromotePendingMembers []*ProfileKeyMember + DeletePendingMembers []*libsignalgo.ServiceID + PromotePendingMembers []*GroupMember ModifyTitle *string ModifyAvatar *string ModifyDisappearingMessagesDuration *uint32 @@ -196,8 +198,8 @@ type GroupChange struct { ModifyDescription *string ModifyAnnouncementsOnly *bool AddBannedMembers []*BannedMember - DeleteBannedMembers []*uuid.UUID - PromotePendingPniAciMembers []*ProfileKeyMember + DeleteBannedMembers []*libsignalgo.ServiceID + PromotePendingPniAciMembers []*PromotePendingPniAciMember ModifyInviteLinkPassword *types.SerializedInviteLinkPassword } @@ -250,38 +252,38 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } members := make(map[uuid.UUID]GroupMemberRole) for _, member := range group.Members { - members[member.UserID] = member.Role + members[member.ACI] = member.Role } - pendingMembers := make(map[uuid.UUID]bool) + pendingMembers := make(map[libsignalgo.ServiceID]bool) for _, pendingMember := range group.PendingMembers { - pendingMembers[pendingMember.UserID] = true + pendingMembers[pendingMember.ServiceID] = true } requestingMembers := make(map[uuid.UUID]bool) for _, requestingMember := range group.RequestingMembers { - requestingMembers[requestingMember.UserID] = true + requestingMembers[requestingMember.ACI] = true } for i, member := range groupChange.AddMembers { - if _, ok := members[member.GroupMember.UserID]; ok { + if _, ok := members[member.GroupMember.ACI]; ok { groupChange.AddMembers = append(groupChange.AddMembers[:i], groupChange.AddMembers[i+1:]...) } } for i, promotePendingMember := range groupChange.PromotePendingMembers { - if _, ok := members[promotePendingMember.UserID]; ok { + if _, ok := members[promotePendingMember.ACI]; ok { groupChange.PromotePendingMembers = append(groupChange.PromotePendingMembers[:i], groupChange.PromotePendingMembers[i+1:]...) } } for i, promoteRequestingMember := range groupChange.PromotePendingMembers { - if _, ok := members[promoteRequestingMember.UserID]; ok { + if _, ok := members[promoteRequestingMember.ACI]; ok { groupChange.PromoteRequestingMembers = append(groupChange.PromoteRequestingMembers[:i], groupChange.PromoteRequestingMembers[i+1:]...) } } for i, pendingMember := range groupChange.AddPendingMembers { - if pendingMembers[pendingMember.GroupMember.UserID] { + if pendingMembers[pendingMember.ServiceID] { groupChange.AddPendingMembers = append(groupChange.AddPendingMembers[:i], groupChange.AddPendingMembers[i+1:]...) } } for i, requestingMember := range groupChange.AddRequestingMembers { - if pendingMembers[requestingMember.UserID] { + if requestingMembers[requestingMember.ACI] { groupChange.AddRequestingMembers = append(groupChange.AddRequestingMembers[:i], groupChange.AddRequestingMembers[i+1:]...) } } @@ -291,7 +293,7 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } } for i, deleteRequestingMember := range groupChange.DeleteRequestingMembers { - if !pendingMembers[*deleteRequestingMember] { + if !requestingMembers[*deleteRequestingMember] { groupChange.DeleteRequestingMembers = append(groupChange.DeleteRequestingMembers[:i], groupChange.DeleteRequestingMembers[i+1:]...) } } @@ -301,7 +303,7 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } } for i, modifyMemberRole := range groupChange.ModifyMemberRoles { - if members[modifyMemberRole.UserID] == modifyMemberRole.Role { + if members[modifyMemberRole.ACI] == modifyMemberRole.Role { groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles[:i], groupChange.ModifyMemberRoles[i+1:]...) } } @@ -563,13 +565,13 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast continue } encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error") return nil, err } decryptedGroup.BannedMembers = append(decryptedGroup.BannedMembers, &BannedMember{ - UserID: userID, + ServiceID: serviceID, Timestamp: bannedMember.Timestamp, }) } @@ -697,19 +699,13 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t // Store the profile keys in case they're new for _, member := range group.Members { - err = cli.Store.RecipientStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) - if err != nil { - return nil, fmt.Errorf("failed to store profile key: %w", err) - } - } - for _, pendingMember := range group.PendingMembers { - err = cli.Store.RecipientStore.StoreProfileKey(ctx, pendingMember.UserID, pendingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, member.ACI, member.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } } for _, requestingMember := range group.RequestingMembers { - err = cli.Store.RecipientStore.StoreProfileKey(ctx, requestingMember.UserID, requestingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, requestingMember.ACI, requestingMember.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } @@ -884,7 +880,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp GroupMember: *decryptedMember, JoinFromInviteLink: addMember.JoinFromInviteLink, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedMember.UserID, decryptedMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedMember.ACI, decryptedMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -896,24 +892,30 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deleteMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deleteMember") return nil, err } - decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &userID) + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } + decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &serviceID.UUID) } for _, modifyMemberRole := range encryptedActions.ModifyMemberRoles { encryptedUserID := libsignalgo.UUIDCiphertext(modifyMemberRole.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for modifyMemberRole") return nil, err } + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } decryptedGroupChange.ModifyMemberRoles = append(decryptedGroupChange.ModifyMemberRoles, &RoleMember{ - UserID: userID, - Role: GroupMemberRole(modifyMemberRole.Role), + ACI: serviceID.UUID, + Role: GroupMemberRole(modifyMemberRole.Role), }) } @@ -922,22 +924,25 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(modifyProfileKey.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for modifyProfileKey") return nil, err } + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(modifyProfileKey.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for modifyProfileKey") return nil, err } decryptedGroupChange.ModifyMemberProfileKeys = append(decryptedGroupChange.ModifyMemberProfileKeys, &ProfileKeyMember{ - UserID: userID, + ACI: serviceID.UUID, ProfileKey: *profileKey, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, serviceID.UUID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -962,7 +967,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deletePendingMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deletePendingMember") return nil, err @@ -975,50 +980,63 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for promotePendingMember") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingMember") return nil, err } - decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ - UserID: userID, + decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &GroupMember{ + ACI: serviceID.UUID, ProfileKey: *profileKey, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, serviceID.UUID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err } } - for _, promotePendingMember := range encryptedActions.PromotePendingPniAciMembers { + for _, promotePendingPniAciMember := range encryptedActions.PromotePendingPniAciMembers { // TODO: pretending this is a PendingMember should do for mautrix-signal, but we probably want to treat them separately at some point - if promotePendingMember == nil { + if promotePendingPniAciMember == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingPniAciMember.UserId) + aciServiceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for promotePendingPniAciMember") return nil, err } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if aciServiceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } + encryptedUserID = libsignalgo.UUIDCiphertext(promotePendingPniAciMember.Pni) + pniServiceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID Pni error for promotePendingPniAciMember") + return nil, err + } + if pniServiceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected PNI, got ACI") + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingPniAciMember.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, aciServiceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingPniAciMember") return nil, err } - decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ - UserID: userID, + decryptedGroupChange.PromotePendingPniAciMembers = append(decryptedGroupChange.PromotePendingPniAciMembers, &PromotePendingPniAciMember{ + ACI: aciServiceID.UUID, ProfileKey: *profileKey, + PNI: pniServiceID.UUID, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, aciServiceID.UUID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1034,7 +1052,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp return nil, err } decryptedGroupChange.AddRequestingMembers = append(decryptedGroupChange.AddRequestingMembers, decryptedRequestingMember) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedRequestingMember.UserID, decryptedRequestingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedRequestingMember.ACI, decryptedRequestingMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1046,12 +1064,12 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deleteRequestingMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deleteRequestingMember") return nil, err } - decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &userID) + decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &serviceID.UUID) } for _, promoteRequestingMember := range encryptedActions.PromoteRequestingMembers { @@ -1059,14 +1077,14 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(promoteRequestingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for promoteRequestingMember") return nil, err } decryptedGroupChange.PromoteRequestingMembers = append(decryptedGroupChange.PromoteRequestingMembers, &RoleMember{ - UserID: userID, - Role: GroupMemberRole(promoteRequestingMember.Role), + ACI: serviceID.UUID, + Role: GroupMemberRole(promoteRequestingMember.Role), }) } @@ -1076,13 +1094,13 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp } bannedMember := addBannedMember.Added encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for addBannedMember") return nil, err } decryptedGroupChange.AddBannedMembers = append(decryptedGroupChange.AddBannedMembers, &BannedMember{ - UserID: userID, + ServiceID: serviceID, Timestamp: bannedMember.Timestamp, }) } @@ -1092,7 +1110,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deleteBannedMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deleteBannedMember") return nil, err @@ -1134,19 +1152,19 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretParams libsignalgo.GroupSecretParams) (*GroupMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(member.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(member.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error") return nil, err } return &GroupMember{ - UserID: userID, + ACI: serviceID.UUID, ProfileKey: *profileKey, Role: GroupMemberRole(member.Role), JoinedAtRevision: member.JoinedAtRevision, @@ -1156,25 +1174,22 @@ func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretPara func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMember, groupSecretParams libsignalgo.GroupSecretParams) (*PendingMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for pendingMember") return nil, err } // pendingMembers don't have profile keys encryptedAddedByUserID := pendingMember.AddedByUserId - addedByUserId, err := groupSecretParams.DecryptUUID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) + addedByServiceId, err := groupSecretParams.DecryptServiceID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) if err != nil { log.Err(err).Msg("DecryptUUID addedByUserId error for pendingMember") return nil, err } return &PendingMember{ - GroupMember: GroupMember{ - UserID: userID, - Role: GroupMemberRole(pendingMember.Member.Role), - JoinedAtRevision: pendingMember.Member.JoinedAtRevision, - }, - AddedByUserID: addedByUserId, + ServiceID: userID, + Role: GroupMemberRole(pendingMember.Member.Role), + AddedByUserID: addedByServiceId.UUID, Timestamp: pendingMember.Timestamp, }, nil } @@ -1182,19 +1197,19 @@ func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMe func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.RequestingMember, groupSecretParams libsignalgo.GroupSecretParams) (*RequestingMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for requestingMember") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for requestingMember") return nil, err } return &RequestingMember{ - UserID: userID, + ACI: serviceID.UUID, ProfileKey: *profileKey, Timestamp: requestingMember.Timestamp, }, nil @@ -1232,17 +1247,23 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup groupChangeActions.ModifyAvatar = &signalpb.GroupChange_Actions_ModifyAvatarAction{Avatar: *decryptedGroupChange.ModifyAvatar} } for _, addMember := range decryptedGroupChange.AddMembers { - encryptedMember, err := cli.encryptMember(ctx, &addMember.GroupMember, &groupSecretParams) + encryptedMember, encryptedPendingMember, err := cli.encryptMember(ctx, &addMember.GroupMember, &groupSecretParams) if err != nil { log.Err(err).Msg("Failed to encrypt GroupMember") } - groupChangeActions.AddMembers = append(groupChangeActions.AddMembers, &signalpb.GroupChange_Actions_AddMemberAction{ - Added: encryptedMember, - JoinFromInviteLink: addMember.JoinFromInviteLink, - }) + if encryptedMember != nil { + groupChangeActions.AddMembers = append(groupChangeActions.AddMembers, &signalpb.GroupChange_Actions_AddMemberAction{ + Added: encryptedMember, + JoinFromInviteLink: addMember.JoinFromInviteLink, + }) + } else { + groupChangeActions.AddPendingMembers = append(groupChangeActions.AddPendingMembers, &signalpb.GroupChange_Actions_AddPendingMemberAction{ + Added: encryptedPendingMember, + }) + } } for _, deleteMember := range decryptedGroupChange.DeleteMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(*deleteMember)) if err != nil { log.Err(err).Msg("Encrypt UserId error for deleteMember") return nil, err @@ -1252,7 +1273,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, modifyMemberRoles := range decryptedGroupChange.ModifyMemberRoles { - encryptedUserID, err := groupSecretParams.EncryptUUID(modifyMemberRoles.UserID) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(modifyMemberRoles.ACI)) if err != nil { log.Err(err).Msg("Encrypt UserId error for modifyMemberRoles") return nil, err @@ -1262,10 +1283,18 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup Role: signalpb.Member_Role(modifyMemberRoles.Role), }) } - // for _, addPendingMember := range decryptedGroupChange.AddPendingMembers { - // } + for _, addPendingMember := range decryptedGroupChange.AddPendingMembers { + encryptedPendingMember, err := cli.encryptPendingMember(ctx, addPendingMember, &groupSecretParams) + if err != nil { + log.Err(err).Msg("Failed to encrypt pendingMember") + return nil, err + } + groupChangeActions.AddPendingMembers = append(groupChangeActions.AddPendingMembers, &signalpb.GroupChange_Actions_AddPendingMemberAction{ + Added: encryptedPendingMember, + }) + } for _, deletePendingMember := range decryptedGroupChange.DeletePendingMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deletePendingMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(deletePendingMember.UUID)) if err != nil { log.Err(err).Msg("Encrypt UserId error for deletePendingMember") return nil, err @@ -1275,7 +1304,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, promotePendingMember := range decryptedGroupChange.PromotePendingMembers { - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, promotePendingMember.UserID) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, promotePendingMember.ACI) if err != nil { log.Err(err).Msg("failed getting expiring profile key credential for addMember") return nil, err @@ -1293,7 +1322,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, addRequestingMember := range decryptedGroupChange.AddRequestingMembers { - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addRequestingMember.UserID) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addRequestingMember.ACI) if err != nil { log.Err(err).Msg("failed getting expiring profile key credential for addMember") return nil, err @@ -1313,7 +1342,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, deleteRequestingMember := range decryptedGroupChange.DeleteRequestingMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteRequestingMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(*deleteRequestingMember)) if err != nil { log.Err(err).Msg("Encrypt UserId error for promotePendingMember") return nil, err @@ -1323,7 +1352,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, promoteRequestingMember := range decryptedGroupChange.PromoteRequestingMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(promoteRequestingMember.UserID) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(promoteRequestingMember.ACI)) if err != nil { log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err @@ -1335,7 +1364,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, addBannedMember := range decryptedGroupChange.AddBannedMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(addBannedMember.UserID) + encryptedUserID, err := groupSecretParams.EncryptServiceID(addBannedMember.ServiceID) if err != nil { log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err @@ -1348,7 +1377,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, deleteBannedMember := range decryptedGroupChange.DeleteBannedMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteBannedMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(*deleteBannedMember) if err != nil { log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err @@ -1399,12 +1428,18 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup return cli.patchGroup(ctx, groupChangeActions, groupMasterKey, nil) } -func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, error) { +func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, *signalpb.PendingMember, error) { log := zerolog.Ctx(ctx) - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, member.UserID) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, member.ACI) if err != nil { - log.Err(err).Msg("failed getting expiring profile key credential for addMember") - return nil, err + log.Err(err).Msg("failed getting expiring profile key credential for member, trying to encrypt as PendingMember") + pendingMember := PendingMember{ + ServiceID: member.UserServiceID(), + Role: member.Role, + AddedByUserID: cli.Store.ACI, + } + encryptedPendingMember, err := cli.encryptPendingMember(ctx, &pendingMember, groupSecretParams) + return nil, encryptedPendingMember, err } presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( prodServerPublicParams, @@ -1412,13 +1447,35 @@ func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, group ) if err != nil { log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") - return nil, err + return nil, nil, err } encryptedMember := signalpb.Member{ Presentation: *presentation, Role: signalpb.Member_Role(member.Role), } - return &encryptedMember, nil + return &encryptedMember, nil, nil +} + +func (cli *Client) encryptPendingMember(ctx context.Context, pendingMember *PendingMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.PendingMember, error) { + log := zerolog.Ctx(ctx) + encryptedUserID, err := groupSecretParams.EncryptServiceID(pendingMember.ServiceID) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for addPendingMember") + return nil, err + } + encryptedAddedByUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(pendingMember.AddedByUserID)) + if err != nil { + log.Err(err).Msg("Encrypt AddedByUserId error for addPendingMember") + return nil, err + } + encryptedPendingMember := signalpb.PendingMember{ + AddedByUserId: encryptedAddedByUserID[:], + Member: &signalpb.Member{ + UserId: encryptedUserID[:], + Role: signalpb.Member_Role(pendingMember.Role), + }, + } + return &encryptedPendingMember, nil } var ( @@ -1613,11 +1670,23 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou } } for _, member := range decryptedGroup.Members { - encryptedMember, err := cli.encryptMember(ctx, member, &groupSecretParams) + encryptedMember, encryptedPendingMember, err := cli.encryptMember(ctx, member, &groupSecretParams) if err != nil { log.Err(err).Msg("Failed to encrypt GroupMember") } - encryptedGroup.Members = append(encryptedGroup.Members, encryptedMember) + if encryptedMember != nil { + encryptedGroup.Members = append(encryptedGroup.Members, encryptedMember) + } else { + encryptedGroup.PendingMembers = append(encryptedGroup.PendingMembers, encryptedPendingMember) + } + } + for _, pendingMember := range decryptedGroup.PendingMembers { + encryptedPendingMember, err := cli.encryptPendingMember(ctx, pendingMember, &groupSecretParams) + if err != nil { + log.Err(err).Msg("Failed to encrypt pendingMember") + return nil, err + } + encryptedGroup.PendingMembers = append(encryptedGroup.PendingMembers, encryptedPendingMember) } return encryptedGroup, nil } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 473dd3e..11211e0 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -544,16 +544,21 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte GroupV2: groupContext, } content := wrapDataMessageInContent(dm) - recipients := group.Members + var recipients []*libsignalgo.ServiceID + for _, member := range group.Members { + serviceID := member.UserServiceID() + recipients = append(recipients, &serviceID) + } for _, member := range group.PendingMembers { - recipients = append(recipients, &member.GroupMember) + recipients = append(recipients, &member.ServiceID) } if groupChange != nil { for _, member := range groupChange.AddPendingMembers { - recipients = append(recipients, &member.GroupMember) + recipients = append(recipients, &member.ServiceID) } for _, member := range groupChange.AddMembers { - recipients = append(recipients, &member.GroupMember) + serviceID := member.UserServiceID() + recipients = append(recipients, &serviceID) } } return cli.sendToGroup(ctx, recipients, content, timestamp) @@ -578,32 +583,37 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi messageTimestamp = content.EditMessage.DataMessage.GetTimestamp() content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) } - return cli.sendToGroup(ctx, group.Members, content, messageTimestamp) + var recipients []*libsignalgo.ServiceID + for _, member := range group.Members { + serviceID := member.UserServiceID() + recipients = append(recipients, &serviceID) + } + return cli.sendToGroup(ctx, recipients, content, messageTimestamp) } -func (cli *Client) sendToGroup(ctx context.Context, recipients []*GroupMember, content *signalpb.Content, messageTimestamp uint64) (*GroupMessageSendResult, error) { +func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.ServiceID, content *signalpb.Content, messageTimestamp uint64) (*GroupMessageSendResult, error) { // Send to each member of the group result := &GroupMessageSendResult{ SuccessfullySentTo: []SuccessfulSendResult{}, FailedToSendTo: []FailedSendResult{}, } - for _, member := range recipients { - if member.UserID == cli.Store.ACI { + for _, recipient := range recipients { + if recipient.Type == libsignalgo.ServiceIDTypeACI && recipient.UUID == cli.Store.ACI { // Don't send normal DataMessages to ourselves continue } - log := zerolog.Ctx(ctx).With().Stringer("member", member.UserID).Logger() + log := zerolog.Ctx(ctx).With().Stringer("member", *recipient).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, member.UserServiceID(), messageTimestamp, content, 0, true) + sentUnidentified, err := cli.sendContent(ctx, *recipient, messageTimestamp, content, 0, true) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ - Recipient: member.UserServiceID(), + Recipient: *recipient, Error: err, }) log.Err(err).Msg("Failed to send to user") } else { result.SuccessfullySentTo = append(result.SuccessfullySentTo, SuccessfulSendResult{ - Recipient: member.UserServiceID(), + Recipient: *recipient, Unidentified: sentUnidentified, }) log.Trace().Msg("Successfully sent to user") diff --git a/portal.go b/portal.go index b5be7f3..0624b89 100644 --- a/portal.go +++ b/portal.go @@ -953,19 +953,19 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou intent := sender.IntentFor(portal) modifyRoles := groupChange.ModifyMemberRoles for _, deleteBannedMember := range groupChange.DeleteBannedMembers { - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteBannedMember, event.MembershipLeave, "unbanned") + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *&deleteBannedMember.UUID, event.MembershipLeave, "unbanned") if err != nil { log.Warn().Stringer("signal_user_id", deleteBannedMember).Msg("Couldn't get puppet for unban") } } for _, addMember := range groupChange.AddMembers { - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: addMember.UserID, Role: addMember.Role}) + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: addMember.ACI, Role: addMember.Role}) var puppet *Puppet if addMember.JoinFromInviteLink { - puppet = portal.bridge.GetPuppetBySignalID(addMember.UserID) + puppet = portal.bridge.GetPuppetBySignalID(addMember.ACI) if puppet != nil { if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(addMember.UserID) + user := portal.bridge.GetUserBySignalID(addMember.ACI) if user != nil { portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, user.MXID, event.MembershipInvite, "Joined via invite Link") } @@ -978,20 +978,23 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } } } else { - puppet, _ = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.UserID, event.MembershipInvite, "added") + puppet, _ = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.ACI, event.MembershipInvite, "added") } if puppet != nil { puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") } else { - log.Warn().Stringer("signal_user_id", addMember.UserID).Msg("Couldn't get puppet for invite") + log.Warn().Stringer("signal_user_id", addMember.ACI).Msg("Couldn't get puppet for invite") } } bannedMembers := make(map[uuid.UUID]bool) for _, addBannedMember := range groupChange.AddBannedMembers { - bannedMembers[addBannedMember.UserID] = true - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addBannedMember.UserID, event.MembershipBan, "banned") + if addBannedMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + bannedMembers[addBannedMember.ServiceID.UUID] = true + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addBannedMember.ServiceID.UUID, event.MembershipBan, "banned") if err != nil { - log.Warn().Stringer("signal_user_id", addBannedMember.UserID).Msg("Couldn't get puppet for ban") + log.Warn().Stringer("signal_user_id", addBannedMember.ServiceID.UUID).Msg("Couldn't get puppet for ban") } } for _, deleteMember := range groupChange.DeleteMembers { @@ -1004,10 +1007,13 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } } for _, deletePendingMember := range groupChange.DeletePendingMembers { - if bannedMembers[*deletePendingMember] { + if deletePendingMember.Type == libsignalgo.ServiceIDTypePNI { continue } - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deletePendingMember, event.MembershipLeave, "invite withdrawn") + if bannedMembers[deletePendingMember.UUID] { + continue + } + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, deletePendingMember.UUID, event.MembershipLeave, "invite withdrawn") if err != nil { log.Warn().Stringer("signal_user_id", deletePendingMember).Msg("Couldn't get puppet for removal") } @@ -1022,35 +1028,46 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } } for _, promotePendingMember := range groupChange.PromotePendingMembers { - puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promotePendingMember.UserID, event.MembershipInvite, "request accepted") - if err == nil { - puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) - } else { - log.Warn().Stringer("signal_user_id", promotePendingMember.UserID).Msg("Couldn't get puppet for invite") + puppet := portal.bridge.GetPuppetBySignalID(promotePendingMember.ACI) + if puppet == nil { + log.Warn().Stringer("signal_user_id", promotePendingMember.ACI).Msg("Couldn't get puppet for invite") + continue } + puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) + } + for _, promotePendingPniAciMember := range groupChange.PromotePendingPniAciMembers { + puppet := portal.bridge.GetPuppetBySignalID(promotePendingPniAciMember.ACI) + if puppet == nil { + log.Warn().Stringer("signal_user_id", promotePendingPniAciMember.ACI).Msg("Couldn't get puppet for invite") + continue + } + puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) } for _, addPendingMember := range groupChange.AddPendingMembers { - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addPendingMember.UserID, event.MembershipInvite, "invited") - if err != nil { - log.Warn().Stringer("signal_user_id", addPendingMember.UserID).Msg("Couldn't get puppet for invite") + if addPendingMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue } - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: addPendingMember.UserID, Role: addPendingMember.Role}) + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addPendingMember.ServiceID.UUID, event.MembershipInvite, "invited") + if err != nil { + log.Warn().Stringer("signal_user_id", addPendingMember.ServiceID).Msg("Couldn't get puppet for invite") + } + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: addPendingMember.ServiceID.UUID, Role: addPendingMember.Role}) } for _, promoteRequestingMember := range groupChange.PromoteRequestingMembers { - puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promoteRequestingMember.UserID, event.MembershipInvite, "accepted") + puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promoteRequestingMember.ACI, event.MembershipInvite, "accepted") if err == nil { err = puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) if err != nil { - log.Warn().Stringer("signal_user_id", promoteRequestingMember.UserID).Msg("failed to join puppet") + log.Warn().Stringer("signal_user_id", promoteRequestingMember.ACI).Msg("failed to join puppet") } } else { - log.Warn().Stringer("signal_user_id", promoteRequestingMember.UserID).Msg("Couldn't get puppet for join") + log.Warn().Stringer("signal_user_id", promoteRequestingMember.ACI).Msg("Couldn't get puppet for join") } - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: promoteRequestingMember.UserID, Role: promoteRequestingMember.Role}) + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: promoteRequestingMember.ACI, Role: promoteRequestingMember.Role}) } for _, addRequestingMember := range groupChange.AddRequestingMembers { // sender and target should be the same SignalID - puppet := portal.bridge.GetPuppetBySignalID(addRequestingMember.UserID) + puppet := portal.bridge.GetPuppetBySignalID(addRequestingMember.ACI) if puppet != nil { portal.sendMembershipWithPuppet(ctx, sender, puppet.IntentFor(portal).UserID, event.MembershipKnock, "knocked") } @@ -1062,9 +1079,9 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou log.Err(err).Msg("Couldn't get power levels") } else { for _, modifyRole := range modifyRoles { - puppet := portal.bridge.GetPuppetBySignalID(modifyRole.UserID) + puppet := portal.bridge.GetPuppetBySignalID(modifyRole.ACI) if puppet == nil { - log.Warn().Stringer("signal_user_id", modifyRole.UserID).Msg("Couldn't get puppet for power level change") + log.Warn().Stringer("signal_user_id", modifyRole.ACI).Msg("Couldn't get puppet for power level change") continue } powerLevel := 0 @@ -1073,7 +1090,7 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } levels.EnsureUserLevel(puppet.IntentFor(portal).UserID, powerLevel) if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(modifyRole.UserID) + user := portal.bridge.GetUserBySignalID(modifyRole.ACI) if user != nil { levels.EnsureUserLevel(user.MXID, powerLevel) } @@ -2237,14 +2254,14 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } } for _, member := range info.Members { - puppet := portal.bridge.GetPuppetBySignalID(member.UserID) + puppet := portal.bridge.GetPuppetBySignalID(member.ACI) if puppet == nil { - log.Warn().Stringer("signal_user_id", member.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", member.ACI).Msg("Couldn't get puppet for group member") continue } puppet.UpdateInfo(ctx, source) intent := puppet.IntentFor(portal) - if member.UserID != source.SignalID && portal.MXID != "" { + if member.ACI != source.SignalID && portal.MXID != "" { userIDs[intent.UserID] = ((int)(member.Role) >> 1) * 50 } delete(currentMembers, intent.UserID) @@ -2252,11 +2269,11 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * if currentMembers[intent.UserID] != event.MembershipJoin { err := intent.EnsureJoined(ctx, portal.MXID) if err != nil { - log.Err(err).Stringer("signal_user_id", member.UserID).Msg("Failed to ensure user is joined to portal") + log.Err(err).Stringer("signal_user_id", member.ACI).Msg("Failed to ensure user is joined to portal") } } if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(member.UserID) + user := portal.bridge.GetUserBySignalID(member.ACI) if user != nil { delete(currentMembers, user.MXID) userIDs[user.MXID] = ((int)(member.Role) >> 1) * 50 @@ -2273,9 +2290,12 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * return userIDs } for _, pendingMember := range info.PendingMembers { - puppet := portal.bridge.GetPuppetBySignalID(pendingMember.UserID) + if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + puppet := portal.bridge.GetPuppetBySignalID(pendingMember.ServiceID.UUID) if puppet == nil { - log.Warn().Stringer("signal_user_id", pendingMember.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", pendingMember.ServiceID.UUID).Msg("Couldn't get puppet for group member") continue } mxid := puppet.IntentFor(portal).UserID @@ -2295,7 +2315,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * userIDs[mxid] = ((int)(pendingMember.Role) >> 1) * 50 delete(currentMembers, mxid) if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(pendingMember.UserID) + user := portal.bridge.GetUserBySignalID(pendingMember.ServiceID.UUID) if user == nil { continue } @@ -2319,9 +2339,9 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } } for _, requestingMember := range info.RequestingMembers { - puppet := portal.bridge.GetPuppetBySignalID(requestingMember.UserID) + puppet := portal.bridge.GetPuppetBySignalID(requestingMember.ACI) if puppet == nil { - log.Warn().Stringer("signal_user_id", requestingMember.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", requestingMember.ACI).Msg("Couldn't get puppet for group member") continue } mxid := puppet.IntentFor(portal).UserID @@ -2341,9 +2361,12 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * delete(currentMembers, mxid) } for _, bannedMember := range info.BannedMembers { - puppet := portal.bridge.GetPuppetBySignalID(bannedMember.UserID) + if bannedMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + puppet := portal.bridge.GetPuppetBySignalID(bannedMember.ServiceID.UUID) if puppet == nil { - log.Warn().Stringer("signal_user_id", bannedMember.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", bannedMember.ServiceID.UUID).Msg("Couldn't get puppet for group member") continue } mxid := puppet.IntentFor(portal).UserID @@ -2355,7 +2378,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } delete(currentMembers, mxid) if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(bannedMember.UserID) + user := portal.bridge.GetUserBySignalID(bannedMember.ServiceID.UUID) if user == nil { continue } @@ -2590,8 +2613,8 @@ func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brGhost bridge.Gh } groupChange := &signalmeow.GroupChange{AddMembers: []*signalmeow.AddMember{{ GroupMember: signalmeow.GroupMember{ - UserID: puppet.SignalID, - Role: role, + ACI: puppet.SignalID, + Role: role, }, }}} revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) @@ -2621,8 +2644,8 @@ func (portal *Portal) HandleMatrixAcceptKnock(brSender bridge.User, brGhost brid } } groupChange := &signalmeow.GroupChange{PromoteRequestingMembers: []*signalmeow.RoleMember{{ - UserID: puppet.SignalID, - Role: role, + ACI: puppet.SignalID, + Role: role, }}} revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { @@ -2675,7 +2698,7 @@ func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost sender := brSender.(*User) puppet := brGhost.(*Puppet) groupChange := &signalmeow.GroupChange{AddBannedMembers: []*signalmeow.BannedMember{{ - UserID: puppet.SignalID, + ServiceID: libsignalgo.NewACIServiceID(puppet.SignalID), Timestamp: uint64(time.Now().UnixMilli()), }}} switch prevMembership := evt.Unsigned.PrevContent.AsMember().Membership; prevMembership { @@ -2684,7 +2707,8 @@ func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost case event.MembershipKnock: groupChange.DeleteRequestingMembers = []*uuid.UUID{&puppet.SignalID} case event.MembershipInvite: - groupChange.DeletePendingMembers = []*uuid.UUID{&puppet.SignalID} + serviceID := libsignalgo.NewACIServiceID(puppet.SignalID) + groupChange.DeletePendingMembers = []*libsignalgo.ServiceID{&serviceID} } revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { @@ -2703,7 +2727,8 @@ func (portal *Portal) HandleMatrixUnban(brSender bridge.User, brGhost bridge.Gho ctx := log.WithContext(context.TODO()) sender := brSender.(*User) puppet := brGhost.(*Puppet) - groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*uuid.UUID{&puppet.SignalID}} + serviceID := libsignalgo.NewACIServiceID(puppet.SignalID) + groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*libsignalgo.ServiceID{&serviceID}} revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error unbanning on Signal") @@ -2748,8 +2773,8 @@ func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.E role = signalmeow.GroupMember_ADMINISTRATOR } groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles, &signalmeow.RoleMember{ - UserID: puppet.SignalID, - Role: role, + ACI: puppet.SignalID, + Role: role, }) } } From fd7c3cd1b5d3b037aa396780cace411dbd2d33eb Mon Sep 17 00:00:00 2001 From: Malte E Date: Thu, 4 Apr 2024 21:40:05 +0200 Subject: [PATCH 145/718] add list-invited and revoke-invite commands, some fixes --- commands.go | 160 ++++++++++++++++++++++++++++++++++++--- pkg/signalmeow/groups.go | 2 +- 2 files changed, 150 insertions(+), 12 deletions(-) diff --git a/commands.go b/commands.go index 1b4fbea..2f224bc 100644 --- a/commands.go +++ b/commands.go @@ -72,6 +72,8 @@ func (br *SignalBridge) RegisterCommands() { cmdResetInviteLink, cmdCreate, cmdInvite, + cmdListInvited, + cmdRevokeInvite, ) } @@ -345,20 +347,156 @@ func fnInvite(ce *WrappedCommandEvent) { var groupChange signalmeow.GroupChange if aci != uuid.Nil { - groupChange.AddMembers = append(groupChange.AddMembers, &signalmeow.AddMember{ - GroupMember: signalmeow.GroupMember{ - ACI: aci, - Role: signalmeow.GroupMember_DEFAULT, + groupChange.AddMembers = []*signalmeow.AddMember{ + { + GroupMember: signalmeow.GroupMember{ + ACI: aci, + Role: signalmeow.GroupMember_DEFAULT, + }, }, - }) + } } else { - groupChange.AddPendingMembers = append(groupChange.AddPendingMembers, &signalmeow.PendingMember{ - ServiceID: libsignalgo.NewPNIServiceID(pni), - AddedByUserID: ce.User.SignalID, - Role: signalmeow.GroupMember_DEFAULT, - }) + groupChange.AddPendingMembers = []*signalmeow.PendingMember{ + { + ServiceID: libsignalgo.NewPNIServiceID(pni), + AddedByUserID: ce.User.SignalID, + Role: signalmeow.GroupMember_DEFAULT, + }, + } } - ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) + revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) + if err != nil { + ce.Reply("Failed to update group: %w", err) + return + } + ce.Portal.Revision = revision + if aci != uuid.Nil { + group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), revision) + if err != nil { + ce.Reply("Failed to fetch group after invite: %w", err) + } + ce.Portal.SyncParticipants(ce.Ctx, user, group) + ce.Portal.Update(ce.Ctx) + return + } + ce.Portal.Update(ce.Ctx) + ce.Reply("Invited " + e164) +} + +var cmdListInvited = &commands.FullHandler{ + Func: wrapCommand(fnListInvited), + Name: "list-invited", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "list pending invites", + Args: "<_international phone number_>", + }, + RequiresLogin: true, + RequiresPortal: true, +} + +func fnListInvited(ce *WrappedCommandEvent) { + group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), ce.Portal.Revision) + if err != nil { + ce.Reply("Failed to fetch group info: %w", err) + return + } + var memberList []string + for _, pendingMember := range group.PendingMembers { + recipientString, err := pendingMemberToString(ce.Ctx, ce.User, pendingMember) + if err != nil { + ce.Reply("Failed to fetch recipient for %s: %w", pendingMember.ServiceID, err) + continue + } + memberList = append(memberList, recipientString) + } + if len(memberList) == 0 { + ce.Reply("No pending Invites") + } else { + ce.Reply(strings.Join(memberList, "\n")) + } +} + +func pendingMemberToString(ctx context.Context, user *User, pendingMember *signalmeow.PendingMember) (string, error) { + var pni, aci uuid.UUID + if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypeACI { + aci = pendingMember.ServiceID.UUID + } else { + pni = pendingMember.ServiceID.UUID + } + recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) + if err != nil { + return "", err + } + if recipient.E164 != "" { + return recipient.E164, nil + } else { + return "Unidentified User", nil + } +} + +var cmdRevokeInvite = &commands.FullHandler{ + Func: wrapCommand(fnRevokeInvite), + Name: "revoke-invite", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "Revoke an invite by phone number.", + Args: "<_international phone number_>", + }, + RequiresLogin: true, + RequiresPortal: true, +} + +func fnRevokeInvite(ce *WrappedCommandEvent) { + if len(ce.Args) == 0 { + ce.Reply("**Usage:** `RevokeInvite `") + return + } + e164 := "+" + numberCleaner.Replace(strings.Join(ce.Args, "")) + + user := ce.User + var serviceID libsignalgo.ServiceID + group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), ce.Portal.Revision) + if err != nil { + ce.Reply("Failed to fetch group info: %w", err) + return + } + var pni, aci uuid.UUID + for _, pendingMember := range group.PendingMembers { + if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypeACI { + aci = pendingMember.ServiceID.UUID + } else { + pni = pendingMember.ServiceID.UUID + } + recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ce.Ctx, aci, pni, nil) + if err != nil { + continue + } + if recipient.E164 == e164 { + serviceID = pendingMember.ServiceID + break + } + } + if serviceID.UUID == uuid.Nil { + ce.Reply("User not in Group") + return + } + var groupChange signalmeow.GroupChange + groupChange.DeletePendingMembers = []*libsignalgo.ServiceID{&serviceID} + revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) + if err != nil { + ce.Reply("Failed to update group: %w", err) + return + } + if aci != uuid.Nil { + target := ce.Bridge.GetPuppetBySignalID(aci) + if target != nil { + ce.Bot.SendCustomMembershipEvent(ce.Ctx, ce.Portal.MXID, target.IntentFor(ce.Portal).UserID, event.MembershipLeave, "removed by "+user.MXID.String()) + } + } + ce.Portal.Revision = revision + ce.Portal.Update(ce.Ctx) + ce.Reply("Revoked the invitation for " + e164) } var cmdResolvePhone = &commands.FullHandler{ diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 0e647d0..e4857bf 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -1294,7 +1294,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, deletePendingMember := range decryptedGroupChange.DeletePendingMembers { - encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(deletePendingMember.UUID)) + encryptedUserID, err := groupSecretParams.EncryptServiceID(*deletePendingMember) if err != nil { log.Err(err).Msg("Encrypt UserId error for deletePendingMember") return nil, err From 9bf99ebe0eeb2e33467290ec7989c82078f02756 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:22:49 +0200 Subject: [PATCH 146/718] Fix comparison in promotePendingPniAciMembers --- pkg/signalmeow/groups.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index e4857bf..829fc03 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -1022,7 +1022,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp log.Err(err).Msg("DecryptUUID Pni error for promotePendingPniAciMember") return nil, err } - if pniServiceID.Type != libsignalgo.ServiceIDTypeACI { + if pniServiceID.Type != libsignalgo.ServiceIDTypePNI { return nil, fmt.Errorf("Wrong ServiceID kind: expected PNI, got ACI") } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingPniAciMember.ProfileKey) From 680e0b8c52a36267844e2bf71e522d2c1c1c0cef Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Mon, 8 Apr 2024 21:24:49 +0200 Subject: [PATCH 147/718] Handle missed GroupChanges using group history (#488) --- pkg/signalmeow/groups.go | 111 ++++++++++++++++++++++++++++++++++++--- portal.go | 45 ++++++++++++++-- 2 files changed, 147 insertions(+), 9 deletions(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 829fc03..1214088 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -178,6 +178,7 @@ type BannedMember struct { type GroupChange struct { groupMasterKey types.SerializedGroupMasterKey + SourceACI uuid.UUID Revision uint32 AddMembers []*AddMember DeleteMembers []*uuid.UUID @@ -317,6 +318,11 @@ func (groupChange *GroupChange) GetAvatarPath() *string { return groupChange.ModifyAvatar } +type GroupChangeState struct { + GroupState *Group + GroupChange *GroupChange +} + type GroupAuth struct { Username string Password string @@ -812,21 +818,26 @@ type GroupCache struct { func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalpb.GroupContextV2) (*GroupChange, error) { masterKeyBytes := libsignalgo.GroupMasterKey(groupContext.MasterKey) groupMasterKey := masterKeyFromBytes(masterKeyBytes) - log := zerolog.Ctx(ctx).With().Str("action", "decrypt group change").Logger() - - encryptedGroupChange := &signalpb.GroupChange{} groupChangeBytes := groupContext.GroupChange + encryptedGroupChange := &signalpb.GroupChange{} err := proto.Unmarshal(groupChangeBytes, encryptedGroupChange) if err != nil { return nil, fmt.Errorf("Error unmarshalling group change: %w", err) } + return cli.decryptGroupChange(ctx, encryptedGroupChange, groupMasterKey, true) +} +func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange *signalpb.GroupChange, groupMasterKey types.SerializedGroupMasterKey, verifySignature bool) (*GroupChange, error) { + log := zerolog.Ctx(ctx).With().Str("action", "decrypt group change").Logger() serverSignature := encryptedGroupChange.ServerSignature encryptedActionsBytes := encryptedGroupChange.Actions - err = libsignalgo.ServerPublicParamsVerifySignature(prodServerPublicParams, encryptedActionsBytes, libsignalgo.NotarySignature(serverSignature)) - if err != nil { - return nil, fmt.Errorf("Failed to verify Server Signature: %w", err) + var err error + if verifySignature { + err = libsignalgo.ServerPublicParamsVerifySignature(prodServerPublicParams, encryptedActionsBytes, libsignalgo.NotarySignature(serverSignature)) + if err != nil { + return nil, fmt.Errorf("Failed to verify Server Signature: %w", err) + } } encryptedActions := signalpb.GroupChange_Actions{} @@ -842,9 +853,18 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp return nil, err } + sourceServiceID, err := groupSecretParams.DecryptServiceID(libsignalgo.UUIDCiphertext(encryptedActions.SourceServiceId)) + if err != nil { + log.Err(err).Msg("Couldn't decrypt source serviceID") + return nil, err + } + if sourceServiceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("wrong serviceid kind: expected aci, got pni") + } decryptedGroupChange := &GroupChange{ groupMasterKey: groupMasterKey, Revision: encryptedActions.Revision, + SourceACI: sourceServiceID.UUID, } if encryptedActions.ModifyTitle != nil { @@ -1794,3 +1814,82 @@ func (cli *Client) CreateGroup(ctx context.Context, decryptedGroup *Group, avata } return group, nil } + +func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdentifier, fromRevision uint32, includeFirstState bool) ([]*GroupChangeState, error) { + log := zerolog.Ctx(ctx).With().Str("action", "GetGroupHistoryPage").Logger() + groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) + if err != nil { + log.Err(err).Msg("Failed to get group master key") + return nil, err + } + if groupMasterKey == "" { + return nil, fmt.Errorf("No group master key found for group identifier %s", gid) + } + masterKeyBytes := masterKeyToBytes(groupMasterKey) + groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) + if err != nil { + return nil, err + } + opts := &web.HTTPReqOpt{ + Username: &groupAuth.Username, + Password: &groupAuth.Password, + ContentType: web.ContentTypeProtobuf, + Host: web.StorageHostname, + } + // highest known epoch seems to always be 5, but that may change in the future. includeLastState is always false + path := fmt.Sprintf("/v1/groups/logs/%d?maxSupportedChangeEpoch=%d&includeFirstState=%t&includeLastState=false", fromRevision, 5, includeFirstState) + response, err := web.SendHTTPRequest(ctx, http.MethodGet, path, opts) + if err != nil { + return nil, err + } + if response.StatusCode != 200 { + return nil, fmt.Errorf("fetchGroupByID SendHTTPRequest bad status: %d", response.StatusCode) + } + var encryptedGroupChanges signalpb.GroupChanges + groupChangesBytes, err := io.ReadAll(response.Body) + if err != nil { + return nil, err + } + err = proto.Unmarshal(groupChangesBytes, &encryptedGroupChanges) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal group: %w", err) + } + + groupChanges, err := cli.decryptGroupChanges(ctx, &encryptedGroupChanges, groupMasterKey) + if err != nil { + return nil, fmt.Errorf("failed to decrypt group: %w", err) + } + return groupChanges, nil +} + +func (cli *Client) decryptGroupChanges(ctx context.Context, encryptedGroupChanges *signalpb.GroupChanges, groupMasterKey types.SerializedGroupMasterKey) ([]*GroupChangeState, error) { + log := zerolog.Ctx(ctx).With().Str("action", "decryptGroupChanges").Logger() + var groupChanges []*GroupChangeState + for _, groupChangeState := range encryptedGroupChanges.GroupChanges { + var group *Group + var err error + // GroupState == nil is normal, except for first and last, depending on the parameters it was fetched with + if groupChangeState.GroupState != nil { + group, err = decryptGroup(ctx, groupChangeState.GroupState, groupMasterKey) + if err != nil { + log.Err(err).Msg("Failed to decrypt Group") + return nil, err + } + } + var groupChange *GroupChange + // GroupChange shouldn't be nil - if it is, something will probably go wrong + if groupChangeState.GroupChange == nil { + return nil, fmt.Errorf("received group change state without group change") + } + groupChange, err = cli.decryptGroupChange(ctx, groupChangeState.GroupChange, groupMasterKey, false) + if err != nil { + log.Err(err).Msg("Failed to decrypt GroupChange") + return nil, err + } + groupChanges = append(groupChanges, &GroupChangeState{ + GroupState: group, + GroupChange: groupChange, + }) + } + return groupChanges, nil +} diff --git a/portal.go b/portal.go index 0624b89..5a4ae72 100644 --- a/portal.go +++ b/portal.go @@ -893,9 +893,18 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg // Always update sender info when we receive a message from them, there's caching inside the function sender.UpdateInfo(genericCtx, source) // Handle earlier missed group changes here. - // If this message is a group change, don't handle it here, it's handled below. - if msg.GetGroupV2().GetGroupChange() == nil && portal.Revision < msg.GetGroupV2().GetRevision() { - portal.UpdateInfo(genericCtx, source, nil, msg.GetGroupV2().GetRevision()) + if msg.GetGroupV2() != nil { + requiredRevision := msg.GetGroupV2().GetRevision() + if msg.GetGroupV2().GetGroupChange() != nil { + requiredRevision = requiredRevision - 1 + } + if portal.Revision < requiredRevision { + err := portal.catchUpHistory(source, portal.Revision+1, requiredRevision, msg.GetTimestamp()) + if err != nil { + portal.log.Err(err).Msg("Failed to catch up group history, trying regular update") + portal.UpdateInfo(genericCtx, source, nil, msg.GetGroupV2().GetRevision()) + } + } } else if portal.IsPrivateChat() && portal.UserID().UUID == portal.Receiver && portal.Name != NoteToSelfName { // Slightly hacky way to make note to self names backfill portal.UpdateDMInfo(genericCtx, false) @@ -921,6 +930,30 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg } } +func (portal *Portal) catchUpHistory(source *User, fromRevision uint32, toRevision uint32, ts uint64) error { + log := portal.log.With(). + Str("action", "catchUpHistory"). + Stringer("source", source.MXID). + Uint32("from_revision", fromRevision). + Uint32("to_revision", toRevision). + Logger() + ctx := log.WithContext(context.TODO()) + groupChanges, err := source.Client.GetGroupHistoryPage(ctx, portal.GroupID(), fromRevision, false) + if err != nil { + log.Err(err).Msg("Failed to get GroupChanges") + return err + } + for _, groupChangeState := range groupChanges { + sender := portal.bridge.GetPuppetBySignalID(groupChangeState.GroupChange.SourceACI) + portal.applySignalGroupChange(ctx, source, sender, groupChangeState.GroupChange, ts) + // for revision > toRevision, we should have received a group change already + if groupChangeState.GroupChange.Revision == toRevision { + break + } + } + return nil +} + func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, groupMeta *signalpb.GroupContextV2, ts uint64) { log := portal.log.With(). Str("action", "handle signal group change"). @@ -934,6 +967,11 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou log.Err(err).Msg("Handling GroupChange failed") return } + portal.applySignalGroupChange(ctx, source, sender, groupChange, ts) +} + +func (portal *Portal) applySignalGroupChange(ctx context.Context, source *User, sender *Puppet, groupChange *signalmeow.GroupChange, ts uint64) { + log := zerolog.Ctx(ctx) if groupChange.Revision <= portal.Revision { return } @@ -952,6 +990,7 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } intent := sender.IntentFor(portal) modifyRoles := groupChange.ModifyMemberRoles + var err error for _, deleteBannedMember := range groupChange.DeleteBannedMembers { _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *&deleteBannedMember.UUID, event.MembershipLeave, "unbanned") if err != nil { From 57348d094386d31e3ab9ca7fcc63f80cf21d02c2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Apr 2024 12:30:38 +0300 Subject: [PATCH 148/718] Update to libsignal 0.44.0 --- pkg/libsignalgo/authcredential.go | 16 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 248 ++++++++++++++----- pkg/libsignalgo/version.go | 2 +- pkg/signalmeow/prod-server-public-params.dat | Bin 641 -> 673 bytes 5 files changed, 197 insertions(+), 71 deletions(-) diff --git a/pkg/libsignalgo/authcredential.go b/pkg/libsignalgo/authcredential.go index 193f5b8..57396ef 100644 --- a/pkg/libsignalgo/authcredential.go +++ b/pkg/libsignalgo/authcredential.go @@ -23,6 +23,7 @@ package libsignalgo */ import "C" import ( + "fmt" "unsafe" "github.com/google/uuid" @@ -45,9 +46,8 @@ func ReceiveAuthCredentialWithPni( redemptionTime uint64, authCredResponse AuthCredentialWithPniResponse, ) (*AuthCredentialWithPni, error) { - c_result := [C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN]C.uchar{} + var c_result C.SignalOwnedBuffer = C.SignalOwnedBuffer{} c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) - c_authCredResponse := (*[C.SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN]C.uchar)(unsafe.Pointer(&authCredResponse[0])) signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_service_id( &c_result, @@ -55,13 +55,16 @@ func ReceiveAuthCredentialWithPni( NewACIServiceID(aci).CFixedBytes(), NewPNIServiceID(pni).CFixedBytes(), C.uint64_t(redemptionTime), - c_authCredResponse, + BytesToBuffer(authCredResponse[:]), ) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - result := AuthCredentialWithPni(C.GoBytes(unsafe.Pointer(&c_result), C.int(C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN))) - return &result, nil + 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) + } + return (*AuthCredentialWithPni)(resultBytes), nil } func NewAuthCredentialWithPniResponse(b []byte) (*AuthCredentialWithPniResponse, error) { @@ -84,14 +87,13 @@ func CreateAuthCredentialWithPniPresentation( c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) c_randomness := (*[C.SignalRANDOMNESS_LEN]C.uchar)(unsafe.Pointer(&randomness[0])) c_groupSecretParams := (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar)(unsafe.Pointer(&groupSecretParams[0])) - c_authCredWithPni := (*[C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN]C.uchar)(unsafe.Pointer(&authCredWithPni[0])) signalFfiError := C.signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic( &c_result, c_serverPublicParams, c_randomness, c_groupSecretParams, - c_authCredWithPni, + BytesToBuffer(authCredWithPni[:]), ) if signalFfiError != nil { return nil, wrapError(signalFfiError) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index ce37388..02e03ee 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit ce3738855295cdafd04f377810ace289a6172d11 +Subproject commit 02e03ee05742079694d643fbc64fa737b275e9f8 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 3fdfdd7..b8bfab8 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -34,6 +34,8 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalPRESENTATION_VERSION_3 2 +#define SignalPRESENTATION_VERSION_4 3 + #define SignalAES_KEY_LEN 32 #define SignalAESGCM_NONCE_LEN 12 @@ -92,9 +94,9 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalRESERVED_LEN 1 -#define SignalSERVER_SECRET_PARAMS_LEN 2689 +#define SignalSERVER_SECRET_PARAMS_LEN 2721 -#define SignalSERVER_PUBLIC_PARAMS_LEN 641 +#define SignalSERVER_PUBLIC_PARAMS_LEN 673 #define SignalUUID_CIPHERTEXT_LEN 65 @@ -182,9 +184,13 @@ typedef enum { SignalErrorCodeIoError = 130, SignalErrorCodeInvalidMediaInput = 131, SignalErrorCodeUnsupportedMediaInput = 132, - SignalErrorCodeNetwork = 133, + SignalErrorCodeConnectionTimedOut = 133, SignalErrorCodeNetworkProtocol = 134, SignalErrorCodeRateLimited = 135, + SignalErrorCodeWebSocket = 136, + SignalErrorCodeCdsiInvalidToken = 137, + SignalErrorCodeConnectionFailed = 138, + SignalErrorCodeChatServiceInactive = 139, SignalErrorCodeSvrDataMissing = 150, SignalErrorCodeSvrRestoreFailed = 151, } SignalErrorCode; @@ -289,6 +295,23 @@ typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMe typedef struct SignalValidatingMac SignalValidatingMac; +/** + * A type alias to be used with [`OwnedBufferOf`], so that `OwnedBufferOf` and + * `OwnedBufferOf<*const c_char>` get distinct names. + */ +typedef const char *SignalCStringPtr; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalCStringPtr *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfCStringPtr; + typedef struct { /** * Telephone number, as an unformatted e164. @@ -334,7 +357,7 @@ typedef struct { typedef struct { SignalOwnedBuffer bytes; SignalOwnedBufferOfusize lengths; -} SignalStringArray; +} SignalBytestringArray; typedef struct { const unsigned char *base; @@ -461,6 +484,71 @@ typedef struct { SignalStoreSenderKey store_sender_key; } SignalSenderKeyStore; +typedef struct { + const SignalBorrowedBuffer *base; + size_t length; +} SignalBorrowedSliceOfBuffers; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseOwnedBufferOfc_uchar)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromisebool)(SignalFfiError *error, const bool *result, const void *context); + +typedef struct { + bool connection_reused; + uint32_t reconnect_count; + uint8_t raw_ip_type; + double duration_secs; + const char *connection_info; +} SignalFfiChatServiceDebugInfo; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseFfiChatServiceDebugInfo)(SignalFfiError *error, const SignalFfiChatServiceDebugInfo *result, const void *context); + +typedef struct { + uint16_t status; + const char *message; + SignalOwnedBufferOfCStringPtr headers; + SignalOwnedBuffer body; +} SignalFfiChatResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseFfiChatResponse)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); + +typedef struct { + SignalFfiChatResponse response; + SignalFfiChatServiceDebugInfo debug_info; +} SignalFfiResponseAndDebugInfo; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + */ +typedef void (*SignalCPromiseFfiResponseAndDebugInfo)(SignalFfiError *error, const SignalFfiResponseAndDebugInfo *result, const void *context); + /** * A C callback used to report the results of Rust futures. * @@ -482,13 +570,7 @@ typedef struct { */ typedef void (*SignalCPromiseFfiCdsiLookupResponse)(SignalFfiError *error, const SignalFfiCdsiLookupResponse *result, const void *context); -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - */ -typedef void (*SignalCPromiseOwnedBufferOfc_uchar)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); +typedef SignalBytestringArray SignalStringArray; typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); @@ -526,14 +608,6 @@ typedef void (*SignalCPromiseTestingHandleType)(SignalFfiError *error, SignalTes */ typedef void (*SignalCPromiseOtherTestingHandleType)(SignalFfiError *error, SignalOtherTestingHandleType *const *result, const void *context); -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - */ -typedef void (*SignalCPromisebool)(SignalFfiError *error, const bool *result, const void *context); - /** * A C callback used to report the results of Rust futures. * @@ -550,9 +624,11 @@ void signal_free_string(const char *buf); void signal_free_buffer(const unsigned char *buf, size_t buf_len); +void signal_free_list_of_strings(SignalOwnedBufferOfCStringPtr buffer); + void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); -void signal_free_string_array(SignalStringArray array); +void signal_free_bytestring_array(SignalBytestringArray array); SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); @@ -1052,14 +1128,6 @@ SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *ou SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer received_ciphertext); -SignalFfiError *signal_auth_credential_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_auth_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer buffer); - SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); SignalFfiError *signal_expiring_profile_key_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); @@ -1128,15 +1196,11 @@ SignalFfiError *signal_server_secret_params_get_public_params(unsigned char (*ou SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], const unsigned char (*params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); -SignalFfiError *signal_server_public_params_receive_auth_credential(unsigned char (*out)[SignalAUTH_CREDENTIAL_LEN], const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, uint32_t redemption_time, const unsigned char (*response)[SignalAUTH_CREDENTIAL_RESPONSE_LEN]); +SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); -SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(unsigned char (*out)[SignalAUTH_CREDENTIAL_WITH_PNI_LEN], const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, const unsigned char (*response)[SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN]); +SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_aci(SignalOwnedBuffer *out, const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); -SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_aci(unsigned char (*out)[SignalAUTH_CREDENTIAL_WITH_PNI_LEN], const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, const unsigned char (*response)[SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN]); - -SignalFfiError *signal_server_public_params_create_auth_credential_presentation_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*auth_credential)[SignalAUTH_CREDENTIAL_LEN]); - -SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*auth_credential)[SignalAUTH_CREDENTIAL_WITH_PNI_LEN]); +SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); @@ -1150,11 +1214,15 @@ SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); -SignalFfiError *signal_server_secret_params_issue_auth_credential_deterministic(unsigned char (*out)[SignalAUTH_CREDENTIAL_RESPONSE_LEN], const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, uint32_t redemption_time); +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_service_id_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_service_id_deterministic(unsigned char (*out)[SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN], const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_aci_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_aci_deterministic(unsigned char (*out)[SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN], const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); + +SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorrowedBuffer bytes); + +SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer bytes); SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); @@ -1280,23 +1348,37 @@ SignalFfiError *signal_backup_auth_credential_presentation_check_valid_contents( SignalFfiError *signal_backup_auth_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, uint64_t now, SignalBorrowedBuffer server_params_bytes); -SignalFfiError *signal_group_send_credential_response_default_expiration_based_on_current_time(uint64_t *out); +SignalFfiError *signal_group_send_derived_key_pair_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_group_send_credential_response_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer concatenated_group_member_ciphertexts, const unsigned char (*requester)[SignalUUID_CIPHERTEXT_LEN], uint64_t expiration, const unsigned char (*server_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); +SignalFfiError *signal_group_send_derived_key_pair_for_expiration(SignalOwnedBuffer *out, uint64_t expiration, const unsigned char (*server_params)[SignalSERVER_SECRET_PARAMS_LEN]); -SignalFfiError *signal_group_send_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); +SignalFfiError *signal_group_send_endorsements_response_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_group_send_credential_response_receive(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_aci, uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); +SignalFfiError *signal_group_send_endorsements_response_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer key_pair, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); -SignalFfiError *signal_group_send_credential_response_receive_with_ciphertexts(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, const unsigned char (*requester)[SignalUUID_CIPHERTEXT_LEN], uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); +SignalFfiError *signal_group_send_endorsements_response_get_expiration(uint64_t *out, SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_group_send_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN]); -SignalFfiError *signal_group_send_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN]); -SignalFfiError *signal_group_send_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); +SignalFfiError *signal_group_send_endorsement_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_group_send_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, SignalBorrowedBuffer group_members, uint64_t now, const unsigned char (*server_params)[SignalSERVER_SECRET_PARAMS_LEN]); +SignalFfiError *signal_group_send_endorsement_combine(SignalOwnedBuffer *out, SignalBorrowedSliceOfBuffers endorsements); + +SignalFfiError *signal_group_send_endorsement_remove(SignalOwnedBuffer *out, SignalBorrowedBuffer endorsement, SignalBorrowedBuffer to_remove); + +SignalFfiError *signal_group_send_endorsement_to_token(SignalOwnedBuffer *out, SignalBorrowedBuffer endorsement, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); + +SignalFfiError *signal_group_send_token_check_valid_contents(SignalBorrowedBuffer bytes); + +SignalFfiError *signal_group_send_token_to_full_token(SignalOwnedBuffer *out, SignalBorrowedBuffer token, uint64_t expiration); + +SignalFfiError *signal_group_send_full_token_check_valid_contents(SignalBorrowedBuffer bytes); + +SignalFfiError *signal_group_send_full_token_get_expiration(uint64_t *out, SignalBorrowedBuffer token); + +SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalBorrowedBuffer user_ids, uint64_t now, SignalBorrowedBuffer key_pair); SignalFfiError *signal_verify_signature(bool *out, SignalBorrowedBuffer cert_pem, SignalBorrowedBuffer body, SignalBorrowedBuffer signature, uint64_t current_timestamp); @@ -1306,8 +1388,42 @@ SignalFfiError *signal_tokio_async_context_destroy(SignalTokioAsyncContext *p); SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment); +SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManager *connection_manager, const char *host, uint16_t port); + +SignalFfiError *signal_connection_manager_clear_proxy(const SignalConnectionManager *connection_manager); + SignalFfiError *signal_connection_manager_destroy(SignalConnectionManager *p); +SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); + +SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); + +SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); + +SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); + +SignalFfiError *signal_chat_destroy(SignalChat *p); + +SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); + +SignalFfiError *signal_http_request_new_with_body(SignalHttpRequest **out, const char *method, const char *path, SignalBorrowedBuffer body_as_slice); + +SignalFfiError *signal_http_request_new_without_body(SignalHttpRequest **out, const char *method, const char *path); + +SignalFfiError *signal_http_request_add_header(const SignalHttpRequest *request, const char *name, const char *value); + +SignalFfiError *signal_chat_service_new(SignalChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password); + +SignalFfiError *signal_chat_service_disconnect(SignalCPromisebool promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); + +SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); + +SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); + +SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + +SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + SignalFfiError *signal_lookup_request_new(SignalLookupRequest **out); SignalFfiError *signal_lookup_request_add_e164(const SignalLookupRequest *request, const char *e164); @@ -1324,24 +1440,12 @@ SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); SignalFfiError *signal_cdsi_lookup_destroy(SignalCdsiLookup *p); -SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request, uint32_t timeout_millis); +SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request); SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, const SignalCdsiLookup *lookup); SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalCdsiLookup *lookup); -SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); - -SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); - -SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password, uint32_t op_timeout_ms); - -SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password, uint32_t op_timeout_ms); - -SignalFfiError *signal_chat_destroy(SignalChat *p); - -SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); - SignalFfiError *signal_pin_hash_destroy(SignalPinHash *p); SignalFfiError *signal_pin_hash_clone(SignalPinHash **new_obj, const SignalPinHash *obj); @@ -1413,7 +1517,7 @@ SignalFfiError *signal_mp4_sanitizer_sanitize(SignalSanitizedMetadata **out, con #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_webp_sanitizer_sanitize(bool *out, const SignalSyncInputStream *input); +SignalFfiError *signal_webp_sanitizer_sanitize(const SignalSyncInputStream *input); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) @@ -1496,8 +1600,28 @@ SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer promi SignalFfiError *signal_testing_return_string_array(SignalStringArray *out); +SignalFfiError *signal_testing_process_bytestring_array(SignalBytestringArray *out, SignalBorrowedSliceOfBuffers input); + SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime); -SignalFfiError *signal_testing_cdsi_lookup_error_convert(bool *out); +SignalFfiError *signal_testing_cdsi_lookup_error_convert(const char *error_description); + +SignalFfiError *signal_testing_chat_service_error_convert(void); + +SignalFfiError *signal_testing_chat_service_inactive_error_convert(void); + +SignalFfiError *signal_testing_chat_service_response_convert(SignalFfiChatResponse *out, bool body_present); + +SignalFfiError *signal_testing_chat_service_debug_info_convert(SignalFfiChatServiceDebugInfo *out); + +SignalFfiError *signal_testing_chat_service_response_and_debug_info_convert(SignalFfiResponseAndDebugInfo *out); + +SignalFfiError *signal_testing_chat_request_get_method(const char **out, const SignalHttpRequest *request); + +SignalFfiError *signal_testing_chat_request_get_path(const char **out, const SignalHttpRequest *request); + +SignalFfiError *signal_testing_chat_request_get_header_value(const char **out, const SignalHttpRequest *request, const char *header_name); + +SignalFfiError *signal_testing_chat_request_get_body(SignalOwnedBuffer *out, const SignalHttpRequest *request); #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index b977e45..ac15575 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.41.0" +const Version = "v0.44.0" diff --git a/pkg/signalmeow/prod-server-public-params.dat b/pkg/signalmeow/prod-server-public-params.dat index bffaafb69f63ec1990647e3554867add48655a69..9391895914908b47e6bdfeb9aa108754b3acd5a3 100644 GIT binary patch delta 40 ycmV+@0N4M41)&A7fdU}Zl|OF)xFP-hgFRD@nH>>Zrr<{RI}IUr(O>AA510p7oDnYo delta 7 OcmZ3;+Q_=0kqH0_IRan+ From d946571c5af1221d8e4cb0b1d0093d35fa715a5c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Apr 2024 19:37:50 +0300 Subject: [PATCH 149/718] Remove invalid cleanup calls --- portal.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/portal.go b/portal.go index 5a4ae72..44f67bb 100644 --- a/portal.go +++ b/portal.go @@ -1184,7 +1184,6 @@ func (portal *Portal) applySignalGroupChange(ctx context.Context, source *User, log.Err(err).Msg("Failed to save portal in database after processing group change") } portal.UpdateBridgeInfo(ctx) - portal.CleanupIfEmpty(ctx) } func (portal *Portal) sendMembershipForPuppetAndUser(ctx context.Context, sender *Puppet, target uuid.UUID, membership event.Membership, action string) (puppet *Puppet, err error) { @@ -2453,7 +2452,6 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } } } - portal.CleanupIfEmpty(ctx) return userIDs } From e369a56c314a62bbdd08cf0bf671ef09397285ac Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Thu, 11 Apr 2024 14:31:27 -0400 Subject: [PATCH 150/718] Minor incoming messages refactor and send m.notice on decryption errors (#496) We were falling through without propagating errors anywhere. I caught most decryption errors and send them along in the new Err field in DecryptionResult, to be then passed along to the bridge as a new type of chat event. I'm going to do another pass to catch any last decryption errors, but this should be a big improvement over what we currently do. --- pkg/signalmeow/events/message.go | 18 +- pkg/signalmeow/receiving.go | 835 +++++++++++++++++-------------- user.go | 13 + 3 files changed, 481 insertions(+), 385 deletions(-) diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index e8ba1cb..0db0f24 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -28,12 +28,13 @@ type SignalEvent interface { isSignalEvent() } -func (*ChatEvent) isSignalEvent() {} -func (*Receipt) isSignalEvent() {} -func (*ReadSelf) isSignalEvent() {} -func (*Call) isSignalEvent() {} -func (*ContactList) isSignalEvent() {} -func (*ACIFound) isSignalEvent() {} +func (*ChatEvent) isSignalEvent() {} +func (*DecryptionError) isSignalEvent() {} +func (*Receipt) isSignalEvent() {} +func (*ReadSelf) isSignalEvent() {} +func (*Call) isSignalEvent() {} +func (*ContactList) isSignalEvent() {} +func (*ACIFound) isSignalEvent() {} type MessageInfo struct { Sender uuid.UUID @@ -47,6 +48,11 @@ type ChatEvent struct { Event signalpb.ChatEventContent } +type DecryptionError struct { + Sender uuid.UUID + Err error +} + type Receipt struct { Sender uuid.UUID Content *signalpb.ReceiptMessage diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 55a44e8..ba29914 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -263,10 +263,8 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web }, nil } -// TODO: we should split this up into multiple functions func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { log := *zerolog.Ctx(ctx) - responseCode := 200 envelope := &signalpb.Envelope{} err := proto.Unmarshal(req.Body, envelope) if err != nil { @@ -274,11 +272,6 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. return nil, err } destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) - if err != nil { - log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") - return nil, err - } - var result *DecryptionResult log.Trace(). Uint64("timestamp", envelope.GetTimestamp()). Str("destination_service_id", envelope.GetDestinationServiceId()). @@ -289,184 +282,38 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. Str("envelope_type", signalpb.Envelope_Type_name[int32(envelope.GetType())]). Msg("Received envelope") + result := cli.decryptEnvelope(ctx, envelope) + + err = cli.handleDecryptedResult(ctx, result, destinationServiceID) + if err != nil { + log.Err(err).Msg("handleDecryptedResult error") + return nil, err + } + + return &web.SimpleResponse{ + Status: 200, + }, nil +} + +func (cli *Client) decryptEnvelope( + ctx context.Context, + envelope *signalpb.Envelope, +) DecryptionResult { + log := zerolog.Ctx(ctx) + + destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) + if err != nil { + log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") + return DecryptionResult{Err: err, Urgent: envelope.GetUrgent()} + } + var result *DecryptionResult + switch *envelope.Type { case signalpb.Envelope_UNIDENTIFIED_SENDER: - if destinationServiceID != cli.Store.ACIServiceID() { - log.Warn().Stringer("destination_service_id", destinationServiceID). - Msg("Received UNIDENTIFIED_SENDER envelope for non-ACI destination") - break - } - usmc, err := libsignalgo.SealedSenderDecryptToUSMC( - ctx, - envelope.GetContent(), - cli.Store.ACIIdentityStore, - ) - if err != nil || usmc == nil { - if err == nil { - err = fmt.Errorf("usmc is nil") - } - log.Err(err).Msg("SealedSenderDecryptToUSMC error") - return nil, err - } - - messageType, err := usmc.GetMessageType() + result, err = cli.decryptUnidentifiedSenderEnvelope(ctx, destinationServiceID, envelope) if err != nil { - log.Err(err).Msg("GetMessageType error") - } - senderCertificate, err := usmc.GetSenderCertificate() - if err != nil { - log.Err(err).Msg("GetSenderCertificate error") - } - senderUUID, err := senderCertificate.GetSenderUUID() - if err != nil { - log.Err(err).Msg("GetSenderUUID error") - } - senderDeviceID, err := senderCertificate.GetDeviceID() - if err != nil { - log.Err(err).Msg("GetDeviceID error") - } - senderAddress, err := libsignalgo.NewACIServiceID(senderUUID).Address(uint(senderDeviceID)) - if err != nil { - log.Err(err).Msg("NewAddress error") - } - senderE164, err := senderCertificate.GetSenderE164() - if err != nil { - log.Err(err).Msg("GetSenderE164 error") - } - usmcContents, err := usmc.GetContents() - if err != nil { - log.Err(err).Msg("GetContents error") - } - log = log.With(). - Stringer("sender_uuid", senderUUID). - Uint32("sender_device_id", senderDeviceID). - Str("sender_e164", senderE164). - Logger() - ctx = log.WithContext(ctx) - log.Trace().Msg("Received SealedSender message") - - cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) - - switch messageType { - case libsignalgo.CiphertextMessageTypeSenderKey: - log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeSenderKey") - decryptedText, err := libsignalgo.GroupDecrypt( - ctx, - usmcContents, - senderAddress, - cli.Store.SenderKeyStore, - ) - if err != nil { - if strings.Contains(err.Error(), "message with old counter") { - log.Warn().Msg("Duplicate message, ignoring") - } else { - log.Err(err).Msg("GroupDecrypt error") - } - } else { - err = stripPadding(&decryptedText) - if err != nil { - return nil, fmt.Errorf("stripPadding error: %v", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - log.Err(err).Msg("Unmarshal error") - } - result = &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - SealedSender: true, - } - } - - case libsignalgo.CiphertextMessageTypePreKey: - log.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") - result, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) - if err != nil { - log.Err(err).Msg("Sealed sender prekey ciphertext decryption error") - } - - case libsignalgo.CiphertextMessageTypeWhisper: - log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeWhisper") - message, err := libsignalgo.DeserializeMessage(usmcContents) - if err != nil { - log.Err(err).Msg("Sealed sender whisper deserialize error") - } - decryptedText, err := libsignalgo.Decrypt( - ctx, - message, - senderAddress, - cli.Store.ACISessionStore, - cli.Store.ACIIdentityStore, - ) - if err != nil { - log.Err(err).Msg("Sealed sender whisper decryption error") - } else { - err = stripPadding(&decryptedText) - if err != nil { - return nil, fmt.Errorf("stripPadding error: %v", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - log.Err(err).Msg("Unmarshal error") - } - result = &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - SealedSender: true, - } - } - - case libsignalgo.CiphertextMessageTypePlaintext: - log.Debug().Msg("SealedSender messageType is CiphertextMessageTypePlaintext") - // TODO: handle plaintext (usually DecryptionErrorMessage) and retries - // when implementing SenderKey groups - - //plaintextContent, err := libsignalgo.DeserializePlaintextContent(usmcContents) - //if err != nil { - // log.Err(err).Msg("DeserializePlaintextContent error") - //} - //body, err := plaintextContent.GetBody() - //if err != nil { - // log.Err(err).Msg("PlaintextContent GetBody error") - //} - //content := signalpb.Content{} - //err = proto.Unmarshal(body, &content) - //if err != nil { - // log.Err(err).Msg("PlaintextContent Unmarshal error") - //} - //result = &DecryptionResult{ - // SenderAddress: *senderAddress, - // Content: &content, - // SealedSender: true, - //} - - return &web.SimpleResponse{ - Status: responseCode, - }, nil - - default: - log.Warn().Msg("SealedSender messageType is unknown") - } - - // If we couldn't decrypt with specific decryption methods, try sealedSenderDecrypt - if result == nil || responseCode != 200 { - log.Debug().Msg("Didn't decrypt with specific methods, trying sealedSenderDecrypt") - var err error - result, err = cli.sealedSenderDecrypt(ctx, envelope) - if err != nil { - if strings.Contains(err.Error(), "self send of a sealed sender message") { - log.Debug().Msg("Message sent by us, ignoring") - } else { - log.Err(err).Msg("sealedSenderDecrypt error") - } - } else { - log.Trace(). - Any("sender_address", result.SenderAddress). - Any("content", result.Content). - Msg("SealedSender decrypt result") - } + log.Err(err).Msg("decryptUnidentifiedSenderEnvelope error") + return DecryptionResult{Err: err, Urgent: envelope.GetUrgent()} } case signalpb.Envelope_PREKEY_BUNDLE: @@ -475,7 +322,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. uint(*envelope.SourceDevice), ) if err != nil { - return nil, fmt.Errorf("NewAddress error: %v", err) + return DecryptionResult{Err: fmt.Errorf("NewAddress error: %v", err), Urgent: envelope.GetUrgent()} } result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) if err != nil { @@ -499,15 +346,21 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. uint(*envelope.SourceDevice), ) if err != nil { - return nil, fmt.Errorf("NewAddress error: %w", err) + return DecryptionResult{Err: fmt.Errorf("NewAddress error: %v", err), Urgent: envelope.GetUrgent()} } sessionStore := cli.Store.SessionStore(destinationServiceID) if sessionStore == nil { - return nil, fmt.Errorf("no session store for destination service ID %s", destinationServiceID) + return DecryptionResult{ + Err: fmt.Errorf("no session store for destination service ID %s", destinationServiceID), + Urgent: envelope.GetUrgent(), + } } identityStore := cli.Store.IdentityStore(destinationServiceID) if identityStore == nil { - return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) + return DecryptionResult{ + Err: fmt.Errorf("no identity store for destination service ID %s", destinationServiceID), + Urgent: envelope.GetUrgent(), + } } decryptedText, err := libsignalgo.Decrypt( ctx, @@ -525,7 +378,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } else { err = stripPadding(&decryptedText) if err != nil { - return nil, fmt.Errorf("stripPadding error: %v", err) + return DecryptionResult{Err: fmt.Errorf("stripPadding error: %v", err), Urgent: envelope.GetUrgent()} } content := signalpb.Content{} err = proto.Unmarshal(decryptedText, &content) @@ -539,226 +392,448 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } case signalpb.Envelope_RECEIPT: + log.Warn().Msg("Received RECEIPT envelope, not yet implemented") // TODO: handle receipt case signalpb.Envelope_KEY_EXCHANGE: - responseCode = 400 + log.Warn().Msg("Received KEY_EXCHANGE envelope, not supported") case signalpb.Envelope_UNKNOWN: - responseCode = 400 + log.Warn().Msg("Received UNKNOWN envelope, not supported") default: log.Warn().Msg("Received actual unknown envelope type") - responseCode = 400 + } + if result == nil { + log.Warn().Msg("Decryption result is nil") + return DecryptionResult{ + Err: fmt.Errorf("decryption result is nil"), + Urgent: envelope.GetUrgent(), + } + } + result.Urgent = envelope.GetUrgent() + return *result +} + +func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destinationServiceID libsignalgo.ServiceID, envelope *signalpb.Envelope) (*DecryptionResult, error) { + log := zerolog.Ctx(ctx) + var result *DecryptionResult + + if destinationServiceID != cli.Store.ACIServiceID() { + log.Warn().Stringer("destination_service_id", destinationServiceID). + Msg("Received UNIDENTIFIED_SENDER envelope for non-ACI destination") + // Return nil, nil to skip the rest of the handling and return 200 OK to the server + return nil, nil + } + usmc, err := libsignalgo.SealedSenderDecryptToUSMC( + ctx, + envelope.GetContent(), + cli.Store.ACIIdentityStore, + ) + if err != nil || usmc == nil { + if err == nil { + err = fmt.Errorf("usmc is nil") + } + log.Err(err).Msg("SealedSenderDecryptToUSMC error") + return nil, err } - // Handle content that is now decrypted - if result != nil && result.Content != nil { - content := result.Content - log.Trace().Any("raw_data", content).Msg("Raw event data") + messageType, err := usmc.GetMessageType() + if err != nil { + log.Err(err).Msg("GetMessageType error") + } + senderCertificate, err := usmc.GetSenderCertificate() + if err != nil { + log.Err(err).Msg("GetSenderCertificate error") + } + senderUUID, err := senderCertificate.GetSenderUUID() + if err != nil { + log.Err(err).Msg("GetSenderUUID error") + } + senderDeviceID, err := senderCertificate.GetDeviceID() + if err != nil { + log.Err(err).Msg("GetDeviceID error") + } + senderAddress, err := libsignalgo.NewACIServiceID(senderUUID).Address(uint(senderDeviceID)) + if err != nil { + log.Err(err).Msg("NewAddress error") + } + senderE164, err := senderCertificate.GetSenderE164() + if err != nil { + log.Err(err).Msg("GetSenderE164 error") + } + usmcContents, err := usmc.GetContents() + if err != nil { + log.Err(err).Msg("GetContents error") + } + newLog := log.With(). + Stringer("sender_uuid", senderUUID). + Uint32("sender_device_id", senderDeviceID). + Str("sender_e164", senderE164). + Logger() + log = &newLog + ctx = log.WithContext(ctx) + log.Trace().Msg("Received SealedSender message") - name, _ := result.SenderAddress.Name() - deviceId, _ := result.SenderAddress.DeviceID() - log = log.With(). - Str("sender_name", name). - Uint("sender_device_id", deviceId). - Str("destination_service_id", destinationServiceID.String()). - Logger() - ctx = log.WithContext(ctx) - log.Debug().Msg("Decrypted message") - printContentFieldString(ctx, content, "Decrypted content fields") + cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) - // If there's a sender key distribution message, process it - if content.GetSenderKeyDistributionMessage() != nil { - log.Debug().Msg("content includes sender key distribution message") - skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(content.GetSenderKeyDistributionMessage()) - if err != nil { - log.Err(err).Msg("DeserializeSenderKeyDistributionMessage error") - return nil, err + switch messageType { + case libsignalgo.CiphertextMessageTypeSenderKey: + log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeSenderKey") + decryptedText, err := libsignalgo.GroupDecrypt( + ctx, + usmcContents, + senderAddress, + cli.Store.SenderKeyStore, + ) + if err != nil { + if strings.Contains(err.Error(), "message with old counter") { + log.Warn().Msg("Duplicate message, ignoring") + } else { + log.Err(err).Msg("GroupDecrypt error") } - err = libsignalgo.ProcessSenderKeyDistributionMessage( - ctx, - skdm, - result.SenderAddress, - cli.Store.SenderKeyStore, - ) + } else { + err = stripPadding(&decryptedText) if err != nil { - log.Err(err).Msg("ProcessSenderKeyDistributionMessage error") - return nil, err + return nil, fmt.Errorf("stripPadding error: %v", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + log.Err(err).Msg("Unmarshal error") + } + result = &DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, + SealedSender: true, } } + case libsignalgo.CiphertextMessageTypePreKey: + log.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") + result, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) + if err != nil { + log.Err(err).Msg("Sealed sender prekey ciphertext decryption error") + } + + case libsignalgo.CiphertextMessageTypeWhisper: + log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeWhisper") + message, err := libsignalgo.DeserializeMessage(usmcContents) + if err != nil { + log.Err(err).Msg("Sealed sender whisper deserialize error") + } + decryptedText, err := libsignalgo.Decrypt( + ctx, + message, + senderAddress, + cli.Store.ACISessionStore, + cli.Store.ACIIdentityStore, + ) + if err != nil { + log.Err(err).Msg("Sealed sender whisper decryption error") + } else { + err = stripPadding(&decryptedText) + if err != nil { + return nil, fmt.Errorf("stripPadding error: %v", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + log.Err(err).Msg("Unmarshal error") + } + result = &DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, + SealedSender: true, + } + } + + case libsignalgo.CiphertextMessageTypePlaintext: + log.Debug().Msg("SealedSender messageType is CiphertextMessageTypePlaintext") + // TODO: handle plaintext (usually DecryptionErrorMessage) and retries + // when implementing SenderKey groups + + //plaintextContent, err := libsignalgo.DeserializePlaintextContent(usmcContents) + //if err != nil { + // log.Err(err).Msg("DeserializePlaintextContent error") + //} + //body, err := plaintextContent.GetBody() + //if err != nil { + // log.Err(err).Msg("PlaintextContent GetBody error") + //} + //content := signalpb.Content{} + //err = proto.Unmarshal(body, &content) + //if err != nil { + // log.Err(err).Msg("PlaintextContent Unmarshal error") + //} + //result = &DecryptionResult{ + // SenderAddress: *senderAddress, + // Content: &content, + // SealedSender: true, + //} + + return nil, nil + + default: + log.Warn().Msg("SealedSender messageType is unknown") + } + + // If we couldn't decrypt with specific decryption methods, try sealedSenderDecrypt + if result == nil { + log.Debug().Msg("Didn't decrypt with specific methods, trying sealedSenderDecrypt") + var err error + result, err = cli.sealedSenderDecrypt(ctx, envelope) + if err != nil { + if strings.Contains(err.Error(), "self send of a sealed sender message") { + log.Debug().Msg("Message sent by us, ignoring") + } else if strings.Contains(err.Error(), "message with old counter") { + log.Info().Msg("Duplicate message, ignoring (sealedSenderDecrypt)") + } else { + log.Err(err).Msg("sealedSenderDecrypt error") + } + } else { + log.Trace(). + Any("sender_address", result.SenderAddress). + Any("content", result.Content). + Msg("SealedSender decrypt result") + } + } + return result, nil +} + +// TODO: we should split this up into multiple functions +func (cli *Client) handleDecryptedResult( + ctx context.Context, + result DecryptionResult, + destinationServiceID libsignalgo.ServiceID, +) error { + log := zerolog.Ctx(ctx) + if result.Content == nil { + log.Warn().Msg("Decrypted content is nil") + return nil + } + + // result.Err is set if there was an error during decryption and we + // should notifiy the user that the message could not be decrypted + if result.Err != nil { + log.Err(result.Err).Bool("urgent", result.Urgent).Msg("Decryption error") theirServiceID, err := result.SenderAddress.NameServiceID() if err != nil { - log.Err(err).Msg("Name error") - return nil, err + log.Err(err).Msg("Name error handling decryption error") } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") - return &web.SimpleResponse{ - Status: responseCode, - }, nil } - - if destinationServiceID == cli.Store.PNIServiceID() { - _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { - if !recipient.NeedsPNISignature { - log.Debug().Msg("Marking recipient as needing PNI signature") - recipient.NeedsPNISignature = true - return true, nil - } - return false, nil - }) - if err != nil { - log.Err(err).Msg("Failed to set needs_pni_signature flag after receiving message to PNI service ID") - } - } - - if content.GetPniSignatureMessage() != nil { - log.Debug().Msg("Content includes PNI signature message") - err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.GetPniSignatureMessage()) - if err != nil { - log.Err(err). - Hex("pni_raw", content.GetPniSignatureMessage().GetPni()). - Stringer("aci", theirServiceID.UUID). - Msg("Failed to verify ACI-PNI mapping") - } - } - - // TODO: handle more sync messages - if content.SyncMessage != nil { - if content.SyncMessage.Keys != nil { - cli.Store.MasterKey = content.SyncMessage.Keys.GetMaster() - err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) - if err != nil { - log.Err(err).Msg("Failed to save device after receiving master key") - } else { - log.Info().Msg("Received master key") - go cli.SyncStorage(ctx) - } - } else if content.SyncMessage.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { - log.Debug().Msg("Received storage manifest fetch latest notice") - go cli.SyncStorage(ctx) - } - syncSent := content.SyncMessage.GetSent() - if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { - destination := syncSent.DestinationServiceId - var syncDestinationServiceID libsignalgo.ServiceID - if destination != nil { - syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) - if err != nil { - log.Err(err).Msg("Sync message destination parse error") - return nil, err - } - } - if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { - log.Warn().Msg("sync message sent destination is nil") - } else if content.SyncMessage.Sent.Message != nil { - // TODO handle expiration start ts, and maybe the sync message ts? - cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, syncDestinationServiceID) - } else if content.SyncMessage.Sent.EditMessage != nil { - cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID) - } - } - if content.SyncMessage.Contacts != nil { - log.Debug().Msg("Recieved sync message contacts") - blob := content.SyncMessage.Contacts.Blob - if blob != nil { - contactsBytes, err := DownloadAttachment(ctx, blob) - if err != nil { - log.Err(err).Msg("Contacts Sync DownloadAttachment error") - } - // unmarshall contacts - contacts, avatars, err := unmarshalContactDetailsMessages(contactsBytes) - if err != nil { - log.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") - } - log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") - convertedContacts := make([]*types.Recipient, 0, len(contacts)) - for i, signalContact := range contacts { - if signalContact.Aci == nil || *signalContact.Aci == "" { - // TODO lookup PNI via CDSI and store that when ACI is missing? - log.Info(). - Any("contact", signalContact). - Msg("Signal Contact UUID is nil, skipping") - continue - } - contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) - if err != nil { - log.Err(err).Msg("StoreContactDetailsAsContact error") - continue - } - convertedContacts = append(convertedContacts, contact) - } - cli.handleEvent(&events.ContactList{ - Contacts: convertedContacts, - }) - } - } - if content.SyncMessage.Read != nil { - cli.handleEvent(&events.ReadSelf{ - Messages: content.SyncMessage.GetRead(), - }) - } - - } - - var sendDeliveryReceipt bool - if content.DataMessage != nil { - sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID) - } else if content.EditMessage != nil { - sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID) - } - if sendDeliveryReceipt { - // TODO send delivery receipts after actually bridging instead of here - err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) - if err != nil { - log.Err(err).Msg("sendDeliveryReceipts error") - } - } - - if content.TypingMessage != nil { - var groupID types.GroupIdentifier - if content.TypingMessage.GetGroupId() != nil { - gidBytes := content.TypingMessage.GetGroupId() - groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) - } - cli.handleEvent(&events.ChatEvent{ - Info: events.MessageInfo{ - Sender: theirServiceID.UUID, - ChatID: groupOrUserID(groupID, theirServiceID), - }, - Event: content.TypingMessage, + // Only send decryption error event if the message was urgent, + // to prevent spamming errors for typing notifications and whatnot + if result.Urgent { + cli.handleEvent(&events.DecryptionError{ + Sender: theirServiceID.UUID, + Err: result.Err, }) } + // Intentionally not returning here. In most cases there's nothing besides the error so + // nothing else will happen, but if there is content we still want to do what we can with it + } - // DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) - if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { - cli.handleEvent(&events.Call{ - Info: events.MessageInfo{ - Sender: theirServiceID.UUID, - ChatID: theirServiceID.String(), - }, - IsRinging: content.CallMessage.Offer != nil, - }) + content := result.Content + log.Trace().Any("raw_data", content).Msg("Raw event data") + + name, _ := result.SenderAddress.Name() + deviceId, _ := result.SenderAddress.DeviceID() + newLog := log.With(). + Str("sender_name", name). + Uint("sender_device_id", deviceId). + Str("destination_service_id", destinationServiceID.String()). + Logger() + log = &newLog + ctx = log.WithContext(ctx) + log.Debug().Msg("Decrypted message") + printContentFieldString(ctx, content, "Decrypted content fields") + + // If there's a sender key distribution message, process it + if content.GetSenderKeyDistributionMessage() != nil { + log.Debug().Msg("content includes sender key distribution message") + skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(content.GetSenderKeyDistributionMessage()) + if err != nil { + log.Err(err).Msg("DeserializeSenderKeyDistributionMessage error") + return err } - - // Read and delivery receipts - if content.ReceiptMessage != nil { - if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() { - // Ignore delivery receipts from other own devices - return &web.SimpleResponse{ - Status: responseCode, - }, nil - } - cli.handleEvent(&events.Receipt{ - Sender: theirServiceID.UUID, - Content: content.ReceiptMessage, - }) + err = libsignalgo.ProcessSenderKeyDistributionMessage( + ctx, + skdm, + result.SenderAddress, + cli.Store.SenderKeyStore, + ) + if err != nil { + log.Err(err).Msg("ProcessSenderKeyDistributionMessage error") + return err } } - return &web.SimpleResponse{ - Status: responseCode, - }, nil + + theirServiceID, err := result.SenderAddress.NameServiceID() + if err != nil { + log.Err(err).Msg("Name error") + return err + } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { + log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") + return nil + } + + if destinationServiceID == cli.Store.PNIServiceID() { + _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { + if !recipient.NeedsPNISignature { + log.Debug().Msg("Marking recipient as needing PNI signature") + recipient.NeedsPNISignature = true + return true, nil + } + return false, nil + }) + if err != nil { + log.Err(err).Msg("Failed to set needs_pni_signature flag after receiving message to PNI service ID") + } + } + + if content.GetPniSignatureMessage() != nil { + log.Debug().Msg("Content includes PNI signature message") + err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.GetPniSignatureMessage()) + if err != nil { + log.Err(err). + Hex("pni_raw", content.GetPniSignatureMessage().GetPni()). + Stringer("aci", theirServiceID.UUID). + Msg("Failed to verify ACI-PNI mapping") + } + } + + // TODO: handle more sync messages + if content.SyncMessage != nil { + if content.SyncMessage.Keys != nil { + cli.Store.MasterKey = content.SyncMessage.Keys.GetMaster() + err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + if err != nil { + log.Err(err).Msg("Failed to save device after receiving master key") + } else { + log.Info().Msg("Received master key") + go cli.SyncStorage(ctx) + } + } else if content.SyncMessage.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { + log.Debug().Msg("Received storage manifest fetch latest notice") + go cli.SyncStorage(ctx) + } + syncSent := content.SyncMessage.GetSent() + if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { + destination := syncSent.DestinationServiceId + var syncDestinationServiceID libsignalgo.ServiceID + if destination != nil { + syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) + if err != nil { + log.Err(err).Msg("Sync message destination parse error") + return err + } + } + if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { + log.Warn().Msg("sync message sent destination is nil") + } else if content.SyncMessage.Sent.Message != nil { + // TODO handle expiration start ts, and maybe the sync message ts? + cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, syncDestinationServiceID) + } else if content.SyncMessage.Sent.EditMessage != nil { + cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID) + } + } + if content.SyncMessage.Contacts != nil { + log.Debug().Msg("Recieved sync message contacts") + blob := content.SyncMessage.Contacts.Blob + if blob != nil { + contactsBytes, err := DownloadAttachment(ctx, blob) + if err != nil { + log.Err(err).Msg("Contacts Sync DownloadAttachment error") + } + // unmarshall contacts + contacts, avatars, err := unmarshalContactDetailsMessages(contactsBytes) + if err != nil { + log.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") + } + log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") + convertedContacts := make([]*types.Recipient, 0, len(contacts)) + for i, signalContact := range contacts { + if signalContact.Aci == nil || *signalContact.Aci == "" { + // TODO lookup PNI via CDSI and store that when ACI is missing? + log.Info(). + Any("contact", signalContact). + Msg("Signal Contact UUID is nil, skipping") + continue + } + contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) + if err != nil { + log.Err(err).Msg("StoreContactDetailsAsContact error") + continue + } + convertedContacts = append(convertedContacts, contact) + } + cli.handleEvent(&events.ContactList{ + Contacts: convertedContacts, + }) + } + } + if content.SyncMessage.Read != nil { + cli.handleEvent(&events.ReadSelf{ + Messages: content.SyncMessage.GetRead(), + }) + } + + } + + var sendDeliveryReceipt bool + if content.DataMessage != nil { + sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID) + } else if content.EditMessage != nil { + sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID) + } + if sendDeliveryReceipt { + // TODO send delivery receipts after actually bridging instead of here + err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) + if err != nil { + log.Err(err).Msg("sendDeliveryReceipts error") + } + } + + if content.TypingMessage != nil { + var groupID types.GroupIdentifier + if content.TypingMessage.GetGroupId() != nil { + gidBytes := content.TypingMessage.GetGroupId() + groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) + } + cli.handleEvent(&events.ChatEvent{ + Info: events.MessageInfo{ + Sender: theirServiceID.UUID, + ChatID: groupOrUserID(groupID, theirServiceID), + }, + Event: content.TypingMessage, + }) + } + + // DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) + if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { + cli.handleEvent(&events.Call{ + Info: events.MessageInfo{ + Sender: theirServiceID.UUID, + ChatID: theirServiceID.String(), + }, + IsRinging: content.CallMessage.Offer != nil, + }) + } + + // Read and delivery receipts + if content.ReceiptMessage != nil { + if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() { + // Ignore delivery receipts from other own devices + return nil + } + cli.handleEvent(&events.Receipt{ + Sender: theirServiceID.UUID, + Content: content.ReceiptMessage, + }) + } + return nil } func printStructFields(message protoreflect.Message, parent string, builder *strings.Builder) { @@ -951,6 +1026,8 @@ type DecryptionResult struct { SenderAddress *libsignalgo.Address Content *signalpb.Content SealedSender bool + Err error + Urgent bool } const prodServerTrustRootStr = "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" diff --git a/user.go b/user.go index db5bd4c..a579e8b 100644 --- a/user.go +++ b/user.go @@ -858,6 +858,19 @@ func (user *User) eventHandler(rawEvt events.SignalEvent) { } else { user.log.Warn().Str("chat_id", evt.Info.ChatID).Msg("Couldn't get portal, dropping message") } + case *events.DecryptionError: + portal := user.GetPortalByChatID(evt.Sender.String()) + if portal == nil { + user.log.Warn().Stringer("chat_id", evt.Sender).Msg("Couldn't get portal for decryption error") + return + } + content := &event.MessageEventContent{MsgType: event.MsgNotice} + name := user.bridge.GetPuppetBySignalID(evt.Sender).Name + if name == "" { + name = "This user" + } + content.Body = fmt.Sprintf("%s sent a message that couldn't be decrypted. It may have been in this chat or a group chat. Please check your Signal app", name) + portal.sendMainIntentMessage(context.TODO(), content) case *events.Receipt: user.handleReceipt(evt) case *events.ReadSelf: From e7b62ee93b9388540d77c4beecc50c264c7fb390 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Sat, 13 Apr 2024 23:06:32 +0200 Subject: [PATCH 151/718] Try fix zero length user ID error (#498) --- pkg/libsignalgo/profilekey.go | 53 ++++++++-------- pkg/signalmeow/groups.go | 111 ++++++++++++++++------------------ 2 files changed, 81 insertions(+), 83 deletions(-) diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index 8d4ba8f..5d5f157 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -214,27 +214,32 @@ func ReceiveExpiringProfileKeyCredential(spp ServerPublicParams, requestContext return &credential, nil } -//func NewProfileKeyCredentialPresentation(b []byte) (ProfileKeyCredentialPresentation, error) { -// C.signal_profile_key_credential_presentation_check_valid_contents(cBytes(b), cLen(b)) -// if res := C.FFI_ProfileKeyCredentialPresentation_checkValidContents(cBytes(b), cLen(b)); res != C.FFI_RETURN_OK { -// return nil, errFromCode(res) -// } -// return ProfileKeyCredentialPresentation(b), nil -//} -// -//func (a ProfileKeyCredentialPresentation) UUIDCiphertext() ([]byte, error) { -// out := make([]byte, C.UUID_CIPHERTEXT_LEN) -// if res := C.FFI_ProfileKeyCredentialPresentation_getUuidCiphertext(cBytes(a), cLen(a), cBytes(out), cLen(out)); res != C.FFI_RETURN_OK { -// return nil, errFromCode(res) -// } -// return out, nil -//} -// -//func (a ProfileKeyCredentialPresentation) ProfileKeyCiphertext() ([]byte, error) { -// out := make([]byte, C.PROFILE_KEY_CIPHERTEXT_LEN) -// if res := C.FFI_ProfileKeyCredentialPresentation_getProfileKeyCiphertext(cBytes(a), cLen(a), cBytes(out), cLen(out)); res != C.FFI_RETURN_OK { -// return nil, errFromCode(res) -// } -// return out, nil -//} -// +func (a ProfileKeyCredentialPresentation) CheckValidContents() error { + signalFfiError := C.signal_profile_key_credential_presentation_check_valid_contents(BytesToBuffer(a)) + runtime.KeepAlive(a) + return wrapError(signalFfiError) +} + +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)) + 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 +} + +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)) + 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 +} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 1214088..0a67ef6 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -943,26 +943,15 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange if modifyProfileKey == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(modifyProfileKey.UserId) - serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) + aci, profileKey, err := decryptPKeyAndIDorPresentation(ctx, modifyProfileKey.UserId, modifyProfileKey.ProfileKey, modifyProfileKey.Presentation, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error for modifyProfileKey") - return nil, err - } - if serviceID.Type != libsignalgo.ServiceIDTypeACI { - return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") - } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(modifyProfileKey.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error for modifyProfileKey") return nil, err } decryptedGroupChange.ModifyMemberProfileKeys = append(decryptedGroupChange.ModifyMemberProfileKeys, &ProfileKeyMember{ - ACI: serviceID.UUID, + ACI: *aci, ProfileKey: *profileKey, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, serviceID.UUID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, *aci, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -999,23 +988,15 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange if promotePendingMember == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) - serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) + aci, profileKey, err := decryptPKeyAndIDorPresentation(ctx, promotePendingMember.UserId, promotePendingMember.ProfileKey, promotePendingMember.Presentation, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error for promotePendingMember") - return nil, err - } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingMember") return nil, err } decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &GroupMember{ - ACI: serviceID.UUID, + ACI: *aci, ProfileKey: *profileKey, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, serviceID.UUID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, *aci, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1027,16 +1008,11 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange if promotePendingPniAciMember == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingPniAciMember.UserId) - aciServiceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) + aci, profileKey, err := decryptPKeyAndIDorPresentation(ctx, promotePendingPniAciMember.UserId, promotePendingPniAciMember.ProfileKey, promotePendingPniAciMember.Presentation, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error for promotePendingPniAciMember") return nil, err } - if aciServiceID.Type != libsignalgo.ServiceIDTypeACI { - return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") - } - encryptedUserID = libsignalgo.UUIDCiphertext(promotePendingPniAciMember.Pni) + encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingPniAciMember.Pni) pniServiceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID Pni error for promotePendingPniAciMember") @@ -1045,18 +1021,12 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange if pniServiceID.Type != libsignalgo.ServiceIDTypePNI { return nil, fmt.Errorf("Wrong ServiceID kind: expected PNI, got ACI") } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingPniAciMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, aciServiceID.UUID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingPniAciMember") - return nil, err - } decryptedGroupChange.PromotePendingPniAciMembers = append(decryptedGroupChange.PromotePendingPniAciMembers, &PromotePendingPniAciMember{ - ACI: aciServiceID.UUID, + ACI: *aci, ProfileKey: *profileKey, PNI: pniServiceID.UUID, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, aciServiceID.UUID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, *aci, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1169,22 +1139,54 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return decryptedGroupChange, nil } -func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretParams libsignalgo.GroupSecretParams) (*GroupMember, error) { +func decryptPKeyAndIDorPresentation(ctx context.Context, userID []byte, profileKeyBytes []byte, presentationBytes []byte, groupSecretParams libsignalgo.GroupSecretParams) (*uuid.UUID, *libsignalgo.ProfileKey, error) { log := zerolog.Ctx(ctx) - encryptedUserID := libsignalgo.UUIDCiphertext(member.UserId) + var encryptedUserID libsignalgo.UUIDCiphertext + var encryptedProfileKey libsignalgo.ProfileKeyCiphertext + if len(userID) == 0 || len(profileKeyBytes) == 0 { + presentation := libsignalgo.ProfileKeyCredentialPresentation(presentationBytes) + err := presentation.CheckValidContents() + if err != nil { + log.Err(err).Msg("Invalid presentation contents") + return nil, nil, err + } + encryptedUserID, err = presentation.UUIDCiphertext() + if err != nil { + log.Err(err).Msg("unable to get UUID from presentation") + return nil, nil, err + } + encryptedProfileKey, err = presentation.ProfileKeyCiphertext() + if err != nil { + log.Err(err).Msg("unable to get ProfileKey from presentation") + return nil, nil, err + } + } else { + encryptedUserID = libsignalgo.UUIDCiphertext(userID) + encryptedProfileKey = libsignalgo.ProfileKeyCiphertext(profileKeyBytes) + } serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error") - return nil, err + log.Err(err).Msg("Failed to decrypt ServiceID") + return nil, nil, err } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(member.ProfileKey) profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error") + return nil, nil, err + } + if serviceID.Type == libsignalgo.ServiceIDTypePNI { + return nil, nil, fmt.Errorf("wrong serviceid kind, expected ACI, got PNI") + } + return &serviceID.UUID, profileKey, nil + +} + +func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretParams libsignalgo.GroupSecretParams) (*GroupMember, error) { + aci, profileKey, err := decryptPKeyAndIDorPresentation(ctx, member.UserId, member.ProfileKey, member.Presentation, groupSecretParams) + if err != nil { return nil, err } return &GroupMember{ - ACI: serviceID.UUID, + ACI: *aci, ProfileKey: *profileKey, Role: GroupMemberRole(member.Role), JoinedAtRevision: member.JoinedAtRevision, @@ -1215,21 +1217,12 @@ func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMe } func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.RequestingMember, groupSecretParams libsignalgo.GroupSecretParams) (*RequestingMember, error) { - log := zerolog.Ctx(ctx) - encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) - serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) + aci, profileKey, err := decryptPKeyAndIDorPresentation(ctx, requestingMember.UserId, requestingMember.ProfileKey, requestingMember.Presentation, groupSecretParams) if err != nil { - log.Err(err).Msg("DecryptUUID UserId error for requestingMember") - return nil, err - } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) - if err != nil { - log.Err(err).Msg("DecryptProfileKey ProfileKey error for requestingMember") return nil, err } return &RequestingMember{ - ACI: serviceID.UUID, + ACI: *aci, ProfileKey: *profileKey, Timestamp: requestingMember.Timestamp, }, nil @@ -1364,7 +1357,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup for _, deleteRequestingMember := range decryptedGroupChange.DeleteRequestingMembers { encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(*deleteRequestingMember)) if err != nil { - log.Err(err).Msg("Encrypt UserId error for promotePendingMember") + log.Err(err).Msg("Encrypt UserId error for deleteRequestingMember") return nil, err } groupChangeActions.DeleteRequestingMembers = append(groupChangeActions.DeleteRequestingMembers, &signalpb.GroupChange_Actions_DeleteRequestingMemberAction{ From c8f2f7892968795925cacbe7386c63e5dd250e9b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 15 Apr 2024 12:41:38 +0300 Subject: [PATCH 152/718] Update dependencies --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 949f87e..d7eff9a 100644 --- a/go.mod +++ b/go.mod @@ -15,13 +15,13 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.1 - golang.org/x/crypto v0.21.0 - golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f - golang.org/x/net v0.22.0 + go.mau.fi/util v0.4.2-0.20240318211948-d27d5a4cda9e + golang.org/x/crypto v0.22.0 + golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 + golang.org/x/net v0.24.0 google.golang.org/protobuf v1.33.0 - maunium.net/go/mautrix v0.18.1-0.20240322180408-ade00e8603f9 - nhooyr.io/websocket v1.8.10 + maunium.net/go/mautrix v0.18.1-0.20240413105730-423d32ddf6d6 + nhooyr.io/websocket v1.8.11 ) require ( @@ -43,7 +43,7 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.0 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index 3916c4d..3fd72f0 100644 --- a/go.sum +++ b/go.sum @@ -69,21 +69,21 @@ 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.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.1 h1:3EC9KxIXo5+h869zDGf5OOZklRd/FjeVnimTwtm3owg= -go.mau.fi/util v0.4.1/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY= +go.mau.fi/util v0.4.2-0.20240318211948-d27d5a4cda9e h1:2jdYsZTTIwSo4TGmVrqLgeCqaxexJ9nY2Tuj1MzDIwc= +go.mau.fi/util v0.4.2-0.20240318211948-d27d5a4cda9e/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw= -golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= +golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -95,7 +95,7 @@ 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.18.1-0.20240322180408-ade00e8603f9 h1:Xl741d8hAFdBPJPT/ydc6zTQM4R4L+5/d1X+AevLdXY= -maunium.net/go/mautrix v0.18.1-0.20240322180408-ade00e8603f9/go.mod h1:STwJZ+6CAeiEQs7fYCkd5aC12XR5DXANE6Swy/PBKGo= -nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= -nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +maunium.net/go/mautrix v0.18.1-0.20240413105730-423d32ddf6d6 h1:zSGNGm31EzKYDmKJG2VS5wYqYDAT5pJhFfGauR6r4yU= +maunium.net/go/mautrix v0.18.1-0.20240413105730-423d32ddf6d6/go.mod h1:STwJZ+6CAeiEQs7fYCkd5aC12XR5DXANE6Swy/PBKGo= +nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= +nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From cd13814b3d87ee38fd59f4b0eca09fc98519f334 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 15 Apr 2024 13:06:38 +0300 Subject: [PATCH 153/718] Add missing check to create command --- commands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.go b/commands.go index 2f224bc..728f2d6 100644 --- a/commands.go +++ b/commands.go @@ -1103,7 +1103,7 @@ func fnCreate(ce *WrappedCommandEvent) { } portal.MXID = ce.RoomID portal.Name = roomName - portal.Encrypted = encryptionEvent.Algorithm == id.AlgorithmMegolmV1 + portal.Encrypted = encryptionEvent != nil && encryptionEvent.Algorithm == id.AlgorithmMegolmV1 if !portal.Encrypted && ce.Bridge.Config.Bridge.Encryption.Default { _, err = portal.MainIntent().SendStateEvent(ce.Ctx, portal.MXID, event.StateEncryption, "", portal.GetEncryptionEventContent()) if err != nil { From 703becae6de32e0f89611d492536883102814452 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 16 Apr 2024 14:05:16 +0300 Subject: [PATCH 154/718] Bump version to v0.6.0 --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ go.mod | 6 +++--- go.sum | 12 ++++++------ main.go | 2 +- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a63f40..ec053c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +# v0.6.0 (2024-04-16) + +* Updated to libsignal v0.44.0. +* Refactored bridge to support Signal's new phone number identifier (PNI) + system in order to fix starting new chats and receiving messages from new + users. + * When starting a chat with a user you haven't talked to before, the portal + room will not have a ghost user for the recipient until they accept the + message request. +* Added support for syncing existing groups on login instead of having to wait + for new messages. +* Added notices if decrypting incoming message from Signal fails. +* Added bridging of group metadata from Matrix to Signal + (thanks to [@maltee1] in [#461]). +* Added command to create new Signal group for Matrix room + (thanks to [@maltee1] in [#461] and [#491]). +* Added commands for inviting users to Signal groups by phone number + (thanks to [@maltee1] in [#495]). +* Improved handling of missed Signal group metadata changes + (thanks to [@maltee1] in [#488]). + +[#461]: https://github.com/mautrix/signal/pull/461 +[#488]: https://github.com/mautrix/signal/pull/488 +[#491]: https://github.com/mautrix/signal/pull/491 +[#495]: https://github.com/mautrix/signal/pull/495 + # v0.5.1 (2024-03-16) * Updated to libsignal v0.41.0. diff --git a/go.mod b/go.mod index d7eff9a..ac97321 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.2-0.20240318211948-d27d5a4cda9e + go.mau.fi/util v0.4.2 golang.org/x/crypto v0.22.0 golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 golang.org/x/net v0.24.0 google.golang.org/protobuf v1.33.0 - maunium.net/go/mautrix v0.18.1-0.20240413105730-423d32ddf6d6 + maunium.net/go/mautrix v0.18.1 nhooyr.io/websocket v1.8.11 ) @@ -41,7 +41,7 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.0 // indirect + github.com/yuin/goldmark v1.7.1 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect golang.org/x/sys v0.19.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index 3fd72f0..aaf41a7 100644 --- a/go.sum +++ b/go.sum @@ -67,10 +67,10 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/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.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= -github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.2-0.20240318211948-d27d5a4cda9e h1:2jdYsZTTIwSo4TGmVrqLgeCqaxexJ9nY2Tuj1MzDIwc= -go.mau.fi/util v0.4.2-0.20240318211948-d27d5a4cda9e/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY= +github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= +github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30= +go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= @@ -95,7 +95,7 @@ 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.18.1-0.20240413105730-423d32ddf6d6 h1:zSGNGm31EzKYDmKJG2VS5wYqYDAT5pJhFfGauR6r4yU= -maunium.net/go/mautrix v0.18.1-0.20240413105730-423d32ddf6d6/go.mod h1:STwJZ+6CAeiEQs7fYCkd5aC12XR5DXANE6Swy/PBKGo= +maunium.net/go/mautrix v0.18.1 h1:a6mUsJixegBNTXUoqC5RQ9gsumIPzKvCubKwF+zmCt4= +maunium.net/go/mautrix v0.18.1/go.mod h1:2oHaq792cSXFGvxLvYw3Gf1L4WVVP4KZcYys5HVk/h8= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index cd9e156..c09bc3d 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.5.1", + Version: "0.6.0", ProtocolName: "Signal", BeeperServiceName: "signal", BeeperNetworkName: "signal", From 2a4b58e04ac3b3b45be89e39d5535cc4e5e5c9d7 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Wed, 1 May 2024 10:16:54 +0200 Subject: [PATCH 155/718] Add support for Matrix -> Signal location messages (#504) Fixes #424 --- config/bridge.go | 23 ++++++++++++----------- config/upgrade.go | 1 + example-config.yaml | 4 ++++ msgconv/from-matrix.go | 28 ++++++++++++++++++++++++++-- msgconv/msgconv.go | 2 ++ portal.go | 1 + 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/config/bridge.go b/config/bridge.go index 2ce4bb9..e3e756c 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -42,17 +42,18 @@ type BridgeConfig struct { PortalMessageBuffer int `yaml:"portal_message_buffer"` - PersonalFilteringSpaces bool `yaml:"personal_filtering_spaces"` - BridgeNotices bool `yaml:"bridge_notices"` - DeliveryReceipts bool `yaml:"delivery_receipts"` - MessageStatusEvents bool `yaml:"message_status_events"` - MessageErrorNotices bool `yaml:"message_error_notices"` - SyncDirectChatList bool `yaml:"sync_direct_chat_list"` - ResendBridgeInfo bool `yaml:"resend_bridge_info"` - PublicPortals bool `yaml:"public_portals"` - CaptionInMessage bool `yaml:"caption_in_message"` - FederateRooms bool `yaml:"federate_rooms"` - BridgeMatrixLeave bool `yaml:"bridge_matrix_leave"` + PersonalFilteringSpaces bool `yaml:"personal_filtering_spaces"` + BridgeNotices bool `yaml:"bridge_notices"` + DeliveryReceipts bool `yaml:"delivery_receipts"` + MessageStatusEvents bool `yaml:"message_status_events"` + MessageErrorNotices bool `yaml:"message_error_notices"` + SyncDirectChatList bool `yaml:"sync_direct_chat_list"` + ResendBridgeInfo bool `yaml:"resend_bridge_info"` + PublicPortals bool `yaml:"public_portals"` + CaptionInMessage bool `yaml:"caption_in_message"` + LocationFormat string `yaml:"location_format"` + FederateRooms bool `yaml:"federate_rooms"` + BridgeMatrixLeave bool `yaml:"bridge_matrix_leave"` DoublePuppetConfig bridgeconfig.DoublePuppetConfig `yaml:",inline"` diff --git a/config/upgrade.go b/config/upgrade.go index 0d943d6..114eb1d 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -96,6 +96,7 @@ func DoUpgrade(helper *up.Helper) { helper.Copy(up.Bool, "bridge", "resend_bridge_info") helper.Copy(up.Bool, "bridge", "public_portals") helper.Copy(up.Bool, "bridge", "caption_in_message") + helper.Copy(up.Str, "bridge", "location_format") helper.Copy(up.Bool, "bridge", "federate_rooms") helper.Copy(up.Map, "bridge", "double_puppet_server_map") helper.Copy(up.Bool, "bridge", "double_puppet_allow_discovery") diff --git a/example-config.yaml b/example-config.yaml index b61c355..71caa9c 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -139,6 +139,10 @@ bridge: # Send captions in the same message as images. This will send data compatible with both MSC2530. # This is currently not supported in most clients. caption_in_message: false + # Format for generating URLs from location messages for sending to Signal + # Google Maps: 'https://www.google.com/maps/place/%[1]s,%[2]s' + # OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]' + location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s' # Whether or not created rooms should have federation enabled. # If false, created portal rooms will never be federated. federate_rooms: true diff --git a/msgconv/from-matrix.go b/msgconv/from-matrix.go index 791ea9e..9a14ead 100644 --- a/msgconv/from-matrix.go +++ b/msgconv/from-matrix.go @@ -20,9 +20,11 @@ import ( "context" "errors" "fmt" + "strings" "time" "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "go.mau.fi/util/exerrors" "go.mau.fi/util/exmime" "go.mau.fi/util/ffmpeg" @@ -109,8 +111,13 @@ func (mc *MessageConverter) ToSignal(ctx context.Context, evt *event.Event, cont Emoji: emoji, } case event.MsgLocation: - // TODO implement - fallthrough + lat, lon, err := parseGeoURI(content.GeoURI) + if err != nil { + log.Err(err).Msg("Invalid geo URI") + return nil, err + } + locationString := fmt.Sprintf(mc.LocationFormat, lat, lon) + dm.Body = &locationString default: return nil, fmt.Errorf("%w %s", ErrUnsupportedMsgType, content.MsgType) } @@ -190,3 +197,20 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. } return att, nil } + +func parseGeoURI(uri string) (lat, long string, err error) { + if !strings.HasPrefix(uri, "geo:") { + err = fmt.Errorf("uri doesn't have geo: prefix") + return + } + // Remove geo: prefix and anything after ; + coordinates := strings.Split(strings.TrimPrefix(uri, "geo:"), ";")[0] + splitCoordinates := strings.Split(coordinates, ",") + if len(splitCoordinates) != 2 { + err = fmt.Errorf("didn't find exactly two numbers separated by a comma") + } else { + lat = splitCoordinates[0] + long = splitCoordinates[1] + } + return +} diff --git a/msgconv/msgconv.go b/msgconv/msgconv.go index b7f9771..0e29157 100644 --- a/msgconv/msgconv.go +++ b/msgconv/msgconv.go @@ -54,6 +54,8 @@ type MessageConverter struct { ConvertGIFToAPNG bool MaxFileSize int64 AsyncFiles bool + + LocationFormat string } func (mc *MessageConverter) IsPrivateChat(ctx context.Context) bool { diff --git a/portal.go b/portal.go index 44f67bb..2e90ac7 100644 --- a/portal.go +++ b/portal.go @@ -236,6 +236,7 @@ func (br *SignalBridge) NewPortal(dbPortal *database.Portal) *Portal { MatrixFmtParams: matrixFormatParams, ConvertVoiceMessages: true, MaxFileSize: br.MediaConfig.UploadSize, + LocationFormat: br.Config.Bridge.LocationFormat, } go portal.messageLoop() From 73e7619312248c0abc2a64a058d1221152f6a8dc Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Wed, 1 May 2024 10:17:07 +0200 Subject: [PATCH 156/718] Properly convert long text messages from Signal (#506) Fixes #479 --- msgconv/from-signal.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index 9b47cca..a5c0174 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -115,7 +115,16 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa return cm } for i, att := range dm.GetAttachments() { - cm.Parts = append(cm.Parts, mc.convertAttachmentToMatrix(ctx, i, att)) + if att.GetContentType() != "text/x-signal-plain" { + cm.Parts = append(cm.Parts, mc.convertAttachmentToMatrix(ctx, i, att)) + } else { + longBody, err := mc.downloadSignalLongText(ctx, att) + if err == nil { + dm.Body = longBody + } else { + zerolog.Ctx(ctx).Err(err).Msg("Failed to download Signal long text") + } + } } for _, contact := range dm.GetContact() { cm.Parts = append(cm.Parts, mc.convertContactToMatrix(ctx, contact)) @@ -415,6 +424,15 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker return converted } +func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *signalpb.AttachmentPointer) (*string, error) { + data, err := signalmeow.DownloadAttachment(ctx, att) + if err != nil { + return nil, fmt.Errorf("failed to download attachment: %w", err) + } + longBody := string(data) + return &longBody, nil +} + func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer) (*ConvertedMessagePart, error) { data, err := signalmeow.DownloadAttachment(ctx, att) if err != nil { From b602e9472b9d7cc6d9915b8c133c727e003bf8b6 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Wed, 1 May 2024 09:17:15 +0100 Subject: [PATCH 157/718] Make Signal ping kill and rebuild websocket if it takes more than 20s (#507) --- pkg/signalmeow/web/signalwebsocket.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 40e43e4..0b97b8a 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -292,9 +292,12 @@ func (s *SignalWebsocket) connectLoop( for { select { case <-ticker.C: - err := ws.Ping(loopCtx) + pingCtx, cancel := context.WithTimeout(loopCtx, 20*time.Second) + err := ws.Ping(pingCtx) + cancel() if err != nil { - loopCancel(fmt.Errorf("error sending keepalive: %w", err)) + log.Err(err).Msg("Error pinging") + loopCancel(err) return } log.Debug().Msg("Sent keepalive") From 7ea4cdfce8981b05fd2862ec6aa0dee54e9aaa0a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 16 May 2024 16:08:51 +0300 Subject: [PATCH 158/718] Bump version to v0.6.1 --- CHANGELOG.md | 10 ++++++++++ go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ main.go | 2 +- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec053c8..df01490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# v0.6.1 (2024-05-16) + +* Added support for bridging location messages from Matrix to Signal + (thanks to [@maltee1] in [#504]). + * Note that Signal doesn't support real location messages, so they're just + bridged as links. The link template is configurable. +* Fixed bridging long text messages from Signal + (thanks to [@maltee1] in [#509]). +* Improved handling of ping timeouts in Signal websocket. + # v0.6.0 (2024-04-16) * Updated to libsignal v0.44.0. diff --git a/go.mod b/go.mod index ac97321..bf3fd25 100644 --- a/go.mod +++ b/go.mod @@ -10,16 +10,16 @@ require ( github.com/lib/pq v1.10.9 github.com/mattn/go-pointer v0.0.1 github.com/mattn/go-sqlite3 v1.14.22 - github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/client_golang v1.19.1 github.com/rs/zerolog v1.32.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 go.mau.fi/util v0.4.2 - golang.org/x/crypto v0.22.0 - golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 - golang.org/x/net v0.24.0 - google.golang.org/protobuf v1.33.0 + golang.org/x/crypto v0.23.0 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 + golang.org/x/net v0.25.0 + google.golang.org/protobuf v1.34.1 maunium.net/go/mautrix v0.18.1 nhooyr.io/websocket v1.8.11 ) @@ -43,7 +43,7 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.1 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.19.0 // indirect + golang.org/x/sys v0.20.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index aaf41a7..30dea68 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxU github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= @@ -73,19 +73,19 @@ go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30= go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= -golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= diff --git a/main.go b/main.go index c09bc3d..0a92c52 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.6.0", + Version: "0.6.1", ProtocolName: "Signal", BeeperServiceName: "signal", BeeperNetworkName: "signal", From 585397a736d800939d500573b1e7e621bb93d05b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 16 May 2024 16:25:00 +0300 Subject: [PATCH 159/718] Fix PR links in changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df01490..9c6bc06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,12 @@ * Note that Signal doesn't support real location messages, so they're just bridged as links. The link template is configurable. * Fixed bridging long text messages from Signal - (thanks to [@maltee1] in [#509]). + (thanks to [@maltee1] in [#506]). * Improved handling of ping timeouts in Signal websocket. +[#504]: https://github.com/mautrix/signal/pull/504 +[#506]: https://github.com/mautrix/signal/pull/506 + # v0.6.0 (2024-04-16) * Updated to libsignal v0.44.0. From 6304b6b8c3eb935733c44de2ef120ce56bfbacdb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 17 May 2024 17:47:16 +0300 Subject: [PATCH 160/718] Remove msc1767 audio field. Fixes #513 --- msgconv/from-signal.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index a5c0174..9caecd6 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -452,7 +452,8 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp fileName += ".ogg" mimeType = "audio/ogg" extra["org.matrix.msc3245.voice"] = map[string]any{} - extra["org.matrix.msc1767.audio"] = map[string]any{} + // TODO include duration here (and in info) if there's some easy way to extract it with ffmpeg + //extra["org.matrix.msc1767.audio"] = map[string]any{"duration": ???} } var file *event.EncryptedFileInfo uploadMime := mimeType From 874712c0f2dac17bc439e6f0a634f2affbb21156 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 3 May 2024 11:45:59 +0200 Subject: [PATCH 161/718] Initial draft bridge with v2 architecture --- connector/connector.go | 440 ++++++++++++++++++++++++++++ connector/mautrix-signal-v2/main.go | 207 +++++++++++++ connector/mautrix-signal-v2/start | 6 + go.mod | 8 +- go.sum | 12 +- 5 files changed, 663 insertions(+), 10 deletions(-) create mode 100644 connector/connector.go create mode 100644 connector/mautrix-signal-v2/main.go create mode 100755 connector/mautrix-signal-v2/start diff --git a/connector/connector.go b/connector/connector.go new file mode 100644 index 0000000..9667ae5 --- /dev/null +++ b/connector/connector.go @@ -0,0 +1,440 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/dbutil" + "golang.org/x/exp/slices" + "google.golang.org/protobuf/proto" + + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" + + legacydb "go.mau.fi/mautrix-signal/database" + "go.mau.fi/mautrix-signal/msgconv" + "go.mau.fi/mautrix-signal/msgconv/matrixfmt" + "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "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/store" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +type SignalConnector struct { + MsgConv *msgconv.MessageConverter + Store *store.Container + Bridge *bridgev2.Bridge +} + +func NewConnector() *SignalConnector { + return &SignalConnector{} +} + +func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { + s.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "signalmeow").Logger())) + s.Bridge = bridge + s.MsgConv = &msgconv.MessageConverter{ + PortalMethods: &msgconvPortalMethods{}, + SignalFmtParams: &signalfmt.FormatParams{ + GetUserInfo: func(ctx context.Context, uuid uuid.UUID) signalfmt.UserInfo { + ghost, err := s.Bridge.GetGhostByID(ctx, makeUserID(uuid)) + if err != nil { + // TODO log? + return signalfmt.UserInfo{} + } + userInfo := signalfmt.UserInfo{ + MXID: ghost.MXID, + Name: ghost.Name, + } + userLogin := s.Bridge.GetCachedUserLoginByID(networkid.UserLoginID(uuid.String())) + if userLogin != nil { + userInfo.MXID = userLogin.UserMXID + // TODO find matrix user displayname? + } + return userInfo + }, + }, + MatrixFmtParams: &matrixfmt.HTMLParser{ + GetUUIDFromMXID: func(ctx context.Context, userID id.UserID) uuid.UUID { + parsed, ok := s.Bridge.Matrix.ParseGhostMXID(userID) + if ok { + u, _ := uuid.Parse(string(parsed)) + return u + } + user, _ := s.Bridge.GetExistingUserByMXID(ctx, userID) + // TODO log errors? + if user != nil { + preferredLogin, _ := ctx.Value(msgconvContextKey).(*msgconvContext).Portal.FindPreferredLogin(ctx, user) + if preferredLogin != nil { + u, _ := uuid.Parse(string(preferredLogin.ID)) + return u + } + } + return uuid.Nil + }, + }, + ConvertVoiceMessages: true, + ConvertGIFToAPNG: true, + MaxFileSize: 100 * 1024 * 1024, + AsyncFiles: true, + LocationFormat: "", + } +} + +func (s *SignalConnector) Start(ctx context.Context) error { + return s.Store.Upgrade(ctx) +} + +var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) +var _ bridgev2.NetworkAPI = (*SignalClient)(nil) +var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) + +func (s *SignalConnector) PrepareLogin(ctx context.Context, login *bridgev2.UserLogin) error { + aci, err := uuid.Parse(string(login.ID)) + if err != nil { + return fmt.Errorf("failed to parse user login ID: %w", err) + } + device, err := s.Store.DeviceByACI(ctx, aci) + if err != nil { + return fmt.Errorf("failed to get device from store: %w", err) + } else if device == nil { + return fmt.Errorf("%w: device not found in store", bridgev2.ErrNotLoggedIn) + } + sc := &SignalClient{ + Main: s, + UserLogin: login, + Client: &signalmeow.Client{ + Store: device, + }, + } + sc.Client.EventHandler = sc.handleSignalEvent + login.Client = sc + return nil +} + +type SignalClient struct { + Main *SignalConnector + UserLogin *bridgev2.UserLogin + Client *signalmeow.Client +} + +func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { + return &bridgev2.PortalInfo{}, nil +} + +func (s *SignalClient) Connect(ctx context.Context) error { + _, err := s.Client.StartReceiveLoops(ctx) + if err != nil { + return err + } + // TODO status + return nil +} + +func (s *SignalClient) IsLoggedIn() bool { + return s.Client.IsLoggedIn() +} + +func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (string, error) { + parts := strings.Split(string(portalID), "|") + if len(parts) == 1 { + if len(parts[0]) == 44 { + return parts[0], nil + } + return "", fmt.Errorf("invalid portal ID: expected group ID to be 44 characters") + } else if len(parts) == 2 { + ourACI := s.Client.Store.ACI.String() + if parts[0] == ourACI { + return parts[1], nil + } else if parts[1] == ourACI { + return parts[0], nil + } else { + return "", fmt.Errorf("invalid portal ID: expected one side to be our ACI") + } + } + return "", fmt.Errorf("invalid portal ID: unexpected number of pipe-separated parts") +} + +func (s *SignalClient) getPortalID(chatID string) networkid.PortalID { + if len(chatID) == 44 { + // Group ID + return networkid.PortalID(chatID) + } else if strings.HasPrefix(chatID, "PNI:") { + // Temporary new DM ID: always put our own ACI first, the portal will never be shared anyway + return networkid.PortalID(fmt.Sprintf("%s|%s", s.Client.Store.ACI, chatID)) + } else { + // DM ID: sort the two parts so the ID is always the same regardless of which side is receiving the message + parts := []string{s.Client.Store.ACI.String(), chatID} + slices.Sort(parts) + return networkid.PortalID(strings.Join(parts, "|")) + } +} + +func makeMessageID(sender uuid.UUID, timestamp uint64) networkid.MessageID { + return networkid.MessageID(fmt.Sprintf("%s|%d", sender, timestamp)) +} + +func makeUserID(user uuid.UUID) networkid.UserID { + return networkid.UserID(user.String()) +} + +func makeUserLoginID(user uuid.UUID) networkid.UserLoginID { + return networkid.UserLoginID(user.String()) +} + +func (s *SignalClient) makeEventSender(sender uuid.UUID) bridgev2.EventSender { + return bridgev2.EventSender{ + IsFromMe: sender == s.Client.Store.ACI, + SenderLogin: makeUserLoginID(sender), + Sender: makeUserID(sender), + } +} + +func makeMessagePartID(index int) networkid.PartID { + if index == 0 { + return "" + } + return networkid.PartID(strconv.Itoa(index)) +} + +type contextKey int + +var msgconvContextKey contextKey + +type msgconvContext struct { + Connector *SignalConnector + Intent bridgev2.MatrixAPI + Client *SignalClient + Portal *bridgev2.Portal + ReplyTo *database.Message +} + +func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Portal, data *events.ChatEvent) (*bridgev2.ConvertedMessage, error) { + dataMsg := data.Event.(*signalpb.DataMessage) + converted := s.Main.MsgConv.ToMatrix(ctx, dataMsg) + var replyTo *networkid.MessageOptionalPartID + if dataMsg.GetQuote() != nil { + quoteAuthor, _ := uuid.Parse(dataMsg.Quote.GetAuthorAci()) + replyTo = &networkid.MessageOptionalPartID{ + MessageID: makeMessageID(quoteAuthor, dataMsg.Quote.GetId()), + } + } + convertedParts := make([]*bridgev2.ConvertedMessagePart, len(converted.Parts)) + for i, part := range converted.Parts { + convertedParts[i] = &bridgev2.ConvertedMessagePart{ + ID: makeMessagePartID(i), + Type: part.Type, + Content: part.Content, + Extra: part.Extra, + } + + } + return &bridgev2.ConvertedMessage{ + ID: makeMessageID(data.Info.Sender, dataMsg.GetTimestamp()), + EventSender: s.makeEventSender(data.Info.Sender), + Timestamp: time.UnixMilli(int64(converted.Timestamp)), + ReplyTo: replyTo, + Parts: convertedParts, + }, nil +} + +func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { + switch evt := rawEvt.(type) { + case *events.ChatEvent: + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &bridgev2.SimpleRemoteEvent[*events.ChatEvent]{ + Type: bridgev2.RemoteEventMessage, + LogContext: func(c zerolog.Context) zerolog.Context { + return c. + Uint64("message_id", innerEvt.GetTimestamp()). + Stringer("sender_id", evt.Info.Sender) + }, + PortalID: s.getPortalID(evt.Info.ChatID), + Data: evt, + CreatePortal: true, + + ConvertMessageFunc: s.convertMessage, + }) + case *signalpb.EditMessage: + case *signalpb.TypingMessage: + } + case *events.DecryptionError: + case *events.Receipt: + case *events.ReadSelf: + case *events.Call: + case *events.ContactList: + case *events.ACIFound: + } +} + +func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *database.Message, err error) { + mcCtx := &msgconvContext{ + Connector: s.Main, + Intent: nil, + Client: s, + Portal: msg.Portal, + ReplyTo: msg.ReplyTo, + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + chatID, err := s.parsePortalID(msg.Portal.ID) + if err != nil { + return nil, err + } + var userID libsignalgo.ServiceID + var groupID types.GroupIdentifier + if len(chatID) == 44 { + groupID = types.GroupIdentifier(chatID) + } else { + userID, err = libsignalgo.ServiceIDFromString(chatID) + if err != nil { + return nil, err + } + } + converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) + if err != nil { + return nil, err + } + wrappedContent := &signalpb.Content{ + DataMessage: converted, + } + if groupID != "" { + res, err := s.Client.SendGroupMessage(ctx, groupID, wrappedContent) + if err != nil { + return nil, err + } + // TODO check result + fmt.Println(res) + } else { + res := s.Client.SendMessage(ctx, userID, wrappedContent) + // TODO check result + fmt.Println(res) + } + meta := map[string]any{ + "reply_to_file": len(converted.Attachments) > 0, + } + dbMsg := &database.Message{ + ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), + MXID: msg.Event.ID, + RoomID: msg.Portal.ID, + SenderID: makeUserID(s.Client.Store.ACI), + Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), + Metadata: meta, + } + if msg.ReplyTo != nil { + dbMsg.RelatesToRowID = msg.ReplyTo.RowID + } + return dbMsg, nil +} + +func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { + //TODO implement me + panic("implement me") +} + +func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (emojiID networkid.EmojiID, err error) { + //TODO implement me + panic("implement me") +} + +func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { + //TODO implement me + panic("implement me") +} + +func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { + //TODO implement me + panic("implement me") +} + +type msgconvPortalMethods struct{} + +func (mpm *msgconvPortalMethods) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { + mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) + uri, _, err := mcCtx.Intent.UploadMedia(ctx, "", data, fileName, contentType) + return uri, err +} + +func (mpm *msgconvPortalMethods) DownloadMatrixMedia(ctx context.Context, uri id.ContentURIString) ([]byte, error) { + return ctx.Value(msgconvContextKey).(*msgconvContext).Connector.Bridge.Bot.DownloadMedia(ctx, uri, nil) +} + +func (mpm *msgconvPortalMethods) GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) { + // Matrix replies are handled in bridgev2 code + return "", "" +} + +func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote { + mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) + if mcCtx.ReplyTo == nil { + return nil + } + quote := &signalpb.DataMessage_Quote{ + Id: proto.Uint64(uint64(mcCtx.ReplyTo.Timestamp.UnixMilli())), + AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), + Type: signalpb.DataMessage_Quote_NORMAL.Enum(), + } + if mcCtx.ReplyTo.Metadata["reply_to_file"] != false { + quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) + } + return quote +} + +func (mpm *msgconvPortalMethods) GetClient(ctx context.Context) *signalmeow.Client { + return ctx.Value(msgconvContextKey).(*msgconvContext).Client.Client +} + +func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { + mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) + portal := mcCtx.Portal + chatID, _ := mcCtx.Client.parsePortalID(portal.ID) + pk := legacydb.PortalKey{ + ChatID: chatID, + } + if len(chatID) != 44 { + pk.Receiver = mcCtx.Client.Client.Store.ACI + } + return &legacydb.Portal{ + PortalKey: pk, + MXID: portal.MXID, + Name: portal.Name, + Topic: portal.Topic, + //AvatarPath: "", + //AvatarHash: "", + //AvatarURL: id.ContentURI{}, + NameSet: portal.NameSet, + AvatarSet: portal.AvatarSet, + TopicSet: portal.TopicSet, + //Revision: portal.Metadata["revision"].(uint32), + Encrypted: true, + //RelayUserID: portal.Relay.UserMXID, + //ExpirationTime: portal.Metadata["expiration_timer"].(uint32), + } +} diff --git a/connector/mautrix-signal-v2/main.go b/connector/mautrix-signal-v2/main.go new file mode 100644 index 0000000..929a9c1 --- /dev/null +++ b/connector/mautrix-signal-v2/main.go @@ -0,0 +1,207 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +import ( + "fmt" + "os" + "strings" + "time" + + "github.com/google/uuid" + "github.com/skip2/go-qrcode" + "go.mau.fi/util/dbutil" + "go.mau.fi/util/exerrors" + "go.mau.fi/util/exzerolog" + "gopkg.in/yaml.v3" + + "go.mau.fi/mautrix-signal/pkg/signalmeow" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/bridgeconfig" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/matrix" + "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" + + "go.mau.fi/mautrix-signal/connector" +) + +func main() { + var cfg bridgeconfig.Config + config := exerrors.Must(os.ReadFile("config.yaml")) + exerrors.PanicIfNotNil(yaml.Unmarshal(config, &cfg)) + log := exerrors.Must(cfg.Logging.Compile()) + exzerolog.SetupDefaults(log) + db := exerrors.Must(dbutil.NewFromConfig("mautrix-signal", cfg.Database, dbutil.ZeroLogger(log.With().Str("db_section", "main").Logger()))) + bridge := bridgev2.NewBridge("", db, *log, matrix.NewConnector(&cfg), connector.NewConnector()) + bridge.CommandPrefix = "!signal" + bridge.Commands.AddHandlers(&bridgev2.FullHandler{ + Func: fnLogin, + Name: "login", + Help: bridgev2.HelpMeta{ + Section: bridgev2.HelpSectionAuth, + Description: "Log into Signal", + }, + }) + bridge.Start() +} + +func sendQR(ce *bridgev2.CommandEvent, code string, prevQR, prevMsg id.EventID) (qr, msg id.EventID) { + content, ok := uploadQR(ce, code) + if !ok { + return prevQR, prevMsg + } + if len(prevQR) != 0 { + content.SetEdit(prevQR) + } + resp, err := ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventMessage, &event.Content{Parsed: &content}, time.Now()) + if err != nil { + ce.Log.Err(err).Msg("Failed to send QR code to user") + } else if len(prevQR) == 0 { + prevQR = resp.EventID + } + content = event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: fmt.Sprintf("Raw linking URI: %s", code), + Format: event.FormatHTML, + FormattedBody: fmt.Sprintf("Raw linking URI: %s", code), + } + if len(prevMsg) != 0 { + content.SetEdit(prevMsg) + } + resp, err = ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventMessage, &event.Content{Parsed: &content}, time.Now()) + if err != nil { + ce.Log.Err(err).Msg("Failed to send raw code to user") + } else if len(prevMsg) == 0 { + prevMsg = resp.EventID + } + return prevQR, prevMsg +} + +func uploadQR(ce *bridgev2.CommandEvent, code string) (event.MessageEventContent, bool) { + const size = 512 + qrCode, err := qrcode.Encode(code, qrcode.Low, size) + if err != nil { + ce.Log.Err(err).Msg("Failed to encode QR code") + ce.Reply("Failed to encode QR code: %v", err) + return event.MessageEventContent{}, false + } + + uri, file, err := ce.Bot.UploadMedia(ce.Ctx, ce.RoomID, qrCode, "qr.png", "image/png") + if err != nil { + ce.Log.Err(err).Msg("Failed to upload QR code") + ce.Reply("Failed to upload QR code: %v", err) + return event.MessageEventContent{}, false + } + return event.MessageEventContent{ + MsgType: event.MsgImage, + Info: &event.FileInfo{ + MimeType: "image/png", + Width: size, + Height: size, + Size: len(qrCode), + }, + Body: "qr.png", + URL: uri, + File: file, + }, true +} +func fnLogin(ce *bridgev2.CommandEvent) { + signal := ce.Bridge.Network.(*connector.SignalConnector) + // TODO configurable device name + provChan := signalmeow.PerformProvisioning(ce.Ctx, signal.Store, "Mautrix-Signal Megabridge") + + resp := <-provChan + if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + ce.Reply("Error getting provisioning URL: %v", resp.Err) + return + } + var qrEventID, msgEventID id.EventID + if resp.State == signalmeow.StateProvisioningURLReceived { + qrEventID, msgEventID = sendQR(ce, resp.ProvisioningURL, qrEventID, msgEventID) + } else { + ce.Reply("Unexpected state: %v", resp.State) + return + } + + // Next, get the results of finishing registration + resp = <-provChan + _, _ = ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventRedaction, &event.Content{ + Parsed: &event.RedactionEventContent{ + Redacts: qrEventID, + }, + }, time.Now()) + _, _ = ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventRedaction, &event.Content{ + Parsed: &event.RedactionEventContent{ + Redacts: msgEventID, + }, + }, time.Now()) + if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + if resp.Err != nil && strings.HasSuffix(resp.Err.Error(), " EOF") { + ce.Reply("Logging in timed out, please try again.") + } else { + ce.Reply("Error finishing registration: %v", resp.Err) + } + return + } + var signalID uuid.UUID + var signalPhone string + if resp.State == signalmeow.StateProvisioningDataReceived { + signalID = resp.ProvisioningData.ACI + signalPhone = resp.ProvisioningData.Number + } else { + ce.Reply("Unexpected state: %v", resp.State) + return + } + + // Finally, get the results of generating and registering prekeys + resp = <-provChan + if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + ce.Reply("Error with prekeys: %v", resp.Err) + return + } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { + ce.Reply("Unexpected state: %v", resp.State) + return + } + + if signalID == uuid.Nil { + ce.Reply("Problem logging in - No SignalID received") + return + } + ul, err := ce.User.NewLogin(ce.Ctx, &database.UserLogin{ + ID: networkid.UserLoginID(signalID.String()), + Metadata: map[string]any{ + "phone": signalPhone, + }, + }, nil) + if err != nil { + ce.Reply("Failed to save new login: %v", err) + return + } + err = ce.Bridge.Network.PrepareLogin(ce.Ctx, ul) + if err != nil { + ce.Reply("Failed to prepare connection after login: %v", err) + return + } + err = ul.Client.Connect(ce.Ctx) + if err != nil { + ce.Reply("Failed to connect after login: %v", err) + return + } + ce.Reply("Successfully logged in as %s (UUID: %s)", signalPhone, signalID) +} diff --git a/connector/mautrix-signal-v2/start b/connector/mautrix-signal-v2/start new file mode 100755 index 0000000..85c97d1 --- /dev/null +++ b/connector/mautrix-signal-v2/start @@ -0,0 +1,6 @@ +#!/bin/bash +export LIBRARY_PATH=$(dirname $(dirname $(pwd))):$LIBRARY_PATH +export MAUTRIX_VERSION=$(cat ../../go.mod | grep 'maunium.net/go/mautrix ' | head -n1 | awk '{ print $2 }') +go install -ldflags "-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date '+%b %_d %Y, %H:%M:%S'`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" || exit 2 +mkdir -p logs +mautrix-signal-v2 "$@" diff --git a/go.mod b/go.mod index bf3fd25..8743805 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,13 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.2 + go.mau.fi/util v0.4.3-0.20240516141139-2ebe792cd8f7 golang.org/x/crypto v0.23.0 - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 + golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.1 + gopkg.in/yaml.v3 v3.0.1 + maunium.net/go/mautrix v0.18.2-0.20240527105318-9254a5d6c1d9 nhooyr.io/websocket v1.8.11 ) @@ -45,6 +46,5 @@ require ( go.mau.fi/zeroconfig v0.1.2 // indirect golang.org/x/sys v0.20.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index 30dea68..f68078a 100644 --- a/go.sum +++ b/go.sum @@ -69,14 +69,14 @@ 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.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30= -go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw= +go.mau.fi/util v0.4.3-0.20240516141139-2ebe792cd8f7 h1:2hnc2iS7usHT3aqIQ8HVtKtPgic+13EVSdZ1m8UBL/E= +go.mau.fi/util v0.4.3-0.20240516141139-2ebe792cd8f7/go.mod h1:m+PJpPMadAW6cj3ldyuO5bLhFreWdwcu+3QTwYNGlGk= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d h1:N0hmiNbwsSNwHBAvR3QB5w25pUwH4tK0Y/RltD1j1h4= +golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -95,7 +95,7 @@ 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.18.1 h1:a6mUsJixegBNTXUoqC5RQ9gsumIPzKvCubKwF+zmCt4= -maunium.net/go/mautrix v0.18.1/go.mod h1:2oHaq792cSXFGvxLvYw3Gf1L4WVVP4KZcYys5HVk/h8= +maunium.net/go/mautrix v0.18.2-0.20240527105318-9254a5d6c1d9 h1:pRnJkxSjLsJSWON0yWzHNDyQqeebvgCeRXzozntEj/0= +maunium.net/go/mautrix v0.18.2-0.20240527105318-9254a5d6c1d9/go.mod h1:Ln4XquIKL5MttTUGNUSbiEGX3XYC0P6jzT9XjLFFPdY= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From e5e3dd1abcee154bce3bafa63903ac0d8f6a595b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 28 May 2024 20:52:07 +0300 Subject: [PATCH 162/718] Add initial user and room metadata support --- commands.go | 2 +- connector/connector.go | 155 +++++++++++++++++++++++++++++++++++------ go.mod | 2 +- go.sum | 4 +- portal.go | 15 ++-- user.go | 2 +- 6 files changed, 148 insertions(+), 32 deletions(-) diff --git a/commands.go b/commands.go index 728f2d6..e3021c0 100644 --- a/commands.go +++ b/commands.go @@ -989,7 +989,7 @@ func fnCreate(ce *WrappedCommandEvent) { avatarSet := false if ok { roomAvatarEvent.Content.ParseRaw(event.StateRoomAvatar) - avatarURL = roomAvatarEvent.Content.AsRoomAvatar().URL + avatarURL = roomAvatarEvent.Content.AsRoomAvatar().URL.ParseOrIgnore() if !avatarURL.IsEmpty() { avatarBytes, err = ce.Bot.DownloadBytes(ce.Ctx, avatarURL) if err != nil { diff --git a/connector/connector.go b/connector/connector.go index 9667ae5..770259c 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -145,8 +145,115 @@ type SignalClient struct { Client *signalmeow.Client } +func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.UserInfo { + isBot := false + ui := &bridgev2.UserInfo{ + IsBot: &isBot, + } + // TODO use template for name + if contact.ContactName != "" { + ui.Name = &contact.ContactName + } else if contact.Profile.Name != "" { + ui.Name = &contact.Profile.Name + } else if contact.E164 != "" { + ui.Name = &contact.E164 + } + // TODO only use this if contact avatars are allowed + if contact.ContactAvatar.Hash != "" { + ui.Avatar = &bridgev2.Avatar{ + ID: networkid.AvatarID("hash:" + contact.ContactAvatar.Hash), + Get: func(ctx context.Context) ([]byte, error) { + if contact.ContactAvatar.Image == nil { + return nil, fmt.Errorf("contact avatar not available") + } + return contact.ContactAvatar.Image, nil + }, + } + } else if contact.Profile.AvatarPath != "" { + ui.Avatar = &bridgev2.Avatar{ + ID: makeAvatarPathID(contact.Profile.AvatarPath), + Get: func(ctx context.Context) ([]byte, error) { + return s.Client.DownloadUserAvatar(ctx, contact.Profile.AvatarPath, contact.Profile.Key) + }, + } + } else { + ui.Avatar = &bridgev2.Avatar{ + ID: "", + Remove: true, + } + } + return ui +} + +func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { + userID, err := parseUserID(ghost.ID) + if err != nil { + return nil, err + } + contact, err := s.Client.ContactByACI(ctx, userID) + if err != nil { + return nil, err + } + return s.contactToUserInfo(contact), nil +} + +func makeAvatarPathID(avatarPath string) networkid.AvatarID { + if avatarPath == "" { + return "" + } + return networkid.AvatarID("path:" + avatarPath) +} + func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { - return &bridgev2.PortalInfo{}, nil + userID, groupID, err := s.parsePortalID(portal.ID) + if err != nil { + return nil, err + } + isSpace := false + if groupID != "" { + groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, 0) + if err != nil { + return nil, err + } + isDM := false + members := make([]networkid.UserID, len(groupInfo.Members)) + for i, member := range groupInfo.Members { + members[i] = makeUserID(member.ACI) + } + return &bridgev2.PortalInfo{ + Name: &groupInfo.Title, + Topic: &groupInfo.Description, + Avatar: &bridgev2.Avatar{ + ID: makeAvatarPathID(groupInfo.AvatarPath), + Get: func(ctx context.Context) ([]byte, error) { + return s.Client.DownloadGroupAvatar(ctx, groupInfo) + }, + Remove: groupInfo.AvatarPath == "", + }, + Members: members, + IsDirectChat: &isDM, + IsSpace: &isSpace, + }, nil + } else if userID.Type == libsignalgo.ServiceIDTypePNI { + isDM := true + // TODO set name/avatar because we don't have the recipient user ID + return &bridgev2.PortalInfo{ + Members: []networkid.UserID{makeUserID(s.Client.Store.ACI)}, + IsDirectChat: &isDM, + IsSpace: &isSpace, + }, nil + } else { + isDM := true + return &bridgev2.PortalInfo{ + Members: []networkid.UserID{makeUserID(userID.UUID), makeUserID(s.Client.Store.ACI)}, + IsDirectChat: &isDM, + IsSpace: &isSpace, + }, nil + } +} + +func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bool { + return userID == makeUserID(s.Client.Store.ACI) } func (s *SignalClient) Connect(ctx context.Context) error { @@ -162,24 +269,31 @@ func (s *SignalClient) IsLoggedIn() bool { return s.Client.IsLoggedIn() } -func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (string, error) { +func parseUserID(userID networkid.UserID) (uuid.UUID, error) { + return uuid.Parse(string(userID)) +} + +func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { parts := strings.Split(string(portalID), "|") if len(parts) == 1 { if len(parts[0]) == 44 { - return parts[0], nil + groupID = types.GroupIdentifier(parts[0]) + } else { + err = fmt.Errorf("invalid portal ID: expected group ID to be 44 characters") } - return "", fmt.Errorf("invalid portal ID: expected group ID to be 44 characters") } else if len(parts) == 2 { ourACI := s.Client.Store.ACI.String() if parts[0] == ourACI { - return parts[1], nil + userID, err = libsignalgo.ServiceIDFromString(parts[1]) } else if parts[1] == ourACI { - return parts[0], nil + userID, err = libsignalgo.ServiceIDFromString(parts[0]) } else { - return "", fmt.Errorf("invalid portal ID: expected one side to be our ACI") + err = fmt.Errorf("invalid portal ID: expected one side to be our ACI") } + } else { + err = fmt.Errorf("invalid portal ID: unexpected number of pipe-separated parts") } - return "", fmt.Errorf("invalid portal ID: unexpected number of pipe-separated parts") + return } func (s *SignalClient) getPortalID(chatID string) networkid.PortalID { @@ -237,6 +351,13 @@ type msgconvContext struct { } func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Portal, data *events.ChatEvent) (*bridgev2.ConvertedMessage, error) { + mcCtx := &msgconvContext{ + Connector: s.Main, + Intent: s.Main.Bridge.Bot, // TODO get correct intent? + Client: s, + Portal: portal, + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) dataMsg := data.Event.(*signalpb.DataMessage) converted := s.Main.MsgConv.ToMatrix(ctx, dataMsg) var replyTo *networkid.MessageOptionalPartID @@ -304,20 +425,10 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma ReplyTo: msg.ReplyTo, } ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - chatID, err := s.parsePortalID(msg.Portal.ID) + userID, groupID, err := s.parsePortalID(msg.Portal.ID) if err != nil { return nil, err } - var userID libsignalgo.ServiceID - var groupID types.GroupIdentifier - if len(chatID) == 44 { - groupID = types.GroupIdentifier(chatID) - } else { - userID, err = libsignalgo.ServiceIDFromString(chatID) - if err != nil { - return nil, err - } - } converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) if err != nil { return nil, err @@ -414,7 +525,11 @@ func (mpm *msgconvPortalMethods) GetClient(ctx context.Context) *signalmeow.Clie func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) portal := mcCtx.Portal - chatID, _ := mcCtx.Client.parsePortalID(portal.ID) + userID, groupID, _ := mcCtx.Client.parsePortalID(portal.ID) + chatID := string(groupID) + if chatID == "" { + chatID = userID.String() + } pk := legacydb.PortalKey{ ChatID: chatID, } diff --git a/go.mod b/go.mod index 8743805..22b07b3 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240527105318-9254a5d6c1d9 + maunium.net/go/mautrix v0.18.2-0.20240528174923-3c7b3e13efe4 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index f68078a..4d6c887 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240527105318-9254a5d6c1d9 h1:pRnJkxSjLsJSWON0yWzHNDyQqeebvgCeRXzozntEj/0= -maunium.net/go/mautrix v0.18.2-0.20240527105318-9254a5d6c1d9/go.mod h1:Ln4XquIKL5MttTUGNUSbiEGX3XYC0P6jzT9XjLFFPdY= +maunium.net/go/mautrix v0.18.2-0.20240528174923-3c7b3e13efe4 h1:b+pK+EJL2XsweSKlwhd8eeqD4v395dKrcJZmCFTBmBY= +maunium.net/go/mautrix v0.18.2-0.20240528174923-3c7b3e13efe4/go.mod h1:Ln4XquIKL5MttTUGNUSbiEGX3XYC0P6jzT9XjLFFPdY= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/portal.go b/portal.go index 2e90ac7..b0ba635 100644 --- a/portal.go +++ b/portal.go @@ -1765,7 +1765,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev initialState = append(initialState, &event.Event{ Type: event.StateRoomAvatar, Content: event.Content{Parsed: &event.RoomAvatarEventContent{ - URL: portal.AvatarURL, + URL: portal.AvatarURL.CUString(), }}, }) } @@ -2910,17 +2910,18 @@ func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { portal.Topic = content.Topic groupChange.ModifyDescription = &content.Topic case *event.RoomAvatarEventContent: - if content.URL == portal.AvatarURL { + url := content.URL.ParseOrIgnore() + if url == portal.AvatarURL { return } var data []byte - if !content.URL.IsEmpty() { - data, err = portal.MainIntent().DownloadBytes(ctx, content.URL) + if !url.IsEmpty() { + data, err = portal.MainIntent().DownloadBytes(ctx, url) if err != nil { - log.Err(err).Stringer("Failed to download updated avatar %s", content.URL) + log.Err(err).Stringer("Failed to download updated avatar %s", url) return } - log.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{sender.MXID, content.URL}) + log.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{sender.MXID, url}) } else { log.Debug().Stringer("%s removed the group avatar", sender.MXID) } @@ -2933,7 +2934,7 @@ func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { hash := sha256.Sum256(data) avatarHash = hex.EncodeToString(hash[:]) avatarChanged = true - avatarURL = content.URL + avatarURL = url } revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { diff --git a/user.go b/user.go index a579e8b..0a72b05 100644 --- a/user.go +++ b/user.go @@ -292,7 +292,7 @@ func (user *User) GetSpaceRoom(ctx context.Context) id.RoomID { Type: event.StateRoomAvatar, Content: event.Content{ Parsed: &event.RoomAvatarEventContent{ - URL: user.bridge.Config.AppService.Bot.ParsedAvatar, + URL: user.bridge.Config.AppService.Bot.ParsedAvatar.CUString(), }, }, }}, From b3e881ce471c7b7d8d3b9a605e4296f265331390 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 29 May 2024 15:09:06 +0300 Subject: [PATCH 163/718] Fix contact avatars --- connector/connector.go | 22 ++++++++++++++++++++++ portal.go | 8 ++++---- puppet.go | 5 ++++- user.go | 2 +- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/connector/connector.go b/connector/connector.go index 770259c..f332dc5 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -412,10 +412,32 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { case *events.ReadSelf: case *events.Call: case *events.ContactList: + s.handleSignalContactList(evt) case *events.ACIFound: } } +func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { + log := s.UserLogin.Log.With().Str("action", "handle contact list").Logger() + ctx := log.WithContext(context.TODO()) + for _, contact := range evt.Contacts { + if contact.ACI != uuid.Nil { + fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) + if err != nil { + log.Err(err).Msg("Failed to get full contact info from store") + continue + } + fullContact.ContactAvatar = contact.ContactAvatar + ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(contact.ACI)) + if err != nil { + log.Err(err).Msg("Failed to get ghost to update contact info") + continue + } + ghost.UpdateInfo(ctx, s.contactToUserInfo(contact)) + } + } +} + func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *database.Message, err error) { mcCtx := &msgconvContext{ Connector: s.Main, diff --git a/portal.go b/portal.go index b0ba635..0369c04 100644 --- a/portal.go +++ b/portal.go @@ -892,7 +892,7 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg Uint64("msg_ts", msg.GetTimestamp()). Logger().WithContext(context.TODO()) // Always update sender info when we receive a message from them, there's caching inside the function - sender.UpdateInfo(genericCtx, source) + sender.UpdateInfo(genericCtx, source, nil) // Handle earlier missed group changes here. if msg.GetGroupV2() != nil { requiredRevision := msg.GetGroupV2().GetRevision() @@ -1800,7 +1800,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev if portal.IsPrivateChat() { dmPuppet = portal.GetDMPuppet() if dmPuppet != nil { - dmPuppet.UpdateInfo(ctx, user) + dmPuppet.UpdateInfo(ctx, user, nil) portal.UpdateDMInfo(ctx, false) } else { portal.UpdatePNIDMInfo(ctx, user) @@ -1900,7 +1900,7 @@ func (portal *Portal) PostReIDUpdate(ctx context.Context, user *User) { if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to update ghost power level after portal re-ID") } - portal.GetDMPuppet().UpdateInfo(ctx, user) + portal.GetDMPuppet().UpdateInfo(ctx, user, nil) portal.UpdateDMInfo(ctx, true) if !portal.Encrypted { _, _ = portal.bridge.Bot.LeaveRoom(ctx, portal.MXID) @@ -2298,7 +2298,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * log.Warn().Stringer("signal_user_id", member.ACI).Msg("Couldn't get puppet for group member") continue } - puppet.UpdateInfo(ctx, source) + puppet.UpdateInfo(ctx, source, nil) intent := puppet.IntentFor(portal) if member.ACI != source.SignalID && portal.MXID != "" { userIDs[intent.UserID] = ((int)(member.Role) >> 1) * 50 diff --git a/puppet.go b/puppet.go index f58befa..857312e 100644 --- a/puppet.go +++ b/puppet.go @@ -232,7 +232,7 @@ func (puppet *Puppet) GetAvatarURL() id.ContentURI { return puppet.AvatarURL } -func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { +func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, contactAvatar *types.ContactAvatar) { log := zerolog.Ctx(ctx).With(). Str("function", "Puppet.UpdateInfo"). Stringer("signal_user_id", puppet.SignalID). @@ -252,6 +252,9 @@ func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { Msg("Ignoring outdated contact info") return } + if contactAvatar != nil { + info.ContactAvatar = *contactAvatar + } log.Trace().Msg("Updating puppet info") diff --git a/user.go b/user.go index 0a72b05..dc16f98 100644 --- a/user.go +++ b/user.go @@ -755,7 +755,7 @@ func (user *User) handleContactList(evt *events.ContactList) { if puppet == nil { continue } - puppet.UpdateInfo(ctx, user) + puppet.UpdateInfo(ctx, user, &contact.ContactAvatar) } } From 954da8480caa7b4c29364634cb3e307b0d815ee1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 29 May 2024 20:46:28 +0300 Subject: [PATCH 164/718] Add connector config --- connector/connector.go | 83 ++++++++++++++++++++++++----- connector/mautrix-signal-v2/main.go | 4 +- go.mod | 2 +- go.sum | 4 +- 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/connector/connector.go b/connector/connector.go index f332dc5..7e24be6 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -21,6 +21,7 @@ import ( "fmt" "strconv" "strings" + "text/template" "time" "github.com/google/uuid" @@ -47,17 +48,65 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) +type SignalConfig struct { + DisplaynameTemplate string `yaml:"displayname_template"` + UseContactAvatars bool `yaml:"use_contact_avatars"` + UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` + NumberInTopic bool `yaml:"number_in_topic"` + DeviceName string `yaml:"device_name"` + + displaynameTemplate *template.Template `yaml:"-"` +} + +type DisplaynameParams struct { + ProfileName string + ContactName string + Username string + PhoneNumber string + UUID string + ACI string + PNI string + AboutEmoji string +} + +func (c *SignalConfig) FormatDisplayname(contact *types.Recipient) string { + var nameBuf strings.Builder + err := c.displaynameTemplate.Execute(&nameBuf, &DisplaynameParams{ + ProfileName: contact.Profile.Name, + ContactName: contact.ContactName, + Username: "", + PhoneNumber: contact.E164, + UUID: contact.ACI.String(), + ACI: contact.ACI.String(), + PNI: contact.PNI.String(), + AboutEmoji: contact.Profile.AboutEmoji, + }) + if err != nil { + panic(err) + } + return nameBuf.String() +} + type SignalConnector struct { MsgConv *msgconv.MessageConverter Store *store.Container Bridge *bridgev2.Bridge + Config *SignalConfig } func NewConnector() *SignalConnector { - return &SignalConnector{} + return &SignalConnector{ + Config: &SignalConfig{}, + } } func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { + var err error + s.Config.displaynameTemplate, err = template.New("displayname").Parse(s.Config.DisplaynameTemplate) + if err != nil { + // TODO return error or do this later? + panic(err) + } s.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "signalmeow").Logger())) s.Bridge = bridge s.MsgConv = &msgconv.MessageConverter{ @@ -150,16 +199,9 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use ui := &bridgev2.UserInfo{ IsBot: &isBot, } - // TODO use template for name - if contact.ContactName != "" { - ui.Name = &contact.ContactName - } else if contact.Profile.Name != "" { - ui.Name = &contact.Profile.Name - } else if contact.E164 != "" { - ui.Name = &contact.E164 - } - // TODO only use this if contact avatars are allowed - if contact.ContactAvatar.Hash != "" { + name := s.Main.Config.FormatDisplayname(contact) + ui.Name = &name + if s.Main.Config.UseContactAvatars && contact.ContactAvatar.Hash != "" { ui.Avatar = &bridgev2.Avatar{ ID: networkid.AvatarID("hash:" + contact.ContactAvatar.Hash), Get: func(ctx context.Context) ([]byte, error) { @@ -235,17 +277,34 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) IsSpace: &isSpace, }, nil } else if userID.Type == libsignalgo.ServiceIDTypePNI { + contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, uuid.Nil, userID.UUID, nil) + if err != nil { + return nil, err + } + var topic, name string + name = s.Main.Config.FormatDisplayname(contact) + if s.Main.Config.NumberInTopic && contact.E164 != "" { + topic = fmt.Sprintf("") + // TODO set topic + } isDM := true - // TODO set name/avatar because we don't have the recipient user ID return &bridgev2.PortalInfo{ Members: []networkid.UserID{makeUserID(s.Client.Store.ACI)}, + Name: &name, + Topic: &topic, IsDirectChat: &isDM, IsSpace: &isSpace, }, nil } else { + var topic, name string + if s.Main.Config.NumberInTopic { + // TODO set topic + } isDM := true return &bridgev2.PortalInfo{ Members: []networkid.UserID{makeUserID(userID.UUID), makeUserID(s.Client.Store.ACI)}, + Name: &name, + Topic: &topic, IsDirectChat: &isDM, IsSpace: &isSpace, }, nil diff --git a/connector/mautrix-signal-v2/main.go b/connector/mautrix-signal-v2/main.go index 929a9c1..1ea34d9 100644 --- a/connector/mautrix-signal-v2/main.go +++ b/connector/mautrix-signal-v2/main.go @@ -48,7 +48,9 @@ func main() { log := exerrors.Must(cfg.Logging.Compile()) exzerolog.SetupDefaults(log) db := exerrors.Must(dbutil.NewFromConfig("mautrix-signal", cfg.Database, dbutil.ZeroLogger(log.With().Str("db_section", "main").Logger()))) - bridge := bridgev2.NewBridge("", db, *log, matrix.NewConnector(&cfg), connector.NewConnector()) + signalConnector := connector.NewConnector() + exerrors.PanicIfNotNil(cfg.Network.Decode(signalConnector.Config)) + bridge := bridgev2.NewBridge("", db, *log, matrix.NewConnector(&cfg), signalConnector) bridge.CommandPrefix = "!signal" bridge.Commands.AddHandlers(&bridgev2.FullHandler{ Func: fnLogin, diff --git a/go.mod b/go.mod index 22b07b3..913d3c1 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240528174923-3c7b3e13efe4 + maunium.net/go/mautrix v0.18.2-0.20240529135554-248de0e6adb2 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 4d6c887..641b71f 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240528174923-3c7b3e13efe4 h1:b+pK+EJL2XsweSKlwhd8eeqD4v395dKrcJZmCFTBmBY= -maunium.net/go/mautrix v0.18.2-0.20240528174923-3c7b3e13efe4/go.mod h1:Ln4XquIKL5MttTUGNUSbiEGX3XYC0P6jzT9XjLFFPdY= +maunium.net/go/mautrix v0.18.2-0.20240529135554-248de0e6adb2 h1:AUKv3tqpdFerCw2X8m05BGfhtP3vH8cDuEtAGxwuUl0= +maunium.net/go/mautrix v0.18.2-0.20240529135554-248de0e6adb2/go.mod h1:Ln4XquIKL5MttTUGNUSbiEGX3XYC0P6jzT9XjLFFPdY= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From c5a7ccaf89167ffc63187da7383c919aa45054fc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 31 May 2024 15:47:27 +0300 Subject: [PATCH 165/718] Fix contact avatars --- portal.go | 8 ++++---- puppet.go | 5 ++++- user.go | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/portal.go b/portal.go index 2e90ac7..6922311 100644 --- a/portal.go +++ b/portal.go @@ -892,7 +892,7 @@ func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg Uint64("msg_ts", msg.GetTimestamp()). Logger().WithContext(context.TODO()) // Always update sender info when we receive a message from them, there's caching inside the function - sender.UpdateInfo(genericCtx, source) + sender.UpdateInfo(genericCtx, source, nil) // Handle earlier missed group changes here. if msg.GetGroupV2() != nil { requiredRevision := msg.GetGroupV2().GetRevision() @@ -1800,7 +1800,7 @@ func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRev if portal.IsPrivateChat() { dmPuppet = portal.GetDMPuppet() if dmPuppet != nil { - dmPuppet.UpdateInfo(ctx, user) + dmPuppet.UpdateInfo(ctx, user, nil) portal.UpdateDMInfo(ctx, false) } else { portal.UpdatePNIDMInfo(ctx, user) @@ -1900,7 +1900,7 @@ func (portal *Portal) PostReIDUpdate(ctx context.Context, user *User) { if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to update ghost power level after portal re-ID") } - portal.GetDMPuppet().UpdateInfo(ctx, user) + portal.GetDMPuppet().UpdateInfo(ctx, user, nil) portal.UpdateDMInfo(ctx, true) if !portal.Encrypted { _, _ = portal.bridge.Bot.LeaveRoom(ctx, portal.MXID) @@ -2298,7 +2298,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * log.Warn().Stringer("signal_user_id", member.ACI).Msg("Couldn't get puppet for group member") continue } - puppet.UpdateInfo(ctx, source) + puppet.UpdateInfo(ctx, source, nil) intent := puppet.IntentFor(portal) if member.ACI != source.SignalID && portal.MXID != "" { userIDs[intent.UserID] = ((int)(member.Role) >> 1) * 50 diff --git a/puppet.go b/puppet.go index f58befa..857312e 100644 --- a/puppet.go +++ b/puppet.go @@ -232,7 +232,7 @@ func (puppet *Puppet) GetAvatarURL() id.ContentURI { return puppet.AvatarURL } -func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { +func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, contactAvatar *types.ContactAvatar) { log := zerolog.Ctx(ctx).With(). Str("function", "Puppet.UpdateInfo"). Stringer("signal_user_id", puppet.SignalID). @@ -252,6 +252,9 @@ func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User) { Msg("Ignoring outdated contact info") return } + if contactAvatar != nil { + info.ContactAvatar = *contactAvatar + } log.Trace().Msg("Updating puppet info") diff --git a/user.go b/user.go index a579e8b..0814c3e 100644 --- a/user.go +++ b/user.go @@ -755,7 +755,7 @@ func (user *User) handleContactList(evt *events.ContactList) { if puppet == nil { continue } - puppet.UpdateInfo(ctx, user) + puppet.UpdateInfo(ctx, user, &contact.ContactAvatar) } } From 3e6561054ef7fd1eb123faf9d8fba7a6b3a41891 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 3 Jun 2024 16:57:45 +0300 Subject: [PATCH 166/718] Update to libsignal 0.49.0 --- pkg/libsignalgo/authcredential.go | 10 +- pkg/libsignalgo/groupsecretparams.go | 5 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 364 ++++++++++++------ pkg/libsignalgo/logging.go | 11 +- pkg/libsignalgo/profilekey.go | 12 +- ...rifysignature.go => serverpublicparams.go} | 21 +- pkg/libsignalgo/version.go | 2 +- pkg/signalmeow/misc.go | 7 +- 9 files changed, 284 insertions(+), 150 deletions(-) rename pkg/libsignalgo/{verifysignature.go => serverpublicparams.go} (68%) diff --git a/pkg/libsignalgo/authcredential.go b/pkg/libsignalgo/authcredential.go index 57396ef..0c7354f 100644 --- a/pkg/libsignalgo/authcredential.go +++ b/pkg/libsignalgo/authcredential.go @@ -40,18 +40,17 @@ func (ac *AuthCredentialWithPni) Slice() []byte { } func ReceiveAuthCredentialWithPni( - serverPublicParams ServerPublicParams, + serverPublicParams *ServerPublicParams, aci uuid.UUID, pni uuid.UUID, redemptionTime uint64, authCredResponse AuthCredentialWithPniResponse, ) (*AuthCredentialWithPni, error) { var c_result C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_service_id( &c_result, - c_serverPublicParams, + serverPublicParams, NewACIServiceID(aci).CFixedBytes(), NewPNIServiceID(pni).CFixedBytes(), C.uint64_t(redemptionTime), @@ -78,19 +77,18 @@ func NewAuthCredentialWithPniResponse(b []byte) (*AuthCredentialWithPniResponse, } func CreateAuthCredentialWithPniPresentation( - serverPublicParams ServerPublicParams, + serverPublicParams *ServerPublicParams, randomness Randomness, groupSecretParams GroupSecretParams, authCredWithPni AuthCredentialWithPni, ) (*AuthCredentialPresentation, error) { var c_result C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) 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_serverPublicParams, + serverPublicParams, c_randomness, c_groupSecretParams, BytesToBuffer(authCredWithPni[:]), diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 76a28f7..0df5ec8 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -208,18 +208,17 @@ func (gsp *GroupSecretParams) EncryptProfileKey(profileKey ProfileKey, u uuid.UU return &result, nil } -func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp ServerPublicParams, credential ExpiringProfileKeyCredential) (*ProfileKeyCredentialPresentation, error) { +func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp *ServerPublicParams, credential ExpiringProfileKeyCredential) (*ProfileKeyCredentialPresentation, error) { var out C.SignalOwnedBuffer = C.SignalOwnedBuffer{} randomness := GenerateRandomness() signalFfiError := C.signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic( &out, - (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&spp)), + 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)), ) runtime.KeepAlive(gsp) - runtime.KeepAlive(spp) runtime.KeepAlive(credential) runtime.KeepAlive(randomness) if signalFfiError != nil { diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 02e03ee..347791c 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 02e03ee05742079694d643fbc64fa737b275e9f8 +Subproject commit 347791c88cdfdb765534b5e2be149f588b75bf49 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index b8bfab8..c349c2c 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -147,6 +147,7 @@ typedef enum { SignalErrorCodeInvalidArgument = 5, SignalErrorCodeInvalidType = 6, SignalErrorCodeInvalidUtf8String = 7, + SignalErrorCodeCancelled = 8, SignalErrorCodeProtobufError = 10, SignalErrorCodeLegacyCiphertextVersion = 21, SignalErrorCodeUnknownCiphertextVersion = 22, @@ -193,6 +194,8 @@ typedef enum { SignalErrorCodeChatServiceInactive = 139, SignalErrorCodeSvrDataMissing = 150, SignalErrorCodeSvrRestoreFailed = 151, + SignalErrorCodeAppExpired = 160, + SignalErrorCodeDeviceDeregistered = 161, } SignalErrorCode; /** @@ -274,6 +277,15 @@ typedef struct SignalSenderKeyRecord SignalSenderKeyRecord; typedef struct SignalServerCertificate SignalServerCertificate; +/** + * Wraps a named type and a single-use guard around [`chat::server_requests::AckEnvelopeFuture`]. + */ +typedef struct SignalServerMessageAck SignalServerMessageAck; + +typedef struct SignalServerPublicParams SignalServerPublicParams; + +typedef struct SignalServerSecretParams SignalServerSecretParams; + typedef struct SignalSessionRecord SignalSessionRecord; typedef struct SignalSgxClientState SignalSgxClientState; @@ -416,14 +428,12 @@ typedef struct { SignalStoreSignedPreKey store_signed_pre_key; } SignalSignedPreKeyStore; -typedef bool (*SignalLogEnabledCallback)(const char *target, SignalLogLevel level); +typedef void (*SignalLogCallback)(void *ctx, const char *target, SignalLogLevel level, const char *file, uint32_t line, const char *message); -typedef void (*SignalLogCallback)(const char *target, SignalLogLevel level, const char *file, uint32_t line, const char *message); - -typedef void (*SignalLogFlushCallback)(void); +typedef void (*SignalLogFlushCallback)(void *ctx); typedef struct { - SignalLogEnabledCallback enabled; + void *ctx; SignalLogCallback log; SignalLogFlushCallback flush; } SignalFfiLogger; @@ -489,24 +499,74 @@ typedef struct { size_t length; } SignalBorrowedSliceOfBuffers; -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - */ -typedef void (*SignalCPromiseOwnedBufferOfc_uchar)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); +typedef uint64_t SignalCancellationId; /** * A C callback used to report the results of Rust futures. * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromisebool)(SignalFfiError *error, const bool *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseOwnedBufferOfc_uchar; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const bool *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromisebool; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, SignalCdsiLookup *const *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseCdsiLookup; + +typedef struct { + SignalOwnedBufferOfFfiCdsiLookupResponseEntry entries; + int32_t debug_permits_used; +} SignalFfiCdsiLookupResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiCdsiLookupResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiCdsiLookupResponse; typedef struct { - bool connection_reused; uint32_t reconnect_count; uint8_t raw_ip_type; double duration_secs; @@ -518,8 +578,15 @@ typedef struct { * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromiseFfiChatServiceDebugInfo)(SignalFfiError *error, const SignalFfiChatServiceDebugInfo *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiChatServiceDebugInfo *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiChatServiceDebugInfo; typedef struct { uint16_t status; @@ -533,8 +600,15 @@ typedef struct { * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromiseFfiChatResponse)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiChatResponse; typedef struct { SignalFfiChatResponse response; @@ -546,29 +620,37 @@ typedef struct { * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. - */ -typedef void (*SignalCPromiseFfiResponseAndDebugInfo)(SignalFfiError *error, const SignalFfiResponseAndDebugInfo *result, const void *context); - -/** - * A C callback used to report the results of Rust futures. * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromiseCdsiLookup)(SignalFfiError *error, SignalCdsiLookup *const *result, const void *context); - typedef struct { - SignalOwnedBufferOfFfiCdsiLookupResponseEntry entries; - int32_t debug_permits_used; -} SignalFfiCdsiLookupResponse; + void (*complete)(SignalFfiError *error, const SignalFfiResponseAndDebugInfo *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiResponseAndDebugInfo; + +typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envelope, uint64_t timestamp_millis, SignalServerMessageAck *cleanup); + +typedef void (*SignalReceivedQueueEmpty)(void *ctx); + +typedef void (*SignalDestroyChatListener)(void *ctx); /** - * A C callback used to report the results of Rust futures. + * Callbacks for [`ChatListener`]. * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. + * Callbacks will be serialized (i.e. two calls will not come in at the same time), but may not + * always happen on the same thread. Calls should be responded to promptly to avoid blocking later + * messages. */ -typedef void (*SignalCPromiseFfiCdsiLookupResponse)(SignalFfiError *error, const SignalFfiCdsiLookupResponse *result, const void *context); +typedef struct { + void *ctx; + SignalReceivedIncomingMessage received_incoming_message; + SignalReceivedQueueEmpty received_queue_empty; + SignalDestroyChatListener destroy; +} SignalFfiChatListenerStruct; + +typedef SignalFfiChatListenerStruct SignalFfiMakeChatListenerStruct; typedef SignalBytestringArray SignalStringArray; @@ -589,32 +671,60 @@ typedef SignalInputStream SignalSyncInputStream; * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromisei32)(SignalFfiError *error, const int32_t *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, const int32_t *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromisei32; /** * A C callback used to report the results of Rust futures. * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromiseTestingHandleType)(SignalFfiError *error, SignalTestingHandleType *const *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, SignalTestingHandleType *const *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseTestingHandleType; /** * A C callback used to report the results of Rust futures. * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromiseOtherTestingHandleType)(SignalFfiError *error, SignalOtherTestingHandleType *const *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, SignalOtherTestingHandleType *const *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseOtherTestingHandleType; /** * A C callback used to report the results of Rust futures. * * cbindgen will produce independent C types like `SignalCPromisei32` and * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ -typedef void (*SignalCPromiseRawPointer)(SignalFfiError *error, const void *const *result, const void *context); +typedef struct { + void (*complete)(SignalFfiError *error, const void *const *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseRawPointer; typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN]; @@ -640,13 +750,15 @@ uint32_t signal_error_get_type(const SignalFfiError *err); SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); + void signal_error_free(SignalFfiError *err); SignalFfiError *signal_identitykeypair_deserialize(SignalPrivateKey **private_key, SignalPublicKey **public_key, SignalBorrowedBuffer input); SignalFfiError *signal_sealed_session_cipher_decrypt(SignalOwnedBuffer *out, const char **sender_e164, const char **sender_uuid, uint32_t *sender_device_id, SignalBorrowedBuffer ctext, const SignalPublicKey *trust_root, uint64_t timestamp, const char *local_e164, const char *local_uuid, unsigned int local_device_id, const SignalSessionStore *session_store, const SignalIdentityKeyStore *identity_store, const SignalPreKeyStore *prekey_store, const SignalSignedPreKeyStore *signed_prekey_store); -void signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); +bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); SignalFfiError *signal_aes256_gcm_siv_destroy(SignalAes256GcmSiv *p); @@ -946,6 +1058,8 @@ SignalFfiError *signal_pre_key_bundle_get_pre_key_public(SignalPublicKey **out, SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_public(SignalPublicKey **out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, const SignalPreKeyBundle *obj); + SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalKyberPublicKey **out, const SignalPreKeyBundle *bundle); SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, const SignalPreKeyBundle *bundle); @@ -1158,12 +1272,20 @@ SignalFfiError *signal_receipt_credential_request_context_check_valid_contents(S SignalFfiError *signal_receipt_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); -SignalFfiError *signal_server_public_params_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_server_secret_params_check_valid_contents(SignalBorrowedBuffer buffer); - SignalFfiError *signal_uuid_ciphertext_check_valid_contents(SignalBorrowedBuffer buffer); +SignalFfiError *signal_server_public_params_destroy(SignalServerPublicParams *p); + +SignalFfiError *signal_server_public_params_deserialize(SignalServerPublicParams **out, SignalBorrowedBuffer buffer); + +SignalFfiError *signal_server_public_params_serialize(SignalOwnedBuffer *out, const SignalServerPublicParams *handle); + +SignalFfiError *signal_server_secret_params_destroy(SignalServerSecretParams *p); + +SignalFfiError *signal_server_secret_params_deserialize(SignalServerSecretParams **out, SignalBorrowedBuffer buffer); + +SignalFfiError *signal_server_secret_params_serialize(SignalOwnedBuffer *out, const SignalServerSecretParams *handle); + SignalFfiError *signal_profile_key_get_commitment(unsigned char (*out)[SignalPROFILE_KEY_COMMITMENT_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); SignalFfiError *signal_profile_key_get_profile_key_version(uint8_t (*out)[SignalPROFILE_KEY_VERSION_ENCODED_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); @@ -1190,53 +1312,49 @@ SignalFfiError *signal_group_secret_params_encrypt_blob_with_padding_determinist SignalFfiError *signal_group_secret_params_decrypt_blob_with_padding(SignalOwnedBuffer *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer ciphertext); -SignalFfiError *signal_server_secret_params_generate_deterministic(unsigned char (*out)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); +SignalFfiError *signal_server_secret_params_generate_deterministic(SignalServerSecretParams **out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); -SignalFfiError *signal_server_secret_params_get_public_params(unsigned char (*out)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*params)[SignalSERVER_SECRET_PARAMS_LEN]); +SignalFfiError *signal_server_secret_params_get_public_params(SignalServerPublicParams **out, const SignalServerSecretParams *params); -SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], const unsigned char (*params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); +SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], const SignalServerSecretParams *params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); -SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); +SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, const SignalServerPublicParams *params, const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); -SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_aci(SignalOwnedBuffer *out, const unsigned char (*params)[SignalSERVER_PUBLIC_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); +SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); -SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); +SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); -SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); +SignalFfiError *signal_server_public_params_receive_expiring_profile_key_credential(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN], const SignalServerPublicParams *server_public_params, const unsigned char (*request_context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], uint64_t current_time_in_seconds); -SignalFfiError *signal_server_public_params_receive_expiring_profile_key_credential(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*request_context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], uint64_t current_time_in_seconds); +SignalFfiError *signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(SignalOwnedBuffer *out, const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key_credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); -SignalFfiError *signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key_credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); +SignalFfiError *signal_server_public_params_create_receipt_credential_request_context_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const uint8_t (*receipt_serial)[SignalRECEIPT_SERIAL_LEN]); -SignalFfiError *signal_server_public_params_create_receipt_credential_request_context_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const uint8_t (*receipt_serial)[SignalRECEIPT_SERIAL_LEN]); +SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_LEN], const SignalServerPublicParams *server_public_params, const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN]); -SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN]); +SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); -SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_service_id_deterministic(SignalOwnedBuffer *out, const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_service_id_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); - -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_aci_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); - -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorrowedBuffer bytes); SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); +SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(const SignalServerSecretParams *server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); -SignalFfiError *signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*commitment)[SignalPROFILE_KEY_COMMITMENT_LEN], uint64_t expiration_in_seconds); +SignalFfiError *signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*commitment)[SignalPROFILE_KEY_COMMITMENT_LEN], uint64_t expiration_in_seconds); -SignalFfiError *signal_server_secret_params_verify_profile_key_credential_presentation(const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); +SignalFfiError *signal_server_secret_params_verify_profile_key_credential_presentation(const SignalServerSecretParams *server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); -SignalFfiError *signal_server_secret_params_issue_receipt_credential_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN], const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], uint64_t receipt_expiration_time, uint64_t receipt_level); +SignalFfiError *signal_server_secret_params_issue_receipt_credential_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN], const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], uint64_t receipt_expiration_time, uint64_t receipt_level); -SignalFfiError *signal_server_secret_params_verify_receipt_credential_presentation(const unsigned char (*server_secret_params)[SignalSERVER_SECRET_PARAMS_LEN], const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); +SignalFfiError *signal_server_secret_params_verify_receipt_credential_presentation(const SignalServerSecretParams *server_secret_params, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); SignalFfiError *signal_group_public_params_get_group_identifier(uint8_t (*out)[SignalGROUP_IDENTIFIER_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN]); -SignalFfiError *signal_server_public_params_verify_signature(const unsigned char (*server_public_params)[SignalSERVER_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer message, const uint8_t (*notary_signature)[SignalSIGNATURE_LEN]); +SignalFfiError *signal_server_public_params_verify_signature(const SignalServerPublicParams *server_public_params, SignalBorrowedBuffer message, const uint8_t (*notary_signature)[SignalSIGNATURE_LEN]); SignalFfiError *signal_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); @@ -1332,16 +1450,18 @@ SignalFfiError *signal_backup_auth_credential_request_context_get_request(Signal SignalFfiError *signal_backup_auth_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes); -SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint64_t receipt_level, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); +SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint8_t backup_level, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); SignalFfiError *signal_backup_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer params_bytes, uint64_t expected_receipt_level); +SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, uint64_t expected_redemption_time, SignalBorrowedBuffer params_bytes); SignalFfiError *signal_backup_auth_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalBorrowedBuffer credential_bytes); +SignalFfiError *signal_backup_auth_credential_get_backup_level(uint8_t *out, SignalBorrowedBuffer credential_bytes); + SignalFfiError *signal_backup_auth_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, SignalBorrowedBuffer server_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); SignalFfiError *signal_backup_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); @@ -1350,7 +1470,7 @@ SignalFfiError *signal_backup_auth_credential_presentation_verify(SignalBorrowed SignalFfiError *signal_group_send_derived_key_pair_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_group_send_derived_key_pair_for_expiration(SignalOwnedBuffer *out, uint64_t expiration, const unsigned char (*server_params)[SignalSERVER_SECRET_PARAMS_LEN]); +SignalFfiError *signal_group_send_derived_key_pair_for_expiration(SignalOwnedBuffer *out, uint64_t expiration, const SignalServerSecretParams *server_params); SignalFfiError *signal_group_send_endorsements_response_check_valid_contents(SignalBorrowedBuffer bytes); @@ -1358,9 +1478,9 @@ SignalFfiError *signal_group_send_endorsements_response_issue_deterministic(Sign SignalFfiError *signal_group_send_endorsements_response_get_expiration(uint64_t *out, SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN]); +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], const SignalServerPublicParams *server_params); -SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, const unsigned char (*server_params)[SignalSERVER_PUBLIC_PARAMS_LEN]); +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, const SignalServerPublicParams *server_params); SignalFfiError *signal_group_send_endorsement_check_valid_contents(SignalBorrowedBuffer bytes); @@ -1382,13 +1502,9 @@ SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalFfiError *signal_verify_signature(bool *out, SignalBorrowedBuffer cert_pem, SignalBorrowedBuffer body, SignalBorrowedBuffer signature, uint64_t current_timestamp); -SignalFfiError *signal_tokio_async_context_new(SignalTokioAsyncContext **out); +SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment, const char *user_agent); -SignalFfiError *signal_tokio_async_context_destroy(SignalTokioAsyncContext *p); - -SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment); - -SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManager *connection_manager, const char *host, uint16_t port); +SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManager *connection_manager, const char *host, int32_t port); SignalFfiError *signal_connection_manager_clear_proxy(const SignalConnectionManager *connection_manager); @@ -1398,31 +1514,11 @@ SignalFfiError *signal_create_otp(const char **out, const char *username, Signal SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); -SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); +SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); -SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); +SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); -SignalFfiError *signal_chat_destroy(SignalChat *p); - -SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); - -SignalFfiError *signal_http_request_new_with_body(SignalHttpRequest **out, const char *method, const char *path, SignalBorrowedBuffer body_as_slice); - -SignalFfiError *signal_http_request_new_without_body(SignalHttpRequest **out, const char *method, const char *path); - -SignalFfiError *signal_http_request_add_header(const SignalHttpRequest *request, const char *name, const char *value); - -SignalFfiError *signal_chat_service_new(SignalChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password); - -SignalFfiError *signal_chat_service_disconnect(SignalCPromisebool promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); - -SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); - -SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); - -SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); - -SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_svr3_remove(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *enclave_password); SignalFfiError *signal_lookup_request_new(SignalLookupRequest **out); @@ -1440,11 +1536,51 @@ SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); SignalFfiError *signal_cdsi_lookup_destroy(SignalCdsiLookup *p); -SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request); +SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request); SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, const SignalCdsiLookup *lookup); -SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime, const SignalCdsiLookup *lookup); +SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalCdsiLookup *lookup); + +SignalFfiError *signal_chat_destroy(SignalChat *p); + +SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); + +SignalFfiError *signal_http_request_new_with_body(SignalHttpRequest **out, const char *method, const char *path, SignalBorrowedBuffer body_as_slice); + +SignalFfiError *signal_http_request_new_without_body(SignalHttpRequest **out, const char *method, const char *path); + +SignalFfiError *signal_http_request_add_header(const SignalHttpRequest *request, const char *name, const char *value); + +SignalFfiError *signal_chat_service_new(SignalChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password); + +SignalFfiError *signal_chat_service_disconnect(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); + +SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); + +SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); + +SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + +SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + +SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + +SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + +SignalFfiError *signal_chat_server_set_listener(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); + +SignalFfiError *signal_testing_chat_service_inject_raw_server_request(const SignalChat *chat, SignalBorrowedBuffer bytes); + +SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p); + +SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalServerMessageAck *ack); + +SignalFfiError *signal_tokio_async_context_destroy(SignalTokioAsyncContext *p); + +SignalFfiError *signal_tokio_async_context_new(SignalTokioAsyncContext **out); + +SignalFfiError *signal_tokio_async_context_cancel(const SignalTokioAsyncContext *context, uint64_t raw_cancellation_id); SignalFfiError *signal_pin_hash_destroy(SignalPinHash *p); @@ -1542,9 +1678,9 @@ SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, const Sign SignalFfiError *signal_testing_NonSuspendingBackgroundThreadRuntime_destroy(SignalNonSuspendingBackgroundThreadRuntime *p); -SignalFfiError *signal_testing_future_success(SignalCPromisei32 promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input); +SignalFfiError *signal_testing_future_success(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input); -SignalFfiError *signal_testing_future_failure(SignalCPromisei32 promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t _input); +SignalFfiError *signal_testing_future_failure(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t _input); SignalFfiError *signal_testing_handle_type_destroy(SignalTestingHandleType *p); @@ -1552,7 +1688,7 @@ SignalFfiError *signal_testing_handle_type_clone(SignalTestingHandleType **new_o SignalFfiError *signal_testing_testing_handle_type_get_value(uint8_t *out, const SignalTestingHandleType *handle); -SignalFfiError *signal_testing_future_produces_pointer_type(SignalCPromiseTestingHandleType promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input); +SignalFfiError *signal_testing_future_produces_pointer_type(SignalCPromiseTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input); SignalFfiError *signal_other_testing_handle_type_destroy(SignalOtherTestingHandleType *p); @@ -1560,55 +1696,55 @@ SignalFfiError *signal_other_testing_handle_type_clone(SignalOtherTestingHandleT SignalFfiError *signal_testing_other_testing_handle_type_get_value(const char **out, const SignalOtherTestingHandleType *handle); -SignalFfiError *signal_testing_future_produces_other_pointer_type(SignalCPromiseOtherTestingHandleType promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const char *input); +SignalFfiError *signal_testing_future_produces_other_pointer_type(SignalCPromiseOtherTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const char *input); SignalFfiError *signal_testing_panic_on_borrow_sync(const void *_input); SignalFfiError *signal_testing_panic_on_borrow_async(const void *_input); -SignalFfiError *signal_testing_panic_on_borrow_io(SignalCPromisebool promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); +SignalFfiError *signal_testing_panic_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); SignalFfiError *signal_testing_error_on_borrow_sync(const void *_input); SignalFfiError *signal_testing_error_on_borrow_async(const void *_input); -SignalFfiError *signal_testing_error_on_borrow_io(SignalCPromisebool promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); +SignalFfiError *signal_testing_error_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); SignalFfiError *signal_testing_panic_on_load_sync(const void *_needs_cleanup, const void *_input); SignalFfiError *signal_testing_panic_on_load_async(const void *_needs_cleanup, const void *_input); -SignalFfiError *signal_testing_panic_on_load_io(SignalCPromisebool promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup, const void *_input); +SignalFfiError *signal_testing_panic_on_load_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup, const void *_input); SignalFfiError *signal_testing_panic_in_body_sync(const void *_input); SignalFfiError *signal_testing_panic_in_body_async(const void *_input); -SignalFfiError *signal_testing_panic_in_body_io(SignalCPromisebool promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); +SignalFfiError *signal_testing_panic_in_body_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); SignalFfiError *signal_testing_panic_on_return_sync(const void **out, const void *_needs_cleanup); SignalFfiError *signal_testing_panic_on_return_async(const void **out, const void *_needs_cleanup); -SignalFfiError *signal_testing_panic_on_return_io(SignalCPromiseRawPointer promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); +SignalFfiError *signal_testing_panic_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); SignalFfiError *signal_testing_error_on_return_sync(const void **out, const void *_needs_cleanup); SignalFfiError *signal_testing_error_on_return_async(const void **out, const void *_needs_cleanup); -SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer promise, const void *promise_context, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); +SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); SignalFfiError *signal_testing_return_string_array(SignalStringArray *out); SignalFfiError *signal_testing_process_bytestring_array(SignalBytestringArray *out, SignalBorrowedSliceOfBuffers input); -SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse promise, const void *promise_context, const SignalTokioAsyncContext *async_runtime); +SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime); + +SignalFfiError *signal_testing_only_completes_by_cancellation(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime); SignalFfiError *signal_testing_cdsi_lookup_error_convert(const char *error_description); -SignalFfiError *signal_testing_chat_service_error_convert(void); - -SignalFfiError *signal_testing_chat_service_inactive_error_convert(void); +SignalFfiError *signal_testing_chat_service_error_convert(const char *error_description); SignalFfiError *signal_testing_chat_service_response_convert(SignalFfiChatResponse *out, bool body_present); diff --git a/pkg/libsignalgo/logging.go b/pkg/libsignalgo/logging.go index 2fcf8ba..a467b57 100644 --- a/pkg/libsignalgo/logging.go +++ b/pkg/libsignalgo/logging.go @@ -29,11 +29,6 @@ import "C" // ffiLogger is the global logger object. var ffiLogger Logger -//export signal_log_enabled_callback -func signal_log_enabled_callback(target *C.char, level C.SignalLogLevel) C.bool { - return C.bool(ffiLogger.Enabled(C.GoString(target), LogLevel(int(level)))) -} - //export signal_log_callback func signal_log_callback(target *C.char, level C.SignalLogLevel, file *C.char, line C.uint32_t, message *C.char) { ffiLogger.Log(C.GoString(target), LogLevel(int(level)), C.GoString(file), uint(line), C.GoString(message)) @@ -55,7 +50,6 @@ const ( ) type Logger interface { - Enabled(target string, level LogLevel) bool Log(target string, level LogLevel, file string, line uint, message string) Flush() } @@ -63,8 +57,7 @@ type Logger interface { func InitLogger(level LogLevel, logger Logger) { ffiLogger = logger C.signal_init_logger(C.SignalLogLevel(level), C.SignalFfiLogger{ - enabled: C.SignalLogEnabledCallback(C.signal_log_enabled_callback), - log: C.SignalLogCallback(C.signal_log_callback), - flush: C.SignalLogFlushCallback(C.signal_log_flush_callback), + log: C.SignalLogCallback(C.signal_log_callback), + flush: C.SignalLogFlushCallback(C.signal_log_flush_callback), }) } diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index 5d5f157..82e3036 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -136,13 +136,11 @@ type ProfileKeyCredentialRequestContext [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_ type ProfileKeyCredentialRequest [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN]byte type ProfileKeyCredentialResponse []byte type ProfileKeyCredentialPresentation []byte -type ServerPublicParams [C.SignalSERVER_PUBLIC_PARAMS_LEN]byte type ExpiringProfileKeyCredential [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]byte type ExpiringProfileKeyCredentialResponse [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]byte -func CreateProfileKeyCredentialRequestContext(serverPublicParams ServerPublicParams, u uuid.UUID, profileKey ProfileKey) (*ProfileKeyCredentialRequestContext, error) { +func CreateProfileKeyCredentialRequestContext(serverPublicParams *ServerPublicParams, u uuid.UUID, profileKey ProfileKey) (*ProfileKeyCredentialRequestContext, error) { c_result := [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]C.uchar{} - c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) 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])) @@ -150,12 +148,11 @@ func CreateProfileKeyCredentialRequestContext(serverPublicParams ServerPublicPar signalFfiError := C.signal_server_public_params_create_profile_key_credential_request_context_deterministic( &c_result, - c_serverPublicParams, + serverPublicParams, c_random, c_uuid, c_profileKey, ) - runtime.KeepAlive(serverPublicParams) runtime.KeepAlive(u) runtime.KeepAlive(profileKey) runtime.KeepAlive(randBytes) @@ -193,16 +190,15 @@ func NewExpiringProfileKeyCredentialResponse(b []byte) (*ExpiringProfileKeyCrede return &response, nil } -func ReceiveExpiringProfileKeyCredential(spp ServerPublicParams, requestContext *ProfileKeyCredentialRequestContext, response *ExpiringProfileKeyCredentialResponse, currentTimeInSeconds uint64) (*ExpiringProfileKeyCredential, error) { +func ReceiveExpiringProfileKeyCredential(spp *ServerPublicParams, requestContext *ProfileKeyCredentialRequestContext, response *ExpiringProfileKeyCredentialResponse, currentTimeInSeconds uint64) (*ExpiringProfileKeyCredential, error) { c_credential := [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]C.uchar{} signalFfiError := C.signal_server_public_params_receive_expiring_profile_key_credential( &c_credential, - (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&spp[0])), + 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)), (C.uint64_t)(currentTimeInSeconds), ) - runtime.KeepAlive(spp) runtime.KeepAlive(requestContext) runtime.KeepAlive(response) runtime.KeepAlive(currentTimeInSeconds) diff --git a/pkg/libsignalgo/verifysignature.go b/pkg/libsignalgo/serverpublicparams.go similarity index 68% rename from pkg/libsignalgo/verifysignature.go rename to pkg/libsignalgo/serverpublicparams.go index 69d354e..6e99471 100644 --- a/pkg/libsignalgo/verifysignature.go +++ b/pkg/libsignalgo/serverpublicparams.go @@ -1,5 +1,5 @@ // mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber +// Copyright (C) 2024 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 @@ -23,21 +23,34 @@ package libsignalgo */ import "C" import ( + "fmt" "runtime" "unsafe" ) +type ServerPublicParams = C.SignalServerPublicParams type NotarySignature [C.SignalSIGNATURE_LEN]byte +func DeserializeServerPublicParams(params []byte) (out *ServerPublicParams, err error) { + if len(params) != C.SignalSERVER_PUBLIC_PARAMS_LEN { + err = fmt.Errorf("invalid server public params length: %d (expected %d)", len(params), int(C.SignalSERVER_PUBLIC_PARAMS_LEN)) + return + } + signalFfiError := C.signal_server_public_params_deserialize(&out, BytesToBuffer(params[:])) + if signalFfiError != nil { + err = wrapError(signalFfiError) + } + return +} + func ServerPublicParamsVerifySignature( - serverPublicParams ServerPublicParams, + serverPublicParams *ServerPublicParams, messageBytes []byte, NotarySignature NotarySignature, ) error { c_notarySignature := (*[C.SignalSIGNATURE_LEN]C.uint8_t)(unsafe.Pointer(&NotarySignature[0])) - c_serverPublicParams := (*[C.SignalSERVER_PUBLIC_PARAMS_LEN]C.uchar)(unsafe.Pointer(&serverPublicParams[0])) signalFfiError := C.signal_server_public_params_verify_signature( - c_serverPublicParams, + serverPublicParams, BytesToBuffer(messageBytes), c_notarySignature, ) diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index ac15575..0bc1cb7 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.44.0" +const Version = "v0.49.0" diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 0c305ee..1062dcb 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -20,6 +20,7 @@ import ( _ "embed" "github.com/rs/zerolog" + "go.mau.fi/util/exerrors" "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) @@ -40,8 +41,6 @@ type FFILogger struct { logger zerolog.Logger } -func (FFILogger) Enabled(target string, level libsignalgo.LogLevel) bool { return true } - func (l FFILogger) Log(target string, level libsignalgo.LogLevel, file string, line uint, message string) { var evt *zerolog.Event switch level { @@ -73,8 +72,8 @@ var _ libsignalgo.Logger = FFILogger{} //go:embed prod-server-public-params.dat var prodServerPublicParamsSlice []byte -var prodServerPublicParams libsignalgo.ServerPublicParams +var prodServerPublicParams *libsignalgo.ServerPublicParams func init() { - prodServerPublicParams = libsignalgo.ServerPublicParams(prodServerPublicParamsSlice) + prodServerPublicParams = exerrors.Must(libsignalgo.DeserializeServerPublicParams(prodServerPublicParamsSlice)) } From 088badafa35320c40e8816b152a0fee2a0ef58fe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 3 Jun 2024 18:37:08 +0300 Subject: [PATCH 167/718] Fix libsignal log interface --- pkg/libsignalgo/logging.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/libsignalgo/logging.go b/pkg/libsignalgo/logging.go index a467b57..132cc8a 100644 --- a/pkg/libsignalgo/logging.go +++ b/pkg/libsignalgo/logging.go @@ -20,22 +20,25 @@ package libsignalgo #cgo LDFLAGS: -lsignal_ffi -ldl -lm #include <./libsignal-ffi.h> -extern bool signal_log_enabled_callback(char *target, SignalLogLevel level); -extern void signal_log_callback(char *target, SignalLogLevel level, char *file, uint32_t line, char *message); +extern bool signal_log_enabled_callback(void *ctx, char *target, SignalLogLevel level); +extern void signal_log_callback(void *ctx, char *target, SignalLogLevel level, char *file, uint32_t line, char *message); extern void signal_log_flush_callback(); */ import "C" +import ( + "unsafe" +) // ffiLogger is the global logger object. var ffiLogger Logger //export signal_log_callback -func signal_log_callback(target *C.char, level C.SignalLogLevel, file *C.char, line C.uint32_t, message *C.char) { +func signal_log_callback(ctx unsafe.Pointer, target *C.char, level C.SignalLogLevel, file *C.char, line C.uint32_t, message *C.char) { ffiLogger.Log(C.GoString(target), LogLevel(int(level)), C.GoString(file), uint(line), C.GoString(message)) } //export signal_log_flush_callback -func signal_log_flush_callback() { +func signal_log_flush_callback(ctx unsafe.Pointer) { ffiLogger.Flush() } From 860fad4d5c26a3f236b3f43923bac3785183d55a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 3 Jun 2024 19:10:09 +0300 Subject: [PATCH 168/718] Fix signal_log_flush_callback signature too --- pkg/libsignalgo/logging.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/libsignalgo/logging.go b/pkg/libsignalgo/logging.go index 132cc8a..2cbee01 100644 --- a/pkg/libsignalgo/logging.go +++ b/pkg/libsignalgo/logging.go @@ -20,9 +20,8 @@ package libsignalgo #cgo LDFLAGS: -lsignal_ffi -ldl -lm #include <./libsignal-ffi.h> -extern bool signal_log_enabled_callback(void *ctx, char *target, SignalLogLevel level); extern void signal_log_callback(void *ctx, char *target, SignalLogLevel level, char *file, uint32_t line, char *message); -extern void signal_log_flush_callback(); +extern void signal_log_flush_callback(void *ctx); */ import "C" import ( From 18116ea9f4ffab560613ff1a90d684af48801b1d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 3 Jun 2024 22:34:33 +0300 Subject: [PATCH 169/718] Move login command to mautrix-go --- connector/connector.go | 2 +- connector/login.go | 155 ++++++++++++++++++++++++++ connector/mautrix-signal-v2/main.go | 166 +--------------------------- go.mod | 2 +- go.sum | 4 +- pkg/signalmeow/provisioning.go | 2 +- 6 files changed, 162 insertions(+), 169 deletions(-) create mode 100644 connector/login.go diff --git a/connector/connector.go b/connector/connector.go index 7e24be6..6c08eee 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -165,7 +165,7 @@ var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.NetworkAPI = (*SignalClient)(nil) var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) -func (s *SignalConnector) PrepareLogin(ctx context.Context, login *bridgev2.UserLogin) error { +func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error { aci, err := uuid.Parse(string(login.ID)) if err != nil { return fmt.Errorf("failed to parse user login ID: %w", err) diff --git a/connector/login.go b/connector/login.go new file mode 100644 index 0000000..0265ae5 --- /dev/null +++ b/connector/login.go @@ -0,0 +1,155 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "fmt" + + "github.com/google/uuid" + + "go.mau.fi/mautrix-signal/pkg/signalmeow" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" +) + +func (s *SignalConnector) GetLoginFlows() []bridgev2.LoginFlow { + return []bridgev2.LoginFlow{{ + Name: "QR", + Description: "Scan a QR code to pair the bridge to your Signal app", + ID: "qr", + }} +} + +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 &QRLogin{User: user, Main: s}, nil +} + +type QRLogin struct { + User *bridgev2.User + Main *SignalConnector + cancelChan context.CancelFunc + ProvChan chan signalmeow.ProvisioningResponse +} + +var _ bridgev2.LoginProcessDisplayAndWait = (*QRLogin)(nil) + +func (qr *QRLogin) Cancel() { + qr.cancelChan() + go func() { + for range qr.ProvChan { + } + }() +} + +func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { + log := qr.Main.Bridge.Log.With(). + Str("action", "login"). + Stringer("user_id", qr.User.MXID). + Logger() + provCtx, cancel := context.WithCancel(log.WithContext(context.Background())) + qr.cancelChan = cancel + // Don't use the start context here: the channel will outlive the start request. + qr.ProvChan = signalmeow.PerformProvisioning(provCtx, qr.Main.Store, qr.Main.Config.DeviceName) + var resp signalmeow.ProvisioningResponse + select { + case resp = <-qr.ProvChan: + if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + return nil, 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? + } + return &bridgev2.LoginStep{ + Type: bridgev2.LoginStepTypeDisplayAndWait, + StepID: "fi.mau.signal.login.qr", + Instructions: "Scan the QR code on your Signal app to log in", + DisplayAndWaitParams: &bridgev2.LoginDisplayAndWaitParams{ + Type: bridgev2.LoginDisplayTypeQR, + Data: resp.ProvisioningURL, + }, + }, nil +} + +func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { + if qr.ProvChan == nil { + return nil, fmt.Errorf("login not started") + } + defer qr.cancelChan() + + var signalID uuid.UUID + var signalPhone string + select { + case resp := <-qr.ProvChan: + if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + return nil, resp.Err + } else if resp.State != signalmeow.StateProvisioningDataReceived { + return nil, fmt.Errorf("unexpected state %v", resp.State) + } else if resp.ProvisioningData.ACI == uuid.Nil { + return nil, fmt.Errorf("no signal account ID received") + } + signalID = resp.ProvisioningData.ACI + signalPhone = resp.ProvisioningData.Number + case <-ctx.Done(): + return nil, ctx.Err() + } + + select { + case resp := <-qr.ProvChan: + if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + return nil, resp.Err + } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { + return nil, fmt.Errorf("unexpected state %v", resp.State) + } + case <-ctx.Done(): + return nil, ctx.Err() + } + + ul, err := qr.User.NewLogin(ctx, &database.UserLogin{ + ID: makeUserLoginID(signalID), + Metadata: map[string]any{ + "phone": signalPhone, + }, + }, nil) + if err != nil { + return nil, fmt.Errorf("failed to save new login: %w", err) + } + backgroundCtx := ul.Log.WithContext(context.Background()) + err = qr.Main.LoadUserLogin(backgroundCtx, ul) + if err != nil { + return nil, fmt.Errorf("failed to prepare connection after login: %w", err) + } + err = ul.Client.Connect(backgroundCtx) + if err != nil { + return nil, fmt.Errorf("failed to connect after login: %w", err) + } + return &bridgev2.LoginStep{ + Type: bridgev2.LoginStepTypeComplete, + StepID: "fi.mau.signal.login.complete", + Instructions: fmt.Sprintf("Successfully logged in as %s / %s", signalPhone, signalID), + CompleteParams: &bridgev2.LoginCompleteParams{ + UserLoginID: ul.ID, + }, + }, nil +} diff --git a/connector/mautrix-signal-v2/main.go b/connector/mautrix-signal-v2/main.go index 1ea34d9..42ebfa9 100644 --- a/connector/mautrix-signal-v2/main.go +++ b/connector/mautrix-signal-v2/main.go @@ -17,28 +17,18 @@ package main import ( - "fmt" "os" - "strings" - "time" - "github.com/google/uuid" - "github.com/skip2/go-qrcode" "go.mau.fi/util/dbutil" "go.mau.fi/util/exerrors" "go.mau.fi/util/exzerolog" "gopkg.in/yaml.v3" + "go.mau.fi/mautrix-signal/connector" "go.mau.fi/mautrix-signal/pkg/signalmeow" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/bridgeconfig" - "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/matrix" - "maunium.net/go/mautrix/bridgev2/networkid" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/connector" ) func main() { @@ -47,163 +37,11 @@ func main() { exerrors.PanicIfNotNil(yaml.Unmarshal(config, &cfg)) log := exerrors.Must(cfg.Logging.Compile()) exzerolog.SetupDefaults(log) + signalmeow.SetLogger(log.With().Str("component", "signalmeow").Logger()) db := exerrors.Must(dbutil.NewFromConfig("mautrix-signal", cfg.Database, dbutil.ZeroLogger(log.With().Str("db_section", "main").Logger()))) signalConnector := connector.NewConnector() exerrors.PanicIfNotNil(cfg.Network.Decode(signalConnector.Config)) bridge := bridgev2.NewBridge("", db, *log, matrix.NewConnector(&cfg), signalConnector) bridge.CommandPrefix = "!signal" - bridge.Commands.AddHandlers(&bridgev2.FullHandler{ - Func: fnLogin, - Name: "login", - Help: bridgev2.HelpMeta{ - Section: bridgev2.HelpSectionAuth, - Description: "Log into Signal", - }, - }) bridge.Start() } - -func sendQR(ce *bridgev2.CommandEvent, code string, prevQR, prevMsg id.EventID) (qr, msg id.EventID) { - content, ok := uploadQR(ce, code) - if !ok { - return prevQR, prevMsg - } - if len(prevQR) != 0 { - content.SetEdit(prevQR) - } - resp, err := ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventMessage, &event.Content{Parsed: &content}, time.Now()) - if err != nil { - ce.Log.Err(err).Msg("Failed to send QR code to user") - } else if len(prevQR) == 0 { - prevQR = resp.EventID - } - content = event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: fmt.Sprintf("Raw linking URI: %s", code), - Format: event.FormatHTML, - FormattedBody: fmt.Sprintf("Raw linking URI: %s", code), - } - if len(prevMsg) != 0 { - content.SetEdit(prevMsg) - } - resp, err = ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventMessage, &event.Content{Parsed: &content}, time.Now()) - if err != nil { - ce.Log.Err(err).Msg("Failed to send raw code to user") - } else if len(prevMsg) == 0 { - prevMsg = resp.EventID - } - return prevQR, prevMsg -} - -func uploadQR(ce *bridgev2.CommandEvent, code string) (event.MessageEventContent, bool) { - const size = 512 - qrCode, err := qrcode.Encode(code, qrcode.Low, size) - if err != nil { - ce.Log.Err(err).Msg("Failed to encode QR code") - ce.Reply("Failed to encode QR code: %v", err) - return event.MessageEventContent{}, false - } - - uri, file, err := ce.Bot.UploadMedia(ce.Ctx, ce.RoomID, qrCode, "qr.png", "image/png") - if err != nil { - ce.Log.Err(err).Msg("Failed to upload QR code") - ce.Reply("Failed to upload QR code: %v", err) - return event.MessageEventContent{}, false - } - return event.MessageEventContent{ - MsgType: event.MsgImage, - Info: &event.FileInfo{ - MimeType: "image/png", - Width: size, - Height: size, - Size: len(qrCode), - }, - Body: "qr.png", - URL: uri, - File: file, - }, true -} -func fnLogin(ce *bridgev2.CommandEvent) { - signal := ce.Bridge.Network.(*connector.SignalConnector) - // TODO configurable device name - provChan := signalmeow.PerformProvisioning(ce.Ctx, signal.Store, "Mautrix-Signal Megabridge") - - resp := <-provChan - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - ce.Reply("Error getting provisioning URL: %v", resp.Err) - return - } - var qrEventID, msgEventID id.EventID - if resp.State == signalmeow.StateProvisioningURLReceived { - qrEventID, msgEventID = sendQR(ce, resp.ProvisioningURL, qrEventID, msgEventID) - } else { - ce.Reply("Unexpected state: %v", resp.State) - return - } - - // Next, get the results of finishing registration - resp = <-provChan - _, _ = ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventRedaction, &event.Content{ - Parsed: &event.RedactionEventContent{ - Redacts: qrEventID, - }, - }, time.Now()) - _, _ = ce.Bot.SendMessage(ce.Ctx, ce.RoomID, event.EventRedaction, &event.Content{ - Parsed: &event.RedactionEventContent{ - Redacts: msgEventID, - }, - }, time.Now()) - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - if resp.Err != nil && strings.HasSuffix(resp.Err.Error(), " EOF") { - ce.Reply("Logging in timed out, please try again.") - } else { - ce.Reply("Error finishing registration: %v", resp.Err) - } - return - } - var signalID uuid.UUID - var signalPhone string - if resp.State == signalmeow.StateProvisioningDataReceived { - signalID = resp.ProvisioningData.ACI - signalPhone = resp.ProvisioningData.Number - } else { - ce.Reply("Unexpected state: %v", resp.State) - return - } - - // Finally, get the results of generating and registering prekeys - resp = <-provChan - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - ce.Reply("Error with prekeys: %v", resp.Err) - return - } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { - ce.Reply("Unexpected state: %v", resp.State) - return - } - - if signalID == uuid.Nil { - ce.Reply("Problem logging in - No SignalID received") - return - } - ul, err := ce.User.NewLogin(ce.Ctx, &database.UserLogin{ - ID: networkid.UserLoginID(signalID.String()), - Metadata: map[string]any{ - "phone": signalPhone, - }, - }, nil) - if err != nil { - ce.Reply("Failed to save new login: %v", err) - return - } - err = ce.Bridge.Network.PrepareLogin(ce.Ctx, ul) - if err != nil { - ce.Reply("Failed to prepare connection after login: %v", err) - return - } - err = ul.Client.Connect(ce.Ctx) - if err != nil { - ce.Reply("Failed to connect after login: %v", err) - return - } - ce.Reply("Successfully logged in as %s (UUID: %s)", signalPhone, signalID) -} diff --git a/go.mod b/go.mod index 913d3c1..42f5fbd 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240529135554-248de0e6adb2 + maunium.net/go/mautrix v0.18.2-0.20240603193336-a599b15466ae nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 641b71f..309bce5 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240529135554-248de0e6adb2 h1:AUKv3tqpdFerCw2X8m05BGfhtP3vH8cDuEtAGxwuUl0= -maunium.net/go/mautrix v0.18.2-0.20240529135554-248de0e6adb2/go.mod h1:Ln4XquIKL5MttTUGNUSbiEGX3XYC0P6jzT9XjLFFPdY= +maunium.net/go/mautrix v0.18.2-0.20240603193336-a599b15466ae h1:PlT6saNJNjRT3i04LNLsFAC5ewZU1HrxBSM4V/Aze7k= +maunium.net/go/mautrix v0.18.2-0.20240603193336-a599b15466ae/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 22a8b52..88f8485 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -81,7 +81,7 @@ type ProvisioningResponse struct { func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, deviceName string) chan ProvisioningResponse { log := zerolog.Ctx(ctx).With().Str("action", "perform provisioning").Logger() - c := make(chan ProvisioningResponse) + c := make(chan ProvisioningResponse, 4) go func() { defer close(c) From 69de6afae21f858517ad669e67b18e10b7adcb72 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 4 Jun 2024 14:36:28 +0300 Subject: [PATCH 170/718] Reorganize v2 packages --- {connector => cmd}/mautrix-signal-v2/main.go | 6 +++--- {connector => cmd}/mautrix-signal-v2/start | 0 {connector => pkg/connector}/connector.go | 0 {connector => pkg/connector}/login.go | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename {connector => cmd}/mautrix-signal-v2/main.go (97%) rename {connector => cmd}/mautrix-signal-v2/start (100%) rename {connector => pkg/connector}/connector.go (100%) rename {connector => pkg/connector}/login.go (100%) diff --git a/connector/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go similarity index 97% rename from connector/mautrix-signal-v2/main.go rename to cmd/mautrix-signal-v2/main.go index 42ebfa9..4e02361 100644 --- a/connector/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -23,12 +23,12 @@ import ( "go.mau.fi/util/exerrors" "go.mau.fi/util/exzerolog" "gopkg.in/yaml.v3" - - "go.mau.fi/mautrix-signal/connector" - "go.mau.fi/mautrix-signal/pkg/signalmeow" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix" + + "go.mau.fi/mautrix-signal/pkg/connector" + "go.mau.fi/mautrix-signal/pkg/signalmeow" ) func main() { diff --git a/connector/mautrix-signal-v2/start b/cmd/mautrix-signal-v2/start similarity index 100% rename from connector/mautrix-signal-v2/start rename to cmd/mautrix-signal-v2/start diff --git a/connector/connector.go b/pkg/connector/connector.go similarity index 100% rename from connector/connector.go rename to pkg/connector/connector.go diff --git a/connector/login.go b/pkg/connector/login.go similarity index 100% rename from connector/login.go rename to pkg/connector/login.go index 0265ae5..34ac514 100644 --- a/connector/login.go +++ b/pkg/connector/login.go @@ -21,10 +21,10 @@ import ( "fmt" "github.com/google/uuid" - - "go.mau.fi/mautrix-signal/pkg/signalmeow" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" + + "go.mau.fi/mautrix-signal/pkg/signalmeow" ) func (s *SignalConnector) GetLoginFlows() []bridgev2.LoginFlow { From 204824bbaeda570f55c7509beff733b229917a29 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 5 Jun 2024 13:52:51 +0300 Subject: [PATCH 171/718] Add logout method and update message interface --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 27 ++++++++++++++++++++------- pkg/connector/login.go | 32 ++++++++++++++++++++++++-------- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 42f5fbd..848b912 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240603193336-a599b15466ae + maunium.net/go/mautrix v0.18.2-0.20240605105031-218ed06e73f6 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 309bce5..dfce129 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240603193336-a599b15466ae h1:PlT6saNJNjRT3i04LNLsFAC5ewZU1HrxBSM4V/Aze7k= -maunium.net/go/mautrix v0.18.2-0.20240603193336-a599b15466ae/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= +maunium.net/go/mautrix v0.18.2-0.20240605105031-218ed06e73f6 h1:JkMk5Urz1niqsqOVWhoHculon2FSVrITM1g1iVMcxhU= +maunium.net/go/mautrix v0.18.2-0.20240605105031-218ed06e73f6/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 6c08eee..a0fc4ee 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -194,6 +194,17 @@ type SignalClient struct { Client *signalmeow.Client } +func (s *SignalClient) LogoutRemote(ctx context.Context) { + err := s.Client.StopReceiveLoops() + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") + } + err = s.Main.Store.DeleteDevice(context.TODO(), &s.Client.Store.DeviceData) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to delete device from store") + } +} + func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.UserInfo { isBot := false ui := &bridgev2.UserInfo{ @@ -409,10 +420,10 @@ type msgconvContext struct { ReplyTo *database.Message } -func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Portal, data *events.ChatEvent) (*bridgev2.ConvertedMessage, error) { +func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data *events.ChatEvent) (*bridgev2.ConvertedMessage, error) { mcCtx := &msgconvContext{ Connector: s.Main, - Intent: s.Main.Bridge.Bot, // TODO get correct intent? + Intent: intent, Client: s, Portal: portal, } @@ -437,11 +448,11 @@ func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Port } return &bridgev2.ConvertedMessage{ - ID: makeMessageID(data.Info.Sender, dataMsg.GetTimestamp()), - EventSender: s.makeEventSender(data.Info.Sender), - Timestamp: time.UnixMilli(int64(converted.Timestamp)), - ReplyTo: replyTo, - Parts: convertedParts, + //ID: makeMessageID(data.Info.Sender, dataMsg.GetTimestamp()), + //EventSender: s.makeEventSender(data.Info.Sender), + Timestamp: time.UnixMilli(int64(converted.Timestamp)), + ReplyTo: replyTo, + Parts: convertedParts, }, nil } @@ -457,6 +468,8 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { Uint64("message_id", innerEvt.GetTimestamp()). Stringer("sender_id", evt.Info.Sender) }, + ID: makeMessageID(evt.Info.Sender, innerEvt.GetTimestamp()), + Sender: s.makeEventSender(evt.Info.Sender), PortalID: s.getPortalID(evt.Info.ChatID), Data: evt, CreatePortal: true, diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 34ac514..cd25e60 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -44,6 +44,7 @@ func (s *SignalConnector) CreateLogin(ctx context.Context, user *bridgev2.User, type QRLogin struct { User *bridgev2.User + Existing *bridgev2.UserLogin Main *SignalConnector cancelChan context.CancelFunc ProvChan chan signalmeow.ProvisioningResponse @@ -114,6 +115,10 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { case <-ctx.Done(): return nil, ctx.Err() } + newLoginID := makeUserLoginID(signalID) + if qr.Existing != nil && qr.Existing.ID != newLoginID { + return nil, fmt.Errorf("user ID mismatch for re-auth") + } select { case resp := <-qr.ProvChan: @@ -126,14 +131,25 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, ctx.Err() } - ul, err := qr.User.NewLogin(ctx, &database.UserLogin{ - ID: makeUserLoginID(signalID), - Metadata: map[string]any{ - "phone": signalPhone, - }, - }, nil) - if err != nil { - return nil, fmt.Errorf("failed to save new login: %w", err) + var ul *bridgev2.UserLogin + var err error + if qr.Existing == nil { + ul, err = qr.User.NewLogin(ctx, &database.UserLogin{ + ID: newLoginID, + Metadata: map[string]any{ + "phone": signalPhone, + }, + }, nil) + if err != nil { + return nil, fmt.Errorf("failed to save new login: %w", err) + } + } else { + ul = qr.Existing + ul.Metadata["phone"] = signalPhone + err = ul.Save(ctx) + if err != nil { + return nil, fmt.Errorf("failed to update existing login: %w", err) + } } backgroundCtx := ul.Log.WithContext(context.Background()) err = qr.Main.LoadUserLogin(backgroundCtx, ul) From 7e74d98371b564ce9125c2ed72e9f780f80c7496 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 6 Jun 2024 16:11:58 +0300 Subject: [PATCH 172/718] Implement Matrix reactions, edits and redactions --- go.mod | 2 +- go.sum | 4 +- pkg/connector/connector.go | 193 +++++++++++++++++++++++++++++++------ pkg/signalmeow/sending.go | 7 ++ 4 files changed, 174 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 848b912..fee3d52 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240605105031-218ed06e73f6 + maunium.net/go/mautrix v0.18.2-0.20240606131110-a0e309fa55ab nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index dfce129..b80546d 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240605105031-218ed06e73f6 h1:JkMk5Urz1niqsqOVWhoHculon2FSVrITM1g1iVMcxhU= -maunium.net/go/mautrix v0.18.2-0.20240605105031-218ed06e73f6/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= +maunium.net/go/mautrix v0.18.2-0.20240606131110-a0e309fa55ab h1:e0Zo3/K+quT6p+U2Gsmw8R1kinzZ0wOkPbVPwoMkrBY= +maunium.net/go/mautrix v0.18.2-0.20240606131110-a0e309fa55ab/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index a0fc4ee..9075567 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -27,6 +27,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/dbutil" + "go.mau.fi/util/variationselector" "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" @@ -381,6 +382,20 @@ func (s *SignalClient) getPortalID(chatID string) networkid.PortalID { } } +func parseMessageID(messageID networkid.MessageID) (sender uuid.UUID, timestamp uint64, err error) { + parts := strings.Split(string(messageID), "|") + if len(parts) != 2 { + err = fmt.Errorf("invalid message ID: expected two pipe-separated parts") + return + } + sender, err = uuid.Parse(parts[0]) + if err != nil { + return + } + timestamp, err = strconv.ParseUint(parts[1], 10, 64) + return +} + func makeMessageID(sender uuid.UUID, timestamp uint64) networkid.MessageID { return networkid.MessageID(fmt.Sprintf("%s|%d", sender, timestamp)) } @@ -519,31 +534,18 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma ReplyTo: msg.ReplyTo, } ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - userID, groupID, err := s.parsePortalID(msg.Portal.ID) - if err != nil { - return nil, err - } converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) if err != nil { return nil, err } - wrappedContent := &signalpb.Content{ - DataMessage: converted, - } - if groupID != "" { - res, err := s.Client.SendGroupMessage(ctx, groupID, wrappedContent) - if err != nil { - return nil, err - } - // TODO check result - fmt.Println(res) - } else { - res := s.Client.SendMessage(ctx, userID, wrappedContent) - // TODO check result - fmt.Println(res) + res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) + if err != nil { + return nil, err } + // TODO check result + fmt.Println(res) meta := map[string]any{ - "reply_to_file": len(converted.Attachments) > 0, + "contains_attachments": len(converted.Attachments) > 0, } dbMsg := &database.Message{ ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), @@ -560,23 +562,156 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma } func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { - //TODO implement me - panic("implement me") + _, targetSentTimestamp, err := parseMessageID(msg.EditTarget.ID) + if err != nil { + return fmt.Errorf("failed to parse target message ID: %w", err) + } else if msg.EditTarget.SenderID != makeUserID(s.Client.Store.ACI) { + return fmt.Errorf("cannot edit other people's messages") + } + mcCtx := &msgconvContext{ + Connector: s.Main, + Intent: nil, + Client: s, + Portal: msg.Portal, + } + if msg.EditTarget.RelatesToRowID != 0 { + var err error + mcCtx.ReplyTo, err = s.Main.Bridge.DB.Message.GetByRowID(ctx, msg.EditTarget.RelatesToRowID) + if err != nil { + return fmt.Errorf("failed to get message reply target: %w", err) + } + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) + if err != nil { + return err + } + res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + DataMessage: converted, + }}) + if err != nil { + return err + } + // TODO check result + fmt.Println(res) + msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) + msg.EditTarget.Metadata["contains_attachments"] = len(converted.Attachments) > 0 + return nil } -func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (emojiID networkid.EmojiID, err error) { - //TODO implement me - panic("implement me") +func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) (signalmeow.SendResult, error) { + userID, groupID, err := s.parsePortalID(portalID) + if err != nil { + return nil, err + } + if groupID != "" { + res, err := s.Client.SendGroupMessage(ctx, groupID, content) + if err != nil { + return nil, err + } + return res, nil + } else { + res := s.Client.SendMessage(ctx, userID, content) + return &res, nil + } +} + +func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { + senderID := makeUserID(s.Client.Store.ACI) + // emojiID is always empty because only one reaction is allowed per message+user + var emojiID networkid.EmojiID + signalEmoji := variationselector.FullyQualify(msg.Content.RelatesTo.Key) + if existing, err := msg.GetExisting(ctx, senderID, emojiID); err != nil { + return nil, fmt.Errorf("failed to check for duplicate reaction: %w", err) + } else if existing != nil && existing.Metadata["emoji"] == signalEmoji { + return nil, nil + } + targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) + if err != nil { + return nil, fmt.Errorf("failed to parse target message ID: %w", err) + } + wrappedContent := &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), + Reaction: &signalpb.DataMessage_Reaction{ + Emoji: proto.String(signalEmoji), + Remove: proto.Bool(false), + TargetAuthorAci: proto.String(targetAuthorACI.String()), + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + }, + }, + } + res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + if err != nil { + return nil, err + } + // TODO check result + fmt.Println(res) + return &database.Reaction{ + RoomID: msg.Portal.ID, + MessageID: msg.TargetMessage.ID, + MessagePartID: msg.TargetMessage.PartID, + SenderID: senderID, + EmojiID: emojiID, + MXID: msg.Event.ID, + Timestamp: time.UnixMilli(msg.Event.Timestamp), + Metadata: map[string]any{ + "emoji": signalEmoji, + }, + }, nil } func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { - //TODO implement me - panic("implement me") + emoji, _ := msg.TargetReaction.Metadata["emoji"].(string) + targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetReaction.MessageID) + if err != nil { + return fmt.Errorf("failed to parse target message ID: %w", err) + } + wrappedContent := &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), + Reaction: &signalpb.DataMessage_Reaction{ + Emoji: proto.String(emoji), + Remove: proto.Bool(true), + TargetAuthorAci: proto.String(targetAuthorACI.String()), + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + }, + }, + } + res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + if err != nil { + return err + } + // TODO check result + fmt.Println(res) + return nil } func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { - //TODO implement me - panic("implement me") + _, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) + if err != nil { + return fmt.Errorf("failed to parse target message ID: %w", err) + } else if msg.TargetMessage.SenderID != makeUserID(s.Client.Store.ACI) { + return fmt.Errorf("cannot delete other people's messages") + } + wrappedContent := &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + Delete: &signalpb.DataMessage_Delete{ + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + }, + }, + } + res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + if err != nil { + return err + } + // TODO check result + fmt.Println(res) + return nil } type msgconvPortalMethods struct{} @@ -606,7 +741,7 @@ func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *ev AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), Type: signalpb.DataMessage_Quote_NORMAL.Enum(), } - if mcCtx.ReplyTo.Metadata["reply_to_file"] != false { + if mcCtx.ReplyTo.Metadata["contains_attachments"] != false { quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) } return quote diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 11211e0..053e335 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -304,6 +304,13 @@ type GroupMessageSendResult struct { FailedToSendTo []FailedSendResult } +type SendResult interface { + isSendResult() +} + +func (gmsr *GroupMessageSendResult) isSendResult() {} +func (smsr *SendMessageResult) isSendResult() {} + func contentFromDataMessage(dataMessage *signalpb.DataMessage) *signalpb.Content { return &signalpb.Content{ DataMessage: dataMessage, From 851aac5f45aa768f7871538d6c17976471a612ea Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 6 Jun 2024 21:01:49 +0300 Subject: [PATCH 173/718] Stop using SimpleRemoteEvent --- go.mod | 2 +- go.sum | 4 +- pkg/connector/connector.go | 206 +++++++++++++++++++++++++++++++------ 3 files changed, 179 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index fee3d52..726ed5a 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240606131110-a0e309fa55ab + maunium.net/go/mautrix v0.18.2-0.20240606175822-a150a4760419 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index b80546d..d6720a8 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240606131110-a0e309fa55ab h1:e0Zo3/K+quT6p+U2Gsmw8R1kinzZ0wOkPbVPwoMkrBY= -maunium.net/go/mautrix v0.18.2-0.20240606131110-a0e309fa55ab/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= +maunium.net/go/mautrix v0.18.2-0.20240606175822-a150a4760419 h1:6JOCYkxS/nfhK/J3o+kkJgUDRaPRGgQXaxZj5HX5jys= +maunium.net/go/mautrix v0.18.2-0.20240606175822-a150a4760419/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 9075567..f46270e 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -435,16 +435,157 @@ type msgconvContext struct { ReplyTo *database.Message } -func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data *events.ChatEvent) (*bridgev2.ConvertedMessage, error) { +type Bv2ChatEvent struct { + *events.ChatEvent + s *SignalClient +} + +var ( + _ bridgev2.RemoteMessage = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEdit = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEventWithTimestamp = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReactionWithMeta = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) +) + +func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + switch { + case innerEvt.Body != nil, innerEvt.Attachments != nil, innerEvt.Contact != nil, innerEvt.Sticker != nil: + return bridgev2.RemoteEventMessage + case innerEvt.Reaction != nil: + if innerEvt.Reaction.GetRemove() { + return bridgev2.RemoteEventReactionRemove + } + return bridgev2.RemoteEventReaction + case innerEvt.Delete != nil: + return bridgev2.RemoteEventMessageRemove + } + case *signalpb.EditMessage: + return bridgev2.RemoteEventEdit + case *signalpb.TypingMessage: + //return bridgev2.RemoteEventTyping + } + return bridgev2.RemoteEventUnknown +} + +func (evt *Bv2ChatEvent) GetPortalID() networkid.PortalID { + return evt.s.getPortalID(evt.Info.ChatID) +} + +func (evt *Bv2ChatEvent) ShouldCreatePortal() bool { + return evt.GetType() == bridgev2.RemoteEventMessage +} + +func (evt *Bv2ChatEvent) AddLogContext(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Info.Sender) + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + c = c.Uint64("message_ts", innerEvt.GetTimestamp()) + switch { + case innerEvt.Reaction != nil: + c = c.Uint64("reaction_target_ts", innerEvt.Reaction.GetTargetSentTimestamp()) + case innerEvt.Delete != nil: + c = c.Uint64("delete_target_ts", innerEvt.Delete.GetTargetSentTimestamp()) + } + case *signalpb.EditMessage: + c = c. + Uint64("edit_target_ts", innerEvt.GetTargetSentTimestamp()). + Uint64("edit_ts", innerEvt.GetDataMessage().GetTimestamp()) + } + return c +} + +func (evt *Bv2ChatEvent) GetSender() bridgev2.EventSender { + return evt.s.makeEventSender(evt.Info.Sender) +} + +func (evt *Bv2ChatEvent) GetID() networkid.MessageID { + ts := evt.getDataMsgTimestamp() + if ts == 0 { + panic(fmt.Errorf("GetID() called for non-DataMessage event")) + } + return makeMessageID(evt.Info.Sender, ts) +} + +func (evt *Bv2ChatEvent) getDataMsgTimestamp() uint64 { + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + return innerEvt.GetTimestamp() + case *signalpb.EditMessage: + return innerEvt.GetDataMessage().GetTimestamp() + default: + return 0 + } +} + +func (evt *Bv2ChatEvent) GetTimestamp() time.Time { + ts := evt.getDataMsgTimestamp() + if ts == 0 { + return time.Now() + } + return time.UnixMilli(int64(ts)) +} + +func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { + var targetAuthorACI string + var targetSentTS uint64 + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + switch { + case innerEvt.Reaction != nil: + targetAuthorACI = innerEvt.Reaction.GetTargetAuthorAci() + targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp() + case innerEvt.Delete != nil: + targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() + default: + panic(fmt.Errorf("GetTargetMessage() called for message type without target")) + } + case *signalpb.EditMessage: + targetSentTS = innerEvt.GetTargetSentTimestamp() + default: + panic(fmt.Errorf("GetTargetMessage() called for message type without target")) + } + targetAuthorUUID := evt.Info.Sender + if targetAuthorACI != "" { + targetAuthorUUID, _ = uuid.Parse(targetAuthorACI) + } + return makeMessageID(targetAuthorUUID, targetSentTS) +} + +func (evt *Bv2ChatEvent) GetReactionEmoji() (string, networkid.EmojiID) { + dataMsg, ok := evt.Event.(*signalpb.DataMessage) + if !ok || dataMsg.Reaction == nil { + panic(fmt.Errorf("GetReactionEmoji() called for non-reaction event")) + } + return dataMsg.GetReaction().GetEmoji(), "" +} + +func (evt *Bv2ChatEvent) GetReactionDBMetadata() map[string]any { + dataMsg, ok := evt.Event.(*signalpb.DataMessage) + if !ok || dataMsg.Reaction == nil { + return map[string]any{} + } + return map[string]any{ + "emoji": dataMsg.GetReaction().GetEmoji(), + } +} + +func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) { mcCtx := &msgconvContext{ - Connector: s.Main, + Connector: evt.s.Main, Intent: intent, - Client: s, + Client: evt.s, Portal: portal, } ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - dataMsg := data.Event.(*signalpb.DataMessage) - converted := s.Main.MsgConv.ToMatrix(ctx, dataMsg) + dataMsg, ok := evt.Event.(*signalpb.DataMessage) + if !ok { + return nil, fmt.Errorf("ConvertMessage() called for non-DataMessage event") + } + converted := evt.s.Main.MsgConv.ToMatrix(ctx, dataMsg) + converted.MergeCaption() var replyTo *networkid.MessageOptionalPartID if dataMsg.GetQuote() != nil { quoteAuthor, _ := uuid.Parse(dataMsg.Quote.GetAuthorAci()) @@ -463,37 +604,42 @@ func (s *SignalClient) convertMessage(ctx context.Context, portal *bridgev2.Port } return &bridgev2.ConvertedMessage{ - //ID: makeMessageID(data.Info.Sender, dataMsg.GetTimestamp()), - //EventSender: s.makeEventSender(data.Info.Sender), - Timestamp: time.UnixMilli(int64(converted.Timestamp)), - ReplyTo: replyTo, - Parts: convertedParts, + ReplyTo: replyTo, + Parts: convertedParts, }, nil } +func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message) (*bridgev2.ConvertedEdit, error) { + mcCtx := &msgconvContext{ + Connector: evt.s.Main, + Intent: intent, + Client: evt.s, + Portal: portal, + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + editMsg, ok := evt.Event.(*signalpb.EditMessage) + if !ok { + return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event") + } + // TODO tell converter about existing parts to avoid reupload? + converted := evt.s.Main.MsgConv.ToMatrix(ctx, editMsg.GetDataMessage()) + converted.MergeCaption() + convertedEdit := &bridgev2.ConvertedEdit{} + // TODO can anything other than the text be edited? + lastPart := converted.Parts[len(converted.Parts)-1] + convertedEdit.ModifiedParts = append(convertedEdit.ModifiedParts, &bridgev2.ConvertedEditPart{ + Part: existing[len(existing)-1], + Type: lastPart.Type, + Content: lastPart.Content, + Extra: lastPart.Extra, + }) + return convertedEdit, nil +} + func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { switch evt := rawEvt.(type) { case *events.ChatEvent: - switch innerEvt := evt.Event.(type) { - case *signalpb.DataMessage: - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &bridgev2.SimpleRemoteEvent[*events.ChatEvent]{ - Type: bridgev2.RemoteEventMessage, - LogContext: func(c zerolog.Context) zerolog.Context { - return c. - Uint64("message_id", innerEvt.GetTimestamp()). - Stringer("sender_id", evt.Info.Sender) - }, - ID: makeMessageID(evt.Info.Sender, innerEvt.GetTimestamp()), - Sender: s.makeEventSender(evt.Info.Sender), - PortalID: s.getPortalID(evt.Info.ChatID), - Data: evt, - CreatePortal: true, - - ConvertMessageFunc: s.convertMessage, - }) - case *signalpb.EditMessage: - case *signalpb.TypingMessage: - } + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) case *events.DecryptionError: case *events.Receipt: case *events.ReadSelf: From 64a364d97de77cf707e3960a7f992c924a5f9728 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 7 Jun 2024 12:57:36 +0300 Subject: [PATCH 174/718] Update reaction deduplication --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 47 ++++++++++++-------------------------- 3 files changed, 17 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index 726ed5a..7d766d8 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240606175822-a150a4760419 + maunium.net/go/mautrix v0.18.2-0.20240607095501-6466bf945260 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index d6720a8..78957fa 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240606175822-a150a4760419 h1:6JOCYkxS/nfhK/J3o+kkJgUDRaPRGgQXaxZj5HX5jys= -maunium.net/go/mautrix v0.18.2-0.20240606175822-a150a4760419/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= +maunium.net/go/mautrix v0.18.2-0.20240607095501-6466bf945260 h1:PRjq8wEtssdiUhwVpo9h2LAlVEB04r3y/YR2XZsdlbg= +maunium.net/go/mautrix v0.18.2-0.20240607095501-6466bf945260/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index f46270e..69ec6b3 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -444,7 +444,8 @@ var ( _ bridgev2.RemoteMessage = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteEdit = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteEventWithTimestamp = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteReactionWithMeta = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReaction = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) ) @@ -562,14 +563,8 @@ func (evt *Bv2ChatEvent) GetReactionEmoji() (string, networkid.EmojiID) { return dataMsg.GetReaction().GetEmoji(), "" } -func (evt *Bv2ChatEvent) GetReactionDBMetadata() map[string]any { - dataMsg, ok := evt.Event.(*signalpb.DataMessage) - if !ok || dataMsg.Reaction == nil { - return map[string]any{} - } - return map[string]any{ - "emoji": dataMsg.GetReaction().GetEmoji(), - } +func (evt *Bv2ChatEvent) GetRemovedEmojiID() networkid.EmojiID { + return "" } func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) { @@ -695,8 +690,6 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma } dbMsg := &database.Message{ ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), - MXID: msg.Event.ID, - RoomID: msg.Portal.ID, SenderID: makeUserID(s.Client.Store.ACI), Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), Metadata: meta, @@ -763,16 +756,15 @@ func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.Porta } } +func (s *SignalClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { + return bridgev2.MatrixReactionPreResponse{ + SenderID: makeUserID(s.Client.Store.ACI), + EmojiID: "", + Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key), + }, nil +} + func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { - senderID := makeUserID(s.Client.Store.ACI) - // emojiID is always empty because only one reaction is allowed per message+user - var emojiID networkid.EmojiID - signalEmoji := variationselector.FullyQualify(msg.Content.RelatesTo.Key) - if existing, err := msg.GetExisting(ctx, senderID, emojiID); err != nil { - return nil, fmt.Errorf("failed to check for duplicate reaction: %w", err) - } else if existing != nil && existing.Metadata["emoji"] == signalEmoji { - return nil, nil - } targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) if err != nil { return nil, fmt.Errorf("failed to parse target message ID: %w", err) @@ -782,7 +774,7 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(signalEmoji), + Emoji: proto.String(msg.PreHandleResp.Emoji), Remove: proto.Bool(false), TargetAuthorAci: proto.String(targetAuthorACI.String()), TargetSentTimestamp: proto.Uint64(targetSentTimestamp), @@ -795,18 +787,7 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M } // TODO check result fmt.Println(res) - return &database.Reaction{ - RoomID: msg.Portal.ID, - MessageID: msg.TargetMessage.ID, - MessagePartID: msg.TargetMessage.PartID, - SenderID: senderID, - EmojiID: emojiID, - MXID: msg.Event.ID, - Timestamp: time.UnixMilli(msg.Event.Timestamp), - Metadata: map[string]any{ - "emoji": signalEmoji, - }, - }, nil + return &database.Reaction{}, nil } func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { From d501ce0578dec93cc3f5bcb6826f0bdc2ba7c930 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 10 Jun 2024 22:15:10 +0300 Subject: [PATCH 175/718] Add portal receiver to DMs --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 45 +++++++++----------------------------- 3 files changed, 13 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index 7d766d8..c602f49 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/net v0.25.0 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240607095501-6466bf945260 + maunium.net/go/mautrix v0.18.2-0.20240610191402-39ce0103d40b nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 78957fa..f67f9ad 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240607095501-6466bf945260 h1:PRjq8wEtssdiUhwVpo9h2LAlVEB04r3y/YR2XZsdlbg= -maunium.net/go/mautrix v0.18.2-0.20240607095501-6466bf945260/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= +maunium.net/go/mautrix v0.18.2-0.20240610191402-39ce0103d40b h1:sEwWJqdshbCZFGlvj6j3IPxBDznQLHG79GZdrMCEZvk= +maunium.net/go/mautrix v0.18.2-0.20240610191402-39ce0103d40b/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 69ec6b3..180a30e 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -28,7 +28,6 @@ import ( "github.com/rs/zerolog" "go.mau.fi/util/dbutil" "go.mau.fi/util/variationselector" - "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" "maunium.net/go/mautrix/bridgev2" @@ -345,43 +344,14 @@ func parseUserID(userID networkid.UserID) (uuid.UUID, error) { } func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { - parts := strings.Split(string(portalID), "|") - if len(parts) == 1 { - if len(parts[0]) == 44 { - groupID = types.GroupIdentifier(parts[0]) - } else { - err = fmt.Errorf("invalid portal ID: expected group ID to be 44 characters") - } - } else if len(parts) == 2 { - ourACI := s.Client.Store.ACI.String() - if parts[0] == ourACI { - userID, err = libsignalgo.ServiceIDFromString(parts[1]) - } else if parts[1] == ourACI { - userID, err = libsignalgo.ServiceIDFromString(parts[0]) - } else { - err = fmt.Errorf("invalid portal ID: expected one side to be our ACI") - } + if len(portalID) == 44 { + groupID = types.GroupIdentifier(portalID) } else { - err = fmt.Errorf("invalid portal ID: unexpected number of pipe-separated parts") + userID, err = libsignalgo.ServiceIDFromString(string(portalID)) } return } -func (s *SignalClient) getPortalID(chatID string) networkid.PortalID { - if len(chatID) == 44 { - // Group ID - return networkid.PortalID(chatID) - } else if strings.HasPrefix(chatID, "PNI:") { - // Temporary new DM ID: always put our own ACI first, the portal will never be shared anyway - return networkid.PortalID(fmt.Sprintf("%s|%s", s.Client.Store.ACI, chatID)) - } else { - // DM ID: sort the two parts so the ID is always the same regardless of which side is receiving the message - parts := []string{s.Client.Store.ACI.String(), chatID} - slices.Sort(parts) - return networkid.PortalID(strings.Join(parts, "|")) - } -} - func parseMessageID(messageID networkid.MessageID) (sender uuid.UUID, timestamp uint64, err error) { parts := strings.Split(string(messageID), "|") if len(parts) != 2 { @@ -471,8 +441,13 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { return bridgev2.RemoteEventUnknown } -func (evt *Bv2ChatEvent) GetPortalID() networkid.PortalID { - return evt.s.getPortalID(evt.Info.ChatID) +func (evt *Bv2ChatEvent) GetPortalKey() networkid.PortalKey { + key := networkid.PortalKey{ID: networkid.PortalID(evt.Info.ChatID)} + // For non-group chats, add receiver + if len(evt.Info.ChatID) != 44 { + key.Receiver = makeUserLoginID(evt.s.Client.Store.ACI) + } + return key } func (evt *Bv2ChatEvent) ShouldCreatePortal() bool { From ecd4f055ae312c61f363659962a5f3b1bb843af7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 11 Jun 2024 15:06:04 +0300 Subject: [PATCH 176/718] Use new main function for v2 bridge --- cmd/mautrix-signal-v2/main.go | 43 ++++++++++++++++--------------- config/upgrade.go | 2 +- go.mod | 16 ++++++------ go.sum | 28 ++++++++++---------- pkg/connector/connector.go | 39 ++++++++++++++++++++++++---- pkg/connector/example-config.yaml | 21 +++++++++++++++ 6 files changed, 100 insertions(+), 49 deletions(-) create mode 100644 pkg/connector/example-config.yaml diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 4e02361..e397e14 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -17,31 +17,32 @@ package main import ( - "os" - - "go.mau.fi/util/dbutil" - "go.mau.fi/util/exerrors" - "go.mau.fi/util/exzerolog" - "gopkg.in/yaml.v3" - "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/bridgeconfig" - "maunium.net/go/mautrix/bridgev2/matrix" + "maunium.net/go/mautrix/bridgev2/matrix/mxmain" "go.mau.fi/mautrix-signal/pkg/connector" "go.mau.fi/mautrix-signal/pkg/signalmeow" ) +// Information to find out exactly which commit the bridge was built from. +// These are filled at build time with the -X linker flag. +var ( + Tag = "unknown" + Commit = "unknown" + BuildTime = "unknown" +) + func main() { - var cfg bridgeconfig.Config - config := exerrors.Must(os.ReadFile("config.yaml")) - exerrors.PanicIfNotNil(yaml.Unmarshal(config, &cfg)) - log := exerrors.Must(cfg.Logging.Compile()) - exzerolog.SetupDefaults(log) - signalmeow.SetLogger(log.With().Str("component", "signalmeow").Logger()) - db := exerrors.Must(dbutil.NewFromConfig("mautrix-signal", cfg.Database, dbutil.ZeroLogger(log.With().Str("db_section", "main").Logger()))) - signalConnector := connector.NewConnector() - exerrors.PanicIfNotNil(cfg.Network.Decode(signalConnector.Config)) - bridge := bridgev2.NewBridge("", db, *log, matrix.NewConnector(&cfg), signalConnector) - bridge.CommandPrefix = "!signal" - bridge.Start() + m := mxmain.BridgeMain{ + Name: "mautrix-signal", + URL: "https://github.com/mautrix/signal", + Description: "A Matrix-Signal puppeting bridge.", + Version: "0.7.0", + + Connector: connector.NewConnector(), + } + m.PostInit = func() { + signalmeow.SetLogger(m.Log.With().Str("component", "signalmeow").Logger()) + } + m.InitVersion(Tag, Commit, BuildTime) + m.Run() } diff --git a/config/upgrade.go b/config/upgrade.go index 114eb1d..219b7fc 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -25,7 +25,7 @@ import ( "maunium.net/go/mautrix/bridge/bridgeconfig" ) -func DoUpgrade(helper *up.Helper) { +func DoUpgrade(helper up.Helper) { bridgeconfig.Upgrader.DoUpgrade(helper) legacyDB, ok := helper.Get(up.Str, "appservice", "database") diff --git a/go.mod b/go.mod index 4d44c1d..e328525 100644 --- a/go.mod +++ b/go.mod @@ -11,17 +11,16 @@ require ( github.com/mattn/go-pointer v0.0.1 github.com/mattn/go-sqlite3 v1.14.22 github.com/prometheus/client_golang v1.19.1 - github.com/rs/zerolog v1.32.0 + github.com/rs/zerolog v1.33.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.3-0.20240516141139-2ebe792cd8f7 - golang.org/x/crypto v0.23.0 - golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d - golang.org/x/net v0.25.0 + go.mau.fi/util v0.4.3-0.20240611114927-6ef09885dd97 + golang.org/x/crypto v0.24.0 + golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 + golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.1 - gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.18.2-0.20240610192549-f9dccaaea049 + maunium.net/go/mautrix v0.18.2-0.20240611120402-f97d365ea9eb nhooyr.io/websocket v1.8.11 ) @@ -44,7 +43,8 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.1 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/sys v0.21.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index edf5156..98c7001 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -69,21 +69,21 @@ 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.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.3-0.20240516141139-2ebe792cd8f7 h1:2hnc2iS7usHT3aqIQ8HVtKtPgic+13EVSdZ1m8UBL/E= -go.mau.fi/util v0.4.3-0.20240516141139-2ebe792cd8f7/go.mod h1:m+PJpPMadAW6cj3ldyuO5bLhFreWdwcu+3QTwYNGlGk= +go.mau.fi/util v0.4.3-0.20240611114927-6ef09885dd97 h1:btYXIv4Iqnboc9FQS99dh8XwMF2QftOhfTeh02K2b4o= +go.mau.fi/util v0.4.3-0.20240611114927-6ef09885dd97/go.mod h1:4etkIWotzgsWICu/1I34Y2LFFekINhFsyWYHXEsxXdY= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d h1:N0hmiNbwsSNwHBAvR3QB5w25pUwH4tK0Y/RltD1j1h4= -golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= +golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -95,7 +95,7 @@ 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.18.2-0.20240610192549-f9dccaaea049 h1:keFLN2tVrt5UmNSm7Mjweue4r4t+WUKk0kmPcWfXUpQ= -maunium.net/go/mautrix v0.18.2-0.20240610192549-f9dccaaea049/go.mod h1:P/FV8cXY262MezYX7ViuhfzeJ0nK4+M8K6ZmxEC/aEA= +maunium.net/go/mautrix v0.18.2-0.20240611120402-f97d365ea9eb h1:PcUevUW1w5PCeqXha1fPIlk25XcdXrogpBsBLB/HbXo= +maunium.net/go/mautrix v0.18.2-0.20240611120402-f97d365ea9eb/go.mod h1:HLNcNm0J4ZDgaoMjoHv5Hc/GkA2FfVUR6KbW7A3Iwv0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 180a30e..d663657 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -18,6 +18,7 @@ package connector import ( "context" + _ "embed" "fmt" "strconv" "strings" @@ -26,10 +27,10 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + up "go.mau.fi/util/configupgrade" "go.mau.fi/util/dbutil" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" @@ -94,12 +95,44 @@ type SignalConnector struct { Config *SignalConfig } +var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) +var _ bridgev2.NetworkAPI = (*SignalClient)(nil) +var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) + func NewConnector() *SignalConnector { return &SignalConnector{ Config: &SignalConfig{}, } } +//go:embed example-config.yaml +var ExampleConfig string + +func (s *SignalConnector) GetName() bridgev2.BridgeName { + return bridgev2.BridgeName{ + DisplayName: "Signal", + NetworkURL: "https://signal.org", + NetworkIcon: "mxc://maunium.net/wPJgTQbZOtpBFmDNkiNEMDUp", + NetworkID: "signal", + BeeperBridgeType: "signal", + DefaultPort: 29328, + } +} + +func upgradeConfig(helper up.Helper) { + helper.Copy(up.Str, "displayname_template") + helper.Copy(up.Bool, "use_contact_avatars") + helper.Copy(up.Bool, "use_outdated_profiles") + helper.Copy(up.Bool, "number_in_topic") + helper.Copy(up.Str, "device_name") + helper.Copy(up.Str, "note_to_self_avatar") + helper.Copy(up.Str, "location_format") +} + +func (s *SignalConnector) GetConfig() (string, any, up.Upgrader) { + return ExampleConfig, s.Config, up.SimpleUpgrader(upgradeConfig) +} + func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { var err error s.Config.displaynameTemplate, err = template.New("displayname").Parse(s.Config.DisplaynameTemplate) @@ -161,10 +194,6 @@ func (s *SignalConnector) Start(ctx context.Context) error { return s.Store.Upgrade(ctx) } -var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) -var _ bridgev2.NetworkAPI = (*SignalClient)(nil) -var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) - func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error { aci, err := uuid.Parse(string(login.ID)) if err != nil { diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml new file mode 100644 index 0000000..4c399b3 --- /dev/null +++ b/pkg/connector/example-config.yaml @@ -0,0 +1,21 @@ +# Displayname template for Signal users. +# {{.ProfileName}} - The Signal profile name set by the user. +# {{.ContactName}} - The name for the user from your phone's contact list. This is not safe on multi-user instances. +# {{.PhoneNumber}} - The phone number of the user. +# {{.UUID}} - The UUID of the Signal user. +# {{.AboutEmoji}} - The emoji set by the user in their profile. +displayname_template: '{{or .ProfileName .PhoneNumber "Unknown user"}}' +# Should avatars from the user's contact list be used? This is not safe on multi-user instances. +use_contact_avatars: false +# Should the bridge sync ghost user info even if profile fetching fails? This is not safe on multi-user instances. +use_outdated_profiles: false +# Should the Signal user's phone number be included in the room topic in private chat portal rooms? +number_in_topic: true +# Default device name that shows up in the Signal app. +device_name: mautrix-signal +# Avatar image for the Note to Self room. +note_to_self_avatar: mxc://maunium.net/REBIVrqjZwmaWpssCZpBlmlL +# Format for generating URLs from location messages for sending to Signal. +# Google Maps: 'https://www.google.com/maps/place/%[1]s,%[2]s' +# OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]s' +location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s' From e637cdfac728306c74b0ec2503b24a681af66151 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 11 Jun 2024 20:29:04 +0300 Subject: [PATCH 177/718] v2: Add bridge states --- go.mod | 4 +- go.sum | 8 +-- pkg/connector/connector.go | 108 ++++++++++++++++++++++++++++++++++++- pkg/connector/login.go | 4 +- 4 files changed, 115 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index e328525..9d49663 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.3-0.20240611114927-6ef09885dd97 + go.mau.fi/util v0.4.3-0.20240611132549-e72a5f4745e7 golang.org/x/crypto v0.24.0 golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.2-0.20240611120402-f97d365ea9eb + maunium.net/go/mautrix v0.18.2-0.20240611172604-d58e8f88173b nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 98c7001..58227d6 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.3-0.20240611114927-6ef09885dd97 h1:btYXIv4Iqnboc9FQS99dh8XwMF2QftOhfTeh02K2b4o= -go.mau.fi/util v0.4.3-0.20240611114927-6ef09885dd97/go.mod h1:4etkIWotzgsWICu/1I34Y2LFFekINhFsyWYHXEsxXdY= +go.mau.fi/util v0.4.3-0.20240611132549-e72a5f4745e7 h1:DviEWXBpeOlFrqIf5s/iBDp1ewZx8fe6imMJ78kq3tA= +go.mau.fi/util v0.4.3-0.20240611132549-e72a5f4745e7/go.mod h1:Eaj7jl37ehkA7S6vE/vfPs5PsY8e91FKZ2BqA3OM/NU= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= @@ -95,7 +95,7 @@ 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.18.2-0.20240611120402-f97d365ea9eb h1:PcUevUW1w5PCeqXha1fPIlk25XcdXrogpBsBLB/HbXo= -maunium.net/go/mautrix v0.18.2-0.20240611120402-f97d365ea9eb/go.mod h1:HLNcNm0J4ZDgaoMjoHv5Hc/GkA2FfVUR6KbW7A3Iwv0= +maunium.net/go/mautrix v0.18.2-0.20240611172604-d58e8f88173b h1:pcehRMwc0JrVokKa6Paucq6JyAvzZBaDt9x7QCeNWlQ= +maunium.net/go/mautrix v0.18.2-0.20240611172604-d58e8f88173b/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index d663657..534dbf5 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -31,6 +31,7 @@ import ( "go.mau.fi/util/dbutil" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" @@ -355,12 +356,115 @@ func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bo return userID == makeUserID(s.Client.Store.ACI) } +func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnectionStatus) { + var peekedConnectionStatus signalmeow.SignalConnectionStatus + for { + var connectionStatus signalmeow.SignalConnectionStatus + if peekedConnectionStatus.Event != signalmeow.SignalConnectionEventNone { + s.UserLogin.Log.Debug(). + Stringer("peeked_connection_status_event", peekedConnectionStatus.Event). + Msg("Using peeked connectionStatus event") + connectionStatus = peekedConnectionStatus + peekedConnectionStatus = signalmeow.SignalConnectionStatus{} + } else { + var ok bool + connectionStatus, ok = <-statusChan + if !ok { + s.UserLogin.Log.Debug().Msg("statusChan channel closed") + return + } + } + + err := connectionStatus.Err + switch connectionStatus.Event { + case signalmeow.SignalConnectionEventConnected: + s.UserLogin.Log.Debug().Msg("Sending Connected BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) + + case signalmeow.SignalConnectionEventDisconnected: + s.UserLogin.Log.Debug().Msg("Received SignalConnectionEventDisconnected") + + // Debounce: wait 7s before sending TransientDisconnect, in case we get a reconnect + // We should wait until the next message comes in, or 7 seconds has passed. + // - If a disconnected event comes in, just loop again, unless it's been more than 7 seconds. + // - If a non-disconnected event comes in, store it in peekedConnectionStatus, + // break out of this loop and go back to the top of the goroutine to handle it in the switch. + // - If 7 seconds passes without any non-disconnect messages, send the TransientDisconnect. + // (Why 7 seconds? It was 5 at first, but websockets min retry is 5 seconds, + // so it would send TransientDisconnect right before reconnecting. 7 seems to work well.) + debounceTimer := time.NewTimer(7 * time.Second) + PeekLoop: + for { + var ok bool + select { + case peekedConnectionStatus, ok = <-statusChan: + // Handle channel closing + if !ok { + s.UserLogin.Log.Debug().Msg("connectionStatus channel closed") + return + } + // If it's another Disconnected event, just keep looping + if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected { + peekedConnectionStatus = signalmeow.SignalConnectionStatus{} + continue + } + // If it's a non-disconnect event, break out of the PeekLoop and handle it in the switch + break PeekLoop + case <-debounceTimer.C: + // Time is up, so break out of the loop and send the TransientDisconnect + break PeekLoop + } + } + // We're out of the PeekLoop, so either we got a non-disconnect event, or it's been 7 seconds (or both). + // We want to send TransientDisconnect if it's been 7 seconds, but not if the latest event was something + // other than Disconnected + if !debounceTimer.Stop() { // If the timer has already expired + // Send TransientDisconnect only if the latest event is a disconnect or no event + // (peekedConnectionStatus could be something else if the timer and the event race) + if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected || + peekedConnectionStatus.Event == signalmeow.SignalConnectionEventNone { + s.UserLogin.Log.Debug().Msg("Sending TransientDisconnect BridgeState") + if err == nil { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect}) + } else { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) + } + } + } + + case signalmeow.SignalConnectionEventLoggedOut: + s.UserLogin.Log.Debug().Msg("Sending BadCredentials BridgeState") + if err == nil { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) + } else { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: err.Error()}) + } + err = s.Client.ClearKeysAndDisconnect(context.TODO()) + if err != nil { + s.UserLogin.Log.Error().Err(err).Msg("Failed to clear keys and disconnect") + } + + case signalmeow.SignalConnectionEventError: + s.UserLogin.Log.Debug().Msg("Sending UnknownError BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + + case signalmeow.SignalConnectionCleanShutdown: + if s.Client.IsLoggedIn() { + s.UserLogin.Log.Debug().Msg("Clean Shutdown - sending no BridgeState") + } else { + s.UserLogin.Log.Debug().Msg("Clean Shutdown, but logged out - Sending BadCredentials BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) + } + } + } +} + func (s *SignalClient) Connect(ctx context.Context) error { - _, err := s.Client.StartReceiveLoops(ctx) + ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { return err } - // TODO status + go s.bridgeStateLoop(ch) return nil } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index cd25e60..4771b65 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -137,7 +137,8 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { ul, err = qr.User.NewLogin(ctx, &database.UserLogin{ ID: newLoginID, Metadata: map[string]any{ - "phone": signalPhone, + "phone": signalPhone, + "remote_name": signalPhone, }, }, nil) if err != nil { @@ -146,6 +147,7 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { } else { ul = qr.Existing ul.Metadata["phone"] = signalPhone + ul.Metadata["remote_name"] = signalPhone err = ul.Save(ctx) if err != nil { return nil, fmt.Errorf("failed to update existing login: %w", err) From ecd444fbf30543ea24b6b3bbfd5ae32986525e45 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Jun 2024 14:58:35 +0300 Subject: [PATCH 178/718] v2: add retry loop in initial connect --- pkg/connector/connector.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 534dbf5..c67cfed 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -458,14 +458,27 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } } } - func (s *SignalClient) Connect(ctx context.Context) error { + s.tryConnect(ctx, 0) + return nil +} + +func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { - return err + zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") + if retryCount < 6 { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) + retryInSeconds := 2 << retryCount + zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") + time.Sleep(time.Duration(retryInSeconds) * time.Second) + s.tryConnect(ctx, retryCount+1) + } else { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + } + } else { + go s.bridgeStateLoop(ch) } - go s.bridgeStateLoop(ch) - return nil } func (s *SignalClient) IsLoggedIn() bool { From 6964a0d175a7506953caf21d7492520c67038112 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Jun 2024 19:45:21 +0300 Subject: [PATCH 179/718] v2: add read receipts and other things --- go.mod | 2 +- go.sum | 4 +- pkg/connector/connector.go | 189 +++++++++++++++++++++++++++++++++++-- 3 files changed, 183 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 9d49663..0cef984 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.2-0.20240611172604-d58e8f88173b + maunium.net/go/mautrix v0.18.2-0.20240612164408-cf6b0e71f0a0 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 58227d6..ba5d33d 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240611172604-d58e8f88173b h1:pcehRMwc0JrVokKa6Paucq6JyAvzZBaDt9x7QCeNWlQ= -maunium.net/go/mautrix v0.18.2-0.20240611172604-d58e8f88173b/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= +maunium.net/go/mautrix v0.18.2-0.20240612164408-cf6b0e71f0a0 h1:e+7glrQSSUm5GROTBYq/ENwhefRFmEXfGwRdP2FllAw= +maunium.net/go/mautrix v0.18.2-0.20240612164408-cf6b0e71f0a0/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index c67cfed..864e3d8 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -29,6 +29,7 @@ import ( "github.com/rs/zerolog" up "go.mau.fi/util/configupgrade" "go.mau.fi/util/dbutil" + "go.mau.fi/util/exzerolog" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" "maunium.net/go/mautrix/bridge/status" @@ -51,11 +52,13 @@ import ( ) type SignalConfig struct { - DisplaynameTemplate string `yaml:"displayname_template"` - UseContactAvatars bool `yaml:"use_contact_avatars"` - UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` - NumberInTopic bool `yaml:"number_in_topic"` - DeviceName string `yaml:"device_name"` + DisplaynameTemplate string `yaml:"displayname_template"` + UseContactAvatars bool `yaml:"use_contact_avatars"` + UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` + NumberInTopic bool `yaml:"number_in_topic"` + DeviceName string `yaml:"device_name"` + NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` + LocationFormat string `yaml:"location_format"` displaynameTemplate *template.Template `yaml:"-"` } @@ -97,6 +100,7 @@ type SignalConnector struct { } var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) +var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) var _ bridgev2.NetworkAPI = (*SignalClient)(nil) var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) @@ -174,7 +178,7 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { user, _ := s.Bridge.GetExistingUserByMXID(ctx, userID) // TODO log errors? if user != nil { - preferredLogin, _ := ctx.Value(msgconvContextKey).(*msgconvContext).Portal.FindPreferredLogin(ctx, user) + preferredLogin, _, _ := ctx.Value(msgconvContextKey).(*msgconvContext).Portal.FindPreferredLogin(ctx, user, true) if preferredLogin != nil { u, _ := uuid.Parse(string(preferredLogin.ID)) return u @@ -185,12 +189,16 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { }, ConvertVoiceMessages: true, ConvertGIFToAPNG: true, - MaxFileSize: 100 * 1024 * 1024, + MaxFileSize: 50 * 1024 * 1024, AsyncFiles: true, - LocationFormat: "", + LocationFormat: s.Config.LocationFormat, } } +func (s *SignalConnector) SetMaxFileSize(maxSize int64) { + s.MsgConv.MaxFileSize = maxSize +} + func (s *SignalConnector) Start(ctx context.Context) error { return s.Store.Upgrade(ctx) } @@ -582,7 +590,7 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { case *signalpb.EditMessage: return bridgev2.RemoteEventEdit case *signalpb.TypingMessage: - //return bridgev2.RemoteEventTyping + return bridgev2.RemoteEventTyping } return bridgev2.RemoteEventUnknown } @@ -752,13 +760,124 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta return convertedEdit, nil } +type Bv2Receipt struct { + Type signalpb.ReceiptMessage_Type + Chat networkid.PortalKey + Sender bridgev2.EventSender + + LastTS time.Time + LastID networkid.MessageID + IDs []networkid.MessageID +} + +func (b *Bv2Receipt) GetType() bridgev2.RemoteEventType { + switch b.Type { + case signalpb.ReceiptMessage_READ: + return bridgev2.RemoteEventReadReceipt + case signalpb.ReceiptMessage_DELIVERY: + return bridgev2.RemoteEventDeliveryReceipt + default: + return bridgev2.RemoteEventUnknown + } +} + +func (b *Bv2Receipt) GetPortalKey() networkid.PortalKey { + return b.Chat +} + +func (b *Bv2Receipt) AddLogContext(c zerolog.Context) zerolog.Context { + return c. + Str("sender_id", string(b.Sender.Sender)). + Stringer("receipt_type", b.Type). + Array("message_ids", exzerolog.ArrayOfStrs(b.IDs)) +} + +func (b *Bv2Receipt) GetSender() bridgev2.EventSender { + return b.Sender +} + +func (b *Bv2Receipt) GetLastReceiptTarget() networkid.MessageID { + return b.LastID +} + +func (b *Bv2Receipt) GetReceiptTargets() []networkid.MessageID { + return b.IDs +} + +var _ bridgev2.RemoteReceipt = (*Bv2Receipt)(nil) + +func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt { + log := zerolog.Ctx(ctx) + receipts := make(map[networkid.PortalKey]*Bv2Receipt) + for _, msgID := range input { + msg, err := getMessageFunc(ctx, msgID) + if err != nil { + log.Err(err).Any("message_id", msgID).Msg("Failed to get target message for receipt") + } else if msg == nil { + log.Debug().Any("message_id", msgID).Msg("Got receipt for unknown message") + } else { + receiptEvt, ok := receipts[msg.Room] + if !ok { + receiptEvt = &Bv2Receipt{Chat: msg.Room} + receipts[msg.Room] = receiptEvt + } + receiptEvt.IDs = append(receiptEvt.IDs, msg.ID) + if receiptEvt.LastTS.Before(msg.Timestamp) { + receiptEvt.LastTS = msg.Timestamp + receiptEvt.LastID = msg.ID + } + } + } + return receipts +} + +func (s *SignalClient) dispatchReceipts(sender uuid.UUID, receiptType signalpb.ReceiptMessage_Type, receipts map[networkid.PortalKey]*Bv2Receipt) { + evtSender := s.makeEventSender(sender) + for chat, receiptEvt := range receipts { + receiptEvt.Chat = chat + receiptEvt.Sender = evtSender + receiptEvt.Type = receiptType + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, receiptEvt) + } +} + +func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { + log := s.UserLogin.Log.With(). + Str("action", "handle signal receipt"). + Stringer("sender_id", evt.Sender). + Stringer("receipt_type", evt.Content.GetType()). + Logger() + ctx := log.WithContext(context.TODO()) + receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(s.Client.Store.ACI, msgTS)) + }) + s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) +} + +func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { + log := s.UserLogin.Log.With(). + Str("action", "handle signal read self"). + Logger() + ctx := log.WithContext(context.TODO()) + receipts := convertReceipts(ctx, evt.Messages, func(ctx context.Context, msgInfo *signalpb.SyncMessage_Read) (*database.Message, error) { + aciUUID, err := uuid.Parse(msgInfo.GetSenderAci()) + if err != nil { + return nil, err + } + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(aciUUID, msgInfo.GetTimestamp())) + }) + s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) +} + func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { switch evt := rawEvt.(type) { case *events.ChatEvent: s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) case *events.DecryptionError: case *events.Receipt: + s.handleSignalReceipt(evt) case *events.ReadSelf: + s.handleSignalReadSelf(evt) case *events.Call: case *events.ContactList: s.handleSignalContactList(evt) @@ -962,6 +1081,58 @@ func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridg return nil } +func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bridgev2.MatrixReadReceipt) error { + if !receipt.ReadUpTo.After(receipt.LastRead) { + return nil + } + if receipt.LastRead.IsZero() { + receipt.LastRead = receipt.ReadUpTo.Add(-5 * time.Second) + } + dbMessages, err := s.Main.Bridge.DB.Message.GetMessagesBetweenTimeQuery(ctx, receipt.Portal.PortalKey, receipt.LastRead, receipt.ReadUpTo) + if err != nil { + return fmt.Errorf("failed to get messages to mark as read: %w", err) + } else if len(dbMessages) == 0 { + return nil + } + messagesToRead := map[uuid.UUID][]uint64{} + for _, msg := range dbMessages { + userID, timestamp, err := parseMessageID(msg.ID) + if err != nil { + return fmt.Errorf("failed to parse message ID %q: %w", msg.ID, err) + } + messagesToRead[userID] = append(messagesToRead[userID], timestamp) + } + zerolog.Ctx(ctx).Debug(). + Any("targets", messagesToRead). + Msg("Collected read receipt target messages") + + // TODO send sync message manually containing all read receipts instead of a separate message for each recipient + + for destination, messages := range messagesToRead { + // Don't send read receipts for own messages + if destination == s.Client.Store.ACI { + continue + } + // Don't use portal.sendSignalMessage because we're sending this straight to + // who sent the original message, not the portal's ChatID + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + result := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(destination), signalmeow.ReadReceptMessageForTimestamps(messages)) + cancel() + if !result.WasSuccessful { + zerolog.Ctx(ctx).Err(result.FailedSendResult.Error). + Stringer("destination", destination). + Uints64("message_ids", messages). + Msg("Failed to send read receipt to Signal") + } else { + zerolog.Ctx(ctx).Debug(). + Stringer("destination", destination). + Uints64("message_ids", messages). + Msg("Sent read receipt to Signal") + } + } + return nil +} + type msgconvPortalMethods struct{} func (mpm *msgconvPortalMethods) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { From 84999d499385ec84254f466ae1a30f7e331be68b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Jun 2024 17:27:19 +0300 Subject: [PATCH 180/718] ci: build binaries and docker images for v2 (#518) --- .gitlab-ci.yml | 7 ++++++- Dockerfile.v2.ci | 15 +++++++++++++++ docker-run.sh | 18 +++++++++++++----- 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 Dockerfile.v2.ci diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6c694eb..03bd8f5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,12 +1,17 @@ include: - project: 'mautrix/ci' file: '/go.yml' +- project: 'mautrix/ci' + file: '/gov2.yml' variables: BUILDER_IMAGE: dock.mau.dev/tulir/gomuks-build-docker/signal - BINARY_NAME: mautrix-signal # 32-bit arm builds aren't supported build arm: rules: - when: never + +build arm v2: + rules: + - when: never diff --git a/Dockerfile.v2.ci b/Dockerfile.v2.ci new file mode 100644 index 0000000..d5868a7 --- /dev/null +++ b/Dockerfile.v2.ci @@ -0,0 +1,15 @@ +FROM alpine:3.20 + +ENV UID=1337 \ + GID=1337 + +RUN apk add --no-cache ffmpeg su-exec ca-certificates bash jq curl yq-go + +ARG EXECUTABLE=./mautrix-signal-v2 +COPY $EXECUTABLE /usr/bin/mautrix-signal-v2 +COPY ./docker-run.sh /docker-run.sh +ENV BRIDGEV2=1 +VOLUME /data +WORKDIR /data + +CMD ["/docker-run.sh"] diff --git a/docker-run.sh b/docker-run.sh index c760f6b..6d6f3a7 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -4,6 +4,11 @@ if [[ -z "$GID" ]]; then GID="$UID" fi +BINARY_NAME=/usr/bin/mautrix-signal +if [[ "$BRIDGEV2" == "1" ]]; then + BINARY_NAME=/usr/bin/mautrix-signal-v2 +fi + # Define functions. function fixperms { chown -R $UID:$GID /data @@ -15,7 +20,11 @@ function fixperms { } if [[ ! -f /data/config.yaml ]]; then - cp /opt/mautrix-signal/example-config.yaml /data/config.yaml + if [[ "$BRIDGEV2" == "1" ]]; then + $BINARY_NAME -c /data/config -e + else + cp /opt/mautrix-signal/example-config.yaml /data/config.yaml + fi echo "Didn't find a config file." echo "Copied default config file to /data/config.yaml" echo "Modify that config file to your liking." @@ -24,7 +33,7 @@ if [[ ! -f /data/config.yaml ]]; then fi if [[ ! -f /data/registration.yaml ]]; then - /usr/bin/mautrix-signal -g -c /data/config.yaml -r /data/registration.yaml || exit $? + $BINARY_NAME -g -c /data/config.yaml -r /data/registration.yaml || exit $? echo "Didn't find a registration file." echo "Generated one for you." echo "See https://docs.mau.fi/bridges/general/registering-appservices.html on how to use it." @@ -34,13 +43,12 @@ fi cd /data fixperms -EXE=/usr/bin/mautrix-signal DLV=/usr/bin/dlv if [ -x "$DLV" ]; then if [ "$DBGWAIT" != 1 ]; then NOWAIT=1 fi - EXE="${DLV} exec ${EXE} ${NOWAIT:+--continue --accept-multiclient} --api-version 2 --headless -l :4040" + BINARY_NAME="${DLV} exec ${BINARY_NAME} ${NOWAIT:+--continue --accept-multiclient} --api-version 2 --headless -l :4040" fi -exec su-exec $UID:$GID $EXE +exec su-exec $UID:$GID $BINARY_NAME From fabe2657074fd17b9b8e519b7988fe1e9ced7a6b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Jun 2024 21:41:56 +0300 Subject: [PATCH 181/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0cef984..bd780c3 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.2-0.20240612164408-cf6b0e71f0a0 + maunium.net/go/mautrix v0.18.2-0.20240613184127-2863a1323b60 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index ba5d33d..e03e111 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240612164408-cf6b0e71f0a0 h1:e+7glrQSSUm5GROTBYq/ENwhefRFmEXfGwRdP2FllAw= -maunium.net/go/mautrix v0.18.2-0.20240612164408-cf6b0e71f0a0/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= +maunium.net/go/mautrix v0.18.2-0.20240613184127-2863a1323b60 h1:JqRWNajY57PTvSrMY3wx46u8pT2eAzmTh4kVJ7Wblhc= +maunium.net/go/mautrix v0.18.2-0.20240613184127-2863a1323b60/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From d1e76ad973d5d987c74ae8e0468d9eac834d3a86 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 14 Jun 2024 12:47:36 +0300 Subject: [PATCH 182/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bd780c3..258845e 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.2-0.20240613184127-2863a1323b60 + maunium.net/go/mautrix v0.18.2-0.20240614094708-b456fb6e0a6b nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index e03e111..61c4295 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240613184127-2863a1323b60 h1:JqRWNajY57PTvSrMY3wx46u8pT2eAzmTh4kVJ7Wblhc= -maunium.net/go/mautrix v0.18.2-0.20240613184127-2863a1323b60/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= +maunium.net/go/mautrix v0.18.2-0.20240614094708-b456fb6e0a6b h1:/JvXcwT+y9SR0AN0fQIhIOz+9Uy9jhwpqqFEYxuTtTI= +maunium.net/go/mautrix v0.18.2-0.20240614094708-b456fb6e0a6b/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 114d478e61b4ce90fecfd922efb0e16bf056c00d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 14 Jun 2024 15:43:59 +0300 Subject: [PATCH 183/718] signalmeow: update protobuf schemas --- .../protobuf/ContactDiscovery.pb.go | 2 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 2 +- pkg/signalmeow/protobuf/Groups.pb.go | 2 +- pkg/signalmeow/protobuf/Provisioning.pb.go | 2 +- pkg/signalmeow/protobuf/SignalService.pb.go | 1836 +++++++++++------ pkg/signalmeow/protobuf/SignalService.proto | 56 +- .../protobuf/StickerResources.pb.go | 2 +- pkg/signalmeow/protobuf/StorageService.pb.go | 588 +++--- pkg/signalmeow/protobuf/StorageService.proto | 9 +- .../protobuf/UnidentifiedDelivery.pb.go | 2 +- .../protobuf/WebSocketResources.pb.go | 2 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 12 files changed, 1639 insertions(+), 868 deletions(-) diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 282d9a8..b252d37 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: ContactDiscovery.proto diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 657dcf5..2cdca84 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: DeviceName.proto diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index a49ea9f..8ec4a97 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: Groups.proto diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 446162e..e2ceb1f 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: Provisioning.proto diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index aa5d674..1ff1228 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: SignalService.proto @@ -1517,8 +1517,9 @@ func (SyncMessage_CallLinkUpdate_Type) EnumDescriptor() ([]byte, []int) { type SyncMessage_CallLogEvent_Type int32 const ( - SyncMessage_CallLogEvent_CLEAR SyncMessage_CallLogEvent_Type = 0 - SyncMessage_CallLogEvent_MARKED_AS_READ SyncMessage_CallLogEvent_Type = 1 + SyncMessage_CallLogEvent_CLEAR SyncMessage_CallLogEvent_Type = 0 + SyncMessage_CallLogEvent_MARKED_AS_READ SyncMessage_CallLogEvent_Type = 1 + SyncMessage_CallLogEvent_MARKED_AS_READ_IN_CONVERSATION SyncMessage_CallLogEvent_Type = 2 ) // Enum value maps for SyncMessage_CallLogEvent_Type. @@ -1526,10 +1527,12 @@ var ( SyncMessage_CallLogEvent_Type_name = map[int32]string{ 0: "CLEAR", 1: "MARKED_AS_READ", + 2: "MARKED_AS_READ_IN_CONVERSATION", } SyncMessage_CallLogEvent_Type_value = map[string]int32{ - "CLEAR": 0, - "MARKED_AS_READ": 1, + "CLEAR": 0, + "MARKED_AS_READ": 1, + "MARKED_AS_READ_IN_CONVERSATION": 2, } ) @@ -2917,6 +2920,7 @@ type SyncMessage struct { CallEvent *SyncMessage_CallEvent `protobuf:"bytes,19,opt,name=callEvent" json:"callEvent,omitempty"` CallLinkUpdate *SyncMessage_CallLinkUpdate `protobuf:"bytes,20,opt,name=callLinkUpdate" json:"callLinkUpdate,omitempty"` CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent" json:"callLogEvent,omitempty"` + DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe" json:"deleteForMe,omitempty"` } func (x *SyncMessage) Reset() { @@ -3084,6 +3088,13 @@ func (x *SyncMessage) GetCallLogEvent() *SyncMessage_CallLogEvent { return nil } +func (x *SyncMessage) GetDeleteForMe() *SyncMessage_DeleteForMe { + if x != nil { + return x.DeleteForMe + } + return nil +} + type AttachmentPointer struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3447,7 +3458,6 @@ type ContactDetails struct { Color *string `protobuf:"bytes,4,opt,name=color" json:"color,omitempty"` Verified *Verified `protobuf:"bytes,5,opt,name=verified" json:"verified,omitempty"` ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` - Blocked *bool `protobuf:"varint,7,opt,name=blocked" json:"blocked,omitempty"` ExpireTimer *uint32 `protobuf:"varint,8,opt,name=expireTimer" json:"expireTimer,omitempty"` InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` @@ -3534,13 +3544,6 @@ func (x *ContactDetails) GetProfileKey() []byte { return nil } -func (x *ContactDetails) GetBlocked() bool { - if x != nil && x.Blocked != nil { - return *x.Blocked - } - return false -} - func (x *ContactDetails) GetExpireTimer() uint32 { if x != nil && x.ExpireTimer != nil { return *x.ExpireTimer @@ -6764,6 +6767,13 @@ type SyncMessage_CallLogEvent struct { Type *SyncMessage_CallLogEvent_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_CallLogEvent_Type" json:"type,omitempty"` Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + // Data identifying a conversation. The service ID for 1:1, the group ID for + // group, or the room ID for an ad-hoc call. See also + // `CallEvent/conversationId`. + ConversationId []byte `protobuf:"bytes,3,opt,name=conversationId" json:"conversationId,omitempty"` + // An identifier for a call. Generated directly for 1:1, or derived from + // the era ID for group and ad-hoc calls. See also `CallEvent/callId`. + CallId *uint64 `protobuf:"varint,4,opt,name=callId" json:"callId,omitempty"` } func (x *SyncMessage_CallLogEvent) Reset() { @@ -6812,6 +6822,83 @@ func (x *SyncMessage_CallLogEvent) GetTimestamp() uint64 { return 0 } +func (x *SyncMessage_CallLogEvent) GetConversationId() []byte { + if x != nil { + return x.ConversationId + } + return nil +} + +func (x *SyncMessage_CallLogEvent) GetCallId() uint64 { + if x != nil && x.CallId != nil { + return *x.CallId + } + return 0 +} + +type SyncMessage_DeleteForMe struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageDeletes []*SyncMessage_DeleteForMe_MessageDeletes `protobuf:"bytes,1,rep,name=messageDeletes" json:"messageDeletes,omitempty"` + ConversationDeletes []*SyncMessage_DeleteForMe_ConversationDelete `protobuf:"bytes,2,rep,name=conversationDeletes" json:"conversationDeletes,omitempty"` + LocalOnlyConversationDeletes []*SyncMessage_DeleteForMe_LocalOnlyConversationDelete `protobuf:"bytes,3,rep,name=localOnlyConversationDeletes" json:"localOnlyConversationDeletes,omitempty"` +} + +func (x *SyncMessage_DeleteForMe) Reset() { + *x = SyncMessage_DeleteForMe{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[66] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17} +} + +func (x *SyncMessage_DeleteForMe) GetMessageDeletes() []*SyncMessage_DeleteForMe_MessageDeletes { + if x != nil { + return x.MessageDeletes + } + return nil +} + +func (x *SyncMessage_DeleteForMe) GetConversationDeletes() []*SyncMessage_DeleteForMe_ConversationDelete { + if x != nil { + return x.ConversationDeletes + } + return nil +} + +func (x *SyncMessage_DeleteForMe) GetLocalOnlyConversationDeletes() []*SyncMessage_DeleteForMe_LocalOnlyConversationDelete { + if x != nil { + return x.LocalOnlyConversationDeletes + } + return nil +} + type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6825,7 +6912,7 @@ type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6838,7 +6925,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6888,7 +6975,7 @@ type SyncMessage_Sent_StoryMessageRecipient struct { func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6901,7 +6988,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6959,7 +7046,7 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6972,7 +7059,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7044,6 +7131,360 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) GetOutputPublicKeys() [][]byte return nil } +type SyncMessage_DeleteForMe_ConversationIdentifier struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Identifier: + // + // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci + // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId + // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 + Identifier isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier `protobuf_oneof:"identifier"` +} + +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) Reset() { + *x = SyncMessage_DeleteForMe_ConversationIdentifier{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe_ConversationIdentifier) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[70] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe_ConversationIdentifier.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe_ConversationIdentifier) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 0} +} + +func (m *SyncMessage_DeleteForMe_ConversationIdentifier) GetIdentifier() isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier { + if m != nil { + return m.Identifier + } + return nil +} + +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadAci() string { + if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci); ok { + return x.ThreadAci + } + return "" +} + +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadGroupId() []byte { + if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId); ok { + return x.ThreadGroupId + } + return nil +} + +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadE164() string { + if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164); ok { + return x.ThreadE164 + } + return "" +} + +type isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier interface { + isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() +} + +type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci struct { + ThreadAci string `protobuf:"bytes,1,opt,name=threadAci,oneof"` +} + +type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId struct { + ThreadGroupId []byte `protobuf:"bytes,2,opt,name=threadGroupId,oneof"` +} + +type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 struct { + ThreadE164 string `protobuf:"bytes,3,opt,name=threadE164,oneof"` +} + +func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { +} + +func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { +} + +func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { +} + +type SyncMessage_DeleteForMe_AddressableMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Author: + // + // *SyncMessage_DeleteForMe_AddressableMessage_AuthorAci + // *SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 + Author isSyncMessage_DeleteForMe_AddressableMessage_Author `protobuf_oneof:"author"` + SentTimestamp *uint64 `protobuf:"varint,3,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` +} + +func (x *SyncMessage_DeleteForMe_AddressableMessage) Reset() { + *x = SyncMessage_DeleteForMe_AddressableMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe_AddressableMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe_AddressableMessage) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe_AddressableMessage) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[71] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe_AddressableMessage.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe_AddressableMessage) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 1} +} + +func (m *SyncMessage_DeleteForMe_AddressableMessage) GetAuthor() isSyncMessage_DeleteForMe_AddressableMessage_Author { + if m != nil { + return m.Author + } + return nil +} + +func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorAci() string { + if x, ok := x.GetAuthor().(*SyncMessage_DeleteForMe_AddressableMessage_AuthorAci); ok { + return x.AuthorAci + } + return "" +} + +func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorE164() string { + if x, ok := x.GetAuthor().(*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164); ok { + return x.AuthorE164 + } + return "" +} + +func (x *SyncMessage_DeleteForMe_AddressableMessage) GetSentTimestamp() uint64 { + if x != nil && x.SentTimestamp != nil { + return *x.SentTimestamp + } + return 0 +} + +type isSyncMessage_DeleteForMe_AddressableMessage_Author interface { + isSyncMessage_DeleteForMe_AddressableMessage_Author() +} + +type SyncMessage_DeleteForMe_AddressableMessage_AuthorAci struct { + AuthorAci string `protobuf:"bytes,1,opt,name=authorAci,oneof"` +} + +type SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 struct { + AuthorE164 string `protobuf:"bytes,2,opt,name=authorE164,oneof"` +} + +func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorAci) isSyncMessage_DeleteForMe_AddressableMessage_Author() { +} + +func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164) isSyncMessage_DeleteForMe_AddressableMessage_Author() { +} + +type SyncMessage_DeleteForMe_MessageDeletes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + Messages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=messages" json:"messages,omitempty"` +} + +func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { + *x = SyncMessage_DeleteForMe_MessageDeletes{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[72] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe_MessageDeletes.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe_MessageDeletes) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 2} +} + +func (x *SyncMessage_DeleteForMe_MessageDeletes) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { + if x != nil { + return x.Conversation + } + return nil +} + +func (x *SyncMessage_DeleteForMe_MessageDeletes) GetMessages() []*SyncMessage_DeleteForMe_AddressableMessage { + if x != nil { + return x.Messages + } + return nil +} + +type SyncMessage_DeleteForMe_ConversationDelete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + MostRecentMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=mostRecentMessages" json:"mostRecentMessages,omitempty"` + IsFullDelete *bool `protobuf:"varint,3,opt,name=isFullDelete" json:"isFullDelete,omitempty"` +} + +func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { + *x = SyncMessage_DeleteForMe_ConversationDelete{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[73] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe_ConversationDelete.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe_ConversationDelete) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 3} +} + +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { + if x != nil { + return x.Conversation + } + return nil +} + +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentMessages() []*SyncMessage_DeleteForMe_AddressableMessage { + if x != nil { + return x.MostRecentMessages + } + return nil +} + +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetIsFullDelete() bool { + if x != nil && x.IsFullDelete != nil { + return *x.IsFullDelete + } + return false +} + +type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` +} + +func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { + *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[74] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe_LocalOnlyConversationDelete.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 4} +} + +func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { + if x != nil { + return x.Conversation + } + return nil +} + type GroupContext_Member struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -7055,7 +7496,7 @@ type GroupContext_Member struct { func (x *GroupContext_Member) Reset() { *x = GroupContext_Member{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7068,7 +7509,7 @@ func (x *GroupContext_Member) String() string { func (*GroupContext_Member) ProtoMessage() {} func (x *GroupContext_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7103,7 +7544,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7116,7 +7557,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7158,7 +7599,7 @@ type GroupDetails_Avatar struct { func (x *GroupDetails_Avatar) Reset() { *x = GroupDetails_Avatar{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7171,7 +7612,7 @@ func (x *GroupDetails_Avatar) String() string { func (*GroupDetails_Avatar) ProtoMessage() {} func (x *GroupDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7212,7 +7653,7 @@ type GroupDetails_Member struct { func (x *GroupDetails_Member) Reset() { *x = GroupDetails_Member{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7225,7 +7666,7 @@ func (x *GroupDetails_Member) String() string { func (*GroupDetails_Member) ProtoMessage() {} func (x *GroupDetails_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7260,7 +7701,7 @@ type PaymentAddress_MobileCoinAddress struct { func (x *PaymentAddress_MobileCoinAddress) Reset() { *x = PaymentAddress_MobileCoinAddress{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7273,7 +7714,7 @@ func (x *PaymentAddress_MobileCoinAddress) String() string { func (*PaymentAddress_MobileCoinAddress) ProtoMessage() {} func (x *PaymentAddress_MobileCoinAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7860,7 +8301,7 @@ var file_SignalService_proto_rawDesc = []byte{ 0x67, 0x65, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x8f, 0x2b, 0x0a, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x97, 0x36, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, @@ -7944,432 +8385,519 @@ var file_SignalService_proto_rawDesc = []byte{ 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0c, 0x63, 0x61, 0x6c, - 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0xf0, 0x07, 0x0a, 0x04, 0x53, 0x65, - 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x45, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x12, 0x32, 0x0a, 0x14, - 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x34, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x6a, 0x0a, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x73, + 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x48, 0x0a, 0x0b, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, + 0x72, 0x4d, 0x65, 0x1a, 0xf0, 0x07, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x45, 0x31, 0x36, 0x34, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x34, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, + 0x0a, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x6a, 0x0a, 0x12, 0x75, 0x6e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x11, 0x69, 0x73, 0x52, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x11, 0x69, 0x73, 0x52, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3f, 0x0a, 0x0c, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x6d, 0x0a, 0x16, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, - 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, + 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, + 0x65, 0x6e, 0x74, 0x52, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x65, + 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x65, 0x64, + 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0xb8, 0x01, 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x12, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x11, - 0x69, 0x73, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x11, - 0x69, 0x73, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x12, 0x3f, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x6d, 0x0a, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, - 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x16, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x0b, 0x65, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, - 0xb8, 0x01, 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, + 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, + 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x12, 0x36, 0x0a, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, + 0x08, 0x04, 0x10, 0x05, 0x1a, 0xa9, 0x01, 0x0a, 0x15, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x4a, 0x04, - 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xa9, 0x01, 0x0a, 0x15, 0x53, - 0x74, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, - 0x69, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x73, - 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, - 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x1a, 0x63, 0x0a, 0x08, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, - 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x12, 0x21, - 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x1a, 0x53, 0x0a, 0x07, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x69, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x63, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x5d, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x53, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x03, 0x12, - 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x4b, 0x45, 0x59, 0x53, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, - 0x50, 0x4e, 0x49, 0x5f, 0x49, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0x06, 0x1a, 0x48, - 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, - 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, - 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x4a, 0x0a, 0x06, 0x56, 0x69, 0x65, 0x77, - 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, - 0x08, 0x01, 0x10, 0x02, 0x1a, 0x83, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, - 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, - 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x75, 0x6e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x1e, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, - 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, - 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, - 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, - 0x69, 0x65, 0x77, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xb3, 0x01, 0x0a, 0x14, 0x53, - 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, - 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, - 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x1f, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, - 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x01, - 0x1a, 0x50, 0x0a, 0x0c, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, + 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x13, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, + 0x74, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, + 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, + 0x69, 0x73, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x54, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x1a, 0x63, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x52, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x12, 0x21, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, + 0x65, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x53, 0x0a, 0x07, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x61, 0x63, 0x69, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, + 0x61, 0x63, 0x69, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x73, + 0x1a, 0xa5, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, + 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, + 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x4e, + 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, + 0x4b, 0x45, 0x59, 0x53, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4e, 0x49, 0x5f, 0x49, 0x44, + 0x45, 0x4e, 0x54, 0x49, 0x54, 0x59, 0x10, 0x06, 0x1a, 0x48, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, - 0x10, 0x02, 0x1a, 0xa5, 0x01, 0x0a, 0x0b, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x2b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, - 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x55, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x43, 0x41, - 0x4c, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, - 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x49, 0x46, 0x45, 0x53, 0x54, 0x10, - 0x02, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x10, 0x03, 0x1a, 0x46, 0x0a, 0x04, 0x4b, 0x65, - 0x79, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, - 0x65, 0x72, 0x1a, 0x8e, 0x02, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x12, 0x18, 0x0a, 0x07, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x4a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x6a, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, - 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x09, - 0x0a, 0x05, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x4c, 0x4f, - 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x04, 0x12, - 0x08, 0x0a, 0x04, 0x53, 0x50, 0x41, 0x4d, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x42, 0x4c, 0x4f, - 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x53, 0x50, 0x41, 0x4d, 0x10, 0x06, 0x4a, 0x04, 0x08, - 0x01, 0x10, 0x02, 0x1a, 0x8e, 0x04, 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, - 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x6d, - 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, - 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, - 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, - 0x43, 0x6f, 0x69, 0x6e, 0x1a, 0xcc, 0x02, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, - 0x6f, 0x69, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x24, 0x0a, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, - 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, - 0x4d, 0x6f, 0x62, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, - 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, - 0x32, 0x0a, 0x14, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, - 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c, - 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x26, 0x0a, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, - 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, - 0x0c, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x1a, 0xd7, 0x01, 0x0a, 0x0f, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, - 0x69, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, - 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, - 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, - 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, - 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x40, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, + 0x10, 0x02, 0x1a, 0x4a, 0x0a, 0x06, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, + 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x83, + 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x70, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x75, 0x6e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, + 0x72, 0x79, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, + 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, + 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, + 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x4a, 0x04, + 0x08, 0x04, 0x10, 0x05, 0x1a, 0xb3, 0x01, 0x0a, 0x14, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, + 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x70, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, + 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x4b, 0x65, 0x79, 0x12, + 0x48, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, + 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x72, 0x50, 0x61, 0x63, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1f, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x0a, + 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x01, 0x1a, 0x50, 0x0a, 0x0c, 0x56, 0x69, + 0x65, 0x77, 0x4f, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x63, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0xa5, 0x01, 0x0a, + 0x0b, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x55, 0x0a, + 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x5f, 0x50, 0x52, 0x4f, 0x46, + 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, + 0x5f, 0x4d, 0x41, 0x4e, 0x49, 0x46, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x53, + 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x10, 0x03, 0x1a, 0x46, 0x0a, 0x04, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26, 0x0a, 0x0e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x1a, 0x8e, 0x02, 0x0a, + 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x41, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x41, 0x63, 0x69, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, + 0x4a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, + 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x6a, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x4c, 0x4f, 0x43, + 0x4b, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, + 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x50, 0x41, + 0x4d, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x41, 0x4e, 0x44, + 0x5f, 0x53, 0x50, 0x41, 0x4d, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x8e, 0x04, + 0x0a, 0x0f, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, + 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, + 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x1a, 0xcc, + 0x02, 0x0a, 0x0a, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x2a, 0x0a, + 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, + 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x12, + 0x1e, 0x0a, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x4d, 0x6f, 0x62, 0x12, + 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x6c, 0x65, 0x64, + 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, + 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x70, 0x65, + 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x0f, 0x0a, + 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x1a, 0xd7, + 0x01, 0x0a, 0x0f, 0x50, 0x6e, 0x69, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, + 0x79, 0x50, 0x61, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x22, 0x0a, 0x0c, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, + 0x12, 0x34, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, + 0x62, 0x65, 0x72, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x15, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x72, 0x74, 0x4b, 0x79, 0x62, 0x65, 0x72, + 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, + 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, + 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3d, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x22, 0x59, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, - 0x55, 0x44, 0x49, 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, - 0x49, 0x44, 0x45, 0x4f, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x47, - 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x41, - 0x44, 0x5f, 0x48, 0x4f, 0x43, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x04, 0x22, 0x3e, 0x0a, 0x09, - 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, - 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, - 0x0a, 0x08, 0x4f, 0x55, 0x54, 0x47, 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, - 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, - 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, - 0x45, 0x54, 0x45, 0x10, 0x03, 0x1a, 0xb2, 0x01, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, - 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, - 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, - 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, - 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x42, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1e, 0x0a, 0x04, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0a, - 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x01, 0x1a, 0x95, 0x01, 0x0a, 0x0c, 0x43, - 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, + 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x59, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x55, 0x44, 0x49, 0x4f, 0x5f, 0x43, + 0x41, 0x4c, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x5f, 0x43, + 0x41, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x43, + 0x41, 0x4c, 0x4c, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x44, 0x5f, 0x48, 0x4f, 0x43, 0x5f, + 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x04, 0x22, 0x3e, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x44, + 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, + 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x55, 0x54, 0x47, + 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, + 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, + 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x1a, + 0xb2, 0x01, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, + 0x12, 0x42, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, + 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x1e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, + 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, + 0x54, 0x45, 0x10, 0x01, 0x1a, 0xf9, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, + 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x22, 0x49, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, + 0x05, 0x43, 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x52, 0x4b, + 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, + 0x4d, 0x41, 0x52, 0x4b, 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x49, + 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, + 0x1a, 0xd7, 0x09, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, + 0x12, 0x5d, 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, + 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, + 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, + 0x6b, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, + 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, 0x86, 0x01, 0x0a, + 0x1c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, + 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x1c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, + 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x73, 0x1a, 0x90, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x12, 0x1e, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, + 0x12, 0x26, 0x0a, 0x0d, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0a, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x45, 0x31, 0x36, 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x86, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1e, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x12, + 0x20, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x31, 0x36, + 0x34, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x1a, 0xca, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, + 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x25, 0x0a, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x12, 0x12, - 0x0a, 0x0e, 0x4d, 0x41, 0x52, 0x4b, 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, - 0x10, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x22, 0xe3, - 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x06, - 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, - 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, - 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, - 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, - 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x12, 0x38, 0x0a, 0x17, - 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, - 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x69, - 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, 0x75, - 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, - 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, - 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, - 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, - 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x11, 0x0a, - 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, - 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x4c, 0x45, 0x53, 0x53, 0x10, 0x02, - 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x04, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x42, - 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, - 0x08, 0x12, 0x10, 0x13, 0x22, 0xf0, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, - 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, - 0x38, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, - 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, - 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, - 0x55, 0x49, 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, - 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, - 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, - 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, - 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, - 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, - 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, - 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, - 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, - 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, - 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, - 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, - 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, + 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x1a, 0x86, + 0x02, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, + 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x69, 0x0a, 0x12, 0x6d, 0x6f, 0x73, 0x74, + 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x12, 0x6d, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x46, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x46, 0x75, 0x6c, + 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x80, 0x01, 0x0a, 0x1b, 0x4c, 0x6f, 0x63, 0x61, + 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, + 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, + 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x22, 0xe3, 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, + 0x63, 0x64, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, + 0x64, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xc9, 0x01, 0x0a, - 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x5f, 0x0a, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, - 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6d, - 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x1a, 0x4b, 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x09, 0x0a, - 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, 0x44, 0x65, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, - 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x13, - 0x50, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, - 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x75, 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, + 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, + 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, + 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x13, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x6c, 0x4d, 0x61, 0x63, 0x12, 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, + 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, + 0x0a, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, + 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, + 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, + 0x45, 0x52, 0x4c, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, + 0x04, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x42, 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0xf0, 0x02, 0x0a, + 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, + 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, + 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, + 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, + 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, + 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, + 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x55, 0x49, 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, + 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, + 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, + 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, + 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xa5, 0x03, + 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, + 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, + 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4a, + 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, + 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, + 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, + 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, + 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x5f, 0x0a, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, + 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, + 0x00, 0x52, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x1a, 0x4b, 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, + 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x42, 0x09, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, + 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x22, 0x45, 0x0a, 0x13, 0x50, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, + 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, } var ( @@ -8385,109 +8913,115 @@ func file_SignalService_proto_rawDescGZIP() []byte { } var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 27) -var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 74) +var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 80) var file_SignalService_proto_goTypes = []interface{}{ - (Envelope_Type)(0), // 0: signalservice.Envelope.Type - (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type - (CallMessage_Hangup_Type)(0), // 2: signalservice.CallMessage.Hangup.Type - (CallMessage_Opaque_Urgency)(0), // 3: signalservice.CallMessage.Opaque.Urgency - (BodyRange_Style)(0), // 4: signalservice.BodyRange.Style - (DataMessage_Flags)(0), // 5: signalservice.DataMessage.Flags - (DataMessage_ProtocolVersion)(0), // 6: signalservice.DataMessage.ProtocolVersion - (DataMessage_Quote_Type)(0), // 7: signalservice.DataMessage.Quote.Type - (DataMessage_Contact_Phone_Type)(0), // 8: signalservice.DataMessage.Contact.Phone.Type - (DataMessage_Contact_Email_Type)(0), // 9: signalservice.DataMessage.Contact.Email.Type - (DataMessage_Contact_PostalAddress_Type)(0), // 10: signalservice.DataMessage.Contact.PostalAddress.Type - (DataMessage_Payment_Activation_Type)(0), // 11: signalservice.DataMessage.Payment.Activation.Type - (ReceiptMessage_Type)(0), // 12: signalservice.ReceiptMessage.Type - (TypingMessage_Action)(0), // 13: signalservice.TypingMessage.Action - (TextAttachment_Style)(0), // 14: signalservice.TextAttachment.Style - (Verified_State)(0), // 15: signalservice.Verified.State - (SyncMessage_Request_Type)(0), // 16: signalservice.SyncMessage.Request.Type - (SyncMessage_StickerPackOperation_Type)(0), // 17: signalservice.SyncMessage.StickerPackOperation.Type - (SyncMessage_FetchLatest_Type)(0), // 18: signalservice.SyncMessage.FetchLatest.Type - (SyncMessage_MessageRequestResponse_Type)(0), // 19: signalservice.SyncMessage.MessageRequestResponse.Type - (SyncMessage_CallEvent_Type)(0), // 20: signalservice.SyncMessage.CallEvent.Type - (SyncMessage_CallEvent_Direction)(0), // 21: signalservice.SyncMessage.CallEvent.Direction - (SyncMessage_CallEvent_Event)(0), // 22: signalservice.SyncMessage.CallEvent.Event - (SyncMessage_CallLinkUpdate_Type)(0), // 23: signalservice.SyncMessage.CallLinkUpdate.Type - (SyncMessage_CallLogEvent_Type)(0), // 24: signalservice.SyncMessage.CallLogEvent.Type - (AttachmentPointer_Flags)(0), // 25: signalservice.AttachmentPointer.Flags - (GroupContext_Type)(0), // 26: signalservice.GroupContext.Type - (*Envelope)(nil), // 27: signalservice.Envelope - (*Content)(nil), // 28: signalservice.Content - (*CallMessage)(nil), // 29: signalservice.CallMessage - (*BodyRange)(nil), // 30: signalservice.BodyRange - (*DataMessage)(nil), // 31: signalservice.DataMessage - (*NullMessage)(nil), // 32: signalservice.NullMessage - (*ReceiptMessage)(nil), // 33: signalservice.ReceiptMessage - (*TypingMessage)(nil), // 34: signalservice.TypingMessage - (*StoryMessage)(nil), // 35: signalservice.StoryMessage - (*Preview)(nil), // 36: signalservice.Preview - (*TextAttachment)(nil), // 37: signalservice.TextAttachment - (*Verified)(nil), // 38: signalservice.Verified - (*SyncMessage)(nil), // 39: signalservice.SyncMessage - (*AttachmentPointer)(nil), // 40: signalservice.AttachmentPointer - (*GroupContext)(nil), // 41: signalservice.GroupContext - (*GroupContextV2)(nil), // 42: signalservice.GroupContextV2 - (*ContactDetails)(nil), // 43: signalservice.ContactDetails - (*GroupDetails)(nil), // 44: signalservice.GroupDetails - (*PaymentAddress)(nil), // 45: signalservice.PaymentAddress - (*DecryptionErrorMessage)(nil), // 46: signalservice.DecryptionErrorMessage - (*PniSignatureMessage)(nil), // 47: signalservice.PniSignatureMessage - (*EditMessage)(nil), // 48: signalservice.EditMessage - (*CallMessage_Offer)(nil), // 49: signalservice.CallMessage.Offer - (*CallMessage_Answer)(nil), // 50: signalservice.CallMessage.Answer - (*CallMessage_IceUpdate)(nil), // 51: signalservice.CallMessage.IceUpdate - (*CallMessage_Busy)(nil), // 52: signalservice.CallMessage.Busy - (*CallMessage_Hangup)(nil), // 53: signalservice.CallMessage.Hangup - (*CallMessage_Opaque)(nil), // 54: signalservice.CallMessage.Opaque - (*DataMessage_Quote)(nil), // 55: signalservice.DataMessage.Quote - (*DataMessage_Contact)(nil), // 56: signalservice.DataMessage.Contact - (*DataMessage_Sticker)(nil), // 57: signalservice.DataMessage.Sticker - (*DataMessage_Reaction)(nil), // 58: signalservice.DataMessage.Reaction - (*DataMessage_Delete)(nil), // 59: signalservice.DataMessage.Delete - (*DataMessage_GroupCallUpdate)(nil), // 60: signalservice.DataMessage.GroupCallUpdate - (*DataMessage_StoryContext)(nil), // 61: signalservice.DataMessage.StoryContext - (*DataMessage_Payment)(nil), // 62: signalservice.DataMessage.Payment - (*DataMessage_GiftBadge)(nil), // 63: signalservice.DataMessage.GiftBadge - (*DataMessage_Quote_QuotedAttachment)(nil), // 64: signalservice.DataMessage.Quote.QuotedAttachment - (*DataMessage_Contact_Name)(nil), // 65: signalservice.DataMessage.Contact.Name - (*DataMessage_Contact_Phone)(nil), // 66: signalservice.DataMessage.Contact.Phone - (*DataMessage_Contact_Email)(nil), // 67: signalservice.DataMessage.Contact.Email - (*DataMessage_Contact_PostalAddress)(nil), // 68: signalservice.DataMessage.Contact.PostalAddress - (*DataMessage_Contact_Avatar)(nil), // 69: signalservice.DataMessage.Contact.Avatar - (*DataMessage_Payment_Amount)(nil), // 70: signalservice.DataMessage.Payment.Amount - (*DataMessage_Payment_Notification)(nil), // 71: signalservice.DataMessage.Payment.Notification - (*DataMessage_Payment_Activation)(nil), // 72: signalservice.DataMessage.Payment.Activation - (*DataMessage_Payment_Amount_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Amount.MobileCoin - (*DataMessage_Payment_Notification_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Notification.MobileCoin - (*TextAttachment_Gradient)(nil), // 75: signalservice.TextAttachment.Gradient - (*SyncMessage_Sent)(nil), // 76: signalservice.SyncMessage.Sent - (*SyncMessage_Contacts)(nil), // 77: signalservice.SyncMessage.Contacts - (*SyncMessage_Blocked)(nil), // 78: signalservice.SyncMessage.Blocked - (*SyncMessage_Request)(nil), // 79: signalservice.SyncMessage.Request - (*SyncMessage_Read)(nil), // 80: signalservice.SyncMessage.Read - (*SyncMessage_Viewed)(nil), // 81: signalservice.SyncMessage.Viewed - (*SyncMessage_Configuration)(nil), // 82: signalservice.SyncMessage.Configuration - (*SyncMessage_StickerPackOperation)(nil), // 83: signalservice.SyncMessage.StickerPackOperation - (*SyncMessage_ViewOnceOpen)(nil), // 84: signalservice.SyncMessage.ViewOnceOpen - (*SyncMessage_FetchLatest)(nil), // 85: signalservice.SyncMessage.FetchLatest - (*SyncMessage_Keys)(nil), // 86: signalservice.SyncMessage.Keys - (*SyncMessage_MessageRequestResponse)(nil), // 87: signalservice.SyncMessage.MessageRequestResponse - (*SyncMessage_OutgoingPayment)(nil), // 88: signalservice.SyncMessage.OutgoingPayment - (*SyncMessage_PniChangeNumber)(nil), // 89: signalservice.SyncMessage.PniChangeNumber - (*SyncMessage_CallEvent)(nil), // 90: signalservice.SyncMessage.CallEvent - (*SyncMessage_CallLinkUpdate)(nil), // 91: signalservice.SyncMessage.CallLinkUpdate - (*SyncMessage_CallLogEvent)(nil), // 92: signalservice.SyncMessage.CallLogEvent - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 93: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 94: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 95: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*GroupContext_Member)(nil), // 96: signalservice.GroupContext.Member - (*ContactDetails_Avatar)(nil), // 97: signalservice.ContactDetails.Avatar - (*GroupDetails_Avatar)(nil), // 98: signalservice.GroupDetails.Avatar - (*GroupDetails_Member)(nil), // 99: signalservice.GroupDetails.Member - (*PaymentAddress_MobileCoinAddress)(nil), // 100: signalservice.PaymentAddress.MobileCoinAddress + (Envelope_Type)(0), // 0: signalservice.Envelope.Type + (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type + (CallMessage_Hangup_Type)(0), // 2: signalservice.CallMessage.Hangup.Type + (CallMessage_Opaque_Urgency)(0), // 3: signalservice.CallMessage.Opaque.Urgency + (BodyRange_Style)(0), // 4: signalservice.BodyRange.Style + (DataMessage_Flags)(0), // 5: signalservice.DataMessage.Flags + (DataMessage_ProtocolVersion)(0), // 6: signalservice.DataMessage.ProtocolVersion + (DataMessage_Quote_Type)(0), // 7: signalservice.DataMessage.Quote.Type + (DataMessage_Contact_Phone_Type)(0), // 8: signalservice.DataMessage.Contact.Phone.Type + (DataMessage_Contact_Email_Type)(0), // 9: signalservice.DataMessage.Contact.Email.Type + (DataMessage_Contact_PostalAddress_Type)(0), // 10: signalservice.DataMessage.Contact.PostalAddress.Type + (DataMessage_Payment_Activation_Type)(0), // 11: signalservice.DataMessage.Payment.Activation.Type + (ReceiptMessage_Type)(0), // 12: signalservice.ReceiptMessage.Type + (TypingMessage_Action)(0), // 13: signalservice.TypingMessage.Action + (TextAttachment_Style)(0), // 14: signalservice.TextAttachment.Style + (Verified_State)(0), // 15: signalservice.Verified.State + (SyncMessage_Request_Type)(0), // 16: signalservice.SyncMessage.Request.Type + (SyncMessage_StickerPackOperation_Type)(0), // 17: signalservice.SyncMessage.StickerPackOperation.Type + (SyncMessage_FetchLatest_Type)(0), // 18: signalservice.SyncMessage.FetchLatest.Type + (SyncMessage_MessageRequestResponse_Type)(0), // 19: signalservice.SyncMessage.MessageRequestResponse.Type + (SyncMessage_CallEvent_Type)(0), // 20: signalservice.SyncMessage.CallEvent.Type + (SyncMessage_CallEvent_Direction)(0), // 21: signalservice.SyncMessage.CallEvent.Direction + (SyncMessage_CallEvent_Event)(0), // 22: signalservice.SyncMessage.CallEvent.Event + (SyncMessage_CallLinkUpdate_Type)(0), // 23: signalservice.SyncMessage.CallLinkUpdate.Type + (SyncMessage_CallLogEvent_Type)(0), // 24: signalservice.SyncMessage.CallLogEvent.Type + (AttachmentPointer_Flags)(0), // 25: signalservice.AttachmentPointer.Flags + (GroupContext_Type)(0), // 26: signalservice.GroupContext.Type + (*Envelope)(nil), // 27: signalservice.Envelope + (*Content)(nil), // 28: signalservice.Content + (*CallMessage)(nil), // 29: signalservice.CallMessage + (*BodyRange)(nil), // 30: signalservice.BodyRange + (*DataMessage)(nil), // 31: signalservice.DataMessage + (*NullMessage)(nil), // 32: signalservice.NullMessage + (*ReceiptMessage)(nil), // 33: signalservice.ReceiptMessage + (*TypingMessage)(nil), // 34: signalservice.TypingMessage + (*StoryMessage)(nil), // 35: signalservice.StoryMessage + (*Preview)(nil), // 36: signalservice.Preview + (*TextAttachment)(nil), // 37: signalservice.TextAttachment + (*Verified)(nil), // 38: signalservice.Verified + (*SyncMessage)(nil), // 39: signalservice.SyncMessage + (*AttachmentPointer)(nil), // 40: signalservice.AttachmentPointer + (*GroupContext)(nil), // 41: signalservice.GroupContext + (*GroupContextV2)(nil), // 42: signalservice.GroupContextV2 + (*ContactDetails)(nil), // 43: signalservice.ContactDetails + (*GroupDetails)(nil), // 44: signalservice.GroupDetails + (*PaymentAddress)(nil), // 45: signalservice.PaymentAddress + (*DecryptionErrorMessage)(nil), // 46: signalservice.DecryptionErrorMessage + (*PniSignatureMessage)(nil), // 47: signalservice.PniSignatureMessage + (*EditMessage)(nil), // 48: signalservice.EditMessage + (*CallMessage_Offer)(nil), // 49: signalservice.CallMessage.Offer + (*CallMessage_Answer)(nil), // 50: signalservice.CallMessage.Answer + (*CallMessage_IceUpdate)(nil), // 51: signalservice.CallMessage.IceUpdate + (*CallMessage_Busy)(nil), // 52: signalservice.CallMessage.Busy + (*CallMessage_Hangup)(nil), // 53: signalservice.CallMessage.Hangup + (*CallMessage_Opaque)(nil), // 54: signalservice.CallMessage.Opaque + (*DataMessage_Quote)(nil), // 55: signalservice.DataMessage.Quote + (*DataMessage_Contact)(nil), // 56: signalservice.DataMessage.Contact + (*DataMessage_Sticker)(nil), // 57: signalservice.DataMessage.Sticker + (*DataMessage_Reaction)(nil), // 58: signalservice.DataMessage.Reaction + (*DataMessage_Delete)(nil), // 59: signalservice.DataMessage.Delete + (*DataMessage_GroupCallUpdate)(nil), // 60: signalservice.DataMessage.GroupCallUpdate + (*DataMessage_StoryContext)(nil), // 61: signalservice.DataMessage.StoryContext + (*DataMessage_Payment)(nil), // 62: signalservice.DataMessage.Payment + (*DataMessage_GiftBadge)(nil), // 63: signalservice.DataMessage.GiftBadge + (*DataMessage_Quote_QuotedAttachment)(nil), // 64: signalservice.DataMessage.Quote.QuotedAttachment + (*DataMessage_Contact_Name)(nil), // 65: signalservice.DataMessage.Contact.Name + (*DataMessage_Contact_Phone)(nil), // 66: signalservice.DataMessage.Contact.Phone + (*DataMessage_Contact_Email)(nil), // 67: signalservice.DataMessage.Contact.Email + (*DataMessage_Contact_PostalAddress)(nil), // 68: signalservice.DataMessage.Contact.PostalAddress + (*DataMessage_Contact_Avatar)(nil), // 69: signalservice.DataMessage.Contact.Avatar + (*DataMessage_Payment_Amount)(nil), // 70: signalservice.DataMessage.Payment.Amount + (*DataMessage_Payment_Notification)(nil), // 71: signalservice.DataMessage.Payment.Notification + (*DataMessage_Payment_Activation)(nil), // 72: signalservice.DataMessage.Payment.Activation + (*DataMessage_Payment_Amount_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Amount.MobileCoin + (*DataMessage_Payment_Notification_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Notification.MobileCoin + (*TextAttachment_Gradient)(nil), // 75: signalservice.TextAttachment.Gradient + (*SyncMessage_Sent)(nil), // 76: signalservice.SyncMessage.Sent + (*SyncMessage_Contacts)(nil), // 77: signalservice.SyncMessage.Contacts + (*SyncMessage_Blocked)(nil), // 78: signalservice.SyncMessage.Blocked + (*SyncMessage_Request)(nil), // 79: signalservice.SyncMessage.Request + (*SyncMessage_Read)(nil), // 80: signalservice.SyncMessage.Read + (*SyncMessage_Viewed)(nil), // 81: signalservice.SyncMessage.Viewed + (*SyncMessage_Configuration)(nil), // 82: signalservice.SyncMessage.Configuration + (*SyncMessage_StickerPackOperation)(nil), // 83: signalservice.SyncMessage.StickerPackOperation + (*SyncMessage_ViewOnceOpen)(nil), // 84: signalservice.SyncMessage.ViewOnceOpen + (*SyncMessage_FetchLatest)(nil), // 85: signalservice.SyncMessage.FetchLatest + (*SyncMessage_Keys)(nil), // 86: signalservice.SyncMessage.Keys + (*SyncMessage_MessageRequestResponse)(nil), // 87: signalservice.SyncMessage.MessageRequestResponse + (*SyncMessage_OutgoingPayment)(nil), // 88: signalservice.SyncMessage.OutgoingPayment + (*SyncMessage_PniChangeNumber)(nil), // 89: signalservice.SyncMessage.PniChangeNumber + (*SyncMessage_CallEvent)(nil), // 90: signalservice.SyncMessage.CallEvent + (*SyncMessage_CallLinkUpdate)(nil), // 91: signalservice.SyncMessage.CallLinkUpdate + (*SyncMessage_CallLogEvent)(nil), // 92: signalservice.SyncMessage.CallLogEvent + (*SyncMessage_DeleteForMe)(nil), // 93: signalservice.SyncMessage.DeleteForMe + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 94: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 95: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 96: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*SyncMessage_DeleteForMe_ConversationIdentifier)(nil), // 97: signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + (*SyncMessage_DeleteForMe_AddressableMessage)(nil), // 98: signalservice.SyncMessage.DeleteForMe.AddressableMessage + (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 99: signalservice.SyncMessage.DeleteForMe.MessageDeletes + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 100: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 101: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*GroupContext_Member)(nil), // 102: signalservice.GroupContext.Member + (*ContactDetails_Avatar)(nil), // 103: signalservice.ContactDetails.Avatar + (*GroupDetails_Avatar)(nil), // 104: signalservice.GroupDetails.Avatar + (*GroupDetails_Member)(nil), // 105: signalservice.GroupDetails.Member + (*PaymentAddress_MobileCoinAddress)(nil), // 106: signalservice.PaymentAddress.MobileCoinAddress } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type @@ -8549,58 +9083,67 @@ var file_SignalService_proto_depIdxs = []int32{ 90, // 56: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent 91, // 57: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate 92, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 26, // 59: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type - 96, // 60: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member - 40, // 61: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer - 97, // 62: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 38, // 63: signalservice.ContactDetails.verified:type_name -> signalservice.Verified - 99, // 64: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member - 98, // 65: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar - 100, // 66: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress - 31, // 67: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 1, // 68: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 69: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 70: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 64, // 71: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 30, // 72: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 73: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 65, // 74: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 66, // 75: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 67, // 76: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 68, // 77: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 69, // 78: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 40, // 79: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 71, // 80: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 72, // 81: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 40, // 82: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 83: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 84: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 85: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 40, // 86: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 73, // 87: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 74, // 88: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 11, // 89: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 31, // 90: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 93, // 91: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 35, // 92: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 94, // 93: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 48, // 94: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 40, // 95: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 16, // 96: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 17, // 97: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 18, // 98: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 19, // 99: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 95, // 100: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 20, // 101: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 21, // 102: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 22, // 103: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 23, // 104: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type - 24, // 105: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 106, // [106:106] is the sub-list for method output_type - 106, // [106:106] is the sub-list for method input_type - 106, // [106:106] is the sub-list for extension type_name - 106, // [106:106] is the sub-list for extension extendee - 0, // [0:106] is the sub-list for field type_name + 93, // 59: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe + 26, // 60: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type + 102, // 61: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member + 40, // 62: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer + 103, // 63: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 38, // 64: signalservice.ContactDetails.verified:type_name -> signalservice.Verified + 105, // 65: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member + 104, // 66: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar + 106, // 67: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress + 31, // 68: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 1, // 69: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 70: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 71: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 64, // 72: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 30, // 73: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 74: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 65, // 75: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 66, // 76: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 67, // 77: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 68, // 78: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 69, // 79: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 80: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 71, // 81: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 72, // 82: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 40, // 83: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 84: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 85: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 86: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 40, // 87: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 73, // 88: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 74, // 89: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 11, // 90: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 31, // 91: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 94, // 92: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 93: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 95, // 94: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 48, // 95: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 96: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 16, // 97: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 17, // 98: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 18, // 99: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 19, // 100: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 96, // 101: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 20, // 102: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 21, // 103: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 22, // 104: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 23, // 105: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 24, // 106: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 99, // 107: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes + 100, // 108: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 101, // 109: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 97, // 110: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 98, // 111: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 97, // 112: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 98, // 113: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 97, // 114: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 115, // [115:115] is the sub-list for method output_type + 115, // [115:115] is the sub-list for method input_type + 115, // [115:115] is the sub-list for extension type_name + 115, // [115:115] is the sub-list for extension extendee + 0, // [0:115] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -9402,7 +9945,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SyncMessage_Sent_UnidentifiedDeliveryStatus); i { + switch v := v.(*SyncMessage_DeleteForMe); i { case 0: return &v.state case 1: @@ -9414,7 +9957,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SyncMessage_Sent_StoryMessageRecipient); i { + switch v := v.(*SyncMessage_Sent_UnidentifiedDeliveryStatus); i { case 0: return &v.state case 1: @@ -9426,7 +9969,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SyncMessage_OutgoingPayment_MobileCoin); i { + switch v := v.(*SyncMessage_Sent_StoryMessageRecipient); i { case 0: return &v.state case 1: @@ -9438,7 +9981,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupContext_Member); i { + switch v := v.(*SyncMessage_OutgoingPayment_MobileCoin); i { case 0: return &v.state case 1: @@ -9450,7 +9993,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContactDetails_Avatar); i { + switch v := v.(*SyncMessage_DeleteForMe_ConversationIdentifier); i { case 0: return &v.state case 1: @@ -9462,7 +10005,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupDetails_Avatar); i { + switch v := v.(*SyncMessage_DeleteForMe_AddressableMessage); i { case 0: return &v.state case 1: @@ -9474,7 +10017,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupDetails_Member); i { + switch v := v.(*SyncMessage_DeleteForMe_MessageDeletes); i { case 0: return &v.state case 1: @@ -9486,6 +10029,78 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SyncMessage_DeleteForMe_ConversationDelete); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SyncMessage_DeleteForMe_LocalOnlyConversationDelete); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupContext_Member); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContactDetails_Avatar); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupDetails_Avatar); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupDetails_Member); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PaymentAddress_MobileCoinAddress); i { case 0: return &v.state @@ -9530,13 +10145,22 @@ func file_SignalService_proto_init() { file_SignalService_proto_msgTypes[61].OneofWrappers = []interface{}{ (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } + file_SignalService_proto_msgTypes[70].OneofWrappers = []interface{}{ + (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci)(nil), + (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId)(nil), + (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164)(nil), + } + file_SignalService_proto_msgTypes[71].OneofWrappers = []interface{}{ + (*SyncMessage_DeleteForMe_AddressableMessage_AuthorAci)(nil), + (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_SignalService_proto_rawDesc, NumEnums: 27, - NumMessages: 74, + NumMessages: 80, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 2cf83ba..dceaf0a 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -637,12 +637,57 @@ message SyncMessage { message CallLogEvent { enum Type { - CLEAR = 0; - MARKED_AS_READ = 1; + CLEAR = 0; + MARKED_AS_READ = 1; + MARKED_AS_READ_IN_CONVERSATION = 2; } - optional Type type = 1; - optional uint64 timestamp = 2; + optional Type type = 1; + optional uint64 timestamp = 2; + /* Data identifying a conversation. The service ID for 1:1, the group ID for + * group, or the room ID for an ad-hoc call. See also + * `CallEvent/conversationId`. */ + optional bytes conversationId = 3; + /* An identifier for a call. Generated directly for 1:1, or derived from + * the era ID for group and ad-hoc calls. See also `CallEvent/callId`. */ + optional uint64 callId = 4; + } + + message DeleteForMe { + message ConversationIdentifier { + oneof identifier { + string threadAci = 1; + bytes threadGroupId = 2; + string threadE164 = 3; + } + } + + message AddressableMessage { + oneof author { + string authorAci = 1; + string authorE164 = 2; + } + optional uint64 sentTimestamp = 3; + } + + message MessageDeletes { + optional ConversationIdentifier conversation = 1; + repeated AddressableMessage messages = 2; + } + + message ConversationDelete { + optional ConversationIdentifier conversation = 1; + repeated AddressableMessage mostRecentMessages = 2; + optional bool isFullDelete = 3; + } + + message LocalOnlyConversationDelete { + optional ConversationIdentifier conversation = 1; + } + + repeated MessageDeletes messageDeletes = 1; + repeated ConversationDelete conversationDeletes = 2; + repeated LocalOnlyConversationDelete localOnlyConversationDeletes = 3; } optional Sent sent = 1; @@ -666,6 +711,7 @@ message SyncMessage { optional CallEvent callEvent = 19; optional CallLinkUpdate callLinkUpdate = 20; optional CallLogEvent callLogEvent = 21; + optional DeleteForMe deleteForMe = 22; } message AttachmentPointer { @@ -741,7 +787,7 @@ message ContactDetails { optional string color = 4; optional Verified verified = 5; optional bytes profileKey = 6; - optional bool blocked = 7; + reserved /*blocked*/ 7; optional uint32 expireTimer = 8; optional uint32 inboxPosition = 10; optional bool archived = 11; diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index 34f48be..e9c864a 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: StickerResources.proto diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index f4894ec..aeb2cbd 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: StorageService.proto @@ -832,7 +832,9 @@ type ContactRecord struct { SystemFamilyName string `protobuf:"bytes,18,opt,name=systemFamilyName,proto3" json:"systemFamilyName,omitempty"` SystemNickname string `protobuf:"bytes,19,opt,name=systemNickname,proto3" json:"systemNickname,omitempty"` Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` - PniSignatureVerified bool `protobuf:"varint,21,opt,name=pniSignatureVerified,proto3" json:"pniSignatureVerified,omitempty"` // NEXT ID: 22 + PniSignatureVerified bool `protobuf:"varint,21,opt,name=pniSignatureVerified,proto3" json:"pniSignatureVerified,omitempty"` + Nickname *ContactRecord_Name `protobuf:"bytes,22,opt,name=nickname,proto3" json:"nickname,omitempty"` + Note string `protobuf:"bytes,23,opt,name=note,proto3" json:"note,omitempty"` // NEXT ID: 24 } func (x *ContactRecord) Reset() { @@ -1014,6 +1016,20 @@ func (x *ContactRecord) GetPniSignatureVerified() bool { return false } +func (x *ContactRecord) GetNickname() *ContactRecord_Name { + if x != nil { + return x.Nickname + } + return nil +} + +func (x *ContactRecord) GetNote() string { + if x != nil { + return x.Note + } + return "" +} + type GroupV1Record struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1704,6 +1720,61 @@ func (x *ManifestRecord_Identifier) GetType() ManifestRecord_Identifier_Type { return ManifestRecord_Identifier_UNKNOWN } +type ContactRecord_Name struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Given string `protobuf:"bytes,1,opt,name=given,proto3" json:"given,omitempty"` + Family string `protobuf:"bytes,2,opt,name=family,proto3" json:"family,omitempty"` +} + +func (x *ContactRecord_Name) Reset() { + *x = ContactRecord_Name{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContactRecord_Name) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactRecord_Name) ProtoMessage() {} + +func (x *ContactRecord_Name) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContactRecord_Name.ProtoReflect.Descriptor instead. +func (*ContactRecord_Name) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{7, 0} +} + +func (x *ContactRecord_Name) GetGiven() string { + if x != nil { + return x.Given + } + return "" +} + +func (x *ContactRecord_Name) GetFamily() string { + if x != nil { + return x.Family + } + return "" +} + type AccountRecord_PinnedConversation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1720,7 +1791,7 @@ type AccountRecord_PinnedConversation struct { func (x *AccountRecord_PinnedConversation) Reset() { *x = AccountRecord_PinnedConversation{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1733,7 +1804,7 @@ func (x *AccountRecord_PinnedConversation) String() string { func (*AccountRecord_PinnedConversation) ProtoMessage() {} func (x *AccountRecord_PinnedConversation) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1814,7 +1885,7 @@ type AccountRecord_UsernameLink struct { func (x *AccountRecord_UsernameLink) Reset() { *x = AccountRecord_UsernameLink{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1827,7 +1898,7 @@ func (x *AccountRecord_UsernameLink) String() string { func (*AccountRecord_UsernameLink) ProtoMessage() {} func (x *AccountRecord_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1876,7 +1947,7 @@ type AccountRecord_PinnedConversation_Contact struct { func (x *AccountRecord_PinnedConversation_Contact) Reset() { *x = AccountRecord_PinnedConversation_Contact{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1889,7 +1960,7 @@ func (x *AccountRecord_PinnedConversation_Contact) String() string { func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1996,7 +2067,7 @@ var file_StorageService_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x15, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x22, 0xc1, 0x06, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, + 0x22, 0xca, 0x07, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, @@ -2044,226 +2115,235 @@ var file_StorageService_proto_rawDesc = []byte{ 0x64, 0x64, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x22, 0x3a, 0x0a, 0x0d, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x02, 0x22, 0xcd, 0x01, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, - 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, - 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, - 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, - 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x22, 0xce, 0x03, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, - 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, - 0x72, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, - 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, - 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, - 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, - 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x3d, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x08, 0x6e, + 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x1a, 0x34, 0x0a, 0x04, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x61, 0x6d, + 0x69, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, + 0x79, 0x22, 0x3a, 0x0a, 0x0d, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, + 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, + 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x22, 0xcd, 0x01, + 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, + 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, + 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, + 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, + 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, + 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, + 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, - 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, - 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, - 0x74, 0x6f, 0x72, 0x79, 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, - 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, - 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, - 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x37, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, - 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, - 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x4a, - 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x3e, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, - 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, - 0x74, 0x72, 0x6f, 0x70, 0x79, 0x22, 0x9a, 0x12, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, - 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, - 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, - 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, - 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x6e, - 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, - 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x72, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, - 0x36, 0x0a, 0x16, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, - 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x16, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, - 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, - 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, - 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x16, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, - 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, - 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, - 0x6b, 0x0a, 0x16, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, - 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x33, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x68, - 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, - 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x16, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x13, - 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, - 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x61, - 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, - 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x70, 0x69, - 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x73, 0x12, 0x33, 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, - 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, - 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x28, - 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, - 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, - 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, - 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x36, 0x0a, 0x16, - 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x18, 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, - 0x6d, 0x6f, 0x6a, 0x69, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x72, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, - 0x64, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x72, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, - 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x16, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, - 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x73, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, - 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, - 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x36, - 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, - 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, - 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, - 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, - 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, - 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, - 0x53, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x12, 0x3a, - 0x0a, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, - 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1d, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, - 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, - 0x6f, 0x6f, 0x6c, 0x52, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, - 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, + 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, + 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xce, 0x03, + 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, + 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, + 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, + 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, + 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, + 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, + 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x1c, 0x64, + 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, + 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x50, 0x0a, + 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, + 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x22, + 0x37, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, + 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x3e, + 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x22, 0x9a, + 0x12, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, + 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, + 0x0a, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, + 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, + 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, + 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x65, 0x61, 0x6c, + 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, + 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, + 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x16, + 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x64, + 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x6e, 0x6f, + 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, + 0x72, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, + 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, 0x6b, 0x0a, 0x16, 0x70, 0x68, 0x6f, 0x6e, + 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, + 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x16, 0x70, + 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, + 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, + 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, + 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x61, 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, + 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, + 0x72, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x73, 0x12, 0x33, + 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, + 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x36, 0x0a, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, + 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x18, + 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, + 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x12, 0x22, 0x0a, + 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, 0x64, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x43, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x70, 0x6c, + 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, + 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x4d, + 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x75, 0x74, + 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, + 0x36, 0x0a, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x69, + 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, + 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x12, 0x3a, 0x0a, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, + 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, + 0x6f, 0x72, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, + 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, + 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x74, + 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x57, 0x0a, + 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, + 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x52, 0x18, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, + 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, - 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x21, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x22, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x68, 0x61, 0x73, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x4d, 0x0a, 0x0c, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x0c, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x1a, 0x86, 0x02, 0x0a, 0x12, 0x50, - 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x53, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x21, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x1e, + 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x22, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, + 0x69, 0x6e, 0x6b, 0x1a, 0x86, 0x02, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, + 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, + 0x26, 0x0a, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, + 0x00, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, + 0x79, 0x1a, 0x3b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, + 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x42, 0x0c, + 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0xf8, 0x01, 0x0a, + 0x0c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, - 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x28, - 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, - 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x1a, 0x3b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x65, 0x31, 0x36, 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x1a, 0xf8, 0x01, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x12, 0x1a, - 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6f, - 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, - 0x72, 0x22, 0x6b, 0x0a, 0x05, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x55, 0x45, 0x10, - 0x01, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x48, 0x49, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, - 0x47, 0x52, 0x45, 0x59, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x4c, 0x49, 0x56, 0x45, 0x10, - 0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, 0x45, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, - 0x4f, 0x52, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x4b, - 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x52, 0x50, 0x4c, 0x45, 0x10, 0x08, 0x22, 0x40, - 0x0a, 0x16, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, - 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4f, - 0x44, 0x59, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x02, - 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1f, - 0x10, 0x20, 0x22, 0xfb, 0x01, 0x0a, 0x1b, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, - 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x20, - 0x0a, 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, - 0x2a, 0x34, 0x0a, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, - 0x12, 0x09, 0x0a, 0x05, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, - 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, - 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x42, 0x3c, 0x0a, 0x38, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x73, 0x50, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, + 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0x6b, 0x0a, 0x05, 0x43, 0x6f, + 0x6c, 0x6f, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x48, + 0x49, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x45, 0x59, 0x10, 0x03, 0x12, + 0x09, 0x0a, 0x05, 0x4f, 0x4c, 0x49, 0x56, 0x45, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, + 0x45, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x52, 0x41, 0x4e, 0x47, 0x45, 0x10, + 0x06, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x4b, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x50, + 0x55, 0x52, 0x50, 0x4c, 0x45, 0x10, 0x08, 0x22, 0x40, 0x0a, 0x16, 0x50, 0x68, 0x6f, 0x6e, 0x65, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, + 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, + 0x0a, 0x09, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x01, 0x12, 0x0a, 0x0a, + 0x06, 0x4e, 0x4f, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, + 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1f, 0x10, 0x20, 0x22, 0xfb, 0x01, 0x0a, 0x1b, + 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x72, 0x65, + 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, + 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x34, 0x0a, 0x0c, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x4e, 0x53, + 0x45, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x42, + 0x3c, 0x0a, 0x38, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x50, 0x01, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2279,7 +2359,7 @@ func file_StorageService_proto_rawDescGZIP() []byte { } var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 18) var file_StorageService_proto_goTypes = []interface{}{ (OptionalBool)(0), // 0: signalservice.OptionalBool (ManifestRecord_Identifier_Type)(0), // 1: signalservice.ManifestRecord.Identifier.Type @@ -2301,9 +2381,10 @@ var file_StorageService_proto_goTypes = []interface{}{ (*AccountRecord)(nil), // 17: signalservice.AccountRecord (*StoryDistributionListRecord)(nil), // 18: signalservice.StoryDistributionListRecord (*ManifestRecord_Identifier)(nil), // 19: signalservice.ManifestRecord.Identifier - (*AccountRecord_PinnedConversation)(nil), // 20: signalservice.AccountRecord.PinnedConversation - (*AccountRecord_UsernameLink)(nil), // 21: signalservice.AccountRecord.UsernameLink - (*AccountRecord_PinnedConversation_Contact)(nil), // 22: signalservice.AccountRecord.PinnedConversation.Contact + (*ContactRecord_Name)(nil), // 20: signalservice.ContactRecord.Name + (*AccountRecord_PinnedConversation)(nil), // 21: signalservice.AccountRecord.PinnedConversation + (*AccountRecord_UsernameLink)(nil), // 22: signalservice.AccountRecord.UsernameLink + (*AccountRecord_PinnedConversation_Contact)(nil), // 23: signalservice.AccountRecord.PinnedConversation.Contact } var file_StorageService_proto_depIdxs = []int32{ 7, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem @@ -2316,20 +2397,21 @@ var file_StorageService_proto_depIdxs = []int32{ 17, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord 18, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord 2, // 9: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState - 3, // 10: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode - 4, // 11: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode - 20, // 12: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation - 16, // 13: signalservice.AccountRecord.payments:type_name -> signalservice.Payments - 0, // 14: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool - 21, // 15: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink - 1, // 16: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type - 22, // 17: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact - 5, // 18: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color - 19, // [19:19] is the sub-list for method output_type - 19, // [19:19] is the sub-list for method input_type - 19, // [19:19] is the sub-list for extension type_name - 19, // [19:19] is the sub-list for extension extendee - 0, // [0:19] is the sub-list for field type_name + 20, // 10: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name + 3, // 11: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode + 4, // 12: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode + 21, // 13: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation + 16, // 14: signalservice.AccountRecord.payments:type_name -> signalservice.Payments + 0, // 15: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool + 22, // 16: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink + 1, // 17: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type + 23, // 18: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact + 5, // 19: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color + 20, // [20:20] is the sub-list for method output_type + 20, // [20:20] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_StorageService_proto_init() } @@ -2507,7 +2589,7 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AccountRecord_PinnedConversation); i { + switch v := v.(*ContactRecord_Name); i { case 0: return &v.state case 1: @@ -2519,7 +2601,7 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AccountRecord_UsernameLink); i { + switch v := v.(*AccountRecord_PinnedConversation); i { case 0: return &v.state case 1: @@ -2531,6 +2613,18 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccountRecord_UsernameLink); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AccountRecord_PinnedConversation_Contact); i { case 0: return &v.state @@ -2550,7 +2644,7 @@ func file_StorageService_proto_init() { (*StorageRecord_Account)(nil), (*StorageRecord_StoryDistributionList)(nil), } - file_StorageService_proto_msgTypes[14].OneofWrappers = []interface{}{ + file_StorageService_proto_msgTypes[15].OneofWrappers = []interface{}{ (*AccountRecord_PinnedConversation_Contact_)(nil), (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), @@ -2561,7 +2655,7 @@ func file_StorageService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_StorageService_proto_rawDesc, NumEnums: 6, - NumMessages: 17, + NumMessages: 18, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index f9370b0..ac26d38 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -79,6 +79,11 @@ message ContactRecord { UNVERIFIED = 2; } + message Name { + string given = 1; + string family = 2; + } + string aci = 1; string e164 = 2; string pni = 15; @@ -100,7 +105,9 @@ message ContactRecord { string systemNickname = 19; bool hidden = 20; bool pniSignatureVerified = 21; - // NEXT ID: 22 + Name nickname = 22; + string note = 23; + // NEXT ID: 24 } message GroupV1Record { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index 9f95088..fbfebf5 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: UnidentifiedDelivery.proto diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index c3aed6d..df73711 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 +// protoc-gen-go v1.34.1 // protoc v3.21.12 // source: WebSocketResources.proto diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 4aefdb7..dac087b 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-915b3f0cd32628c6dfddb40934d1c3b47c52e991} -DESKTOP_GIT_REVISION=${1:-3eed6cb350f5e54df09e18a9012f4db74cecb7b6} +ANDROID_GIT_REVISION=${1:-c4805126008977827f8ee08e016568fc9a374b4d} +DESKTOP_GIT_REVISION=${1:-af1c593fef4e485127ea356b3b592f3c781c2a16} update_proto() { case "$1" in From 20e5f43be8818a36b575d0243dbf534b82434025 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 14 Jun 2024 15:44:43 +0300 Subject: [PATCH 184/718] signalmeow/store: fix master key being non-nil slice when scanned from db --- pkg/signalmeow/store/container.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index d649b92..9edafef 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -65,6 +65,9 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { return nil, fmt.Errorf("failed to deserialize PNI identity key pair: %w", err) } + if len(device.MasterKey) == 0 { + device.MasterKey = nil + } baseStore := &sqlStore{Container: c, AccountID: device.ACI} aciStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.ACIServiceID()} pniStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.PNIServiceID()} From 790152b38ad4b1717758c44fd498a8f8758ad84f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 14 Jun 2024 15:56:17 +0300 Subject: [PATCH 185/718] libsignalgo: update libsignal to v0.51.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 10 ++++++++++ pkg/libsignalgo/version.go | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 347791c..95bf4e7 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 347791c88cdfdb765534b5e2be149f588b75bf49 +Subproject commit 95bf4e77155b5110e80a8d140cce7adaef8aa0ac diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index c349c2c..bd99f60 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -292,6 +292,11 @@ typedef struct SignalSgxClientState SignalSgxClientState; /** * The top-level error type (opaquely) returned to C clients when something goes wrong. + * + * Ideally this would use [ThinBox][], and then we wouldn't need an extra level of indirection when + * returning it to C, but unfortunately that isn't stable yet. + * + * [ThinBox]: https://doc.rust-lang.org/std/boxed/struct.ThinBox.html */ typedef struct SignalFfiError SignalFfiError; @@ -634,6 +639,8 @@ typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envel typedef void (*SignalReceivedQueueEmpty)(void *ctx); +typedef void (*SignalConnectionInterrupted)(void *ctx); + typedef void (*SignalDestroyChatListener)(void *ctx); /** @@ -647,6 +654,7 @@ typedef struct { void *ctx; SignalReceivedIncomingMessage received_incoming_message; SignalReceivedQueueEmpty received_queue_empty; + SignalConnectionInterrupted connection_interrupted; SignalDestroyChatListener destroy; } SignalFfiChatListenerStruct; @@ -1572,6 +1580,8 @@ SignalFfiError *signal_chat_server_set_listener(const SignalTokioAsyncContext *r SignalFfiError *signal_testing_chat_service_inject_raw_server_request(const SignalChat *chat, SignalBorrowedBuffer bytes); +SignalFfiError *signal_testing_chat_service_inject_connection_interrupted(const SignalChat *chat); + SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p); SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalServerMessageAck *ack); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 0bc1cb7..cf2f348 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.49.0" +const Version = "v0.51.0" From 65e2b4c9e15e1eb5fa21607c1a4f196f09976ead Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 14 Jun 2024 15:57:17 +0300 Subject: [PATCH 186/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 258845e..4d6711e 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.2-0.20240614094708-b456fb6e0a6b + maunium.net/go/mautrix v0.18.2-0.20240614100125-869a04dadbe4 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 61c4295..18026e7 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.18.2-0.20240614094708-b456fb6e0a6b h1:/JvXcwT+y9SR0AN0fQIhIOz+9Uy9jhwpqqFEYxuTtTI= -maunium.net/go/mautrix v0.18.2-0.20240614094708-b456fb6e0a6b/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= +maunium.net/go/mautrix v0.18.2-0.20240614100125-869a04dadbe4 h1:zyTy499oODvoaLBYKEWn7PNsWVmKVGzwNlSh32fR/Js= +maunium.net/go/mautrix v0.18.2-0.20240614100125-869a04dadbe4/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 94a2aacce51d163be49792cd08b0c419eda58308 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Jun 2024 23:51:39 +0300 Subject: [PATCH 187/718] v2: Add GetTimeout for typing events --- pkg/connector/connector.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 864e3d8..24a2364 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -571,6 +571,7 @@ var ( _ bridgev2.RemoteReaction = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteTyping = (*Bv2ChatEvent)(nil) ) func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { @@ -595,6 +596,14 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { return bridgev2.RemoteEventUnknown } +func (evt *Bv2ChatEvent) GetTimeout() time.Duration { + if evt.Event.(*signalpb.TypingMessage).GetAction() == signalpb.TypingMessage_STARTED { + return 15 * time.Second + } else { + return 0 + } +} + func (evt *Bv2ChatEvent) GetPortalKey() networkid.PortalKey { key := networkid.PortalKey{ID: networkid.PortalID(evt.Info.ChatID)} // For non-group chats, add receiver From 00abe8099f55f4be9ea630f9e98aeaa91443877f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Jun 2024 23:52:05 +0300 Subject: [PATCH 188/718] Bump version to v0.6.2 --- CHANGELOG.md | 7 +++++++ go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- main.go | 2 +- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c6bc06..cfad0bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v0.6.2 (2024-06-16) + +* Fixed voice messages not being rendered correctly in Element X. +* Fixed contact avatars not being bridged correctly even when enabled in + the bridge config. +* Implemented connector for the upcoming bridgev2 architecture. + # v0.6.1 (2024-05-16) * Added support for bridging location messages from Matrix to Signal diff --git a/go.mod b/go.mod index 4d6711e..635898b 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.4.3-0.20240611132549-e72a5f4745e7 + go.mau.fi/util v0.5.0 golang.org/x/crypto v0.24.0 - golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 - google.golang.org/protobuf v1.34.1 - maunium.net/go/mautrix v0.18.2-0.20240614100125-869a04dadbe4 + google.golang.org/protobuf v1.34.2 + maunium.net/go/mautrix v0.19.0-beta.1 nhooyr.io/websocket v1.8.11 ) @@ -41,7 +41,7 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.1 // indirect + github.com/yuin/goldmark v1.7.2 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect golang.org/x/sys v0.21.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index 18026e7..49aba40 100644 --- a/go.sum +++ b/go.sum @@ -67,16 +67,16 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/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.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= -github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.4.3-0.20240611132549-e72a5f4745e7 h1:DviEWXBpeOlFrqIf5s/iBDp1ewZx8fe6imMJ78kq3tA= -go.mau.fi/util v0.4.3-0.20240611132549-e72a5f4745e7/go.mod h1:Eaj7jl37ehkA7S6vE/vfPs5PsY8e91FKZ2BqA3OM/NU= +github.com/yuin/goldmark v1.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= +github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.mau.fi/util v0.5.0 h1:8yELAl+1CDRrwGe9NUmREgVclSs26Z68pTWePHVxuDo= +go.mau.fi/util v0.5.0/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= -golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -84,8 +84,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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= @@ -95,7 +95,7 @@ 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.18.2-0.20240614100125-869a04dadbe4 h1:zyTy499oODvoaLBYKEWn7PNsWVmKVGzwNlSh32fR/Js= -maunium.net/go/mautrix v0.18.2-0.20240614100125-869a04dadbe4/go.mod h1:qdyAG5Uvdz3kdw3wCCz/FGnnwjoXK+/b6Iy3fRXnKM0= +maunium.net/go/mautrix v0.19.0-beta.1 h1:QGqcafucRwnKv/hPc8stGqUuZYZcHJ4PyCki7shMAXA= +maunium.net/go/mautrix v0.19.0-beta.1/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index 0a92c52..16dbd05 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.6.1", + Version: "0.6.2", ProtocolName: "Signal", BeeperServiceName: "signal", BeeperNetworkName: "signal", From 6428e69426a9ecde50568dae31f5065b63ab302b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 14:18:13 +0300 Subject: [PATCH 189/718] changelog: add missed row --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfad0bd..f31a4c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # v0.6.2 (2024-06-16) +* Updated to libsignal v0.51.0. * Fixed voice messages not being rendered correctly in Element X. * Fixed contact avatars not being bridged correctly even when enabled in the bridge config. From eb2106dd8f599a090fcf8fa141f7954b93cd673f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 14:18:45 +0300 Subject: [PATCH 190/718] provisioning: stop using libserv --- go.mod | 1 - go.sum | 2 -- provisioning.go | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 635898b..545d155 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module go.mau.fi/mautrix-signal go 1.21 require ( - github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index 49aba40..4667517 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ 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/beeper/libserv v0.0.0-20231231202820-c7303abfc32c h1:WqjRVgUO039eiISCjsZC4F9onOEV93DJAk6v33rsZzY= -github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c/go.mod h1:b9FFm9y4mEm36G8ytVmS1vkNzJa0KepmcdVY+qf7qRU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= diff --git a/provisioning.go b/provisioning.go index 211bd46..3be384b 100644 --- a/provisioning.go +++ b/provisioning.go @@ -28,11 +28,11 @@ import ( "sync" "time" - "github.com/beeper/libserv/pkg/requestlog" "github.com/google/uuid" "github.com/gorilla/mux" "github.com/rs/zerolog" "github.com/rs/zerolog/hlog" + "go.mau.fi/util/requestlog" "maunium.net/go/mautrix" "maunium.net/go/mautrix/id" From a670cc4198b510a9bbceeacec049ae4b9b0702d2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 14:23:20 +0300 Subject: [PATCH 191/718] v2: add method for registering for push notifications --- go.mod | 2 +- go.sum | 4 +- pkg/connector/connector.go | 22 ++++++++++ pkg/signalmeow/pushreg.go | 82 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 pkg/signalmeow/pushreg.go diff --git a/go.mod b/go.mod index 545d155..8a124e3 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 4667517..436318e 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1 h1:QGqcafucRwnKv/hPc8stGqUuZYZcHJ4PyCki7shMAXA= -maunium.net/go/mautrix v0.19.0-beta.1/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa h1:9roSXY6+pcSY9jxnUprAi0gbbrUbFYcl5gAQSgNgXVs= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 24a2364..3b0f44a 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -102,6 +102,7 @@ type SignalConnector struct { var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) var _ bridgev2.NetworkAPI = (*SignalClient)(nil) +var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) func NewConnector() *SignalConnector { @@ -232,6 +233,27 @@ type SignalClient struct { Client *signalmeow.Client } +var pushCfg = &bridgev2.PushConfig{ + FCM: &bridgev2.FCMPushConfig{ + // https://github.com/signalapp/Signal-Android/blob/main/app/src/main/res/values/firebase_messaging.xml#L4 + SenderID: "312334754206", + }, + APNs: &bridgev2.APNsPushConfig{ + BundleID: "org.whispersystems.signal", + }, +} + +func (s *SignalClient) GetPushConfigs() *bridgev2.PushConfig { + return pushCfg +} + +func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { + if pushType != bridgev2.PushTypeFCM { + return fmt.Errorf("unsupported push type: %s", pushType) + } + return s.Client.RegisterFCM(ctx, token) +} + func (s *SignalClient) LogoutRemote(ctx context.Context) { err := s.Client.StopReceiveLoops() if err != nil { diff --git a/pkg/signalmeow/pushreg.go b/pkg/signalmeow/pushreg.go new file mode 100644 index 0000000..fe45785 --- /dev/null +++ b/pkg/signalmeow/pushreg.go @@ -0,0 +1,82 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +type ReqRegisterFCM struct { + GCMRegistrationID string `json:"gcmRegistrationId,omitempty"` + WebSocketChannel bool `json:"webSocketChannel"` +} + +type ReqRegisterAPNs struct { + APNRegistrationID string `json:"apnRegistrationId,omitempty"` + VoIPRegistrationID string `json:"voipRegistrationId,omitempty"` +} + +func (cli *Client) registerPush(ctx context.Context, pushType string, data any) error { + username, password := cli.Store.BasicAuthCreds() + req := &web.HTTPReqOpt{ + Username: &username, + Password: &password, + } + var method string + if data != nil { + method = http.MethodPut + req.ContentType = web.ContentTypeJSON + var err error + req.Body, err = json.Marshal(data) + if err != nil { + return err + } + } else { + method = http.MethodDelete + } + resp, err := web.SendHTTPRequest(ctx, method, "/v1/accounts/"+pushType, req) + if err != nil { + return err + } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { + return fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + return nil +} + +func (cli *Client) RegisterFCM(ctx context.Context, token string) error { + if token == "" { + return cli.registerPush(ctx, "gcm", nil) + } + return cli.registerPush(ctx, "gcm", &ReqRegisterFCM{ + GCMRegistrationID: token, + WebSocketChannel: true, + }) +} + +func (cli *Client) RegisterAPNs(ctx context.Context, token string) error { + if token == "" { + return cli.registerPush(ctx, "apn", nil) + } + return cli.registerPush(ctx, "apn", &ReqRegisterAPNs{ + APNRegistrationID: token, + }) +} From ec7f6db5edf1b842dc9bb20eb90955bbe114ef35 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 16:44:16 +0300 Subject: [PATCH 192/718] v2: add clean shutdown --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8a124e3..001f1e6 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa + maunium.net/go/mautrix v0.19.0-beta.1.0.20240617130007-833995832be3 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 436318e..339257f 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240617115738-3828c08f27fa h1:9roSXY6+pcSY9jxnUprAi0gbbrUbFYcl5gAQSgNgXVs= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617130007-833995832be3 h1:FZ6uHxsDt9Z0/z8pgt6Ai+beV9+Te+RJBftgAgV7/r0= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617130007-833995832be3/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 3b0f44a..dd7f60f 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -488,11 +488,19 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } } } + func (s *SignalClient) Connect(ctx context.Context) error { s.tryConnect(ctx, 0) return nil } +func (s *SignalClient) Disconnect() { + err := s.Client.StopReceiveLoops() + if err != nil { + s.UserLogin.Log.Err(err).Msg("Failed to stop receive loops") + } +} + func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { From 73fcf0c42c3b118ccb96df14a5765060fa3c1af6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 18:18:13 +0300 Subject: [PATCH 193/718] main: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 001f1e6..7f48ddb 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240617130007-833995832be3 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240617151654-afeadfb15fee nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 339257f..98e7437 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240617130007-833995832be3 h1:FZ6uHxsDt9Z0/z8pgt6Ai+beV9+Te+RJBftgAgV7/r0= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240617130007-833995832be3/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617151654-afeadfb15fee h1:CQyItqakHeYb19uj1FAooHVMK53e45TjoINGmcnKsLc= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617151654-afeadfb15fee/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From ac75fae4e295f0dd94e60c6aa5e9bbf1df469ffe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 21:40:06 +0300 Subject: [PATCH 194/718] v2: add build scripts --- .gitignore | 1 + build-go-v2.sh | 9 +++++++++ build-v2.sh | 4 ++++ 3 files changed, 14 insertions(+) create mode 100755 build-go-v2.sh create mode 100755 build-v2.sh diff --git a/.gitignore b/.gitignore index c4d535d..0031287 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ /mautrix-signal /mautrix-signalgo +/mautrix-signal-v2 /start /libsignal_ffi.a diff --git a/build-go-v2.sh b/build-go-v2.sh new file mode 100755 index 0000000..199f474 --- /dev/null +++ b/build-go-v2.sh @@ -0,0 +1,9 @@ +#!/bin/sh +MAUTRIX_VERSION=$(cat go.mod | grep 'maunium.net/go/mautrix ' | awk '{ print $2 }') +GO_LDFLAGS="-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date -Iseconds`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" +if [ "$DBG" = 1 ]; then + GO_GCFLAGS='all=-N -l' +else + GO_LDFLAGS="-s -w ${GO_LDFLAGS}" +fi +go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal-v2 ./cmd/mautrix-signal-v2 "$@" diff --git a/build-v2.sh b/build-v2.sh new file mode 100755 index 0000000..b541932 --- /dev/null +++ b/build-v2.sh @@ -0,0 +1,4 @@ +#!/bin/sh +#./build-rust.sh +#cp -f pkg/libsignalgo/libsignal/target/release/libsignal_ffi.a . +LIBRARY_PATH=.:$LIBRARY_PATH ./build-go-v2.sh From 72cd8a3ca4068f9a83061ae2e402a8cad680f245 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Jun 2024 15:15:12 +0300 Subject: [PATCH 195/718] v2: add disappearing messages --- go.mod | 2 +- go.sum | 4 +-- msgconv/from-signal.go | 2 +- msgconv/msgconv.go | 1 + pkg/connector/connector.go | 51 +++++++++++++++++++++++++++----------- pkg/connector/login.go | 14 +++++++---- 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 7f48ddb..fbcc2a0 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240617151654-afeadfb15fee + maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 98e7437..915da1a 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240617151654-afeadfb15fee h1:CQyItqakHeYb19uj1FAooHVMK53e45TjoINGmcnKsLc= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240617151654-afeadfb15fee/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280 h1:+EHJF8h7obPow7kDnsmGoWN+bTCjHGxCKaH99MldZUI= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index 9caecd6..8a4b5d1 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -173,7 +173,7 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C if timer == 0 { part.Content.Body = "Disappearing messages disabled" } - if updatePortal { + if updatePortal && !mc.NoUpdateDisappearing { portal := mc.GetData(ctx) portal.ExpirationTime = timer err := portal.Update(ctx) diff --git a/msgconv/msgconv.go b/msgconv/msgconv.go index 0e29157..33ac4a5 100644 --- a/msgconv/msgconv.go +++ b/msgconv/msgconv.go @@ -54,6 +54,7 @@ type MessageConverter struct { ConvertGIFToAPNG bool MaxFileSize int64 AsyncFiles bool + NoUpdateDisappearing bool LocationFormat string } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index dd7f60f..cf6a51f 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -193,6 +193,7 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { MaxFileSize: 50 * 1024 * 1024, AsyncFiles: true, LocationFormat: s.Config.LocationFormat, + NoUpdateDisappearing: true, } } @@ -764,11 +765,33 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po Content: part.Content, Extra: part.Extra, } - + } + var disappear database.DisappearingSetting + if converted.DisappearIn != 0 { + disappear = database.DisappearingSetting{ + Type: database.DisappearingTypeAfterRead, + Timer: time.Duration(converted.DisappearIn) * time.Second, + } + if evt.Info.Sender == evt.s.Client.Store.ACI { + disappear.DisappearAt = time.UnixMilli(int64(dataMsg.GetTimestamp())).Add(disappear.Timer) + } + if portal.Metadata.DisappearTimer != disappear.Timer { + portal.Metadata.DisappearType = disappear.Type + portal.Metadata.DisappearTimer = disappear.Timer + // TODO if the message doesn't have the DataMessage_EXPIRATION_TIMER_UPDATE, + // we should send a message to the portal notifying of the implicit update + err := portal.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save portal metadata after updating disappearing timer") + } else { + zerolog.Ctx(ctx).Debug().Dur("new_timer", portal.Metadata.DisappearTimer).Msg("Updated disappearing timer in portal") + } + } } return &bridgev2.ConvertedMessage{ - ReplyTo: replyTo, - Parts: convertedParts, + ReplyTo: replyTo, + Parts: convertedParts, + Disappear: disappear, }, nil } @@ -945,7 +968,7 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { } } -func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *database.Message, err error) { +func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) { mcCtx := &msgconvContext{ Connector: s.Main, Intent: nil, @@ -964,19 +987,20 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma } // TODO check result fmt.Println(res) - meta := map[string]any{ - "contains_attachments": len(converted.Attachments) > 0, - } dbMsg := &database.Message{ ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), SenderID: makeUserID(s.Client.Store.ACI), Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), - Metadata: meta, + } + dbMsg.Metadata.Extra = map[string]any{ + "contains_attachments": len(converted.Attachments) > 0, } if msg.ReplyTo != nil { dbMsg.RelatesToRowID = msg.ReplyTo.RowID } - return dbMsg, nil + return &bridgev2.MatrixMessageResponse{ + DB: dbMsg, + }, nil } func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { @@ -1014,7 +1038,7 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri // TODO check result fmt.Println(res) msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) - msg.EditTarget.Metadata["contains_attachments"] = len(converted.Attachments) > 0 + msg.EditTarget.Metadata.Extra["contains_attachments"] = len(converted.Attachments) > 0 return nil } @@ -1070,7 +1094,6 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M } func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { - emoji, _ := msg.TargetReaction.Metadata["emoji"].(string) targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetReaction.MessageID) if err != nil { return fmt.Errorf("failed to parse target message ID: %w", err) @@ -1080,7 +1103,7 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(emoji), + Emoji: proto.String(msg.TargetReaction.Metadata.Emoji), Remove: proto.Bool(true), TargetAuthorAci: proto.String(targetAuthorACI.String()), TargetSentTimestamp: proto.Uint64(targetSentTimestamp), @@ -1199,7 +1222,7 @@ func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *ev AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), Type: signalpb.DataMessage_Quote_NORMAL.Enum(), } - if mcCtx.ReplyTo.Metadata["contains_attachments"] != false { + if mcCtx.ReplyTo.Metadata.Extra["contains_attachments"] != false { quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) } return quote @@ -1237,6 +1260,6 @@ func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { //Revision: portal.Metadata["revision"].(uint32), Encrypted: true, //RelayUserID: portal.Relay.UserMXID, - //ExpirationTime: portal.Metadata["expiration_timer"].(uint32), + ExpirationTime: uint32(portal.Metadata.DisappearTimer.Milliseconds()), } } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 4771b65..ecb12f7 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -136,9 +136,13 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { if qr.Existing == nil { ul, err = qr.User.NewLogin(ctx, &database.UserLogin{ ID: newLoginID, - Metadata: map[string]any{ - "phone": signalPhone, - "remote_name": signalPhone, + Metadata: database.UserLoginMetadata{ + StandardUserLoginMetadata: database.StandardUserLoginMetadata{ + RemoteName: signalPhone, + }, + Extra: map[string]any{ + "phone": signalPhone, + }, }, }, nil) if err != nil { @@ -146,8 +150,8 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { } } else { ul = qr.Existing - ul.Metadata["phone"] = signalPhone - ul.Metadata["remote_name"] = signalPhone + ul.Metadata.Extra["phone"] = signalPhone + ul.Metadata.RemoteName = signalPhone err = ul.Save(ctx) if err != nil { return nil, fmt.Errorf("failed to update existing login: %w", err) From 4d601ab465d3c95f380b136d7ec7bc3582326d22 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Jun 2024 15:44:27 +0300 Subject: [PATCH 196/718] v2: add typing notifications --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fbcc2a0..f3becff 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240619124218-2e23f6372f66 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 915da1a..6c6d36b 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240619092812-451658374280 h1:+EHJF8h7obPow7kDnsmGoWN+bTCjHGxCKaH99MldZUI= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619124218-2e23f6372f66 h1:O7IzqKzbgIPwosfI4nJg97JM1JKP4+KuMCploezxQpI= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619124218-2e23f6372f66/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index cf6a51f..d9e71c1 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -1195,6 +1195,22 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri return nil } +func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2.MatrixTyping) error { + userID, _, err := s.parsePortalID(typing.Portal.ID) + if err != nil { + return err + } + // Only send typing notifications in DMs for now + // Sending efficiently to groups requires implementing the proper SenderKey stuff first + if !userID.IsEmpty() && userID.Type == libsignalgo.ServiceIDTypeACI { + typingMessage := signalmeow.TypingMessage(typing.IsTyping) + result := s.Client.SendMessage(ctx, userID, typingMessage) + fmt.Println(result) + // TODO check result + } + return nil +} + type msgconvPortalMethods struct{} func (mpm *msgconvPortalMethods) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { From e37ad78f55a262284dadb48890c0b67f17910a4f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Jun 2024 22:59:44 +0300 Subject: [PATCH 197/718] v2: add support for starting DMs and ACI found events --- go.mod | 2 +- go.sum | 4 +- pkg/connector/connector.go | 188 +++++++++++++++++++++++++++++++------ 3 files changed, 164 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index f3becff..fd1ea3f 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240619124218-2e23f6372f66 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240619195836-2a7a5070fb32 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 6c6d36b..a6c0ff3 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240619124218-2e23f6372f66 h1:O7IzqKzbgIPwosfI4nJg97JM1JKP4+KuMCploezxQpI= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240619124218-2e23f6372f66/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619195836-2a7a5070fb32 h1:BiUVpB1hejeuCivlLOv5jKzU/Y8TTwDlQ0i1qO+JGdI= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619195836-2a7a5070fb32/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index d9e71c1..cb1788d 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -19,6 +19,7 @@ package connector import ( "context" _ "embed" + "errors" "fmt" "strconv" "strings" @@ -103,6 +104,7 @@ var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) var _ bridgev2.NetworkAPI = (*SignalClient)(nil) var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) +var _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) func NewConnector() *SignalConnector { @@ -323,13 +325,13 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) if err != nil { return nil, err } - isSpace := false if groupID != "" { groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, 0) if err != nil { return nil, err } isDM := false + isSpace := false members := make([]networkid.UserID, len(groupInfo.Members)) for i, member := range groupInfo.Members { members[i] = makeUserID(member.ACI) @@ -348,41 +350,127 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) IsDirectChat: &isDM, IsSpace: &isSpace, }, nil - } else if userID.Type == libsignalgo.ServiceIDTypePNI { - contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, uuid.Nil, userID.UUID, nil) + } else { + aci, pni := serviceIDToACIAndPNI(userID) + contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) if err != nil { return nil, err } - var topic, name string - name = s.Main.Config.FormatDisplayname(contact) - if s.Main.Config.NumberInTopic && contact.E164 != "" { - topic = fmt.Sprintf("") - // TODO set topic + return s.makeCreateDMResponse(contact).PortalInfo, nil + } +} + +func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { + number, err := bridgev2.CleanPhoneNumber(number) + if err != nil { + return nil, err + } + e164Number, err := strconv.ParseUint(strings.TrimPrefix(number, "+"), 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing phone number: %w", err) + } + e164String := fmt.Sprintf("+%d", e164Number) + var aci, pni uuid.UUID + var recipient *types.Recipient + if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { + return nil, fmt.Errorf("error looking up number in local contact list: %w", err) + } else if recipient != nil { + aci = recipient.ACI + pni = recipient.PNI + } else if resp, err := s.Client.LookupPhone(ctx, e164Number); err != nil { + return nil, fmt.Errorf("error looking up number on server: %w", err) + } else { + aci = resp[e164Number].ACI + pni = resp[e164Number].PNI + if aci == uuid.Nil && pni == uuid.Nil { + return nil, errors.New("user not found on Signal") } - isDM := true - return &bridgev2.PortalInfo{ - Members: []networkid.UserID{makeUserID(s.Client.Store.ACI)}, - Name: &name, - Topic: &topic, - IsDirectChat: &isDM, - IsSpace: &isSpace, + recipient, err = s.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI + } + zerolog.Ctx(ctx).Debug(). + Uint64("e164", e164Number). + Stringer("aci", aci). + Stringer("pni", pni). + Msg("Found resolve identifier target user") + + // createChat is a no-op: chats don't need to be created, and we always return chat info + if aci != uuid.Nil { + ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(aci)) + if err != nil { + return nil, fmt.Errorf("failed to get ghost: %w", err) + } + return &bridgev2.ResolveIdentifierResponse{ + UserID: makeUserID(aci), + UserInfo: s.contactToUserInfo(recipient), + Ghost: ghost, + Chat: s.makeCreateDMResponse(recipient), }, nil } else { - var topic, name string - if s.Main.Config.NumberInTopic { - // TODO set topic - } - isDM := true - return &bridgev2.PortalInfo{ - Members: []networkid.UserID{makeUserID(userID.UUID), makeUserID(s.Client.Store.ACI)}, - Name: &name, - Topic: &topic, - IsDirectChat: &isDM, - IsSpace: &isSpace, + return &bridgev2.ResolveIdentifierResponse{ + UserID: makeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), + UserInfo: s.contactToUserInfo(recipient), + Chat: s.makeCreateDMResponse(recipient), }, nil } } +const PrivateChatTopic = "Signal private chat" +const NoteToSelfName = "Signal Note to Self" + +func serviceIDToACIAndPNI(serviceID libsignalgo.ServiceID) (aci, pni uuid.UUID) { + if serviceID.Type == libsignalgo.ServiceIDTypeACI { + return serviceID.UUID, uuid.Nil + } else { + return uuid.Nil, serviceID.UUID + } +} + +func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { + isDirectChat := true + isSpace := false + name := "" + topic := PrivateChatTopic + members := []networkid.UserID{makeUserID(s.Client.Store.ACI)} + if s.Main.Config.NumberInTopic && recipient.E164 != "" { + topic = fmt.Sprintf("%s with %s", PrivateChatTopic, recipient.E164) + } + var serviceID libsignalgo.ServiceID + if recipient.ACI == uuid.Nil { + name = s.Main.Config.FormatDisplayname(recipient) + serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) + } else { + if recipient.ACI == s.Client.Store.ACI { + name = NoteToSelfName + } else { + // The other user is only present if their ACI is known + members = append(members, makeUserID(recipient.ACI)) + } + serviceID = libsignalgo.NewACIServiceID(recipient.ACI) + } + return &bridgev2.CreateChatResponse{ + PortalID: networkid.PortalKey{ + ID: networkid.PortalID(serviceID.String()), + Receiver: s.UserLogin.ID, + }, + PortalInfo: &bridgev2.PortalInfo{ + Name: &name, + Topic: &topic, + Members: members, + IsDirectChat: &isDirectChat, + IsSpace: &isSpace, + }, + } +} + +func (s *SignalClient) CreateGroup(ctx context.Context, name string, users ...networkid.UserID) (*bridgev2.CreateChatResponse, error) { + //TODO implement me + return nil, fmt.Errorf("not implemented") +} + func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bool { return userID == makeUserID(s.Client.Store.ACI) } @@ -525,7 +613,18 @@ func (s *SignalClient) IsLoggedIn() bool { } func parseUserID(userID networkid.UserID) (uuid.UUID, error) { - return uuid.Parse(string(userID)) + serviceID, err := parseUserIDAsServiceID(userID) + if err != nil { + return uuid.Nil, err + } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return uuid.Nil, fmt.Errorf("invalid user ID: expected ACI type") + } else { + return serviceID.UUID, nil + } +} + +func parseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { + return libsignalgo.ServiceIDFromString(string(userID)) } func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { @@ -559,6 +658,10 @@ func makeUserID(user uuid.UUID) networkid.UserID { return networkid.UserID(user.String()) } +func makeUserIDFromServiceID(user libsignalgo.ServiceID) networkid.UserID { + return networkid.UserID(user.String()) +} + func makeUserLoginID(user uuid.UUID) networkid.UserLoginID { return networkid.UserLoginID(user.String()) } @@ -944,6 +1047,37 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { case *events.ContactList: s.handleSignalContactList(evt) case *events.ACIFound: + s.handleSignalACIFound(evt) + } +} + +func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { + log := s.UserLogin.Log.With(). + Str("action", "handle aci found"). + Stringer("aci", evt.ACI). + Stringer("pni", evt.PNI). + Logger() + ctx := log.WithContext(context.TODO()) + pniPortalKey := networkid.PortalKey{ + ID: networkid.PortalID(evt.PNI.String()), + Receiver: s.UserLogin.ID, + } + aciPortalKey := networkid.PortalKey{ + ID: networkid.PortalID(evt.ACI.String()), + Receiver: s.UserLogin.ID, + } + result, portal, err := s.Main.Bridge.ReIDPortal(ctx, pniPortalKey, aciPortalKey) + if err != nil { + log.Err(err).Msg("Failed to re-ID portal") + } else if result == bridgev2.ReIDResultSourceReIDd || result == bridgev2.ReIDResultTargetDeletedAndSourceReIDd { + // If the source portal is re-ID'd, we need to sync metadata and participants. + // If the source is deleted, then it doesn't matter, any existing target will already be correct + info, err := s.GetChatInfo(ctx, portal) + if err != nil { + log.Err(err).Msg("Failed to get chat info to update portal after re-ID") + } else { + portal.UpdateInfo(ctx, info, s.UserLogin, nil, time.Time{}) + } } } From d06f4b5aa4b558933a4311ac3e2be7ce095961cb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Jun 2024 23:21:52 +0300 Subject: [PATCH 198/718] v2: split connector into multiple files --- pkg/connector/chatinfo.go | 233 ++++++ pkg/connector/client.go | 197 +++++ pkg/connector/config.go | 86 +++ pkg/connector/connector.go | 1264 --------------------------------- pkg/connector/handlematrix.go | 278 ++++++++ pkg/connector/handlesignal.go | 431 +++++++++++ pkg/connector/id.go | 130 ++++ pkg/connector/msgconvproxy.go | 115 +++ 8 files changed, 1470 insertions(+), 1264 deletions(-) create mode 100644 pkg/connector/chatinfo.go create mode 100644 pkg/connector/client.go create mode 100644 pkg/connector/config.go create mode 100644 pkg/connector/handlematrix.go create mode 100644 pkg/connector/handlesignal.go create mode 100644 pkg/connector/id.go create mode 100644 pkg/connector/msgconvproxy.go diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go new file mode 100644 index 0000000..eea4381 --- /dev/null +++ b/pkg/connector/chatinfo.go @@ -0,0 +1,233 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +const PrivateChatTopic = "Signal private chat" +const NoteToSelfName = "Signal Note to Self" + +func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { + userID, err := parseUserID(ghost.ID) + if err != nil { + return nil, err + } + contact, err := s.Client.ContactByACI(ctx, userID) + if err != nil { + return nil, err + } + return s.contactToUserInfo(contact), nil +} + +func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { + userID, groupID, err := s.parsePortalID(portal.ID) + if err != nil { + return nil, err + } + if groupID != "" { + groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, 0) + if err != nil { + return nil, err + } + isDM := false + isSpace := false + members := make([]networkid.UserID, len(groupInfo.Members)) + for i, member := range groupInfo.Members { + members[i] = makeUserID(member.ACI) + } + return &bridgev2.PortalInfo{ + Name: &groupInfo.Title, + Topic: &groupInfo.Description, + Avatar: &bridgev2.Avatar{ + ID: makeAvatarPathID(groupInfo.AvatarPath), + Get: func(ctx context.Context) ([]byte, error) { + return s.Client.DownloadGroupAvatar(ctx, groupInfo) + }, + Remove: groupInfo.AvatarPath == "", + }, + Members: members, + IsDirectChat: &isDM, + IsSpace: &isSpace, + }, nil + } else { + aci, pni := serviceIDToACIAndPNI(userID) + contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) + if err != nil { + return nil, err + } + return s.makeCreateDMResponse(contact).PortalInfo, nil + } +} + +func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.UserInfo { + isBot := false + ui := &bridgev2.UserInfo{ + IsBot: &isBot, + } + name := s.Main.Config.FormatDisplayname(contact) + ui.Name = &name + if s.Main.Config.UseContactAvatars && contact.ContactAvatar.Hash != "" { + ui.Avatar = &bridgev2.Avatar{ + ID: networkid.AvatarID("hash:" + contact.ContactAvatar.Hash), + Get: func(ctx context.Context) ([]byte, error) { + if contact.ContactAvatar.Image == nil { + return nil, fmt.Errorf("contact avatar not available") + } + return contact.ContactAvatar.Image, nil + }, + } + } else if contact.Profile.AvatarPath != "" { + ui.Avatar = &bridgev2.Avatar{ + ID: makeAvatarPathID(contact.Profile.AvatarPath), + Get: func(ctx context.Context) ([]byte, error) { + return s.Client.DownloadUserAvatar(ctx, contact.Profile.AvatarPath, contact.Profile.Key) + }, + } + } else { + ui.Avatar = &bridgev2.Avatar{ + ID: "", + Remove: true, + } + } + return ui +} + +func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { + number, err := bridgev2.CleanPhoneNumber(number) + if err != nil { + return nil, err + } + e164Number, err := strconv.ParseUint(strings.TrimPrefix(number, "+"), 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing phone number: %w", err) + } + e164String := fmt.Sprintf("+%d", e164Number) + var aci, pni uuid.UUID + var recipient *types.Recipient + if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { + return nil, fmt.Errorf("error looking up number in local contact list: %w", err) + } else if recipient != nil { + aci = recipient.ACI + pni = recipient.PNI + } else if resp, err := s.Client.LookupPhone(ctx, e164Number); err != nil { + return nil, fmt.Errorf("error looking up number on server: %w", err) + } else { + aci = resp[e164Number].ACI + pni = resp[e164Number].PNI + if aci == uuid.Nil && pni == uuid.Nil { + return nil, errors.New("user not found on Signal") + } + recipient, err = s.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI + } + zerolog.Ctx(ctx).Debug(). + Uint64("e164", e164Number). + Stringer("aci", aci). + Stringer("pni", pni). + Msg("Found resolve identifier target user") + + // createChat is a no-op: chats don't need to be created, and we always return chat info + if aci != uuid.Nil { + ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(aci)) + if err != nil { + return nil, fmt.Errorf("failed to get ghost: %w", err) + } + return &bridgev2.ResolveIdentifierResponse{ + UserID: makeUserID(aci), + UserInfo: s.contactToUserInfo(recipient), + Ghost: ghost, + Chat: s.makeCreateDMResponse(recipient), + }, nil + } else { + return &bridgev2.ResolveIdentifierResponse{ + UserID: makeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), + UserInfo: s.contactToUserInfo(recipient), + Chat: s.makeCreateDMResponse(recipient), + }, nil + } +} + +func (s *SignalClient) CreateGroup(ctx context.Context, name string, users ...networkid.UserID) (*bridgev2.CreateChatResponse, error) { + //TODO implement me + return nil, fmt.Errorf("not implemented") +} + +func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { + isDirectChat := true + isSpace := false + name := "" + topic := PrivateChatTopic + members := []networkid.UserID{makeUserID(s.Client.Store.ACI)} + if s.Main.Config.NumberInTopic && recipient.E164 != "" { + topic = fmt.Sprintf("%s with %s", PrivateChatTopic, recipient.E164) + } + var serviceID libsignalgo.ServiceID + if recipient.ACI == uuid.Nil { + name = s.Main.Config.FormatDisplayname(recipient) + serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) + } else { + if recipient.ACI == s.Client.Store.ACI { + name = NoteToSelfName + } else { + // The other user is only present if their ACI is known + members = append(members, makeUserID(recipient.ACI)) + } + serviceID = libsignalgo.NewACIServiceID(recipient.ACI) + } + return &bridgev2.CreateChatResponse{ + PortalID: s.makeDMPortalKey(serviceID), + PortalInfo: &bridgev2.PortalInfo{ + Name: &name, + Topic: &topic, + Members: members, + IsDirectChat: &isDirectChat, + IsSpace: &isSpace, + }, + } +} + +func makeAvatarPathID(avatarPath string) networkid.AvatarID { + if avatarPath == "" { + return "" + } + return networkid.AvatarID("path:" + avatarPath) +} + +func serviceIDToACIAndPNI(serviceID libsignalgo.ServiceID) (aci, pni uuid.UUID) { + if serviceID.Type == libsignalgo.ServiceIDTypeACI { + return serviceID.UUID, uuid.Nil + } else { + return uuid.Nil, serviceID.UUID + } +} diff --git a/pkg/connector/client.go b/pkg/connector/client.go new file mode 100644 index 0000000..6034a7c --- /dev/null +++ b/pkg/connector/client.go @@ -0,0 +1,197 @@ +package connector + +import ( + "context" + "fmt" + "time" + + "github.com/rs/zerolog" + "maunium.net/go/mautrix/bridge/status" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/signalmeow" +) + +type SignalClient struct { + Main *SignalConnector + UserLogin *bridgev2.UserLogin + Client *signalmeow.Client +} + +var _ bridgev2.NetworkAPI = (*SignalClient)(nil) +var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) +var _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) + +var pushCfg = &bridgev2.PushConfig{ + FCM: &bridgev2.FCMPushConfig{ + // https://github.com/signalapp/Signal-Android/blob/main/app/src/main/res/values/firebase_messaging.xml#L4 + SenderID: "312334754206", + }, + APNs: &bridgev2.APNsPushConfig{ + BundleID: "org.whispersystems.signal", + }, +} + +func (s *SignalClient) GetPushConfigs() *bridgev2.PushConfig { + return pushCfg +} + +func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { + if pushType != bridgev2.PushTypeFCM { + return fmt.Errorf("unsupported push type: %s", pushType) + } + return s.Client.RegisterFCM(ctx, token) +} + +func (s *SignalClient) LogoutRemote(ctx context.Context) { + err := s.Client.StopReceiveLoops() + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") + } + err = s.Main.Store.DeleteDevice(context.TODO(), &s.Client.Store.DeviceData) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to delete device from store") + } +} + +func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bool { + return userID == makeUserID(s.Client.Store.ACI) +} + +func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnectionStatus) { + var peekedConnectionStatus signalmeow.SignalConnectionStatus + for { + var connectionStatus signalmeow.SignalConnectionStatus + if peekedConnectionStatus.Event != signalmeow.SignalConnectionEventNone { + s.UserLogin.Log.Debug(). + Stringer("peeked_connection_status_event", peekedConnectionStatus.Event). + Msg("Using peeked connectionStatus event") + connectionStatus = peekedConnectionStatus + peekedConnectionStatus = signalmeow.SignalConnectionStatus{} + } else { + var ok bool + connectionStatus, ok = <-statusChan + if !ok { + s.UserLogin.Log.Debug().Msg("statusChan channel closed") + return + } + } + + err := connectionStatus.Err + switch connectionStatus.Event { + case signalmeow.SignalConnectionEventConnected: + s.UserLogin.Log.Debug().Msg("Sending Connected BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) + + case signalmeow.SignalConnectionEventDisconnected: + s.UserLogin.Log.Debug().Msg("Received SignalConnectionEventDisconnected") + + // Debounce: wait 7s before sending TransientDisconnect, in case we get a reconnect + // We should wait until the next message comes in, or 7 seconds has passed. + // - If a disconnected event comes in, just loop again, unless it's been more than 7 seconds. + // - If a non-disconnected event comes in, store it in peekedConnectionStatus, + // break out of this loop and go back to the top of the goroutine to handle it in the switch. + // - If 7 seconds passes without any non-disconnect messages, send the TransientDisconnect. + // (Why 7 seconds? It was 5 at first, but websockets min retry is 5 seconds, + // so it would send TransientDisconnect right before reconnecting. 7 seems to work well.) + debounceTimer := time.NewTimer(7 * time.Second) + PeekLoop: + for { + var ok bool + select { + case peekedConnectionStatus, ok = <-statusChan: + // Handle channel closing + if !ok { + s.UserLogin.Log.Debug().Msg("connectionStatus channel closed") + return + } + // If it's another Disconnected event, just keep looping + if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected { + peekedConnectionStatus = signalmeow.SignalConnectionStatus{} + continue + } + // If it's a non-disconnect event, break out of the PeekLoop and handle it in the switch + break PeekLoop + case <-debounceTimer.C: + // Time is up, so break out of the loop and send the TransientDisconnect + break PeekLoop + } + } + // We're out of the PeekLoop, so either we got a non-disconnect event, or it's been 7 seconds (or both). + // We want to send TransientDisconnect if it's been 7 seconds, but not if the latest event was something + // other than Disconnected + if !debounceTimer.Stop() { // If the timer has already expired + // Send TransientDisconnect only if the latest event is a disconnect or no event + // (peekedConnectionStatus could be something else if the timer and the event race) + if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected || + peekedConnectionStatus.Event == signalmeow.SignalConnectionEventNone { + s.UserLogin.Log.Debug().Msg("Sending TransientDisconnect BridgeState") + if err == nil { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect}) + } else { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) + } + } + } + + case signalmeow.SignalConnectionEventLoggedOut: + s.UserLogin.Log.Debug().Msg("Sending BadCredentials BridgeState") + if err == nil { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) + } else { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: err.Error()}) + } + err = s.Client.ClearKeysAndDisconnect(context.TODO()) + if err != nil { + s.UserLogin.Log.Error().Err(err).Msg("Failed to clear keys and disconnect") + } + + case signalmeow.SignalConnectionEventError: + s.UserLogin.Log.Debug().Msg("Sending UnknownError BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + + case signalmeow.SignalConnectionCleanShutdown: + if s.Client.IsLoggedIn() { + s.UserLogin.Log.Debug().Msg("Clean Shutdown - sending no BridgeState") + } else { + s.UserLogin.Log.Debug().Msg("Clean Shutdown, but logged out - Sending BadCredentials BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) + } + } + } +} + +func (s *SignalClient) Connect(ctx context.Context) error { + s.tryConnect(ctx, 0) + return nil +} + +func (s *SignalClient) Disconnect() { + err := s.Client.StopReceiveLoops() + if err != nil { + s.UserLogin.Log.Err(err).Msg("Failed to stop receive loops") + } +} + +func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { + ch, err := s.Client.StartReceiveLoops(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") + if retryCount < 6 { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) + retryInSeconds := 2 << retryCount + zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") + time.Sleep(time.Duration(retryInSeconds) * time.Second) + s.tryConnect(ctx, retryCount+1) + } else { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + } + } else { + go s.bridgeStateLoop(ch) + } +} + +func (s *SignalClient) IsLoggedIn() bool { + return s.Client.IsLoggedIn() +} diff --git a/pkg/connector/config.go b/pkg/connector/config.go new file mode 100644 index 0000000..20fb6e8 --- /dev/null +++ b/pkg/connector/config.go @@ -0,0 +1,86 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + _ "embed" + "strings" + "text/template" + + up "go.mau.fi/util/configupgrade" + "maunium.net/go/mautrix/id" + + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +//go:embed example-config.yaml +var ExampleConfig string + +type SignalConfig struct { + DisplaynameTemplate string `yaml:"displayname_template"` + UseContactAvatars bool `yaml:"use_contact_avatars"` + UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` + NumberInTopic bool `yaml:"number_in_topic"` + DeviceName string `yaml:"device_name"` + NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` + LocationFormat string `yaml:"location_format"` + + displaynameTemplate *template.Template `yaml:"-"` +} + +type DisplaynameParams struct { + ProfileName string + ContactName string + Username string + PhoneNumber string + UUID string + ACI string + PNI string + AboutEmoji string +} + +func (c *SignalConfig) FormatDisplayname(contact *types.Recipient) string { + var nameBuf strings.Builder + err := c.displaynameTemplate.Execute(&nameBuf, &DisplaynameParams{ + ProfileName: contact.Profile.Name, + ContactName: contact.ContactName, + Username: "", + PhoneNumber: contact.E164, + UUID: contact.ACI.String(), + ACI: contact.ACI.String(), + PNI: contact.PNI.String(), + AboutEmoji: contact.Profile.AboutEmoji, + }) + if err != nil { + panic(err) + } + return nameBuf.String() +} + +func upgradeConfig(helper up.Helper) { + helper.Copy(up.Str, "displayname_template") + helper.Copy(up.Bool, "use_contact_avatars") + helper.Copy(up.Bool, "use_outdated_profiles") + helper.Copy(up.Bool, "number_in_topic") + helper.Copy(up.Str, "device_name") + helper.Copy(up.Str, "note_to_self_avatar") + helper.Copy(up.Str, "location_format") +} + +func (s *SignalConnector) GetConfig() (string, any, up.Upgrader) { + return ExampleConfig, s.Config, up.SimpleUpgrader(upgradeConfig) +} diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index cb1788d..fe594dd 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -18,81 +18,22 @@ package connector import ( "context" - _ "embed" - "errors" "fmt" - "strconv" - "strings" "text/template" - "time" "github.com/google/uuid" - "github.com/rs/zerolog" - up "go.mau.fi/util/configupgrade" "go.mau.fi/util/dbutil" - "go.mau.fi/util/exzerolog" - "go.mau.fi/util/variationselector" - "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" - "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" - legacydb "go.mau.fi/mautrix-signal/database" "go.mau.fi/mautrix-signal/msgconv" "go.mau.fi/mautrix-signal/msgconv/matrixfmt" "go.mau.fi/mautrix-signal/msgconv/signalfmt" - "go.mau.fi/mautrix-signal/pkg/libsignalgo" "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/store" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -type SignalConfig struct { - DisplaynameTemplate string `yaml:"displayname_template"` - UseContactAvatars bool `yaml:"use_contact_avatars"` - UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` - NumberInTopic bool `yaml:"number_in_topic"` - DeviceName string `yaml:"device_name"` - NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` - LocationFormat string `yaml:"location_format"` - - displaynameTemplate *template.Template `yaml:"-"` -} - -type DisplaynameParams struct { - ProfileName string - ContactName string - Username string - PhoneNumber string - UUID string - ACI string - PNI string - AboutEmoji string -} - -func (c *SignalConfig) FormatDisplayname(contact *types.Recipient) string { - var nameBuf strings.Builder - err := c.displaynameTemplate.Execute(&nameBuf, &DisplaynameParams{ - ProfileName: contact.Profile.Name, - ContactName: contact.ContactName, - Username: "", - PhoneNumber: contact.E164, - UUID: contact.ACI.String(), - ACI: contact.ACI.String(), - PNI: contact.PNI.String(), - AboutEmoji: contact.Profile.AboutEmoji, - }) - if err != nil { - panic(err) - } - return nameBuf.String() -} - type SignalConnector struct { MsgConv *msgconv.MessageConverter Store *store.Container @@ -102,10 +43,6 @@ type SignalConnector struct { var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) -var _ bridgev2.NetworkAPI = (*SignalClient)(nil) -var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) -var _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) -var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) func NewConnector() *SignalConnector { return &SignalConnector{ @@ -113,9 +50,6 @@ func NewConnector() *SignalConnector { } } -//go:embed example-config.yaml -var ExampleConfig string - func (s *SignalConnector) GetName() bridgev2.BridgeName { return bridgev2.BridgeName{ DisplayName: "Signal", @@ -127,20 +61,6 @@ func (s *SignalConnector) GetName() bridgev2.BridgeName { } } -func upgradeConfig(helper up.Helper) { - helper.Copy(up.Str, "displayname_template") - helper.Copy(up.Bool, "use_contact_avatars") - helper.Copy(up.Bool, "use_outdated_profiles") - helper.Copy(up.Bool, "number_in_topic") - helper.Copy(up.Str, "device_name") - helper.Copy(up.Str, "note_to_self_avatar") - helper.Copy(up.Str, "location_format") -} - -func (s *SignalConnector) GetConfig() (string, any, up.Upgrader) { - return ExampleConfig, s.Config, up.SimpleUpgrader(upgradeConfig) -} - func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { var err error s.Config.displaynameTemplate, err = template.New("displayname").Parse(s.Config.DisplaynameTemplate) @@ -229,1187 +149,3 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use login.Client = sc return nil } - -type SignalClient struct { - Main *SignalConnector - UserLogin *bridgev2.UserLogin - Client *signalmeow.Client -} - -var pushCfg = &bridgev2.PushConfig{ - FCM: &bridgev2.FCMPushConfig{ - // https://github.com/signalapp/Signal-Android/blob/main/app/src/main/res/values/firebase_messaging.xml#L4 - SenderID: "312334754206", - }, - APNs: &bridgev2.APNsPushConfig{ - BundleID: "org.whispersystems.signal", - }, -} - -func (s *SignalClient) GetPushConfigs() *bridgev2.PushConfig { - return pushCfg -} - -func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { - if pushType != bridgev2.PushTypeFCM { - return fmt.Errorf("unsupported push type: %s", pushType) - } - return s.Client.RegisterFCM(ctx, token) -} - -func (s *SignalClient) LogoutRemote(ctx context.Context) { - err := s.Client.StopReceiveLoops() - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") - } - err = s.Main.Store.DeleteDevice(context.TODO(), &s.Client.Store.DeviceData) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to delete device from store") - } -} - -func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.UserInfo { - isBot := false - ui := &bridgev2.UserInfo{ - IsBot: &isBot, - } - name := s.Main.Config.FormatDisplayname(contact) - ui.Name = &name - if s.Main.Config.UseContactAvatars && contact.ContactAvatar.Hash != "" { - ui.Avatar = &bridgev2.Avatar{ - ID: networkid.AvatarID("hash:" + contact.ContactAvatar.Hash), - Get: func(ctx context.Context) ([]byte, error) { - if contact.ContactAvatar.Image == nil { - return nil, fmt.Errorf("contact avatar not available") - } - return contact.ContactAvatar.Image, nil - }, - } - } else if contact.Profile.AvatarPath != "" { - ui.Avatar = &bridgev2.Avatar{ - ID: makeAvatarPathID(contact.Profile.AvatarPath), - Get: func(ctx context.Context) ([]byte, error) { - return s.Client.DownloadUserAvatar(ctx, contact.Profile.AvatarPath, contact.Profile.Key) - }, - } - } else { - ui.Avatar = &bridgev2.Avatar{ - ID: "", - Remove: true, - } - } - return ui -} - -func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { - userID, err := parseUserID(ghost.ID) - if err != nil { - return nil, err - } - contact, err := s.Client.ContactByACI(ctx, userID) - if err != nil { - return nil, err - } - return s.contactToUserInfo(contact), nil -} - -func makeAvatarPathID(avatarPath string) networkid.AvatarID { - if avatarPath == "" { - return "" - } - return networkid.AvatarID("path:" + avatarPath) -} - -func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { - userID, groupID, err := s.parsePortalID(portal.ID) - if err != nil { - return nil, err - } - if groupID != "" { - groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, 0) - if err != nil { - return nil, err - } - isDM := false - isSpace := false - members := make([]networkid.UserID, len(groupInfo.Members)) - for i, member := range groupInfo.Members { - members[i] = makeUserID(member.ACI) - } - return &bridgev2.PortalInfo{ - Name: &groupInfo.Title, - Topic: &groupInfo.Description, - Avatar: &bridgev2.Avatar{ - ID: makeAvatarPathID(groupInfo.AvatarPath), - Get: func(ctx context.Context) ([]byte, error) { - return s.Client.DownloadGroupAvatar(ctx, groupInfo) - }, - Remove: groupInfo.AvatarPath == "", - }, - Members: members, - IsDirectChat: &isDM, - IsSpace: &isSpace, - }, nil - } else { - aci, pni := serviceIDToACIAndPNI(userID) - contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) - if err != nil { - return nil, err - } - return s.makeCreateDMResponse(contact).PortalInfo, nil - } -} - -func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { - number, err := bridgev2.CleanPhoneNumber(number) - if err != nil { - return nil, err - } - e164Number, err := strconv.ParseUint(strings.TrimPrefix(number, "+"), 10, 64) - if err != nil { - return nil, fmt.Errorf("error parsing phone number: %w", err) - } - e164String := fmt.Sprintf("+%d", e164Number) - var aci, pni uuid.UUID - var recipient *types.Recipient - if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { - return nil, fmt.Errorf("error looking up number in local contact list: %w", err) - } else if recipient != nil { - aci = recipient.ACI - pni = recipient.PNI - } else if resp, err := s.Client.LookupPhone(ctx, e164Number); err != nil { - return nil, fmt.Errorf("error looking up number on server: %w", err) - } else { - aci = resp[e164Number].ACI - pni = resp[e164Number].PNI - if aci == uuid.Nil && pni == uuid.Nil { - return nil, errors.New("user not found on Signal") - } - recipient, err = s.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") - } - aci, pni = recipient.ACI, recipient.PNI - } - zerolog.Ctx(ctx).Debug(). - Uint64("e164", e164Number). - Stringer("aci", aci). - Stringer("pni", pni). - Msg("Found resolve identifier target user") - - // createChat is a no-op: chats don't need to be created, and we always return chat info - if aci != uuid.Nil { - ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(aci)) - if err != nil { - return nil, fmt.Errorf("failed to get ghost: %w", err) - } - return &bridgev2.ResolveIdentifierResponse{ - UserID: makeUserID(aci), - UserInfo: s.contactToUserInfo(recipient), - Ghost: ghost, - Chat: s.makeCreateDMResponse(recipient), - }, nil - } else { - return &bridgev2.ResolveIdentifierResponse{ - UserID: makeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), - UserInfo: s.contactToUserInfo(recipient), - Chat: s.makeCreateDMResponse(recipient), - }, nil - } -} - -const PrivateChatTopic = "Signal private chat" -const NoteToSelfName = "Signal Note to Self" - -func serviceIDToACIAndPNI(serviceID libsignalgo.ServiceID) (aci, pni uuid.UUID) { - if serviceID.Type == libsignalgo.ServiceIDTypeACI { - return serviceID.UUID, uuid.Nil - } else { - return uuid.Nil, serviceID.UUID - } -} - -func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { - isDirectChat := true - isSpace := false - name := "" - topic := PrivateChatTopic - members := []networkid.UserID{makeUserID(s.Client.Store.ACI)} - if s.Main.Config.NumberInTopic && recipient.E164 != "" { - topic = fmt.Sprintf("%s with %s", PrivateChatTopic, recipient.E164) - } - var serviceID libsignalgo.ServiceID - if recipient.ACI == uuid.Nil { - name = s.Main.Config.FormatDisplayname(recipient) - serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) - } else { - if recipient.ACI == s.Client.Store.ACI { - name = NoteToSelfName - } else { - // The other user is only present if their ACI is known - members = append(members, makeUserID(recipient.ACI)) - } - serviceID = libsignalgo.NewACIServiceID(recipient.ACI) - } - return &bridgev2.CreateChatResponse{ - PortalID: networkid.PortalKey{ - ID: networkid.PortalID(serviceID.String()), - Receiver: s.UserLogin.ID, - }, - PortalInfo: &bridgev2.PortalInfo{ - Name: &name, - Topic: &topic, - Members: members, - IsDirectChat: &isDirectChat, - IsSpace: &isSpace, - }, - } -} - -func (s *SignalClient) CreateGroup(ctx context.Context, name string, users ...networkid.UserID) (*bridgev2.CreateChatResponse, error) { - //TODO implement me - return nil, fmt.Errorf("not implemented") -} - -func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bool { - return userID == makeUserID(s.Client.Store.ACI) -} - -func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnectionStatus) { - var peekedConnectionStatus signalmeow.SignalConnectionStatus - for { - var connectionStatus signalmeow.SignalConnectionStatus - if peekedConnectionStatus.Event != signalmeow.SignalConnectionEventNone { - s.UserLogin.Log.Debug(). - Stringer("peeked_connection_status_event", peekedConnectionStatus.Event). - Msg("Using peeked connectionStatus event") - connectionStatus = peekedConnectionStatus - peekedConnectionStatus = signalmeow.SignalConnectionStatus{} - } else { - var ok bool - connectionStatus, ok = <-statusChan - if !ok { - s.UserLogin.Log.Debug().Msg("statusChan channel closed") - return - } - } - - err := connectionStatus.Err - switch connectionStatus.Event { - case signalmeow.SignalConnectionEventConnected: - s.UserLogin.Log.Debug().Msg("Sending Connected BridgeState") - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) - - case signalmeow.SignalConnectionEventDisconnected: - s.UserLogin.Log.Debug().Msg("Received SignalConnectionEventDisconnected") - - // Debounce: wait 7s before sending TransientDisconnect, in case we get a reconnect - // We should wait until the next message comes in, or 7 seconds has passed. - // - If a disconnected event comes in, just loop again, unless it's been more than 7 seconds. - // - If a non-disconnected event comes in, store it in peekedConnectionStatus, - // break out of this loop and go back to the top of the goroutine to handle it in the switch. - // - If 7 seconds passes without any non-disconnect messages, send the TransientDisconnect. - // (Why 7 seconds? It was 5 at first, but websockets min retry is 5 seconds, - // so it would send TransientDisconnect right before reconnecting. 7 seems to work well.) - debounceTimer := time.NewTimer(7 * time.Second) - PeekLoop: - for { - var ok bool - select { - case peekedConnectionStatus, ok = <-statusChan: - // Handle channel closing - if !ok { - s.UserLogin.Log.Debug().Msg("connectionStatus channel closed") - return - } - // If it's another Disconnected event, just keep looping - if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected { - peekedConnectionStatus = signalmeow.SignalConnectionStatus{} - continue - } - // If it's a non-disconnect event, break out of the PeekLoop and handle it in the switch - break PeekLoop - case <-debounceTimer.C: - // Time is up, so break out of the loop and send the TransientDisconnect - break PeekLoop - } - } - // We're out of the PeekLoop, so either we got a non-disconnect event, or it's been 7 seconds (or both). - // We want to send TransientDisconnect if it's been 7 seconds, but not if the latest event was something - // other than Disconnected - if !debounceTimer.Stop() { // If the timer has already expired - // Send TransientDisconnect only if the latest event is a disconnect or no event - // (peekedConnectionStatus could be something else if the timer and the event race) - if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected || - peekedConnectionStatus.Event == signalmeow.SignalConnectionEventNone { - s.UserLogin.Log.Debug().Msg("Sending TransientDisconnect BridgeState") - if err == nil { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect}) - } else { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) - } - } - } - - case signalmeow.SignalConnectionEventLoggedOut: - s.UserLogin.Log.Debug().Msg("Sending BadCredentials BridgeState") - if err == nil { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - } else { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: err.Error()}) - } - err = s.Client.ClearKeysAndDisconnect(context.TODO()) - if err != nil { - s.UserLogin.Log.Error().Err(err).Msg("Failed to clear keys and disconnect") - } - - case signalmeow.SignalConnectionEventError: - s.UserLogin.Log.Debug().Msg("Sending UnknownError BridgeState") - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) - - case signalmeow.SignalConnectionCleanShutdown: - if s.Client.IsLoggedIn() { - s.UserLogin.Log.Debug().Msg("Clean Shutdown - sending no BridgeState") - } else { - s.UserLogin.Log.Debug().Msg("Clean Shutdown, but logged out - Sending BadCredentials BridgeState") - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - } - } - } -} - -func (s *SignalClient) Connect(ctx context.Context) error { - s.tryConnect(ctx, 0) - return nil -} - -func (s *SignalClient) Disconnect() { - err := s.Client.StopReceiveLoops() - if err != nil { - s.UserLogin.Log.Err(err).Msg("Failed to stop receive loops") - } -} - -func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { - ch, err := s.Client.StartReceiveLoops(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") - if retryCount < 6 { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) - retryInSeconds := 2 << retryCount - zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") - time.Sleep(time.Duration(retryInSeconds) * time.Second) - s.tryConnect(ctx, retryCount+1) - } else { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) - } - } else { - go s.bridgeStateLoop(ch) - } -} - -func (s *SignalClient) IsLoggedIn() bool { - return s.Client.IsLoggedIn() -} - -func parseUserID(userID networkid.UserID) (uuid.UUID, error) { - serviceID, err := parseUserIDAsServiceID(userID) - if err != nil { - return uuid.Nil, err - } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { - return uuid.Nil, fmt.Errorf("invalid user ID: expected ACI type") - } else { - return serviceID.UUID, nil - } -} - -func parseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { - return libsignalgo.ServiceIDFromString(string(userID)) -} - -func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { - if len(portalID) == 44 { - groupID = types.GroupIdentifier(portalID) - } else { - userID, err = libsignalgo.ServiceIDFromString(string(portalID)) - } - return -} - -func parseMessageID(messageID networkid.MessageID) (sender uuid.UUID, timestamp uint64, err error) { - parts := strings.Split(string(messageID), "|") - if len(parts) != 2 { - err = fmt.Errorf("invalid message ID: expected two pipe-separated parts") - return - } - sender, err = uuid.Parse(parts[0]) - if err != nil { - return - } - timestamp, err = strconv.ParseUint(parts[1], 10, 64) - return -} - -func makeMessageID(sender uuid.UUID, timestamp uint64) networkid.MessageID { - return networkid.MessageID(fmt.Sprintf("%s|%d", sender, timestamp)) -} - -func makeUserID(user uuid.UUID) networkid.UserID { - return networkid.UserID(user.String()) -} - -func makeUserIDFromServiceID(user libsignalgo.ServiceID) networkid.UserID { - return networkid.UserID(user.String()) -} - -func makeUserLoginID(user uuid.UUID) networkid.UserLoginID { - return networkid.UserLoginID(user.String()) -} - -func (s *SignalClient) makeEventSender(sender uuid.UUID) bridgev2.EventSender { - return bridgev2.EventSender{ - IsFromMe: sender == s.Client.Store.ACI, - SenderLogin: makeUserLoginID(sender), - Sender: makeUserID(sender), - } -} - -func makeMessagePartID(index int) networkid.PartID { - if index == 0 { - return "" - } - return networkid.PartID(strconv.Itoa(index)) -} - -type contextKey int - -var msgconvContextKey contextKey - -type msgconvContext struct { - Connector *SignalConnector - Intent bridgev2.MatrixAPI - Client *SignalClient - Portal *bridgev2.Portal - ReplyTo *database.Message -} - -type Bv2ChatEvent struct { - *events.ChatEvent - s *SignalClient -} - -var ( - _ bridgev2.RemoteMessage = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteEdit = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteEventWithTimestamp = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteReaction = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteTyping = (*Bv2ChatEvent)(nil) -) - -func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { - switch innerEvt := evt.Event.(type) { - case *signalpb.DataMessage: - switch { - case innerEvt.Body != nil, innerEvt.Attachments != nil, innerEvt.Contact != nil, innerEvt.Sticker != nil: - return bridgev2.RemoteEventMessage - case innerEvt.Reaction != nil: - if innerEvt.Reaction.GetRemove() { - return bridgev2.RemoteEventReactionRemove - } - return bridgev2.RemoteEventReaction - case innerEvt.Delete != nil: - return bridgev2.RemoteEventMessageRemove - } - case *signalpb.EditMessage: - return bridgev2.RemoteEventEdit - case *signalpb.TypingMessage: - return bridgev2.RemoteEventTyping - } - return bridgev2.RemoteEventUnknown -} - -func (evt *Bv2ChatEvent) GetTimeout() time.Duration { - if evt.Event.(*signalpb.TypingMessage).GetAction() == signalpb.TypingMessage_STARTED { - return 15 * time.Second - } else { - return 0 - } -} - -func (evt *Bv2ChatEvent) GetPortalKey() networkid.PortalKey { - key := networkid.PortalKey{ID: networkid.PortalID(evt.Info.ChatID)} - // For non-group chats, add receiver - if len(evt.Info.ChatID) != 44 { - key.Receiver = makeUserLoginID(evt.s.Client.Store.ACI) - } - return key -} - -func (evt *Bv2ChatEvent) ShouldCreatePortal() bool { - return evt.GetType() == bridgev2.RemoteEventMessage -} - -func (evt *Bv2ChatEvent) AddLogContext(c zerolog.Context) zerolog.Context { - c = c.Stringer("sender_id", evt.Info.Sender) - switch innerEvt := evt.Event.(type) { - case *signalpb.DataMessage: - c = c.Uint64("message_ts", innerEvt.GetTimestamp()) - switch { - case innerEvt.Reaction != nil: - c = c.Uint64("reaction_target_ts", innerEvt.Reaction.GetTargetSentTimestamp()) - case innerEvt.Delete != nil: - c = c.Uint64("delete_target_ts", innerEvt.Delete.GetTargetSentTimestamp()) - } - case *signalpb.EditMessage: - c = c. - Uint64("edit_target_ts", innerEvt.GetTargetSentTimestamp()). - Uint64("edit_ts", innerEvt.GetDataMessage().GetTimestamp()) - } - return c -} - -func (evt *Bv2ChatEvent) GetSender() bridgev2.EventSender { - return evt.s.makeEventSender(evt.Info.Sender) -} - -func (evt *Bv2ChatEvent) GetID() networkid.MessageID { - ts := evt.getDataMsgTimestamp() - if ts == 0 { - panic(fmt.Errorf("GetID() called for non-DataMessage event")) - } - return makeMessageID(evt.Info.Sender, ts) -} - -func (evt *Bv2ChatEvent) getDataMsgTimestamp() uint64 { - switch innerEvt := evt.Event.(type) { - case *signalpb.DataMessage: - return innerEvt.GetTimestamp() - case *signalpb.EditMessage: - return innerEvt.GetDataMessage().GetTimestamp() - default: - return 0 - } -} - -func (evt *Bv2ChatEvent) GetTimestamp() time.Time { - ts := evt.getDataMsgTimestamp() - if ts == 0 { - return time.Now() - } - return time.UnixMilli(int64(ts)) -} - -func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { - var targetAuthorACI string - var targetSentTS uint64 - switch innerEvt := evt.Event.(type) { - case *signalpb.DataMessage: - switch { - case innerEvt.Reaction != nil: - targetAuthorACI = innerEvt.Reaction.GetTargetAuthorAci() - targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp() - case innerEvt.Delete != nil: - targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() - default: - panic(fmt.Errorf("GetTargetMessage() called for message type without target")) - } - case *signalpb.EditMessage: - targetSentTS = innerEvt.GetTargetSentTimestamp() - default: - panic(fmt.Errorf("GetTargetMessage() called for message type without target")) - } - targetAuthorUUID := evt.Info.Sender - if targetAuthorACI != "" { - targetAuthorUUID, _ = uuid.Parse(targetAuthorACI) - } - return makeMessageID(targetAuthorUUID, targetSentTS) -} - -func (evt *Bv2ChatEvent) GetReactionEmoji() (string, networkid.EmojiID) { - dataMsg, ok := evt.Event.(*signalpb.DataMessage) - if !ok || dataMsg.Reaction == nil { - panic(fmt.Errorf("GetReactionEmoji() called for non-reaction event")) - } - return dataMsg.GetReaction().GetEmoji(), "" -} - -func (evt *Bv2ChatEvent) GetRemovedEmojiID() networkid.EmojiID { - return "" -} - -func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) { - mcCtx := &msgconvContext{ - Connector: evt.s.Main, - Intent: intent, - Client: evt.s, - Portal: portal, - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - dataMsg, ok := evt.Event.(*signalpb.DataMessage) - if !ok { - return nil, fmt.Errorf("ConvertMessage() called for non-DataMessage event") - } - converted := evt.s.Main.MsgConv.ToMatrix(ctx, dataMsg) - converted.MergeCaption() - var replyTo *networkid.MessageOptionalPartID - if dataMsg.GetQuote() != nil { - quoteAuthor, _ := uuid.Parse(dataMsg.Quote.GetAuthorAci()) - replyTo = &networkid.MessageOptionalPartID{ - MessageID: makeMessageID(quoteAuthor, dataMsg.Quote.GetId()), - } - } - convertedParts := make([]*bridgev2.ConvertedMessagePart, len(converted.Parts)) - for i, part := range converted.Parts { - convertedParts[i] = &bridgev2.ConvertedMessagePart{ - ID: makeMessagePartID(i), - Type: part.Type, - Content: part.Content, - Extra: part.Extra, - } - } - var disappear database.DisappearingSetting - if converted.DisappearIn != 0 { - disappear = database.DisappearingSetting{ - Type: database.DisappearingTypeAfterRead, - Timer: time.Duration(converted.DisappearIn) * time.Second, - } - if evt.Info.Sender == evt.s.Client.Store.ACI { - disappear.DisappearAt = time.UnixMilli(int64(dataMsg.GetTimestamp())).Add(disappear.Timer) - } - if portal.Metadata.DisappearTimer != disappear.Timer { - portal.Metadata.DisappearType = disappear.Type - portal.Metadata.DisappearTimer = disappear.Timer - // TODO if the message doesn't have the DataMessage_EXPIRATION_TIMER_UPDATE, - // we should send a message to the portal notifying of the implicit update - err := portal.Save(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save portal metadata after updating disappearing timer") - } else { - zerolog.Ctx(ctx).Debug().Dur("new_timer", portal.Metadata.DisappearTimer).Msg("Updated disappearing timer in portal") - } - } - } - return &bridgev2.ConvertedMessage{ - ReplyTo: replyTo, - Parts: convertedParts, - Disappear: disappear, - }, nil -} - -func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message) (*bridgev2.ConvertedEdit, error) { - mcCtx := &msgconvContext{ - Connector: evt.s.Main, - Intent: intent, - Client: evt.s, - Portal: portal, - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - editMsg, ok := evt.Event.(*signalpb.EditMessage) - if !ok { - return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event") - } - // TODO tell converter about existing parts to avoid reupload? - converted := evt.s.Main.MsgConv.ToMatrix(ctx, editMsg.GetDataMessage()) - converted.MergeCaption() - convertedEdit := &bridgev2.ConvertedEdit{} - // TODO can anything other than the text be edited? - lastPart := converted.Parts[len(converted.Parts)-1] - convertedEdit.ModifiedParts = append(convertedEdit.ModifiedParts, &bridgev2.ConvertedEditPart{ - Part: existing[len(existing)-1], - Type: lastPart.Type, - Content: lastPart.Content, - Extra: lastPart.Extra, - }) - return convertedEdit, nil -} - -type Bv2Receipt struct { - Type signalpb.ReceiptMessage_Type - Chat networkid.PortalKey - Sender bridgev2.EventSender - - LastTS time.Time - LastID networkid.MessageID - IDs []networkid.MessageID -} - -func (b *Bv2Receipt) GetType() bridgev2.RemoteEventType { - switch b.Type { - case signalpb.ReceiptMessage_READ: - return bridgev2.RemoteEventReadReceipt - case signalpb.ReceiptMessage_DELIVERY: - return bridgev2.RemoteEventDeliveryReceipt - default: - return bridgev2.RemoteEventUnknown - } -} - -func (b *Bv2Receipt) GetPortalKey() networkid.PortalKey { - return b.Chat -} - -func (b *Bv2Receipt) AddLogContext(c zerolog.Context) zerolog.Context { - return c. - Str("sender_id", string(b.Sender.Sender)). - Stringer("receipt_type", b.Type). - Array("message_ids", exzerolog.ArrayOfStrs(b.IDs)) -} - -func (b *Bv2Receipt) GetSender() bridgev2.EventSender { - return b.Sender -} - -func (b *Bv2Receipt) GetLastReceiptTarget() networkid.MessageID { - return b.LastID -} - -func (b *Bv2Receipt) GetReceiptTargets() []networkid.MessageID { - return b.IDs -} - -var _ bridgev2.RemoteReceipt = (*Bv2Receipt)(nil) - -func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt { - log := zerolog.Ctx(ctx) - receipts := make(map[networkid.PortalKey]*Bv2Receipt) - for _, msgID := range input { - msg, err := getMessageFunc(ctx, msgID) - if err != nil { - log.Err(err).Any("message_id", msgID).Msg("Failed to get target message for receipt") - } else if msg == nil { - log.Debug().Any("message_id", msgID).Msg("Got receipt for unknown message") - } else { - receiptEvt, ok := receipts[msg.Room] - if !ok { - receiptEvt = &Bv2Receipt{Chat: msg.Room} - receipts[msg.Room] = receiptEvt - } - receiptEvt.IDs = append(receiptEvt.IDs, msg.ID) - if receiptEvt.LastTS.Before(msg.Timestamp) { - receiptEvt.LastTS = msg.Timestamp - receiptEvt.LastID = msg.ID - } - } - } - return receipts -} - -func (s *SignalClient) dispatchReceipts(sender uuid.UUID, receiptType signalpb.ReceiptMessage_Type, receipts map[networkid.PortalKey]*Bv2Receipt) { - evtSender := s.makeEventSender(sender) - for chat, receiptEvt := range receipts { - receiptEvt.Chat = chat - receiptEvt.Sender = evtSender - receiptEvt.Type = receiptType - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, receiptEvt) - } -} - -func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { - log := s.UserLogin.Log.With(). - Str("action", "handle signal receipt"). - Stringer("sender_id", evt.Sender). - Stringer("receipt_type", evt.Content.GetType()). - Logger() - ctx := log.WithContext(context.TODO()) - receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { - return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(s.Client.Store.ACI, msgTS)) - }) - s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) -} - -func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { - log := s.UserLogin.Log.With(). - Str("action", "handle signal read self"). - Logger() - ctx := log.WithContext(context.TODO()) - receipts := convertReceipts(ctx, evt.Messages, func(ctx context.Context, msgInfo *signalpb.SyncMessage_Read) (*database.Message, error) { - aciUUID, err := uuid.Parse(msgInfo.GetSenderAci()) - if err != nil { - return nil, err - } - return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(aciUUID, msgInfo.GetTimestamp())) - }) - s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) -} - -func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { - switch evt := rawEvt.(type) { - case *events.ChatEvent: - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) - case *events.DecryptionError: - case *events.Receipt: - s.handleSignalReceipt(evt) - case *events.ReadSelf: - s.handleSignalReadSelf(evt) - case *events.Call: - case *events.ContactList: - s.handleSignalContactList(evt) - case *events.ACIFound: - s.handleSignalACIFound(evt) - } -} - -func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { - log := s.UserLogin.Log.With(). - Str("action", "handle aci found"). - Stringer("aci", evt.ACI). - Stringer("pni", evt.PNI). - Logger() - ctx := log.WithContext(context.TODO()) - pniPortalKey := networkid.PortalKey{ - ID: networkid.PortalID(evt.PNI.String()), - Receiver: s.UserLogin.ID, - } - aciPortalKey := networkid.PortalKey{ - ID: networkid.PortalID(evt.ACI.String()), - Receiver: s.UserLogin.ID, - } - result, portal, err := s.Main.Bridge.ReIDPortal(ctx, pniPortalKey, aciPortalKey) - if err != nil { - log.Err(err).Msg("Failed to re-ID portal") - } else if result == bridgev2.ReIDResultSourceReIDd || result == bridgev2.ReIDResultTargetDeletedAndSourceReIDd { - // If the source portal is re-ID'd, we need to sync metadata and participants. - // If the source is deleted, then it doesn't matter, any existing target will already be correct - info, err := s.GetChatInfo(ctx, portal) - if err != nil { - log.Err(err).Msg("Failed to get chat info to update portal after re-ID") - } else { - portal.UpdateInfo(ctx, info, s.UserLogin, nil, time.Time{}) - } - } -} - -func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { - log := s.UserLogin.Log.With().Str("action", "handle contact list").Logger() - ctx := log.WithContext(context.TODO()) - for _, contact := range evt.Contacts { - if contact.ACI != uuid.Nil { - fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) - if err != nil { - log.Err(err).Msg("Failed to get full contact info from store") - continue - } - fullContact.ContactAvatar = contact.ContactAvatar - ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(contact.ACI)) - if err != nil { - log.Err(err).Msg("Failed to get ghost to update contact info") - continue - } - ghost.UpdateInfo(ctx, s.contactToUserInfo(contact)) - } - } -} - -func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) { - mcCtx := &msgconvContext{ - Connector: s.Main, - Intent: nil, - Client: s, - Portal: msg.Portal, - ReplyTo: msg.ReplyTo, - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) - if err != nil { - return nil, err - } - res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) - if err != nil { - return nil, err - } - // TODO check result - fmt.Println(res) - dbMsg := &database.Message{ - ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), - SenderID: makeUserID(s.Client.Store.ACI), - Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), - } - dbMsg.Metadata.Extra = map[string]any{ - "contains_attachments": len(converted.Attachments) > 0, - } - if msg.ReplyTo != nil { - dbMsg.RelatesToRowID = msg.ReplyTo.RowID - } - return &bridgev2.MatrixMessageResponse{ - DB: dbMsg, - }, nil -} - -func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { - _, targetSentTimestamp, err := parseMessageID(msg.EditTarget.ID) - if err != nil { - return fmt.Errorf("failed to parse target message ID: %w", err) - } else if msg.EditTarget.SenderID != makeUserID(s.Client.Store.ACI) { - return fmt.Errorf("cannot edit other people's messages") - } - mcCtx := &msgconvContext{ - Connector: s.Main, - Intent: nil, - Client: s, - Portal: msg.Portal, - } - if msg.EditTarget.RelatesToRowID != 0 { - var err error - mcCtx.ReplyTo, err = s.Main.Bridge.DB.Message.GetByRowID(ctx, msg.EditTarget.RelatesToRowID) - if err != nil { - return fmt.Errorf("failed to get message reply target: %w", err) - } - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) - if err != nil { - return err - } - res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - DataMessage: converted, - }}) - if err != nil { - return err - } - // TODO check result - fmt.Println(res) - msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) - msg.EditTarget.Metadata.Extra["contains_attachments"] = len(converted.Attachments) > 0 - return nil -} - -func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) (signalmeow.SendResult, error) { - userID, groupID, err := s.parsePortalID(portalID) - if err != nil { - return nil, err - } - if groupID != "" { - res, err := s.Client.SendGroupMessage(ctx, groupID, content) - if err != nil { - return nil, err - } - return res, nil - } else { - res := s.Client.SendMessage(ctx, userID, content) - return &res, nil - } -} - -func (s *SignalClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { - return bridgev2.MatrixReactionPreResponse{ - SenderID: makeUserID(s.Client.Store.ACI), - EmojiID: "", - Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key), - }, nil -} - -func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { - targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) - if err != nil { - return nil, fmt.Errorf("failed to parse target message ID: %w", err) - } - wrappedContent := &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), - RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), - Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.PreHandleResp.Emoji), - Remove: proto.Bool(false), - TargetAuthorAci: proto.String(targetAuthorACI.String()), - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - }, - }, - } - res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) - if err != nil { - return nil, err - } - // TODO check result - fmt.Println(res) - return &database.Reaction{}, nil -} - -func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { - targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetReaction.MessageID) - if err != nil { - return fmt.Errorf("failed to parse target message ID: %w", err) - } - wrappedContent := &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), - RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), - Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.TargetReaction.Metadata.Emoji), - Remove: proto.Bool(true), - TargetAuthorAci: proto.String(targetAuthorACI.String()), - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - }, - }, - } - res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) - if err != nil { - return err - } - // TODO check result - fmt.Println(res) - return nil -} - -func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { - _, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) - if err != nil { - return fmt.Errorf("failed to parse target message ID: %w", err) - } else if msg.TargetMessage.SenderID != makeUserID(s.Client.Store.ACI) { - return fmt.Errorf("cannot delete other people's messages") - } - wrappedContent := &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), - Delete: &signalpb.DataMessage_Delete{ - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - }, - }, - } - res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) - if err != nil { - return err - } - // TODO check result - fmt.Println(res) - return nil -} - -func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bridgev2.MatrixReadReceipt) error { - if !receipt.ReadUpTo.After(receipt.LastRead) { - return nil - } - if receipt.LastRead.IsZero() { - receipt.LastRead = receipt.ReadUpTo.Add(-5 * time.Second) - } - dbMessages, err := s.Main.Bridge.DB.Message.GetMessagesBetweenTimeQuery(ctx, receipt.Portal.PortalKey, receipt.LastRead, receipt.ReadUpTo) - if err != nil { - return fmt.Errorf("failed to get messages to mark as read: %w", err) - } else if len(dbMessages) == 0 { - return nil - } - messagesToRead := map[uuid.UUID][]uint64{} - for _, msg := range dbMessages { - userID, timestamp, err := parseMessageID(msg.ID) - if err != nil { - return fmt.Errorf("failed to parse message ID %q: %w", msg.ID, err) - } - messagesToRead[userID] = append(messagesToRead[userID], timestamp) - } - zerolog.Ctx(ctx).Debug(). - Any("targets", messagesToRead). - Msg("Collected read receipt target messages") - - // TODO send sync message manually containing all read receipts instead of a separate message for each recipient - - for destination, messages := range messagesToRead { - // Don't send read receipts for own messages - if destination == s.Client.Store.ACI { - continue - } - // Don't use portal.sendSignalMessage because we're sending this straight to - // who sent the original message, not the portal's ChatID - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - result := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(destination), signalmeow.ReadReceptMessageForTimestamps(messages)) - cancel() - if !result.WasSuccessful { - zerolog.Ctx(ctx).Err(result.FailedSendResult.Error). - Stringer("destination", destination). - Uints64("message_ids", messages). - Msg("Failed to send read receipt to Signal") - } else { - zerolog.Ctx(ctx).Debug(). - Stringer("destination", destination). - Uints64("message_ids", messages). - Msg("Sent read receipt to Signal") - } - } - return nil -} - -func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2.MatrixTyping) error { - userID, _, err := s.parsePortalID(typing.Portal.ID) - if err != nil { - return err - } - // Only send typing notifications in DMs for now - // Sending efficiently to groups requires implementing the proper SenderKey stuff first - if !userID.IsEmpty() && userID.Type == libsignalgo.ServiceIDTypeACI { - typingMessage := signalmeow.TypingMessage(typing.IsTyping) - result := s.Client.SendMessage(ctx, userID, typingMessage) - fmt.Println(result) - // TODO check result - } - return nil -} - -type msgconvPortalMethods struct{} - -func (mpm *msgconvPortalMethods) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { - mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) - uri, _, err := mcCtx.Intent.UploadMedia(ctx, "", data, fileName, contentType) - return uri, err -} - -func (mpm *msgconvPortalMethods) DownloadMatrixMedia(ctx context.Context, uri id.ContentURIString) ([]byte, error) { - return ctx.Value(msgconvContextKey).(*msgconvContext).Connector.Bridge.Bot.DownloadMedia(ctx, uri, nil) -} - -func (mpm *msgconvPortalMethods) GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) { - // Matrix replies are handled in bridgev2 code - return "", "" -} - -func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote { - mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) - if mcCtx.ReplyTo == nil { - return nil - } - quote := &signalpb.DataMessage_Quote{ - Id: proto.Uint64(uint64(mcCtx.ReplyTo.Timestamp.UnixMilli())), - AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), - Type: signalpb.DataMessage_Quote_NORMAL.Enum(), - } - if mcCtx.ReplyTo.Metadata.Extra["contains_attachments"] != false { - quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) - } - return quote -} - -func (mpm *msgconvPortalMethods) GetClient(ctx context.Context) *signalmeow.Client { - return ctx.Value(msgconvContextKey).(*msgconvContext).Client.Client -} - -func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { - mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) - portal := mcCtx.Portal - userID, groupID, _ := mcCtx.Client.parsePortalID(portal.ID) - chatID := string(groupID) - if chatID == "" { - chatID = userID.String() - } - pk := legacydb.PortalKey{ - ChatID: chatID, - } - if len(chatID) != 44 { - pk.Receiver = mcCtx.Client.Client.Store.ACI - } - return &legacydb.Portal{ - PortalKey: pk, - MXID: portal.MXID, - Name: portal.Name, - Topic: portal.Topic, - //AvatarPath: "", - //AvatarHash: "", - //AvatarURL: id.ContentURI{}, - NameSet: portal.NameSet, - AvatarSet: portal.AvatarSet, - TopicSet: portal.TopicSet, - //Revision: portal.Metadata["revision"].(uint32), - Encrypted: true, - //RelayUserID: portal.Relay.UserMXID, - ExpirationTime: uint32(portal.Metadata.DisappearTimer.Milliseconds()), - } -} diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go new file mode 100644 index 0000000..839c644 --- /dev/null +++ b/pkg/connector/handlematrix.go @@ -0,0 +1,278 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/variationselector" + "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" +) + +func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) (signalmeow.SendResult, error) { + userID, groupID, err := s.parsePortalID(portalID) + if err != nil { + return nil, err + } + if groupID != "" { + res, err := s.Client.SendGroupMessage(ctx, groupID, content) + if err != nil { + return nil, err + } + return res, nil + } else { + res := s.Client.SendMessage(ctx, userID, content) + return &res, nil + } +} + +func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) { + mcCtx := &msgconvContext{ + Connector: s.Main, + Intent: nil, + Client: s, + Portal: msg.Portal, + ReplyTo: msg.ReplyTo, + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) + if err != nil { + return nil, err + } + res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) + if err != nil { + return nil, err + } + // TODO check result + fmt.Println(res) + dbMsg := &database.Message{ + ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), + SenderID: makeUserID(s.Client.Store.ACI), + Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), + } + dbMsg.Metadata.Extra = map[string]any{ + "contains_attachments": len(converted.Attachments) > 0, + } + if msg.ReplyTo != nil { + dbMsg.RelatesToRowID = msg.ReplyTo.RowID + } + return &bridgev2.MatrixMessageResponse{ + DB: dbMsg, + }, nil +} + +func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { + _, targetSentTimestamp, err := parseMessageID(msg.EditTarget.ID) + if err != nil { + return fmt.Errorf("failed to parse target message ID: %w", err) + } else if msg.EditTarget.SenderID != makeUserID(s.Client.Store.ACI) { + return fmt.Errorf("cannot edit other people's messages") + } + mcCtx := &msgconvContext{ + Connector: s.Main, + Intent: nil, + Client: s, + Portal: msg.Portal, + } + if msg.EditTarget.RelatesToRowID != 0 { + var err error + mcCtx.ReplyTo, err = s.Main.Bridge.DB.Message.GetByRowID(ctx, msg.EditTarget.RelatesToRowID) + if err != nil { + return fmt.Errorf("failed to get message reply target: %w", err) + } + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) + if err != nil { + return err + } + res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + DataMessage: converted, + }}) + if err != nil { + return err + } + // TODO check result + fmt.Println(res) + msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) + msg.EditTarget.Metadata.Extra["contains_attachments"] = len(converted.Attachments) > 0 + return nil +} + +func (s *SignalClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { + return bridgev2.MatrixReactionPreResponse{ + SenderID: makeUserID(s.Client.Store.ACI), + EmojiID: "", + Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key), + }, nil +} + +func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { + targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) + if err != nil { + return nil, fmt.Errorf("failed to parse target message ID: %w", err) + } + wrappedContent := &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), + Reaction: &signalpb.DataMessage_Reaction{ + Emoji: proto.String(msg.PreHandleResp.Emoji), + Remove: proto.Bool(false), + TargetAuthorAci: proto.String(targetAuthorACI.String()), + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + }, + }, + } + res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + if err != nil { + return nil, err + } + // TODO check result + fmt.Println(res) + return &database.Reaction{}, nil +} + +func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { + targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetReaction.MessageID) + if err != nil { + return fmt.Errorf("failed to parse target message ID: %w", err) + } + wrappedContent := &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), + Reaction: &signalpb.DataMessage_Reaction{ + Emoji: proto.String(msg.TargetReaction.Metadata.Emoji), + Remove: proto.Bool(true), + TargetAuthorAci: proto.String(targetAuthorACI.String()), + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + }, + }, + } + res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + if err != nil { + return err + } + // TODO check result + fmt.Println(res) + return nil +} + +func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { + _, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) + if err != nil { + return fmt.Errorf("failed to parse target message ID: %w", err) + } else if msg.TargetMessage.SenderID != makeUserID(s.Client.Store.ACI) { + return fmt.Errorf("cannot delete other people's messages") + } + wrappedContent := &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + Delete: &signalpb.DataMessage_Delete{ + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + }, + }, + } + res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + if err != nil { + return err + } + // TODO check result + fmt.Println(res) + return nil +} + +func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bridgev2.MatrixReadReceipt) error { + if !receipt.ReadUpTo.After(receipt.LastRead) { + return nil + } + if receipt.LastRead.IsZero() { + receipt.LastRead = receipt.ReadUpTo.Add(-5 * time.Second) + } + dbMessages, err := s.Main.Bridge.DB.Message.GetMessagesBetweenTimeQuery(ctx, receipt.Portal.PortalKey, receipt.LastRead, receipt.ReadUpTo) + if err != nil { + return fmt.Errorf("failed to get messages to mark as read: %w", err) + } else if len(dbMessages) == 0 { + return nil + } + messagesToRead := map[uuid.UUID][]uint64{} + for _, msg := range dbMessages { + userID, timestamp, err := parseMessageID(msg.ID) + if err != nil { + return fmt.Errorf("failed to parse message ID %q: %w", msg.ID, err) + } + messagesToRead[userID] = append(messagesToRead[userID], timestamp) + } + zerolog.Ctx(ctx).Debug(). + Any("targets", messagesToRead). + Msg("Collected read receipt target messages") + + // TODO send sync message manually containing all read receipts instead of a separate message for each recipient + + for destination, messages := range messagesToRead { + // Don't send read receipts for own messages + if destination == s.Client.Store.ACI { + continue + } + // Don't use portal.sendSignalMessage because we're sending this straight to + // who sent the original message, not the portal's ChatID + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + result := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(destination), signalmeow.ReadReceptMessageForTimestamps(messages)) + cancel() + if !result.WasSuccessful { + zerolog.Ctx(ctx).Err(result.FailedSendResult.Error). + Stringer("destination", destination). + Uints64("message_ids", messages). + Msg("Failed to send read receipt to Signal") + } else { + zerolog.Ctx(ctx).Debug(). + Stringer("destination", destination). + Uints64("message_ids", messages). + Msg("Sent read receipt to Signal") + } + } + return nil +} + +func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2.MatrixTyping) error { + userID, _, err := s.parsePortalID(typing.Portal.ID) + if err != nil { + return err + } + // Only send typing notifications in DMs for now + // Sending efficiently to groups requires implementing the proper SenderKey stuff first + if !userID.IsEmpty() && userID.Type == libsignalgo.ServiceIDTypeACI { + typingMessage := signalmeow.TypingMessage(typing.IsTyping) + result := s.Client.SendMessage(ctx, userID, typingMessage) + fmt.Println(result) + // TODO check result + } + return nil +} diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go new file mode 100644 index 0000000..bfbc773 --- /dev/null +++ b/pkg/connector/handlesignal.go @@ -0,0 +1,431 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/exzerolog" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/signalmeow/events" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" +) + +func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { + switch evt := rawEvt.(type) { + case *events.ChatEvent: + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) + case *events.DecryptionError: + case *events.Receipt: + s.handleSignalReceipt(evt) + case *events.ReadSelf: + s.handleSignalReadSelf(evt) + case *events.Call: + case *events.ContactList: + s.handleSignalContactList(evt) + case *events.ACIFound: + s.handleSignalACIFound(evt) + } +} + +type Bv2ChatEvent struct { + *events.ChatEvent + s *SignalClient +} + +var ( + _ bridgev2.RemoteMessage = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEdit = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEventWithTimestamp = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReaction = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteTyping = (*Bv2ChatEvent)(nil) +) + +func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + switch { + case innerEvt.Body != nil, innerEvt.Attachments != nil, innerEvt.Contact != nil, innerEvt.Sticker != nil: + return bridgev2.RemoteEventMessage + case innerEvt.Reaction != nil: + if innerEvt.Reaction.GetRemove() { + return bridgev2.RemoteEventReactionRemove + } + return bridgev2.RemoteEventReaction + case innerEvt.Delete != nil: + return bridgev2.RemoteEventMessageRemove + } + case *signalpb.EditMessage: + return bridgev2.RemoteEventEdit + case *signalpb.TypingMessage: + return bridgev2.RemoteEventTyping + } + return bridgev2.RemoteEventUnknown +} + +func (evt *Bv2ChatEvent) GetTimeout() time.Duration { + if evt.Event.(*signalpb.TypingMessage).GetAction() == signalpb.TypingMessage_STARTED { + return 15 * time.Second + } else { + return 0 + } +} + +func (evt *Bv2ChatEvent) GetPortalKey() networkid.PortalKey { + return evt.s.makePortalKey(evt.Info.ChatID) +} + +func (evt *Bv2ChatEvent) ShouldCreatePortal() bool { + return evt.GetType() == bridgev2.RemoteEventMessage +} + +func (evt *Bv2ChatEvent) AddLogContext(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Info.Sender) + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + c = c.Uint64("message_ts", innerEvt.GetTimestamp()) + switch { + case innerEvt.Reaction != nil: + c = c.Uint64("reaction_target_ts", innerEvt.Reaction.GetTargetSentTimestamp()) + case innerEvt.Delete != nil: + c = c.Uint64("delete_target_ts", innerEvt.Delete.GetTargetSentTimestamp()) + } + case *signalpb.EditMessage: + c = c. + Uint64("edit_target_ts", innerEvt.GetTargetSentTimestamp()). + Uint64("edit_ts", innerEvt.GetDataMessage().GetTimestamp()) + } + return c +} + +func (evt *Bv2ChatEvent) GetSender() bridgev2.EventSender { + return evt.s.makeEventSender(evt.Info.Sender) +} + +func (evt *Bv2ChatEvent) GetID() networkid.MessageID { + ts := evt.getDataMsgTimestamp() + if ts == 0 { + panic(fmt.Errorf("GetID() called for non-DataMessage event")) + } + return makeMessageID(evt.Info.Sender, ts) +} + +func (evt *Bv2ChatEvent) getDataMsgTimestamp() uint64 { + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + return innerEvt.GetTimestamp() + case *signalpb.EditMessage: + return innerEvt.GetDataMessage().GetTimestamp() + default: + return 0 + } +} + +func (evt *Bv2ChatEvent) GetTimestamp() time.Time { + ts := evt.getDataMsgTimestamp() + if ts == 0 { + return time.Now() + } + return time.UnixMilli(int64(ts)) +} + +func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { + var targetAuthorACI string + var targetSentTS uint64 + switch innerEvt := evt.Event.(type) { + case *signalpb.DataMessage: + switch { + case innerEvt.Reaction != nil: + targetAuthorACI = innerEvt.Reaction.GetTargetAuthorAci() + targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp() + case innerEvt.Delete != nil: + targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() + default: + panic(fmt.Errorf("GetTargetMessage() called for message type without target")) + } + case *signalpb.EditMessage: + targetSentTS = innerEvt.GetTargetSentTimestamp() + default: + panic(fmt.Errorf("GetTargetMessage() called for message type without target")) + } + targetAuthorUUID := evt.Info.Sender + if targetAuthorACI != "" { + targetAuthorUUID, _ = uuid.Parse(targetAuthorACI) + } + return makeMessageID(targetAuthorUUID, targetSentTS) +} + +func (evt *Bv2ChatEvent) GetReactionEmoji() (string, networkid.EmojiID) { + dataMsg, ok := evt.Event.(*signalpb.DataMessage) + if !ok || dataMsg.Reaction == nil { + panic(fmt.Errorf("GetReactionEmoji() called for non-reaction event")) + } + return dataMsg.GetReaction().GetEmoji(), "" +} + +func (evt *Bv2ChatEvent) GetRemovedEmojiID() networkid.EmojiID { + return "" +} + +func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) { + mcCtx := &msgconvContext{ + Connector: evt.s.Main, + Intent: intent, + Client: evt.s, + Portal: portal, + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + dataMsg, ok := evt.Event.(*signalpb.DataMessage) + if !ok { + return nil, fmt.Errorf("ConvertMessage() called for non-DataMessage event") + } + converted := evt.s.Main.MsgConv.ToMatrix(ctx, dataMsg) + converted.MergeCaption() + var replyTo *networkid.MessageOptionalPartID + if dataMsg.GetQuote() != nil { + quoteAuthor, _ := uuid.Parse(dataMsg.Quote.GetAuthorAci()) + replyTo = &networkid.MessageOptionalPartID{ + MessageID: makeMessageID(quoteAuthor, dataMsg.Quote.GetId()), + } + } + convertedParts := make([]*bridgev2.ConvertedMessagePart, len(converted.Parts)) + for i, part := range converted.Parts { + convertedParts[i] = &bridgev2.ConvertedMessagePart{ + ID: makeMessagePartID(i), + Type: part.Type, + Content: part.Content, + Extra: part.Extra, + } + } + var disappear database.DisappearingSetting + if converted.DisappearIn != 0 { + disappear = database.DisappearingSetting{ + Type: database.DisappearingTypeAfterRead, + Timer: time.Duration(converted.DisappearIn) * time.Second, + } + if evt.Info.Sender == evt.s.Client.Store.ACI { + disappear.DisappearAt = time.UnixMilli(int64(dataMsg.GetTimestamp())).Add(disappear.Timer) + } + if portal.Metadata.DisappearTimer != disappear.Timer { + portal.Metadata.DisappearType = disappear.Type + portal.Metadata.DisappearTimer = disappear.Timer + // TODO if the message doesn't have the DataMessage_EXPIRATION_TIMER_UPDATE, + // we should send a message to the portal notifying of the implicit update + err := portal.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save portal metadata after updating disappearing timer") + } else { + zerolog.Ctx(ctx).Debug().Dur("new_timer", portal.Metadata.DisappearTimer).Msg("Updated disappearing timer in portal") + } + } + } + return &bridgev2.ConvertedMessage{ + ReplyTo: replyTo, + Parts: convertedParts, + Disappear: disappear, + }, nil +} + +func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message) (*bridgev2.ConvertedEdit, error) { + mcCtx := &msgconvContext{ + Connector: evt.s.Main, + Intent: intent, + Client: evt.s, + Portal: portal, + } + ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) + editMsg, ok := evt.Event.(*signalpb.EditMessage) + if !ok { + return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event") + } + // TODO tell converter about existing parts to avoid reupload? + converted := evt.s.Main.MsgConv.ToMatrix(ctx, editMsg.GetDataMessage()) + converted.MergeCaption() + convertedEdit := &bridgev2.ConvertedEdit{} + // TODO can anything other than the text be edited? + lastPart := converted.Parts[len(converted.Parts)-1] + convertedEdit.ModifiedParts = append(convertedEdit.ModifiedParts, &bridgev2.ConvertedEditPart{ + Part: existing[len(existing)-1], + Type: lastPart.Type, + Content: lastPart.Content, + Extra: lastPart.Extra, + }) + return convertedEdit, nil +} + +type Bv2Receipt struct { + Type signalpb.ReceiptMessage_Type + Chat networkid.PortalKey + Sender bridgev2.EventSender + + LastTS time.Time + LastID networkid.MessageID + IDs []networkid.MessageID +} + +func (b *Bv2Receipt) GetType() bridgev2.RemoteEventType { + switch b.Type { + case signalpb.ReceiptMessage_READ: + return bridgev2.RemoteEventReadReceipt + case signalpb.ReceiptMessage_DELIVERY: + return bridgev2.RemoteEventDeliveryReceipt + default: + return bridgev2.RemoteEventUnknown + } +} + +func (b *Bv2Receipt) GetPortalKey() networkid.PortalKey { + return b.Chat +} + +func (b *Bv2Receipt) AddLogContext(c zerolog.Context) zerolog.Context { + return c. + Str("sender_id", string(b.Sender.Sender)). + Stringer("receipt_type", b.Type). + Array("message_ids", exzerolog.ArrayOfStrs(b.IDs)) +} + +func (b *Bv2Receipt) GetSender() bridgev2.EventSender { + return b.Sender +} + +func (b *Bv2Receipt) GetLastReceiptTarget() networkid.MessageID { + return b.LastID +} + +func (b *Bv2Receipt) GetReceiptTargets() []networkid.MessageID { + return b.IDs +} + +var _ bridgev2.RemoteReceipt = (*Bv2Receipt)(nil) + +func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt { + log := zerolog.Ctx(ctx) + receipts := make(map[networkid.PortalKey]*Bv2Receipt) + for _, msgID := range input { + msg, err := getMessageFunc(ctx, msgID) + if err != nil { + log.Err(err).Any("message_id", msgID).Msg("Failed to get target message for receipt") + } else if msg == nil { + log.Debug().Any("message_id", msgID).Msg("Got receipt for unknown message") + } else { + receiptEvt, ok := receipts[msg.Room] + if !ok { + receiptEvt = &Bv2Receipt{Chat: msg.Room} + receipts[msg.Room] = receiptEvt + } + receiptEvt.IDs = append(receiptEvt.IDs, msg.ID) + if receiptEvt.LastTS.Before(msg.Timestamp) { + receiptEvt.LastTS = msg.Timestamp + receiptEvt.LastID = msg.ID + } + } + } + return receipts +} + +func (s *SignalClient) dispatchReceipts(sender uuid.UUID, receiptType signalpb.ReceiptMessage_Type, receipts map[networkid.PortalKey]*Bv2Receipt) { + evtSender := s.makeEventSender(sender) + for chat, receiptEvt := range receipts { + receiptEvt.Chat = chat + receiptEvt.Sender = evtSender + receiptEvt.Type = receiptType + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, receiptEvt) + } +} + +func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { + log := s.UserLogin.Log.With(). + Str("action", "handle signal receipt"). + Stringer("sender_id", evt.Sender). + Stringer("receipt_type", evt.Content.GetType()). + Logger() + ctx := log.WithContext(context.TODO()) + receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(s.Client.Store.ACI, msgTS)) + }) + s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) +} + +func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { + log := s.UserLogin.Log.With(). + Str("action", "handle signal read self"). + Logger() + ctx := log.WithContext(context.TODO()) + receipts := convertReceipts(ctx, evt.Messages, func(ctx context.Context, msgInfo *signalpb.SyncMessage_Read) (*database.Message, error) { + aciUUID, err := uuid.Parse(msgInfo.GetSenderAci()) + if err != nil { + return nil, err + } + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(aciUUID, msgInfo.GetTimestamp())) + }) + s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) +} + +func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { + log := s.UserLogin.Log.With(). + Str("action", "handle aci found"). + Stringer("aci", evt.ACI). + Stringer("pni", evt.PNI). + Logger() + ctx := log.WithContext(context.TODO()) + pniPortalKey := s.makeDMPortalKey(evt.PNI) + aciPortalKey := s.makeDMPortalKey(evt.ACI) + result, portal, err := s.Main.Bridge.ReIDPortal(ctx, pniPortalKey, aciPortalKey) + if err != nil { + log.Err(err).Msg("Failed to re-ID portal") + } else if result == bridgev2.ReIDResultSourceReIDd || result == bridgev2.ReIDResultTargetDeletedAndSourceReIDd { + // If the source portal is re-ID'd, we need to sync metadata and participants. + // If the source is deleted, then it doesn't matter, any existing target will already be correct + info, err := s.GetChatInfo(ctx, portal) + if err != nil { + log.Err(err).Msg("Failed to get chat info to update portal after re-ID") + } else { + portal.UpdateInfo(ctx, info, s.UserLogin, nil, time.Time{}) + } + } +} + +func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { + log := s.UserLogin.Log.With().Str("action", "handle contact list").Logger() + ctx := log.WithContext(context.TODO()) + for _, contact := range evt.Contacts { + if contact.ACI != uuid.Nil { + fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) + if err != nil { + log.Err(err).Msg("Failed to get full contact info from store") + continue + } + fullContact.ContactAvatar = contact.ContactAvatar + ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(contact.ACI)) + if err != nil { + log.Err(err).Msg("Failed to get ghost to update contact info") + continue + } + ghost.UpdateInfo(ctx, s.contactToUserInfo(contact)) + } + } +} diff --git a/pkg/connector/id.go b/pkg/connector/id.go new file mode 100644 index 0000000..147b21f --- /dev/null +++ b/pkg/connector/id.go @@ -0,0 +1,130 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "fmt" + "strconv" + "strings" + + "github.com/google/uuid" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +func parseUserID(userID networkid.UserID) (uuid.UUID, error) { + serviceID, err := parseUserIDAsServiceID(userID) + if err != nil { + return uuid.Nil, err + } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return uuid.Nil, fmt.Errorf("invalid user ID: expected ACI type") + } else { + return serviceID.UUID, nil + } +} + +func parseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { + return libsignalgo.ServiceIDFromString(string(userID)) +} + +func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { + if len(portalID) == 44 { + groupID = types.GroupIdentifier(portalID) + } else { + userID, err = libsignalgo.ServiceIDFromString(string(portalID)) + } + return +} + +func parseMessageID(messageID networkid.MessageID) (sender uuid.UUID, timestamp uint64, err error) { + parts := strings.Split(string(messageID), "|") + if len(parts) != 2 { + err = fmt.Errorf("invalid message ID: expected two pipe-separated parts") + return + } + sender, err = uuid.Parse(parts[0]) + if err != nil { + return + } + timestamp, err = strconv.ParseUint(parts[1], 10, 64) + return +} + +func makeGroupPortalID(groupID types.GroupIdentifier) networkid.PortalID { + return networkid.PortalID(groupID) +} + +func makeGroupPortalKey(groupID types.GroupIdentifier) networkid.PortalKey { + return networkid.PortalKey{ + ID: makeGroupPortalID(groupID), + Receiver: "", + } +} + +func makeDMPortalID(serviceID libsignalgo.ServiceID) networkid.PortalID { + return networkid.PortalID(serviceID.String()) +} + +func (s *SignalClient) makePortalKey(chatID string) networkid.PortalKey { + key := networkid.PortalKey{ID: networkid.PortalID(chatID)} + // For non-group chats, add receiver + if len(chatID) != 44 { + key.Receiver = s.UserLogin.ID + } + return key +} + +func (s *SignalClient) makeDMPortalKey(serviceID libsignalgo.ServiceID) networkid.PortalKey { + return networkid.PortalKey{ + ID: makeDMPortalID(serviceID), + Receiver: s.UserLogin.ID, + } +} + +func makeMessageID(sender uuid.UUID, timestamp uint64) networkid.MessageID { + return networkid.MessageID(fmt.Sprintf("%s|%d", sender, timestamp)) +} + +func makeUserID(user uuid.UUID) networkid.UserID { + return networkid.UserID(user.String()) +} + +func makeUserIDFromServiceID(user libsignalgo.ServiceID) networkid.UserID { + return networkid.UserID(user.String()) +} + +func makeUserLoginID(user uuid.UUID) networkid.UserLoginID { + return networkid.UserLoginID(user.String()) +} + +func (s *SignalClient) makeEventSender(sender uuid.UUID) bridgev2.EventSender { + return bridgev2.EventSender{ + IsFromMe: sender == s.Client.Store.ACI, + SenderLogin: makeUserLoginID(sender), + Sender: makeUserID(sender), + } +} + +func makeMessagePartID(index int) networkid.PartID { + if index == 0 { + return "" + } + return networkid.PartID(strconv.Itoa(index)) +} diff --git a/pkg/connector/msgconvproxy.go b/pkg/connector/msgconvproxy.go new file mode 100644 index 0000000..bf1ef3d --- /dev/null +++ b/pkg/connector/msgconvproxy.go @@ -0,0 +1,115 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + + "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" + + legacydb "go.mau.fi/mautrix-signal/database" + "go.mau.fi/mautrix-signal/msgconv" + "go.mau.fi/mautrix-signal/pkg/signalmeow" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" +) + +type contextKey int + +var msgconvContextKey contextKey + +type msgconvContext struct { + Connector *SignalConnector + Intent bridgev2.MatrixAPI + Client *SignalClient + Portal *bridgev2.Portal + ReplyTo *database.Message +} + +type msgconvPortalMethods struct{} + +var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) + +func (mpm *msgconvPortalMethods) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { + mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) + uri, _, err := mcCtx.Intent.UploadMedia(ctx, "", data, fileName, contentType) + return uri, err +} + +func (mpm *msgconvPortalMethods) DownloadMatrixMedia(ctx context.Context, uri id.ContentURIString) ([]byte, error) { + return ctx.Value(msgconvContextKey).(*msgconvContext).Connector.Bridge.Bot.DownloadMedia(ctx, uri, nil) +} + +func (mpm *msgconvPortalMethods) GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) { + // Matrix replies are handled in bridgev2 code + return "", "" +} + +func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote { + mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) + if mcCtx.ReplyTo == nil { + return nil + } + quote := &signalpb.DataMessage_Quote{ + Id: proto.Uint64(uint64(mcCtx.ReplyTo.Timestamp.UnixMilli())), + AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), + Type: signalpb.DataMessage_Quote_NORMAL.Enum(), + } + if mcCtx.ReplyTo.Metadata.Extra["contains_attachments"] != false { + quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) + } + return quote +} + +func (mpm *msgconvPortalMethods) GetClient(ctx context.Context) *signalmeow.Client { + return ctx.Value(msgconvContextKey).(*msgconvContext).Client.Client +} + +func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { + mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) + portal := mcCtx.Portal + userID, groupID, _ := mcCtx.Client.parsePortalID(portal.ID) + chatID := string(groupID) + if chatID == "" { + chatID = userID.String() + } + pk := legacydb.PortalKey{ + ChatID: chatID, + } + if len(chatID) != 44 { + pk.Receiver = mcCtx.Client.Client.Store.ACI + } + return &legacydb.Portal{ + PortalKey: pk, + MXID: portal.MXID, + Name: portal.Name, + Topic: portal.Topic, + //AvatarPath: "", + //AvatarHash: "", + //AvatarURL: id.ContentURI{}, + NameSet: portal.NameSet, + AvatarSet: portal.AvatarSet, + TopicSet: portal.TopicSet, + //Revision: portal.Metadata["revision"].(uint32), + Encrypted: true, + //RelayUserID: portal.Relay.UserMXID, + ExpirationTime: uint32(portal.Metadata.DisappearTimer.Milliseconds()), + } +} From 58a1b873489a8afb88dcd9eb6b48304b6c60cf64 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Jun 2024 23:30:38 +0300 Subject: [PATCH 199/718] v2: implement note to self avatar --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/chatinfo.go | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fd1ea3f..e36b1c1 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240619195836-2a7a5070fb32 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240619204109-68d8ab6896fd nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index a6c0ff3..9c14fb4 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240619195836-2a7a5070fb32 h1:BiUVpB1hejeuCivlLOv5jKzU/Y8TTwDlQ0i1qO+JGdI= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240619195836-2a7a5070fb32/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619204109-68d8ab6896fd h1:NZYFpztfJCdynpWJTGOyPcYfr+95zCut/IobMzaKCdU= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240619204109-68d8ab6896fd/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index eea4381..ceb2a86 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -18,6 +18,7 @@ package connector import ( "context" + "crypto/sha256" "errors" "fmt" "strconv" @@ -193,12 +194,19 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev topic = fmt.Sprintf("%s with %s", PrivateChatTopic, recipient.E164) } var serviceID libsignalgo.ServiceID + var avatar *bridgev2.Avatar if recipient.ACI == uuid.Nil { name = s.Main.Config.FormatDisplayname(recipient) serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) } else { if recipient.ACI == s.Client.Store.ACI { name = NoteToSelfName + avatar = &bridgev2.Avatar{ + ID: networkid.AvatarID(s.Main.Config.NoteToSelfAvatar), + Remove: len(s.Main.Config.NoteToSelfAvatar) == 0, + MXC: s.Main.Config.NoteToSelfAvatar, + Hash: sha256.Sum256([]byte(s.Main.Config.NoteToSelfAvatar)), + } } else { // The other user is only present if their ACI is known members = append(members, makeUserID(recipient.ACI)) @@ -209,6 +217,7 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev PortalID: s.makeDMPortalKey(serviceID), PortalInfo: &bridgev2.PortalInfo{ Name: &name, + Avatar: avatar, Topic: &topic, Members: members, IsDirectChat: &isDirectChat, From 70d747e1bd6415bfbaa1d567c6f3b0c488609735 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Jun 2024 16:52:02 +0300 Subject: [PATCH 200/718] v2: allow re-authing existing login --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/login.go | 17 +++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index e36b1c1..5a418be 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240619204109-68d8ab6896fd + maunium.net/go/mautrix v0.19.0-beta.1.0.20240620135116-0418273bdbb1 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 9c14fb4..fe0d52e 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240619204109-68d8ab6896fd h1:NZYFpztfJCdynpWJTGOyPcYfr+95zCut/IobMzaKCdU= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240619204109-68d8ab6896fd/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240620135116-0418273bdbb1 h1:sSz/VCo3GLtnAjMBpjfn7dtN1f7RDdZ+9OTZdaxZSJc= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240620135116-0418273bdbb1/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/login.go b/pkg/connector/login.go index ecb12f7..cd0aa1f 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -44,7 +44,6 @@ func (s *SignalConnector) CreateLogin(ctx context.Context, user *bridgev2.User, type QRLogin struct { User *bridgev2.User - Existing *bridgev2.UserLogin Main *SignalConnector cancelChan context.CancelFunc ProvChan chan signalmeow.ProvisioningResponse @@ -116,9 +115,6 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, ctx.Err() } newLoginID := makeUserLoginID(signalID) - if qr.Existing != nil && qr.Existing.ID != newLoginID { - return nil, fmt.Errorf("user ID mismatch for re-auth") - } select { case resp := <-qr.ProvChan: @@ -131,9 +127,15 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, ctx.Err() } - var ul *bridgev2.UserLogin - var err error - if qr.Existing == nil { + ul, err := qr.Main.Bridge.GetUserLoginByID(ctx, newLoginID) + if err != nil { + return nil, fmt.Errorf("failed to get existing login: %w", err) + } + if ul.UserMXID != qr.User.MXID { + // TODO delete old user login instead of failing new login + return nil, fmt.Errorf("login ID already in use by another user") + } + if ul == nil { ul, err = qr.User.NewLogin(ctx, &database.UserLogin{ ID: newLoginID, Metadata: database.UserLoginMetadata{ @@ -149,7 +151,6 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, fmt.Errorf("failed to save new login: %w", err) } } else { - ul = qr.Existing ul.Metadata.Extra["phone"] = signalPhone ul.Metadata.RemoteName = signalPhone err = ul.Save(ctx) From 5e4ddb93baeac0513c8678046ca59e2b4383339f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Jun 2024 17:29:55 +0300 Subject: [PATCH 201/718] v2: add contact listing method --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/chatinfo.go | 32 ++++++++++++++++++++++++- pkg/connector/client.go | 2 ++ pkg/signalmeow/store/recipient_store.go | 20 +++++++++++----- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 5a418be..c5862b4 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240620135116-0418273bdbb1 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240620142853-7b6f3ba0541d nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index fe0d52e..bbb191e 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240620135116-0418273bdbb1 h1:sSz/VCo3GLtnAjMBpjfn7dtN1f7RDdZ+9OTZdaxZSJc= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240620135116-0418273bdbb1/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240620142853-7b6f3ba0541d h1:s3wbfQ3jJOlZy0oYE/dVSTxAHDMQHwBlHVLqQZGeQX4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240620142853-7b6f3ba0541d/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index ceb2a86..7c4c646 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -91,7 +91,11 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.UserInfo { isBot := false ui := &bridgev2.UserInfo{ - IsBot: &isBot, + IsBot: &isBot, + Identifiers: []string{}, + } + if contact.E164 != "" { + ui.Identifiers = append(ui.Identifiers, "tel:"+contact.E164) } name := s.Main.Config.FormatDisplayname(contact) ui.Name = &name @@ -184,6 +188,32 @@ func (s *SignalClient) CreateGroup(ctx context.Context, name string, users ...ne return nil, fmt.Errorf("not implemented") } +func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveIdentifierResponse, error) { + recipients, err := s.Client.Store.RecipientStore.LoadAllContacts(ctx) + if err != nil { + return nil, err + } + resp := make([]*bridgev2.ResolveIdentifierResponse, len(recipients)) + for i, recipient := range recipients { + recipientResp := &bridgev2.ResolveIdentifierResponse{ + UserInfo: s.contactToUserInfo(recipient), + Chat: s.makeCreateDMResponse(recipient), + } + if recipient.ACI != uuid.Nil { + recipientResp.UserID = makeUserID(recipient.ACI) + ghost, err := s.Main.Bridge.GetGhostByID(ctx, recipientResp.UserID) + if err != nil { + return nil, fmt.Errorf("failed to get ghost for %s: %w", recipient.ACI, err) + } + recipientResp.Ghost = ghost + } else { + recipientResp.UserID = makeUserIDFromServiceID(libsignalgo.NewPNIServiceID(recipient.PNI)) + } + resp[i] = recipientResp + } + return resp, nil +} + func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { isDirectChat := true isSpace := false diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 6034a7c..20f3d8e 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -21,7 +21,9 @@ type SignalClient struct { var _ bridgev2.NetworkAPI = (*SignalClient)(nil) var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) +var _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) var _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) +var _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) var pushCfg = &bridgev2.PushConfig{ FCM: &bridgev2.FCMPushConfig{ diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 216dfc8..3463a00 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -40,6 +40,8 @@ type RecipientStore interface { LoadRecipientByE164(ctx context.Context, e164 string) (*types.Recipient, error) StoreRecipient(ctx context.Context, recipient *types.Recipient) error UpdateRecipientE164(ctx context.Context, aci, pni uuid.UUID, e164 string) (*types.Recipient, error) + + LoadAllContacts(ctx context.Context) ([]*types.Recipient, error) } var _ RecipientStore = (*sqlStore)(nil) @@ -62,12 +64,13 @@ const ( FROM signalmeow_recipients WHERE account_id = $1 ` - getRecipientByACIQuery = getAllRecipientsQuery + `AND aci_uuid = $2` - getRecipientByPNIQuery = getAllRecipientsQuery + `AND pni_uuid = $2` - getRecipientByACIOrPNIQuery = getAllRecipientsQuery + `AND (($2<>'00000000-0000-0000-0000-000000000000' AND aci_uuid = $2) OR ($3<>'00000000-0000-0000-0000-000000000000' AND pni_uuid = $3))` - getRecipientByPhoneQuery = getAllRecipientsQuery + `AND e164_number = $2` - deleteRecipientByPNIQuery = `DELETE FROM signalmeow_recipients WHERE account_id = $1 AND pni_uuid = $2` - upsertACIRecipientQuery = ` + getAllRecipientsWithNameOrPhoneQuery = getAllRecipientsQuery + `AND (contact_name <> '' OR profile_name <> '' OR e164_number <> '')` + getRecipientByACIQuery = getAllRecipientsQuery + `AND aci_uuid = $2` + getRecipientByPNIQuery = getAllRecipientsQuery + `AND pni_uuid = $2` + getRecipientByACIOrPNIQuery = getAllRecipientsQuery + `AND (($2<>'00000000-0000-0000-0000-000000000000' AND aci_uuid = $2) OR ($3<>'00000000-0000-0000-0000-000000000000' AND pni_uuid = $3))` + getRecipientByPhoneQuery = getAllRecipientsQuery + `AND e164_number = $2` + deleteRecipientByPNIQuery = `DELETE FROM signalmeow_recipients WHERE account_id = $1 AND pni_uuid = $2` + upsertACIRecipientQuery = ` INSERT INTO signalmeow_recipients ( account_id, aci_uuid, @@ -278,6 +281,11 @@ func (s *sqlStore) LoadRecipientByE164(ctx context.Context, e164 string) (*types return scanRecipient(s.db.QueryRow(ctx, getRecipientByPhoneQuery, s.AccountID, e164)) } +func (s *sqlStore) LoadAllContacts(ctx context.Context) ([]*types.Recipient, error) { + rows, err := s.db.Query(ctx, getAllRecipientsWithNameOrPhoneQuery, s.AccountID) + return dbutil.NewRowIterWithError(rows, scanRecipient, err).AsList() +} + func (s *sqlStore) DeleteRecipientByPNI(ctx context.Context, pni uuid.UUID) error { _, err := s.db.Exec(ctx, deleteRecipientByPNIQuery, s.AccountID, pni) return err From 32401e37f1d63c14ed8dbbde095c598ab21604f0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 21 Jun 2024 20:13:52 +0300 Subject: [PATCH 202/718] v2: update mautrix-go and fix bug in login --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 40 ++++++++++++++++++++++++++++++----- pkg/connector/connector.go | 8 +++++-- pkg/connector/handlematrix.go | 1 + pkg/connector/handlesignal.go | 1 + pkg/connector/login.go | 9 ++++---- 7 files changed, 51 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index c5862b4..d5f40d6 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240620142853-7b6f3ba0541d + maunium.net/go/mautrix v0.19.0-beta.1.0.20240621171215-921240d99bf7 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index bbb191e..3e03464 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240620142853-7b6f3ba0541d h1:s3wbfQ3jJOlZy0oYE/dVSTxAHDMQHwBlHVLqQZGeQX4= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240620142853-7b6f3ba0541d/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240621171215-921240d99bf7 h1:kdp/zZXtl0vMXa6/Vto34mQ4YhHoj4DHSffr4j101eA= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240621171215-921240d99bf7/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 20f3d8e..6f1a3ec 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -19,11 +19,41 @@ type SignalClient struct { Client *signalmeow.Client } -var _ bridgev2.NetworkAPI = (*SignalClient)(nil) -var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) -var _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) -var _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) -var _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) +var signalCaps = &bridgev2.NetworkRoomCapabilities{ + FormattedText: true, + UserMentions: true, + LocationMessages: true, + Captions: true, + Replies: true, + Edits: true, + EditMaxCount: 10, + EditMaxAge: 24 * time.Hour, + Deletes: true, + DeleteMaxAge: 24 * time.Hour, + DefaultFileRestriction: &bridgev2.FileRestriction{ + MaxSize: 100 * 1024 * 1024, + }, + ReadReceipts: true, + Reactions: true, + ReactionCount: 1, +} + +func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *bridgev2.NetworkRoomCapabilities { + return signalCaps +} + +var ( + _ bridgev2.NetworkAPI = (*SignalClient)(nil) + _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) +) var pushCfg = &bridgev2.PushConfig{ FCM: &bridgev2.FCMPushConfig{ diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index fe594dd..2e6d59d 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -80,7 +80,7 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { return signalfmt.UserInfo{} } userInfo := signalfmt.UserInfo{ - MXID: ghost.MXID, + MXID: ghost.Intent.GetMXID(), Name: ghost.Name, } userLogin := s.Bridge.GetCachedUserLoginByID(networkid.UserLoginID(uuid.String())) @@ -124,7 +124,11 @@ func (s *SignalConnector) SetMaxFileSize(maxSize int64) { } func (s *SignalConnector) Start(ctx context.Context) error { - return s.Store.Upgrade(ctx) + err := s.Store.Upgrade(ctx) + if err != nil { + return bridgev2.DBUpgradeError{Err: err, Section: "signalmeow"} + } + return nil } func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error { diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 839c644..30b10e6 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -122,6 +122,7 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri fmt.Println(res) msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) msg.EditTarget.Metadata.Extra["contains_attachments"] = len(converted.Attachments) > 0 + msg.EditTarget.Metadata.EditCount++ return nil } diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index bfbc773..479ce2a 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -273,6 +273,7 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta Content: lastPart.Content, Extra: lastPart.Extra, }) + convertedEdit.ModifiedParts[0].Part.Metadata.EditCount++ return convertedEdit, nil } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index cd0aa1f..4205f67 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/google/uuid" + "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -127,13 +128,13 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, ctx.Err() } - ul, err := qr.Main.Bridge.GetUserLoginByID(ctx, newLoginID) + ul, err := qr.Main.Bridge.GetExistingUserLoginByID(ctx, newLoginID) if err != nil { return nil, fmt.Errorf("failed to get existing login: %w", err) } - if ul.UserMXID != qr.User.MXID { - // TODO delete old user login instead of failing new login - return nil, fmt.Errorf("login ID already in use by another user") + if ul != nil && ul.UserMXID != qr.User.MXID { + ul.Delete(ctx, status.BridgeState{StateEvent: status.StateLoggedOut, Error: "overridden-by-another-user"}, false) + ul = nil } if ul == nil { ul, err = qr.User.NewLogin(ctx, &database.UserLogin{ From 98747f267be942598f3d42f294909ae73278d31f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Jun 2024 15:34:26 +0300 Subject: [PATCH 203/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d5f40d6..b279c4c 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240621171215-921240d99bf7 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240624123328-e13b62807ff7 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 3e03464..fea9103 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240621171215-921240d99bf7 h1:kdp/zZXtl0vMXa6/Vto34mQ4YhHoj4DHSffr4j101eA= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240621171215-921240d99bf7/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240624123328-e13b62807ff7 h1:l2nguDM5+Dlud5hdsaUBgyBT7FJ86BknpGmUTI/CemA= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240624123328-e13b62807ff7/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 2e6d59d..fec0f42 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -50,6 +50,14 @@ func NewConnector() *SignalConnector { } } +var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ + DisappearingMessages: true, +} + +func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { + return signalGeneralCaps +} + func (s *SignalConnector) GetName() bridgev2.BridgeName { return bridgev2.BridgeName{ DisplayName: "Signal", From f4fc21eeb95a4b7e30cdc8cf0976d6a1d79437f0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Jun 2024 15:57:25 +0300 Subject: [PATCH 204/718] v2: update ghost info more often --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/connector.go | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b279c4c..9d0253d 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240624123328-e13b62807ff7 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240624125613-855715bbed92 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index fea9103..2387052 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240624123328-e13b62807ff7 h1:l2nguDM5+Dlud5hdsaUBgyBT7FJ86BknpGmUTI/CemA= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240624123328-e13b62807ff7/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240624125613-855715bbed92 h1:TcVnSLhftv6pCz+bO9+y5fjHlGewRRUtJw0bIgfr+Ss= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240624125613-855715bbed92/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index fec0f42..5fdec0a 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -52,6 +52,7 @@ func NewConnector() *SignalConnector { var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ DisappearingMessages: true, + AggressiveUpdateInfo: true, } func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { From 25dbeb31904e696d67c07af444e003c1fc272700 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Jun 2024 20:10:49 +0300 Subject: [PATCH 205/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9d0253d..0e08d47 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240624125613-855715bbed92 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240624171009-09a8a5104a6c nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 2387052..d405943 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240624125613-855715bbed92 h1:TcVnSLhftv6pCz+bO9+y5fjHlGewRRUtJw0bIgfr+Ss= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240624125613-855715bbed92/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240624171009-09a8a5104a6c h1:jm1n2dI2mVDnmrxFgRA1a3MfYdkwBYgKseVKgJHv/a4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240624171009-09a8a5104a6c/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 760ec87c9bf3010ae236e92265a9d573b163d4df Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Jun 2024 21:10:14 +0300 Subject: [PATCH 206/718] v2: fix expiration timer unit --- pkg/connector/msgconvproxy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/connector/msgconvproxy.go b/pkg/connector/msgconvproxy.go index bf1ef3d..8ffeb6f 100644 --- a/pkg/connector/msgconvproxy.go +++ b/pkg/connector/msgconvproxy.go @@ -110,6 +110,6 @@ func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { //Revision: portal.Metadata["revision"].(uint32), Encrypted: true, //RelayUserID: portal.Relay.UserMXID, - ExpirationTime: uint32(portal.Metadata.DisappearTimer.Milliseconds()), + ExpirationTime: uint32(portal.Metadata.DisappearTimer.Seconds()), } } From a74bad426513704cce7581c2b48208e542accfe7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Jun 2024 13:45:39 +0300 Subject: [PATCH 207/718] v2: add automatic migration from v1 --- cmd/mautrix-signal-v2/legacymigrate.go | 49 +++++++ cmd/mautrix-signal-v2/legacymigrate.sql | 175 ++++++++++++++++++++++++ cmd/mautrix-signal-v2/main.go | 26 ++-- go.mod | 4 +- go.sum | 8 +- 5 files changed, 248 insertions(+), 14 deletions(-) create mode 100644 cmd/mautrix-signal-v2/legacymigrate.go create mode 100644 cmd/mautrix-signal-v2/legacymigrate.sql diff --git a/cmd/mautrix-signal-v2/legacymigrate.go b/cmd/mautrix-signal-v2/legacymigrate.go new file mode 100644 index 0000000..377b5af --- /dev/null +++ b/cmd/mautrix-signal-v2/legacymigrate.go @@ -0,0 +1,49 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +import ( + _ "embed" + + up "go.mau.fi/util/configupgrade" + + "maunium.net/go/mautrix/bridgev2/bridgeconfig" +) + +const legacyMigrateRenameTables = ` +ALTER TABLE portal RENAME TO portal_old; +ALTER TABLE puppet RENAME TO puppet_old; +ALTER TABLE "user" RENAME TO user_old; +ALTER TABLE user_portal RENAME TO user_portal_old; +ALTER TABLE message RENAME TO message_old; +ALTER TABLE reaction RENAME TO reaction_old; +ALTER TABLE disappearing_message RENAME TO disappearing_message_old; +` + +//go:embed legacymigrate.sql +var legacyMigrateCopyData string + +func migrateLegacyConfig(helper up.Helper) { + helper.Set(up.Str, "mautrix.bridge.e2ee", "encryption", "pickle_key") + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "displayname_template"}, []string{"network", "displayname_template"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "note_to_self_avatar"}, []string{"network", "note_to_self_avatar"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "location_format"}, []string{"network", "location_format"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "use_contact_avatars"}, []string{"network", "use_contact_avatars"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "use_outdated_profiles"}, []string{"network", "use_outdated_profiles"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "number_in_topic"}, []string{"network", "number_in_topic"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"signal", "device_name"}, []string{"network", "device_name"}) +} diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql new file mode 100644 index 0000000..60b08d5 --- /dev/null +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -0,0 +1,175 @@ +INSERT INTO portal ( + bridge_id, id, receiver, mxid, parent_id, parent_receiver, + name, topic, avatar_id, avatar_hash, avatar_mxc, + name_set, avatar_set, topic_set, in_space, metadata +) +SELECT + '', -- bridge_id + chat_id, -- id + CASE + WHEN receiver='00000000-0000-0000-0000-000000000000' THEN '' + ELSE CAST(receiver AS TEXT) + END, -- receiver + mxid, + NULL, -- parent_id + '', -- parent_receiver + name, + topic, + CASE + WHEN avatar_path='notetoself' THEN avatar_url + WHEN avatar_path<>'' THEN ('path:' || avatar_path) + WHEN avatar_hash<>'' THEN ('hash:' || avatar_hash) + ELSE '' + END, -- avatar_id + avatar_hash, -- avatar_hash + avatar_url, -- avatar_mxc + name_set, + avatar_set, + topic_set, + false, -- in_space + CAST( + CASE WHEN expiration_time = 0 + THEN '{}' + ELSE '{"disappear_type": "after_read", "disappear_timer": "' || (expiration_time * 1000000000) || '"}' + END + -- only: postgres + AS jsonb + -- only: sqlite (line commented) +-- AS text + ) -- metadata + -- TODO migrate relay user id +FROM portal_old; + +INSERT INTO ghost ( + bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, metadata +) +SELECT + '', -- bridge_id + cast(uuid AS TEXT), -- id + name, + CASE + WHEN avatar_path<>'' THEN ('path:' || avatar_path) + WHEN avatar_hash<>'' THEN ('hash:' || avatar_hash) + ELSE '' + END, -- avatar_id + avatar_hash, -- avatar_hash + avatar_url, -- avatar_mxc + name_set, + avatar_set, + CAST( + CASE + WHEN profile_fetched_at IS NOT NULL THEN ('{"profile_fetched_at":' || profile_fetched_at || '}') + ELSE '{}' + END + -- only: postgres + AS jsonb + -- only: sqlite (line commented) +-- AS text + ) -- metadata +FROM puppet_old; + +INSERT INTO message ( + bridge_id, id, part_id, mxid, room_id, room_receiver, + sender_id, timestamp, relates_to, metadata +) +SELECT + '', -- bridge_id + cast(sender AS TEXT) || '|' || timestamp, -- id + CAST(part_index AS TEXT), -- part_id + mxid, + signal_chat_id, -- room_id + CASE + WHEN signal_receiver='00000000-0000-0000-0000-000000000000' THEN '' + ELSE cast(signal_receiver AS TEXT) + END, -- room_receiver + cast(sender AS TEXT), -- sender_id + timestamp * 1000000, + NULL, -- relates_to + -- only: postgres + '{}'::jsonb -- metadata + -- only: sqlite (line commented +-- '{}' +FROM message_old; + +INSERT INTO disappearing_message ( + bridge_id, mx_room, mxid, type, timer, disappear_at +) +SELECT + '', -- bridge_id + room_id, -- mx_room + mxid, + 'after_read', -- type + expiration_seconds * 1000000000, -- timer + CASE WHEN expiration_ts IS NOT NULL THEN expiration_ts * 1000000000 END -- disappear_at +FROM disappearing_message_old; + +INSERT INTO reaction ( + bridge_id, message_id, message_part_id, sender_id, emoji_id, + room_id, room_receiver, mxid, timestamp, metadata +) +SELECT + '', -- bridge_id + cast(msg_author AS TEXT) || '|' || msg_timestamp, -- message_id + '', -- message_part_id + cast(author AS TEXT), -- sender_id + '', -- emoji_id + signal_chat_id, -- room_id + CASE + WHEN signal_receiver='00000000-0000-0000-0000-000000000000' THEN '' + ELSE cast(signal_receiver AS TEXT) + END, -- room_receiver + mxid, + msg_timestamp * 1000000, -- timestamp (actual reaction timestamp not available) + CAST( + '{"emoji":"' || emoji || '"}' + -- only: postgres + AS jsonb + -- only: sqlite (line commented) +-- AS text + ) -- metadata +FROM reaction_old; + +INSERT INTO "user" (bridge_id, mxid, management_room, access_token) +SELECT '', mxid, management_room, NULL +FROM user_old; + +INSERT INTO user_login (bridge_id, user_mxid, id, space_room, metadata) +SELECT + '', + mxid, + cast(uuid AS TEXT), + space_room, + CAST( + '{"phone":"' || phone || '","remote_name":"' || phone || '"}' + -- only: postgres + AS jsonb + -- only: sqlite (line commented) +-- AS text + ) +FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; + +INSERT INTO user_portal ( + bridge_id, user_mxid, login_id, portal_id, portal_receiver, in_space, preferred, last_read +) +SELECT + '', -- bridge_id + user_mxid, + cast(user_old.uuid AS TEXT), -- login_id + portal_chat_id, -- portal_id + CASE + WHEN portal_receiver='00000000-0000-0000-0000-000000000000' THEN '' + ELSE cast(portal_receiver AS TEXT) + END, -- portal_receiver + in_space, + false, -- preferred + CASE WHEN last_read_ts = 0 THEN NULL ELSE last_read_ts * 1000000 END -- last_read +FROM user_portal_old +LEFT JOIN user_old ON user_old.mxid = user_portal_old.user_mxid; + +DROP TABLE disappearing_message_old; +DROP TABLE reaction_old; +DROP TABLE user_portal_old; +DROP TABLE message_old; +DROP TABLE puppet_old; +DROP TABLE portal_old; +DROP TABLE user_old; diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index e397e14..bc55d45 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -17,6 +17,7 @@ package main import ( + "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix/mxmain" "go.mau.fi/mautrix-signal/pkg/connector" @@ -31,17 +32,26 @@ var ( BuildTime = "unknown" ) -func main() { - m := mxmain.BridgeMain{ - Name: "mautrix-signal", - URL: "https://github.com/mautrix/signal", - Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.0", +var m = mxmain.BridgeMain{ + Name: "mautrix-signal", + URL: "https://github.com/mautrix/signal", + Description: "A Matrix-Signal puppeting bridge.", + Version: "0.7.0", - Connector: connector.NewConnector(), - } + Connector: connector.NewConnector(), +} + +func main() { + bridgeconfig.HackyMigrateLegacyNetworkConfig = migrateLegacyConfig m.PostInit = func() { signalmeow.SetLogger(m.Log.With().Str("component", "signalmeow").Logger()) + m.CheckLegacyDB( + 20, + "v0.5.1", + "v0.7.0", + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData), + true, + ) } m.InitVersion(Tag, Commit, BuildTime) m.Run() diff --git a/go.mod b/go.mod index 0e08d47..046efb6 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.0 + go.mau.fi/util v0.5.1-0.20240625085258-678695edd51c golang.org/x/crypto v0.24.0 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240624171009-09a8a5104a6c + maunium.net/go/mautrix v0.19.0-beta.1.0.20240625104456-54ff874fac72 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index d405943..3ee63e2 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.0 h1:8yELAl+1CDRrwGe9NUmREgVclSs26Z68pTWePHVxuDo= -go.mau.fi/util v0.5.0/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/util v0.5.1-0.20240625085258-678695edd51c h1:LAXHOnupWCFvTyx4ZAu5t+6n7zADldeRHIk1s+2luow= +go.mau.fi/util v0.5.1-0.20240625085258-678695edd51c/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240624171009-09a8a5104a6c h1:jm1n2dI2mVDnmrxFgRA1a3MfYdkwBYgKseVKgJHv/a4= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240624171009-09a8a5104a6c/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625104456-54ff874fac72 h1:66ojF6y1KlyOyPLj6/XVxoj+ex/LmxFoCiR6SzvEFBI= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625104456-54ff874fac72/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 0b0379aebf17ddbfd76d50db6fc709f8d0580242 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Jun 2024 15:04:54 +0300 Subject: [PATCH 208/718] v2: add backwards-compatible resolve identifier provisioning API --- cmd/mautrix-signal-v2/legacyprovision.go | 133 +++++++++++++++++++++ cmd/mautrix-signal-v2/main.go | 12 ++ go.mod | 2 +- go.sum | 4 +- legacyprovision/types.go | 92 ++++++++++++++ pkg/connector/chatinfo.go | 3 +- provisioning.go | 145 ++++++----------------- 7 files changed, 280 insertions(+), 111 deletions(-) create mode 100644 cmd/mautrix-signal-v2/legacyprovision.go create mode 100644 legacyprovision/types.go diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal-v2/legacyprovision.go new file mode 100644 index 0000000..5b8e203 --- /dev/null +++ b/cmd/mautrix-signal-v2/legacyprovision.go @@ -0,0 +1,133 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 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 istributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" + "github.com/rs/zerolog" + + "go.mau.fi/mautrix-signal/legacyprovision" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/bridgev2" +) + +func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +func legacyProvLogout(w http.ResponseWriter, r *http.Request) { + user := m.Matrix.Provisioning.GetUser(r) + for { + login := user.GetDefaultLogin() + if login == nil { + break + } + login.Logout(r.Context()) + } + legacyprovision.JSONResponse(w, http.StatusOK, nil) +} + +func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, create bool) { + login := m.Matrix.Provisioning.GetLoginForRequest(w, r) + if login == nil { + return + } + api := login.Client.(bridgev2.IdentifierResolvingNetworkAPI) + resp, err := api.ResolveIdentifier(r.Context(), mux.Vars(r)["phonenum"], create) + if err != nil { + zerolog.Ctx(r.Context()).Err(err).Msg("Failed to resolve identifier") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + Error: fmt.Sprintf("Failed to resolve identifier: %v", err), + ErrCode: "M_UNKNOWN", + }) + return + } else if resp == nil { + legacyprovision.JSONResponse(w, http.StatusNotFound, &legacyprovision.Error{ + ErrCode: mautrix.MNotFound.ErrCode, + Error: "User not found on Signal", + }) + return + } + status := http.StatusOK + apiResp := &legacyprovision.ResolveIdentifierResponse{ + ChatID: legacyprovision.ResolveIdentifierResponseChatID{ + UUID: string(resp.UserID), + Number: "", + }, + } + if resp.Ghost != nil { + if resp.UserInfo != nil { + resp.Ghost.UpdateInfo(r.Context(), resp.UserInfo) + } + apiResp.OtherUser = &legacyprovision.ResolveIdentifierResponseOtherUser{ + MXID: resp.Ghost.Intent.GetMXID(), + DisplayName: resp.Ghost.Name, + AvatarURL: resp.Ghost.AvatarMXC.ParseOrIgnore(), + } + } + if resp.Chat != nil { + if resp.Chat.Portal == nil { + resp.Chat.Portal, err = m.Bridge.GetPortalByID(r.Context(), resp.Chat.PortalID) + if err != nil { + zerolog.Ctx(r.Context()).Err(err).Msg("Failed to get portal") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ + Err: "Failed to get portal", + ErrCode: "M_UNKNOWN", + }) + return + } + } + if create && resp.Chat.Portal.MXID == "" { + apiResp.JustCreated = true + status = http.StatusCreated + err = resp.Chat.Portal.CreateMatrixRoom(r.Context(), login, resp.Chat.PortalInfo) + if err != nil { + zerolog.Ctx(r.Context()).Err(err).Msg("Failed to create portal room") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ + Err: "Failed to create portal room", + ErrCode: "M_UNKNOWN", + }) + return + } + } + apiResp.RoomID = resp.Chat.Portal.MXID + } + legacyprovision.JSONResponse(w, status, &legacyprovision.Response{ + Success: true, + Status: "ok", + ResolveIdentifierResponse: apiResp, + }) +} + +func legacyProvResolveIdentifier(w http.ResponseWriter, r *http.Request) { + legacyResolveIdentifierOrStartChat(w, r, false) +} + +func legacyProvPM(w http.ResponseWriter, r *http.Request) { + legacyResolveIdentifierOrStartChat(w, r, true) +} diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index bc55d45..7c0762c 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -17,6 +17,8 @@ package main import ( + "net/http" + "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix/mxmain" @@ -53,6 +55,16 @@ func main() { true, ) } + m.PostStart = func() { + if m.Matrix.Provisioning != nil { + m.Matrix.Provisioning.Router.HandleFunc("/v2/link/new", legacyProvLinkNew).Methods(http.MethodPost) + m.Matrix.Provisioning.Router.HandleFunc("/v2/link/wait/scan", legacyProvLinkWaitScan).Methods(http.MethodPost) + m.Matrix.Provisioning.Router.HandleFunc("/v2/link/wait/account", legacyProvLinkWaitAccount).Methods(http.MethodPost) + m.Matrix.Provisioning.Router.HandleFunc("/v2/logout", legacyProvLogout).Methods(http.MethodPost) + m.Matrix.Provisioning.Router.HandleFunc("/v2/resolve_identifier/{phonenum}", legacyProvResolveIdentifier).Methods(http.MethodGet) + m.Matrix.Provisioning.Router.HandleFunc("/v2/pm/{phonenum}", legacyProvPM).Methods(http.MethodPost) + } + } m.InitVersion(Tag, Commit, BuildTime) m.Run() } diff --git a/go.mod b/go.mod index 046efb6..0f99be4 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240625104456-54ff874fac72 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240625120422-13b2d6275302 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 3ee63e2..c6356ce 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240625104456-54ff874fac72 h1:66ojF6y1KlyOyPLj6/XVxoj+ex/LmxFoCiR6SzvEFBI= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240625104456-54ff874fac72/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625120422-13b2d6275302 h1:PbCdso3xltp5ztKXpAW4C4tC8LLgxeHkJ4mF/7HE3Z0= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625120422-13b2d6275302/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/legacyprovision/types.go b/legacyprovision/types.go new file mode 100644 index 0000000..72f393a --- /dev/null +++ b/legacyprovision/types.go @@ -0,0 +1,92 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 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 istributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package legacyprovision + +import ( + "encoding/json" + "net/http" + + "maunium.net/go/mautrix/id" +) + +func JSONResponse(w http.ResponseWriter, status int, response any) { + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(status) + _ = json.NewEncoder(w).Encode(response) +} + +type Error struct { + Success bool `json:"success"` + Error string `json:"error"` + ErrCode string `json:"errcode"` +} + +type Response struct { + Success bool `json:"success"` + Status string `json:"status"` + + // For response in LinkNew + SessionID string `json:"session_id,omitempty"` + URI string `json:"uri,omitempty"` + + // For response in LinkWaitForAccount + UUID string `json:"uuid,omitempty"` + Number string `json:"number,omitempty"` + + // For response in ResolveIdentifier + *ResolveIdentifierResponse +} + +type WhoAmIResponse struct { + Permissions int `json:"permissions"` + MXID string `json:"mxid"` + Signal *WhoAmIResponseSignal `json:"signal,omitempty"` +} + +type WhoAmIResponseSignal struct { + Number string `json:"number"` + UUID string `json:"uuid"` + Name string `json:"name"` + Ok bool `json:"ok"` +} + +type ResolveIdentifierResponse struct { + RoomID id.RoomID `json:"room_id"` + ChatID ResolveIdentifierResponseChatID `json:"chat_id"` + JustCreated bool `json:"just_created"` + OtherUser *ResolveIdentifierResponseOtherUser `json:"other_user,omitempty"` +} + +type ResolveIdentifierResponseChatID struct { + UUID string `json:"uuid"` + Number string `json:"number"` +} + +type ResolveIdentifierResponseOtherUser struct { + MXID id.UserID `json:"mxid"` + DisplayName string `json:"displayname"` + AvatarURL id.ContentURI `json:"avatar_url"` +} + +type LinkWaitForScanRequest struct { + SessionID string `json:"session_id"` +} + +type LinkWaitForAccountRequest struct { + SessionID string `json:"session_id"` + DeviceName string `json:"device_name"` // TODO this seems to not be used anywhere +} diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 7c4c646..f0f06f3 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -19,7 +19,6 @@ package connector import ( "context" "crypto/sha256" - "errors" "fmt" "strconv" "strings" @@ -148,7 +147,7 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre aci = resp[e164Number].ACI pni = resp[e164Number].PNI if aci == uuid.Nil && pni == uuid.Nil { - return nil, errors.New("user not found on Signal") + return nil, nil } recipient, err = s.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) if err != nil { diff --git a/provisioning.go b/provisioning.go index 3be384b..46b52d1 100644 --- a/provisioning.go +++ b/provisioning.go @@ -36,6 +36,7 @@ import ( "maunium.net/go/mautrix" "maunium.net/go/mautrix/id" + "go.mau.fi/mautrix-signal/legacyprovision" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" @@ -86,18 +87,12 @@ func (prov *ProvisioningAPI) Init() { } } -func jsonResponse(w http.ResponseWriter, status int, response any) { - w.Header().Add("Content-Type", "application/json") - w.WriteHeader(status) - _ = json.NewEncoder(w).Encode(response) -} - func (prov *ProvisioningAPI) AuthMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { auth := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") if auth != prov.bridge.Config.Bridge.Provisioning.SharedSecret { zerolog.Ctx(r.Context()).Warn().Msg("Authentication token does not match shared secret") - jsonResponse(w, http.StatusForbidden, &mautrix.RespError{ + legacyprovision.JSONResponse(w, http.StatusForbidden, &mautrix.RespError{ Err: "Authentication token does not match shared secret", ErrCode: mautrix.MForbidden.ErrCode, }) @@ -109,60 +104,7 @@ func (prov *ProvisioningAPI) AuthMiddleware(h http.Handler) http.Handler { }) } -type Error struct { - Success bool `json:"success"` - Error string `json:"error"` - ErrCode string `json:"errcode"` -} - -type Response struct { - Success bool `json:"success"` - Status string `json:"status"` - - // For response in LinkNew - SessionID string `json:"session_id,omitempty"` - URI string `json:"uri,omitempty"` - - // For response in LinkWaitForAccount - UUID string `json:"uuid,omitempty"` - Number string `json:"number,omitempty"` - - // For response in ResolveIdentifier - *ResolveIdentifierResponse -} - -type WhoAmIResponse struct { - Permissions int `json:"permissions"` - MXID string `json:"mxid"` - Signal *WhoAmIResponseSignal `json:"signal,omitempty"` -} - -type WhoAmIResponseSignal struct { - Number string `json:"number"` - UUID string `json:"uuid"` - Name string `json:"name"` - Ok bool `json:"ok"` -} - -type ResolveIdentifierResponse struct { - RoomID id.RoomID `json:"room_id"` - ChatID ResolveIdentifierResponseChatID `json:"chat_id"` - JustCreated bool `json:"just_created"` - OtherUser *ResolveIdentifierResponseOtherUser `json:"other_user,omitempty"` -} - -type ResolveIdentifierResponseChatID struct { - UUID string `json:"uuid"` - Number string `json:"number"` -} - -type ResolveIdentifierResponseOtherUser struct { - MXID string `json:"mxid"` - DisplayName string `json:"displayname"` - AvatarURL string `json:"avatar_url"` -} - -func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, inputPhone string) (int, *ResolveIdentifierResponse, error) { +func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, inputPhone string) (int, *legacyprovision.ResolveIdentifierResponse, error) { if user.Client == nil { return http.StatusUnauthorized, nil, errors.New("not currently connected to Signal") } @@ -199,14 +141,14 @@ func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, Msg("Found DM target user") var targetServiceID libsignalgo.ServiceID - var otherUserInfo *ResolveIdentifierResponseOtherUser + var otherUserInfo *legacyprovision.ResolveIdentifierResponseOtherUser if aci != uuid.Nil { targetServiceID = libsignalgo.NewACIServiceID(aci) puppet := prov.bridge.GetPuppetBySignalID(aci) - otherUserInfo = &ResolveIdentifierResponseOtherUser{ - MXID: puppet.MXID.String(), + otherUserInfo = &legacyprovision.ResolveIdentifierResponseOtherUser{ + MXID: puppet.MXID, DisplayName: puppet.Name, - AvatarURL: puppet.AvatarURL.String(), + AvatarURL: puppet.AvatarURL, } } else { targetServiceID = libsignalgo.NewPNIServiceID(pni) @@ -214,9 +156,9 @@ func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, } portal := user.GetPortalByChatID(targetServiceID.String()) - return http.StatusOK, &ResolveIdentifierResponse{ + return http.StatusOK, &legacyprovision.ResolveIdentifierResponse{ RoomID: portal.MXID, - ChatID: ResolveIdentifierResponseChatID{ + ChatID: legacyprovision.ResolveIdentifierResponseChatID{ UUID: targetServiceID.String(), Number: e164String, }, @@ -245,14 +187,14 @@ func (prov *ProvisioningAPI) ResolveIdentifier(w http.ResponseWriter, r *http.Re } else { log.Err(err).Msg("error looking up contact") } - jsonResponse(w, status, Error{ + legacyprovision.JSONResponse(w, status, legacyprovision.Error{ Success: false, Error: err.Error(), ErrCode: errCode, }) return } - jsonResponse(w, status, Response{ + legacyprovision.JSONResponse(w, status, legacyprovision.Response{ Success: true, Status: "ok", ResolveIdentifierResponse: resp, @@ -280,7 +222,7 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { } else { log.Err(err).Msg("error looking up contact") } - jsonResponse(w, status, Error{ + legacyprovision.JSONResponse(w, status, legacyprovision.Error{ Success: false, Error: err.Error(), ErrCode: errCode, @@ -292,7 +234,7 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { if portal.MXID == "" { if err := portal.CreateMatrixRoom(r.Context(), user, 0); err != nil { log.Err(err).Msg("error looking up contact") - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: "Error creating Matrix room", ErrCode: "M_INTERNAL", @@ -306,7 +248,7 @@ func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { status = http.StatusCreated } - jsonResponse(w, status, Response{ + legacyprovision.JSONResponse(w, status, legacyprovision.Response{ Success: true, Status: "ok", ResolveIdentifierResponse: resp, @@ -401,7 +343,7 @@ func (prov *ProvisioningAPI) checkSessionAndReturnHandle(ctx context.Context, w handle := prov.existingSession(user) if handle == nil { log.Warn().Msg("no session found") - jsonResponse(w, http.StatusNotFound, Error{ + legacyprovision.JSONResponse(w, http.StatusNotFound, legacyprovision.Error{ Success: false, Error: "No session found", ErrCode: "M_NOT_FOUND", @@ -413,7 +355,7 @@ func (prov *ProvisioningAPI) checkSessionAndReturnHandle(ctx context.Context, w Int("handle_id", handle.id). Int("current_session", currentSession). Msg("session_id does not match user's session_id") - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: "session_id does not match user's session_id", ErrCode: "M_BAD_JSON", @@ -431,12 +373,12 @@ func (prov *ProvisioningAPI) WhoAmI(w http.ResponseWriter, r *http.Request) { Logger() log.Debug().Msg("getting whoami") - data := WhoAmIResponse{ + data := legacyprovision.WhoAmIResponse{ Permissions: int(user.PermissionLevel), MXID: user.MXID.String(), } if user.IsLoggedIn() { - data.Signal = &WhoAmIResponseSignal{ + data.Signal = &legacyprovision.WhoAmIResponseSignal{ Number: user.SignalUsername, UUID: user.SignalID.String(), Ok: user.Client.IsConnected(), @@ -446,7 +388,7 @@ func (prov *ProvisioningAPI) WhoAmI(w http.ResponseWriter, r *http.Request) { data.Signal.Name = puppet.Name } } - jsonResponse(w, http.StatusOK, data) + legacyprovision.JSONResponse(w, http.StatusOK, data) } func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { @@ -460,7 +402,7 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { handle, err := prov.loginOrSendError(ctx, w, user) if err != nil { - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: err.Error(), ErrCode: "M_INTERNAL", @@ -475,7 +417,7 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { case resp := <-handle.channel: if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { log.Err(resp.Err).Msg("Error getting provisioning URL") - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: resp.Err.Error(), ErrCode: "M_INTERNAL", @@ -484,7 +426,7 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { } if resp.State != signalmeow.StateProvisioningURLReceived { log.Err(resp.Err).Stringer("state", resp.State).Msg("unexpected state") - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: fmt.Sprintf("Unexpected state %s", resp.State.String()), ErrCode: "M_INTERNAL", @@ -493,7 +435,7 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { } log.Debug().Str("provisioning_url", resp.ProvisioningURL).Msg("provisioning URL received") - jsonResponse(w, http.StatusOK, Response{ + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ Success: true, Status: "provisioning_url_received", SessionID: fmt.Sprintf("%d", handle.id), @@ -501,7 +443,7 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { }) case <-time.After(30 * time.Second): log.Warn().Msg("Timeout waiting for provisioning response (new)") - jsonResponse(w, http.StatusGatewayTimeout, Error{ + legacyprovision.JSONResponse(w, http.StatusGatewayTimeout, legacyprovision.Error{ Success: false, Error: "Timeout waiting for provisioning response (new)", ErrCode: "M_TIMEOUT", @@ -509,17 +451,13 @@ func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { } } -type LinkWaitForScanRequest struct { - SessionID string `json:"session_id"` -} - func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) - var body LinkWaitForScanRequest + var body legacyprovision.LinkWaitForScanRequest err := json.NewDecoder(r.Body).Decode(&body) if err != nil { - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: "Error decoding JSON body", ErrCode: "M_BAD_JSON", @@ -528,7 +466,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ } sessionID, err := strconv.Atoi(body.SessionID) if err != nil { - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: "Error decoding session ID in JSON body", ErrCode: "M_BAD_JSON", @@ -561,7 +499,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ // If we error waiting for the scan, treat it as a normal error not 5xx // so that the client will retry quietly. Also, it's really not an internal // error, sitting with a WS open waiting for a scan is inherently flaky. - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: resp.Err.Error(), ErrCode: "M_INTERNAL", @@ -570,7 +508,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ } if resp.State != signalmeow.StateProvisioningDataReceived { log.Err(resp.Err).Stringer("state", resp.State).Msg("unexpected state") - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: fmt.Sprintf("Unexpected state %s", resp.State.String()), ErrCode: "M_INTERNAL", @@ -578,7 +516,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ return } log.Debug().Msg("provisioning data received") - jsonResponse(w, http.StatusOK, Response{ + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ Success: true, Status: "provisioning_data_received", }) @@ -591,7 +529,7 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ case <-time.After(45 * time.Second): log.Warn().Msg("Timeout waiting for provisioning response (scan)") // Using 400 here to match the old bridge - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: "Timeout waiting for QR code scan", ErrCode: "M_BAD_REQUEST", @@ -600,18 +538,13 @@ func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Requ } } -type LinkWaitForAccountRequest struct { - SessionID string `json:"session_id"` - DeviceName string `json:"device_name"` // TODO this seems to not be used anywhere -} - func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(provisioningUserKey).(*User) - var body LinkWaitForAccountRequest + var body legacyprovision.LinkWaitForAccountRequest err := json.NewDecoder(r.Body).Decode(&body) if err != nil { - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: "Error decoding JSON body", ErrCode: "M_BAD_JSON", @@ -620,7 +553,7 @@ func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.R } sessionID, err := strconv.Atoi(body.SessionID) if err != nil { - jsonResponse(w, http.StatusBadRequest, Error{ + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ Success: false, Error: "Error decoding session ID in JSON body", ErrCode: "M_BAD_JSON", @@ -647,7 +580,7 @@ func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.R case resp := <-handle.channel: if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { log.Err(resp.Err).Msg("Error waiting for account") - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: resp.Err.Error(), ErrCode: "M_INTERNAL", @@ -656,7 +589,7 @@ func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.R } if resp.State != signalmeow.StateProvisioningPreKeysRegistered { log.Err(resp.Err).Stringer("state", resp.State).Msg("unexpected state") - jsonResponse(w, http.StatusInternalServerError, Error{ + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Success: false, Error: fmt.Sprintf("Unexpected state %s", resp.State.String()), ErrCode: "M_INTERNAL", @@ -665,7 +598,7 @@ func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.R } log.Debug().Msg("prekeys registered") - jsonResponse(w, http.StatusOK, Response{ + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ Success: true, Status: "prekeys_registered", UUID: user.SignalID.String(), @@ -677,7 +610,7 @@ func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.R return case <-time.After(30 * time.Second): log.Warn().Msg("Timeout waiting for provisioning response (account)") - jsonResponse(w, http.StatusGatewayTimeout, Error{ + legacyprovision.JSONResponse(w, http.StatusGatewayTimeout, legacyprovision.Error{ Success: false, Error: "Timeout waiting for provisioning response (account)", ErrCode: "M_TIMEOUT", @@ -700,7 +633,7 @@ func (prov *ProvisioningAPI) Logout(w http.ResponseWriter, r *http.Request) { // For now do nothing - we need this API to return 200 to be compatible with // the old Signal bridge, which needed a call to Logout before allowing LinkNew // to be called, but we don't actually want to logout, we want to allow a reconnect. - jsonResponse(w, http.StatusOK, Response{ + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ Success: true, Status: "logged_out", }) From 43ee1bb438497e7bfc8dbdeed903d3dc66de5253 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Jun 2024 16:14:21 +0300 Subject: [PATCH 209/718] signalmeow: don't update e164 if it's empty --- pkg/signalmeow/receiving.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index ba29914..96d066a 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -475,7 +475,12 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin ctx = log.WithContext(ctx) log.Trace().Msg("Received SealedSender message") - cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) + if senderE164 != "" { + _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) + if err != nil { + log.Warn().Err(err).Msg("Failed to update sender E164 in recipient store") + } + } switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: From 0c82b56012f1a0ee1db2f9997fa9411a6ac15c0f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Jun 2024 21:28:08 +0300 Subject: [PATCH 210/718] signalmeow: fix edge case in LoadAndUpdateRecipient --- pkg/signalmeow/store/recipient_store.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 3463a00..bdcd0c0 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -244,6 +244,14 @@ func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUI if err != nil { return fmt.Errorf("failed to run updater function: %w", err) } + // SQL only supports one ON CONFLICT clause, which means StoreRecipient will key on the ACI if it's present. + // If we're adding an ACI to a PNI row, just delete the PNI row first to avoid conflicts on the PNI key. + if outRecipient.PNI != uuid.Nil && outRecipient.ACI == uuid.Nil && aci != uuid.Nil { + err = s.DeleteRecipientByPNI(ctx, outRecipient.PNI) + if err != nil { + return fmt.Errorf("failed to delete old PNI row: %w", err) + } + } if outRecipient.PNI == uuid.Nil && pni != uuid.Nil { outRecipient.PNI = pni changed = true From 7291895376c19b755176fc2f45baffc32909bfae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Jun 2024 21:33:37 +0300 Subject: [PATCH 211/718] v2: update mautrix-go to fix state bug after syncing members --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0f99be4..ac9d0a0 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240625085258-678695edd51c + go.mau.fi/util v0.5.1-0.20240625181823-38eefa626984 golang.org/x/crypto v0.24.0 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240625120422-13b2d6275302 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240625183146-ae054177794b nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index c6356ce..49ae2b7 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240625085258-678695edd51c h1:LAXHOnupWCFvTyx4ZAu5t+6n7zADldeRHIk1s+2luow= -go.mau.fi/util v0.5.1-0.20240625085258-678695edd51c/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/util v0.5.1-0.20240625181823-38eefa626984 h1:63X00R1qL5G+m2LWxdKzAS8cyihFu5IaaOzJ7QHvkzs= +go.mau.fi/util v0.5.1-0.20240625181823-38eefa626984/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240625120422-13b2d6275302 h1:PbCdso3xltp5ztKXpAW4C4tC8LLgxeHkJ4mF/7HE3Z0= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240625120422-13b2d6275302/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625183146-ae054177794b h1:mwtsH2BvxwOCn+VG79gsl7f5prD1YcqG06HCZXKcix4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625183146-ae054177794b/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 86135c576a67da44cff331bd4a047e7a37d2f6f5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Jun 2024 21:47:38 +0300 Subject: [PATCH 212/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ac9d0a0..a59527c 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240625183146-ae054177794b + maunium.net/go/mautrix v0.19.0-beta.1.0.20240625184543-3f8bb2fd54b1 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 49ae2b7..40f1dee 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240625183146-ae054177794b h1:mwtsH2BvxwOCn+VG79gsl7f5prD1YcqG06HCZXKcix4= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240625183146-ae054177794b/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625184543-3f8bb2fd54b1 h1:V+PMBFKZwUA0Jy5DrLh1TtDZhnagQMFN9/2/m3T+SLc= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240625184543-3f8bb2fd54b1/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From baf113fb03296e641ec951fd97036f2e9a4ec9dc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 14:43:43 +0300 Subject: [PATCH 213/718] v2: add backwards-compatible login API --- cmd/mautrix-signal-v2/legacyprovision.go | 153 ++++++++++++++++++++++- cmd/mautrix-signal-v2/main.go | 2 +- go.mod | 2 +- go.sum | 4 +- pkg/connector/login.go | 1 + 5 files changed, 153 insertions(+), 9 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal-v2/legacyprovision.go index 5b8e203..87140b9 100644 --- a/cmd/mautrix-signal-v2/legacyprovision.go +++ b/cmd/mautrix-signal-v2/legacyprovision.go @@ -17,27 +17,170 @@ package main import ( + "encoding/json" "fmt" "net/http" + "strconv" + "sync" + "sync/atomic" "github.com/gorilla/mux" "github.com/rs/zerolog" - - "go.mau.fi/mautrix-signal/legacyprovision" "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridgev2" + + "go.mau.fi/mautrix-signal/legacyprovision" ) +var legacyProvisionHandleID atomic.Uint32 +var loginSessions = make(map[uint32]*legacyLoginProcess) +var loginSessionsLock sync.Mutex + +type legacyLoginProcess struct { + ID uint32 + Login bridgev2.LoginProcess + User *bridgev2.User + Done *bridgev2.UserLogin +} + +func (llp *legacyLoginProcess) Delete() { + loginSessionsLock.Lock() + delete(loginSessions, llp.ID) + loginSessionsLock.Unlock() +} + func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotImplemented) + handleID := legacyProvisionHandleID.Add(1) + user := m.Matrix.Provisioning.GetUser(r) + defLogin := user.GetDefaultLogin() + if defLogin != nil && defLogin.Client != nil && defLogin.Client.IsLoggedIn() { + legacyprovision.JSONResponse(w, http.StatusConflict, &legacyprovision.Error{ + Error: "Already logged in", + ErrCode: "FI.MAU.ALREADY_LOGGED_IN", + }) + return + } + log := zerolog.Ctx(r.Context()) + login, err := m.Connector.CreateLogin(r.Context(), user, "qr") + if err != nil { + log.Err(err).Msg("Failed to create login") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + Error: "Internal error starting login", + ErrCode: "M_UNKNOWN", + }) + return + } + firstStep, err := login.Start(r.Context()) + if err != nil { + log.Err(err).Msg("Failed to start login") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + Error: "Internal error starting login", + ErrCode: "M_UNKNOWN", + }) + return + } else if firstStep.Type != bridgev2.LoginStepTypeDisplayAndWait || firstStep.DisplayAndWaitParams.Type != bridgev2.LoginDisplayTypeQR { + log.Error().Any("first_step", firstStep).Msg("Unexpected first step") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + Error: "Unexpected first login step", + ErrCode: "M_UNKNOWN", + }) + return + } + loginSessionsLock.Lock() + loginSessions[handleID] = &legacyLoginProcess{ + ID: handleID, + Login: login, + User: user, + } + loginSessionsLock.Unlock() + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ + Success: true, + Status: "provisioning_url_received", + SessionID: strconv.Itoa(int(handleID)), + URI: firstStep.DisplayAndWaitParams.Data, + }) +} + +func getLoginProcess(w http.ResponseWriter, r *http.Request) *legacyLoginProcess { + var body legacyprovision.LinkWaitForAccountRequest + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ + Success: false, + Error: "Error decoding JSON body", + ErrCode: mautrix.MBadJSON.ErrCode, + }) + return nil + } + sessionID, err := strconv.Atoi(body.SessionID) + if err != nil { + legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ + Success: false, + Error: "Error decoding session ID in JSON body", + ErrCode: mautrix.MBadJSON.ErrCode, + }) + return nil + } + process, ok := loginSessions[uint32(sessionID)] + user := m.Matrix.Provisioning.GetUser(r) + if !ok || process.User != user { + legacyprovision.JSONResponse(w, http.StatusNotFound, legacyprovision.Error{ + Success: false, + Error: "No session found", + ErrCode: mautrix.MNotFound.ErrCode, + }) + return nil + } + return process } func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotImplemented) + login := getLoginProcess(w, r) + if login == nil { + return + } + res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) + if err != nil { + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + Error: "Failed to log in", + ErrCode: "M_UNKNOWN", + }) + login.Delete() + return + } else if res.Type != bridgev2.LoginStepTypeComplete { + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + Error: "Unexpected login step", + ErrCode: "M_UNKNOWN", + }) + login.Delete() + return + } + login.Done = res.CompleteParams.UserLogin + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ + Success: true, + Status: "provisioning_data_received", + }) } func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotImplemented) + login := getLoginProcess(w, r) + if login == nil { + return + } + if login.Done != nil { + legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ + Success: true, + Status: "prekeys_registered", + UUID: string(login.Done.ID), + Number: login.Done.Metadata.RemoteName, + }) + login.Delete() + } else { + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + Error: "Login not completed", + ErrCode: "M_UNKNOWN", + }) + } } func legacyProvLogout(w http.ResponseWriter, r *http.Request) { diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 7c0762c..0e85c38 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 2), true, ) } diff --git a/go.mod b/go.mod index a59527c..1462e0b 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240625184543-3f8bb2fd54b1 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240626114248-5dbfd7093e58 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 40f1dee..be925ba 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240625184543-3f8bb2fd54b1 h1:V+PMBFKZwUA0Jy5DrLh1TtDZhnagQMFN9/2/m3T+SLc= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240625184543-3f8bb2fd54b1/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240626114248-5dbfd7093e58 h1:N2Mll8zmQPEFhLgJdH/QPw9Wu4nnLD1LIrAyk0vohHo= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240626114248-5dbfd7093e58/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 4205f67..824f8f1 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -174,6 +174,7 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { Instructions: fmt.Sprintf("Successfully logged in as %s / %s", signalPhone, signalID), CompleteParams: &bridgev2.LoginCompleteParams{ UserLoginID: ul.ID, + UserLogin: ul, }, }, nil } From 4352712426a4352bc2f8aa347e79206a462fe231 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 17:15:05 +0300 Subject: [PATCH 214/718] v2: remove -v2 suffix in binary name inside docker image --- Dockerfile.v2.ci | 2 +- docker-run.sh | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Dockerfile.v2.ci b/Dockerfile.v2.ci index d5868a7..0ff0c8c 100644 --- a/Dockerfile.v2.ci +++ b/Dockerfile.v2.ci @@ -6,7 +6,7 @@ ENV UID=1337 \ RUN apk add --no-cache ffmpeg su-exec ca-certificates bash jq curl yq-go ARG EXECUTABLE=./mautrix-signal-v2 -COPY $EXECUTABLE /usr/bin/mautrix-signal-v2 +COPY $EXECUTABLE /usr/bin/mautrix-signal COPY ./docker-run.sh /docker-run.sh ENV BRIDGEV2=1 VOLUME /data diff --git a/docker-run.sh b/docker-run.sh index 6d6f3a7..bcc6bc4 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -5,9 +5,6 @@ if [[ -z "$GID" ]]; then fi BINARY_NAME=/usr/bin/mautrix-signal -if [[ "$BRIDGEV2" == "1" ]]; then - BINARY_NAME=/usr/bin/mautrix-signal-v2 -fi # Define functions. function fixperms { From 72e9cc6c11ff8e0e52aae68a5e1d44702e7d9971 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 20:09:00 +0300 Subject: [PATCH 215/718] v2: add extra wait step to login --- cmd/mautrix-signal-v2/legacyprovision.go | 35 +++++++++------ go.mod | 2 +- go.sum | 4 +- pkg/connector/login.go | 55 ++++++++++++++++++------ 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal-v2/legacyprovision.go index 87140b9..007cf33 100644 --- a/cmd/mautrix-signal-v2/legacyprovision.go +++ b/cmd/mautrix-signal-v2/legacyprovision.go @@ -30,6 +30,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "go.mau.fi/mautrix-signal/legacyprovision" + "go.mau.fi/mautrix-signal/pkg/connector" ) var legacyProvisionHandleID atomic.Uint32 @@ -40,7 +41,6 @@ type legacyLoginProcess struct { ID uint32 Login bridgev2.LoginProcess User *bridgev2.User - Done *bridgev2.UserLogin } func (llp *legacyLoginProcess) Delete() { @@ -78,7 +78,7 @@ func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { ErrCode: "M_UNKNOWN", }) return - } else if firstStep.Type != bridgev2.LoginStepTypeDisplayAndWait || firstStep.DisplayAndWaitParams.Type != bridgev2.LoginDisplayTypeQR { + } else if firstStep.StepID != connector.LoginStepQR || firstStep.Type != bridgev2.LoginStepTypeDisplayAndWait || firstStep.DisplayAndWaitParams.Type != bridgev2.LoginDisplayTypeQR { log.Error().Any("first_step", firstStep).Msg("Unexpected first step") legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ Error: "Unexpected first login step", @@ -141,13 +141,15 @@ func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { } res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) if err != nil { + zerolog.Ctx(r.Context()).Err(err).Msg("Failed to log in") legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Error: "Failed to log in", ErrCode: "M_UNKNOWN", }) login.Delete() return - } else if res.Type != bridgev2.LoginStepTypeComplete { + } else if res.StepID != connector.LoginStepProcess { + zerolog.Ctx(r.Context()).Error().Any("first_step", res).Msg("Unexpected login step") legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ Error: "Unexpected login step", ErrCode: "M_UNKNOWN", @@ -155,7 +157,6 @@ func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { login.Delete() return } - login.Done = res.CompleteParams.UserLogin legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ Success: true, Status: "provisioning_data_received", @@ -167,20 +168,28 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { if login == nil { return } - if login.Done != nil { + res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) + if err != nil { + zerolog.Ctx(r.Context()).Err(err).Msg("Failed to log in") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + Error: "Failed to log in", + ErrCode: "M_UNKNOWN", + }) + } else if res.StepID != connector.LoginStepComplete || res.Type != bridgev2.LoginStepTypeComplete { + zerolog.Ctx(r.Context()).Error().Any("first_step", res).Msg("Unexpected login step") + legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + Error: "Unexpected login step", + ErrCode: "M_UNKNOWN", + }) + } else { legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ Success: true, Status: "prekeys_registered", - UUID: string(login.Done.ID), - Number: login.Done.Metadata.RemoteName, - }) - login.Delete() - } else { - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Error: "Login not completed", - ErrCode: "M_UNKNOWN", + UUID: string(res.CompleteParams.UserLogin.ID), + Number: res.CompleteParams.UserLogin.Metadata.RemoteName, }) } + login.Delete() } func legacyProvLogout(w http.ResponseWriter, r *http.Request) { diff --git a/go.mod b/go.mod index 1462e0b..af271eb 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240626114248-5dbfd7093e58 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240626170142-1a18d9ee55f1 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index be925ba..43b7309 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240626114248-5dbfd7093e58 h1:N2Mll8zmQPEFhLgJdH/QPw9Wu4nnLD1LIrAyk0vohHo= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240626114248-5dbfd7093e58/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240626170142-1a18d9ee55f1 h1:iE/MzeUGHAs2pbtq/hVnJp7pFQhgjRnZZFfnFDwZdq0= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240626170142-1a18d9ee55f1/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 824f8f1..24cbcd7 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -26,6 +26,7 @@ import ( "maunium.net/go/mautrix/bridgev2/database" "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" ) func (s *SignalConnector) GetLoginFlows() []bridgev2.LoginFlow { @@ -48,6 +49,8 @@ type QRLogin struct { Main *SignalConnector cancelChan context.CancelFunc ProvChan chan signalmeow.ProvisioningResponse + + ProvData *store.DeviceData } var _ bridgev2.LoginProcessDisplayAndWait = (*QRLogin)(nil) @@ -60,6 +63,12 @@ func (qr *QRLogin) Cancel() { }() } +const ( + LoginStepQR = "fi.mau.signal.login.qr" + LoginStepProcess = "fi.mau.signal.login.processing" + LoginStepComplete = "fi.mau.signal.login.complete" +) + func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { log := qr.Main.Bridge.Log.With(). Str("action", "login"). @@ -84,7 +93,7 @@ func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { } return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeDisplayAndWait, - StepID: "fi.mau.signal.login.qr", + StepID: LoginStepQR, Instructions: "Scan the QR code on your Signal app to log in", DisplayAndWaitParams: &bridgev2.LoginDisplayAndWaitParams{ Type: bridgev2.LoginDisplayTypeQR, @@ -97,25 +106,45 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { if qr.ProvChan == nil { return nil, fmt.Errorf("login not started") } - defer qr.cancelChan() - var signalID uuid.UUID - var signalPhone string + if qr.ProvData == nil { + return qr.qrWait(ctx) + } else { + return qr.processingWait(ctx) + } +} + +func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { select { case resp := <-qr.ProvChan: if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + qr.cancelChan() return nil, resp.Err } else if resp.State != signalmeow.StateProvisioningDataReceived { + qr.cancelChan() return nil, fmt.Errorf("unexpected state %v", resp.State) } else if resp.ProvisioningData.ACI == uuid.Nil { + qr.cancelChan() return nil, fmt.Errorf("no signal account ID received") } - signalID = resp.ProvisioningData.ACI - signalPhone = resp.ProvisioningData.Number + qr.ProvData = resp.ProvisioningData + return &bridgev2.LoginStep{ + Type: bridgev2.LoginStepTypeDisplayAndWait, + StepID: LoginStepProcess, + Instructions: fmt.Sprintf("Processing login as %s...", resp.ProvisioningData.Number), + DisplayAndWaitParams: &bridgev2.LoginDisplayAndWaitParams{ + Type: bridgev2.LoginDisplayTypeNothing, + }, + }, nil case <-ctx.Done(): + qr.cancelChan() return nil, ctx.Err() } - newLoginID := makeUserLoginID(signalID) +} + +func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, error) { + defer qr.cancelChan() + newLoginID := makeUserLoginID(qr.ProvData.ACI) select { case resp := <-qr.ProvChan: @@ -141,10 +170,10 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { ID: newLoginID, Metadata: database.UserLoginMetadata{ StandardUserLoginMetadata: database.StandardUserLoginMetadata{ - RemoteName: signalPhone, + RemoteName: qr.ProvData.Number, }, Extra: map[string]any{ - "phone": signalPhone, + "phone": qr.ProvData.Number, }, }, }, nil) @@ -152,8 +181,8 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, fmt.Errorf("failed to save new login: %w", err) } } else { - ul.Metadata.Extra["phone"] = signalPhone - ul.Metadata.RemoteName = signalPhone + ul.Metadata.Extra["phone"] = qr.ProvData.Number + ul.Metadata.RemoteName = qr.ProvData.Number err = ul.Save(ctx) if err != nil { return nil, fmt.Errorf("failed to update existing login: %w", err) @@ -170,8 +199,8 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { } return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, - StepID: "fi.mau.signal.login.complete", - Instructions: fmt.Sprintf("Successfully logged in as %s / %s", signalPhone, signalID), + StepID: LoginStepComplete, + Instructions: fmt.Sprintf("Successfully logged in as %s / %s", qr.ProvData.Number, qr.ProvData.ACI), CompleteParams: &bridgev2.LoginCompleteParams{ UserLoginID: ul.ID, UserLogin: ul, From d50bc09788a0793d84e62d9db11abf6849cb38a0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 21:00:58 +0300 Subject: [PATCH 216/718] v2: make legacy provisioning logout a no-op --- cmd/mautrix-signal-v2/legacyprovision.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal-v2/legacyprovision.go index 007cf33..0eef485 100644 --- a/cmd/mautrix-signal-v2/legacyprovision.go +++ b/cmd/mautrix-signal-v2/legacyprovision.go @@ -193,14 +193,7 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { } func legacyProvLogout(w http.ResponseWriter, r *http.Request) { - user := m.Matrix.Provisioning.GetUser(r) - for { - login := user.GetDefaultLogin() - if login == nil { - break - } - login.Logout(r.Context()) - } + // No-op for backwards compatibility legacyprovision.JSONResponse(w, http.StatusOK, nil) } From 80e59d62bf4a70826d29348e5eb1d7d58967ca20 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 21:15:32 +0300 Subject: [PATCH 217/718] v2: fix typo in legacymigrate.sql --- cmd/mautrix-signal-v2/legacymigrate.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index 60b08d5..32f7aa0 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -87,7 +87,7 @@ SELECT NULL, -- relates_to -- only: postgres '{}'::jsonb -- metadata - -- only: sqlite (line commented + -- only: sqlite (line commented) -- '{}' FROM message_old; From 29d248b125a84b4d0ffb88b1ac9a05219c764bc2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 21:32:05 +0300 Subject: [PATCH 218/718] v2: fix more legacymigrate.sql issues --- cmd/mautrix-signal-v2/legacymigrate.sql | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index 32f7aa0..ba91f9c 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -75,7 +75,7 @@ INSERT INTO message ( SELECT '', -- bridge_id cast(sender AS TEXT) || '|' || timestamp, -- id - CAST(part_index AS TEXT), -- part_id + CASE WHEN part_index=0 THEN '' ELSE CAST(part_index AS TEXT) END, -- part_id mxid, signal_chat_id, -- room_id CASE @@ -85,10 +85,7 @@ SELECT cast(sender AS TEXT), -- sender_id timestamp * 1000000, NULL, -- relates_to - -- only: postgres - '{}'::jsonb -- metadata - -- only: sqlite (line commented) --- '{}' + '{}' -- metadata FROM message_old; INSERT INTO disappearing_message ( From 4e5db9026c4984f25910a7d20b1ab62ec629b8f9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Jun 2024 21:45:32 +0300 Subject: [PATCH 219/718] v2: update mautrix-go to maybe fix migration on SQLite --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index af271eb..9f3eef2 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240625181823-38eefa626984 + go.mau.fi/util v0.5.1-0.20240626184357-b3f4d78c25cf golang.org/x/crypto v0.24.0 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240626170142-1a18d9ee55f1 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240626184459-c9314c6a63f8 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 43b7309..a2117b9 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240625181823-38eefa626984 h1:63X00R1qL5G+m2LWxdKzAS8cyihFu5IaaOzJ7QHvkzs= -go.mau.fi/util v0.5.1-0.20240625181823-38eefa626984/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/util v0.5.1-0.20240626184357-b3f4d78c25cf h1:ceXQTB6IqjqGBGhzOTEBGbxQu7xDyuT9YR06gxr9Ncw= +go.mau.fi/util v0.5.1-0.20240626184357-b3f4d78c25cf/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240626170142-1a18d9ee55f1 h1:iE/MzeUGHAs2pbtq/hVnJp7pFQhgjRnZZFfnFDwZdq0= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240626170142-1a18d9ee55f1/go.mod h1:pFbqAannSyJnohVycF4NW3IngBLWUt/f9KYfJcwyQec= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240626184459-c9314c6a63f8 h1:zxjQQrIOXw5MyE82I2SmWsgAFgh9lB8Ijjdilld59/U= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240626184459-c9314c6a63f8/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From be21dac6cf66b53a7d7ed717cc8c28a51cbc544b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Jun 2024 11:34:48 +0300 Subject: [PATCH 220/718] v2: improve handling of logins in bad credentials --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 19 +++++++++++++++++++ pkg/connector/connector.go | 12 ++++++------ 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 9f3eef2..19843dc 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240626184459-c9314c6a63f8 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240627083250-e25578d435a2 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index a2117b9..f73fa34 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240626184459-c9314c6a63f8 h1:zxjQQrIOXw5MyE82I2SmWsgAFgh9lB8Ijjdilld59/U= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240626184459-c9314c6a63f8/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240627083250-e25578d435a2 h1:HnP1dmvCVO/V22BdJre56Vu1IaEtMRUt86AD/1rmyME= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240627083250-e25578d435a2/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 6f1a3ec..285e207 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -70,6 +70,9 @@ func (s *SignalClient) GetPushConfigs() *bridgev2.PushConfig { } func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { + if s.Client == nil { + return bridgev2.ErrNotLoggedIn + } if pushType != bridgev2.PushTypeFCM { return fmt.Errorf("unsupported push type: %s", pushType) } @@ -77,6 +80,9 @@ func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType b } func (s *SignalClient) LogoutRemote(ctx context.Context) { + if s.Client == nil { + return + } err := s.Client.StopReceiveLoops() if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") @@ -88,6 +94,9 @@ func (s *SignalClient) LogoutRemote(ctx context.Context) { } func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bool { + if s.Client == nil { + return false + } return userID == makeUserID(s.Client.Store.ACI) } @@ -200,6 +209,9 @@ func (s *SignalClient) Connect(ctx context.Context) error { } func (s *SignalClient) Disconnect() { + if s.Client == nil { + return + } err := s.Client.StopReceiveLoops() if err != nil { s.UserLogin.Log.Err(err).Msg("Failed to stop receive loops") @@ -207,6 +219,10 @@ func (s *SignalClient) Disconnect() { } func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { + if s.Client == nil { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You're not logged into Signal"}) + return + } ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") @@ -225,5 +241,8 @@ func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { } func (s *SignalClient) IsLoggedIn() bool { + if s.Client == nil { + return false + } return s.Client.IsLoggedIn() } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 5fdec0a..8aec917 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -148,17 +148,17 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use device, err := s.Store.DeviceByACI(ctx, aci) if err != nil { return fmt.Errorf("failed to get device from store: %w", err) - } else if device == nil { - return fmt.Errorf("%w: device not found in store", bridgev2.ErrNotLoggedIn) } sc := &SignalClient{ Main: s, UserLogin: login, - Client: &signalmeow.Client{ - Store: device, - }, } - sc.Client.EventHandler = sc.handleSignalEvent + if device != nil { + sc.Client = &signalmeow.Client{ + Store: device, + EventHandler: sc.handleSignalEvent, + } + } login.Client = sc return nil } From 1366e2721bb9bbb96ceaed4f3e0aa5ca8740dcc7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Jun 2024 11:35:06 +0300 Subject: [PATCH 221/718] v2: bridge more types of messages as normal messages --- pkg/connector/handlesignal.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 479ce2a..6af25ab 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -68,7 +68,10 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { switch innerEvt := evt.Event.(type) { case *signalpb.DataMessage: switch { - case innerEvt.Body != nil, innerEvt.Attachments != nil, innerEvt.Contact != nil, innerEvt.Sticker != nil: + case innerEvt.Body != nil, innerEvt.Attachments != nil, innerEvt.Contact != nil, innerEvt.Sticker != nil, + innerEvt.Payment != nil, innerEvt.GiftBadge != nil, + innerEvt.GetRequiredProtocolVersion() > uint32(signalpb.DataMessage_CURRENT), + innerEvt.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0: return bridgev2.RemoteEventMessage case innerEvt.Reaction != nil: if innerEvt.Reaction.GetRemove() { From 5b1941c0ab5db50df70b592d5fba43722a1a448b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Jun 2024 11:53:21 +0300 Subject: [PATCH 222/718] v2: check send message results --- pkg/connector/handlematrix.go | 56 ++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 30b10e6..052428f 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -18,6 +18,7 @@ package connector import ( "context" + "errors" "fmt" "time" @@ -34,20 +35,43 @@ import ( signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) -func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) (signalmeow.SendResult, error) { +func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { userID, groupID, err := s.parsePortalID(portalID) if err != nil { - return nil, err + return err } if groupID != "" { - res, err := s.Client.SendGroupMessage(ctx, groupID, content) + result, err := s.Client.SendGroupMessage(ctx, groupID, content) if err != nil { - return nil, err + return err } - return res, nil + totalRecipients := len(result.FailedToSendTo) + len(result.SuccessfullySentTo) + log := zerolog.Ctx(ctx).With(). + Int("total_recipients", totalRecipients). + Int("failed_to_send_to_count", len(result.FailedToSendTo)). + Int("successfully_sent_to_count", len(result.SuccessfullySentTo)). + Logger() + if len(result.FailedToSendTo) > 0 { + log.Error().Msg("Failed to send event to some members of Signal group") + } + if len(result.SuccessfullySentTo) == 0 && len(result.FailedToSendTo) == 0 { + log.Debug().Msg("No successes or failures - Probably sent to myself") + } else if len(result.SuccessfullySentTo) == 0 { + log.Error().Msg("Failed to send event to all members of Signal group") + return errors.New("failed to send to any members of Signal group") + + } else if len(result.SuccessfullySentTo) < totalRecipients { + log.Warn().Msg("Only sent event to some members of Signal group") + } else { + log.Debug().Msg("Sent event to all members of Signal group") + } + return nil } else { res := s.Client.SendMessage(ctx, userID, content) - return &res, nil + if !res.WasSuccessful { + return res.Error + } + return nil } } @@ -64,12 +88,10 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma if err != nil { return nil, err } - res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) + err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) if err != nil { return nil, err } - // TODO check result - fmt.Println(res) dbMsg := &database.Message{ ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), SenderID: makeUserID(s.Client.Store.ACI), @@ -111,15 +133,13 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri if err != nil { return err } - res, err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ + err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ TargetSentTimestamp: proto.Uint64(targetSentTimestamp), DataMessage: converted, }}) if err != nil { return err } - // TODO check result - fmt.Println(res) msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) msg.EditTarget.Metadata.Extra["contains_attachments"] = len(converted.Attachments) > 0 msg.EditTarget.Metadata.EditCount++ @@ -151,12 +171,10 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M }, }, } - res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent) if err != nil { return nil, err } - // TODO check result - fmt.Println(res) return &database.Reaction{}, nil } @@ -177,12 +195,10 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid }, }, } - res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent) if err != nil { return err } - // TODO check result - fmt.Println(res) return nil } @@ -201,12 +217,10 @@ func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridg }, }, } - res, err := s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent) if err != nil { return err } - // TODO check result - fmt.Println(res) return nil } From fdb9e7dc09599fd982cff4ea90903971e368983e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Jun 2024 16:43:53 +0300 Subject: [PATCH 223/718] v2: fix handling disappearing timer changes --- msgconv/from-signal.go | 16 ++++++++++------ msgconv/msgconv.go | 3 ++- pkg/connector/connector.go | 17 ++++++++++++++++- pkg/connector/handlesignal.go | 17 +++++++++++++---- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/msgconv/from-signal.go b/msgconv/from-signal.go index 8a4b5d1..918c749 100644 --- a/msgconv/from-signal.go +++ b/msgconv/from-signal.go @@ -173,12 +173,16 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C if timer == 0 { part.Content.Body = "Disappearing messages disabled" } - if updatePortal && !mc.NoUpdateDisappearing { - portal := mc.GetData(ctx) - portal.ExpirationTime = timer - err := portal.Update(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") + if updatePortal { + if mc.UpdateDisappearing != nil { + mc.UpdateDisappearing(ctx, time.Duration(timer)*time.Second) + } else { + portal := mc.GetData(ctx) + portal.ExpirationTime = timer + err := portal.Update(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") + } } } return part diff --git a/msgconv/msgconv.go b/msgconv/msgconv.go index 33ac4a5..ee3ff55 100644 --- a/msgconv/msgconv.go +++ b/msgconv/msgconv.go @@ -18,6 +18,7 @@ package msgconv import ( "context" + "time" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -54,7 +55,7 @@ type MessageConverter struct { ConvertGIFToAPNG bool MaxFileSize int64 AsyncFiles bool - NoUpdateDisappearing bool + UpdateDisappearing func(ctx context.Context, newTimer time.Duration) LocationFormat string } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 8aec917..dcb7ada 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -20,10 +20,13 @@ import ( "context" "fmt" "text/template" + "time" "github.com/google/uuid" + "github.com/rs/zerolog" "go.mau.fi/util/dbutil" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/id" @@ -124,7 +127,19 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { MaxFileSize: 50 * 1024 * 1024, AsyncFiles: true, LocationFormat: s.Config.LocationFormat, - NoUpdateDisappearing: true, + UpdateDisappearing: func(ctx context.Context, newTimer time.Duration) { + portal := ctx.Value(msgconvContextKey).(*msgconvContext).Portal + portal.Metadata.DisappearTimer = newTimer + if newTimer == 0 { + portal.Metadata.DisappearType = "" + } else { + portal.Metadata.DisappearType = database.DisappearingTypeAfterRead + } + err := portal.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") + } + }, } } diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 6af25ab..5d10716 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -23,10 +23,12 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/exfmt" "go.mau.fi/util/exzerolog" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -235,13 +237,20 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po if portal.Metadata.DisappearTimer != disappear.Timer { portal.Metadata.DisappearType = disappear.Type portal.Metadata.DisappearTimer = disappear.Timer - // TODO if the message doesn't have the DataMessage_EXPIRATION_TIMER_UPDATE, - // we should send a message to the portal notifying of the implicit update err := portal.Save(ctx) if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save portal metadata after updating disappearing timer") + zerolog.Ctx(ctx).Err(err).Msg("Failed to save portal metadata after implicitly updating disappearing timer") } else { - zerolog.Ctx(ctx).Debug().Dur("new_timer", portal.Metadata.DisappearTimer).Msg("Updated disappearing timer in portal") + zerolog.Ctx(ctx).Debug().Dur("new_timer", portal.Metadata.DisappearTimer).Msg("Implicitly updated disappearing timer in portal") + } + _, err = portal.Bridge.Bot.SendMessage(ctx, portal.MXID, event.EventMessage, &event.Content{ + Parsed: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: fmt.Sprintf("Automatically enabled disappearing message timer (%s) because incoming message is disappearing", exfmt.Duration(disappear.Timer)), + }, + }, time.UnixMilli(int64(dataMsg.GetTimestamp()))) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to send notice about disappearing message timer changing implicitly") } } } From 6a92ccc1dd49df2f023c4984fb7dc0054ae6b7d9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Jun 2024 19:00:05 +0300 Subject: [PATCH 224/718] v2: add group change handling --- go.mod | 2 +- go.sum | 4 +- pkg/connector/chatinfo.go | 25 +------ pkg/connector/groupinfo.go | 135 ++++++++++++++++++++++++++++++++++ pkg/connector/handlesignal.go | 59 +++++++++------ 5 files changed, 175 insertions(+), 50 deletions(-) create mode 100644 pkg/connector/groupinfo.go diff --git a/go.mod b/go.mod index 19843dc..7edae3d 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240627083250-e25578d435a2 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240627155110-35f8d837b5f5 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index f73fa34..476c3d9 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240627083250-e25578d435a2 h1:HnP1dmvCVO/V22BdJre56Vu1IaEtMRUt86AD/1rmyME= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240627083250-e25578d435a2/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240627155110-35f8d837b5f5 h1:dJBtUNpc9G0IKq1uRU6kZetBmgMtcmh1F/sMiyDpbDc= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240627155110-35f8d837b5f5/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index f0f06f3..aa5c7c8 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -53,30 +53,7 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) return nil, err } if groupID != "" { - groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, 0) - if err != nil { - return nil, err - } - isDM := false - isSpace := false - members := make([]networkid.UserID, len(groupInfo.Members)) - for i, member := range groupInfo.Members { - members[i] = makeUserID(member.ACI) - } - return &bridgev2.PortalInfo{ - Name: &groupInfo.Title, - Topic: &groupInfo.Description, - Avatar: &bridgev2.Avatar{ - ID: makeAvatarPathID(groupInfo.AvatarPath), - Get: func(ctx context.Context) ([]byte, error) { - return s.Client.DownloadGroupAvatar(ctx, groupInfo) - }, - Remove: groupInfo.AvatarPath == "", - }, - Members: members, - IsDirectChat: &isDM, - IsSpace: &isSpace, - }, nil + return s.getGroupInfo(ctx, groupID, 0) } else { aci, pni := serviceIDToACIAndPNI(userID) contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go new file mode 100644 index 0000000..e436412 --- /dev/null +++ b/pkg/connector/groupinfo.go @@ -0,0 +1,135 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "time" + + "github.com/rs/zerolog" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32) (*bridgev2.PortalInfo, error) { + groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, minRevision) + if err != nil { + return nil, err + } + isDM := false + isSpace := false + members := make([]networkid.UserID, len(groupInfo.Members)) + for i, member := range groupInfo.Members { + members[i] = makeUserID(member.ACI) + } + return &bridgev2.PortalInfo{ + Name: &groupInfo.Title, + Topic: &groupInfo.Description, + Avatar: s.makeGroupAvatar(groupInfo), + Disappear: &database.DisappearingSetting{ + Type: database.DisappearingTypeAfterRead, + Timer: time.Duration(groupInfo.DisappearingMessagesDuration) * time.Second, + }, + Members: members, + IsDirectChat: &isDM, + IsSpace: &isSpace, + ExtraUpdates: makeRevisionUpdater(groupInfo.Revision), + }, nil +} + +func (s *SignalClient) makeGroupAvatar(meta signalmeow.GroupAvatarMeta) *bridgev2.Avatar { + path := meta.GetAvatarPath() + if path == nil { + return nil + } + return &bridgev2.Avatar{ + ID: makeAvatarPathID(*path), + Get: func(ctx context.Context) ([]byte, error) { + return s.Client.DownloadGroupAvatar(ctx, meta) + }, + Remove: *path == "", + } +} + +func makeRevisionUpdater(rev uint32) func(ctx context.Context, portal *bridgev2.Portal) bool { + return func(ctx context.Context, portal *bridgev2.Portal) bool { + currentRev, _ := database.GetNumberFromMap[uint32](portal.Metadata.Extra, "revision") + if currentRev < rev { + portal.Metadata.Extra["revision"] = rev + return true + } + return false + } +} + +func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint32, groupChange *signalmeow.GroupChange) *bridgev2.ChatInfoChange { + ic := &bridgev2.ChatInfoChange{ + PortalInfo: &bridgev2.PortalInfo{ + ExtraUpdates: makeRevisionUpdater(rev), + Name: groupChange.ModifyTitle, + Topic: groupChange.ModifyDescription, + Avatar: s.makeGroupAvatar(groupChange), + }, + } + if groupChange.ModifyDisappearingMessagesDuration != nil { + ic.PortalInfo.Disappear = &database.DisappearingSetting{ + Type: database.DisappearingTypeAfterRead, + Timer: time.Duration(*groupChange.ModifyDisappearingMessagesDuration) * time.Second, + } + } + // TODO handle member/permission/etc changes + return ic +} + +func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal, fromRevision, toRevision uint32, ts uint64) { + if fromRevision >= toRevision { + return + } + log := zerolog.Ctx(ctx).With(). + Str("action", "catch up group changes"). + Uint32("from_revision", fromRevision). + Uint32("to_revision", toRevision). + Logger() + if fromRevision == 0 { + log.Info().Msg("Syncing full group info") + info, err := s.getGroupInfo(ctx, types.GroupIdentifier(portal.ID), toRevision) + if err != nil { + log.Err(err).Msg("Failed to get group info") + } else { + portal.UpdateInfo(ctx, info, s.UserLogin, nil, time.Time{}) + } + } else { + log.Info().Msg("Syncing missed group changes") + groupChanges, err := s.Client.GetGroupHistoryPage(ctx, types.GroupIdentifier(portal.ID), fromRevision, false) + if err != nil { + log.Err(err).Msg("Failed to get group history page") + return + } + for _, gc := range groupChanges { + log.Debug().Uint32("current_rev", gc.GroupChange.Revision).Msg("Processing group change") + chatInfoChange := s.groupChangeToChatInfoChange(ctx, gc.GroupChange.Revision, gc.GroupChange) + portal.ProcessChatInfoChange(ctx, s.makeEventSender(gc.GroupChange.SourceACI), s.UserLogin, chatInfoChange, time.UnixMilli(int64(ts))) + if gc.GroupChange.Revision == toRevision { + break + } + } + } +} diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 5d10716..768b69c 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -23,12 +23,10 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "go.mau.fi/util/exfmt" "go.mau.fi/util/exzerolog" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" - "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -64,6 +62,8 @@ var ( _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) _ bridgev2.RemoteTyping = (*Bv2ChatEvent)(nil) + _ bridgev2.RemotePreHandler = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteChatInfoChange = (*Bv2ChatEvent)(nil) ) func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { @@ -82,6 +82,8 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { return bridgev2.RemoteEventReaction case innerEvt.Delete != nil: return bridgev2.RemoteEventMessageRemove + case innerEvt.GetGroupV2().GetGroupChange() != nil: + return bridgev2.RemoteEventChatInfoChange } case *signalpb.EditMessage: return bridgev2.RemoteEventEdit @@ -91,6 +93,34 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { return bridgev2.RemoteEventUnknown } +func (evt *Bv2ChatEvent) GetChatInfoChange(ctx context.Context) (*bridgev2.ChatInfoChange, error) { + dm, _ := evt.Event.(*signalpb.DataMessage) + gv2 := dm.GetGroupV2() + if gv2 == nil || gv2.GroupChange == nil { + return nil, fmt.Errorf("GetChatInfoChange() called for non-GroupChange event") + } + groupChange, err := evt.s.Client.DecryptGroupChange(ctx, gv2) + if err != nil { + return nil, fmt.Errorf("failed to decrypt group change: %w", err) + } + return evt.s.groupChangeToChatInfoChange(ctx, gv2.GetRevision(), groupChange), nil +} + +func (evt *Bv2ChatEvent) PreHandle(ctx context.Context, portal *bridgev2.Portal) { + dataMsg, ok := evt.Event.(*signalpb.DataMessage) + if !ok || dataMsg.GroupV2 == nil { + return + } + portalRev, _ := database.GetNumberFromMap[uint32](portal.Metadata.Extra, "revision") + if evt.Info.GroupRevision > portalRev { + toRevision := evt.Info.GroupRevision + if dataMsg.GetGroupV2().GetGroupChange() != nil { + toRevision-- + } + evt.s.catchUpGroup(ctx, portal, portalRev, toRevision, dataMsg.GetTimestamp()) + } +} + func (evt *Bv2ChatEvent) GetTimeout() time.Duration { if evt.Event.(*signalpb.TypingMessage).GetAction() == signalpb.TypingMessage_STARTED { return 15 * time.Second @@ -104,7 +134,7 @@ func (evt *Bv2ChatEvent) GetPortalKey() networkid.PortalKey { } func (evt *Bv2ChatEvent) ShouldCreatePortal() bool { - return evt.GetType() == bridgev2.RemoteEventMessage + return evt.GetType() == bridgev2.RemoteEventMessage || evt.GetType() == bridgev2.RemoteEventChatInfoChange } func (evt *Bv2ChatEvent) AddLogContext(c zerolog.Context) zerolog.Context { @@ -231,28 +261,11 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po Type: database.DisappearingTypeAfterRead, Timer: time.Duration(converted.DisappearIn) * time.Second, } + dataMsgTS := time.UnixMilli(int64(dataMsg.GetTimestamp())) if evt.Info.Sender == evt.s.Client.Store.ACI { - disappear.DisappearAt = time.UnixMilli(int64(dataMsg.GetTimestamp())).Add(disappear.Timer) - } - if portal.Metadata.DisappearTimer != disappear.Timer { - portal.Metadata.DisappearType = disappear.Type - portal.Metadata.DisappearTimer = disappear.Timer - err := portal.Save(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save portal metadata after implicitly updating disappearing timer") - } else { - zerolog.Ctx(ctx).Debug().Dur("new_timer", portal.Metadata.DisappearTimer).Msg("Implicitly updated disappearing timer in portal") - } - _, err = portal.Bridge.Bot.SendMessage(ctx, portal.MXID, event.EventMessage, &event.Content{ - Parsed: &event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: fmt.Sprintf("Automatically enabled disappearing message timer (%s) because incoming message is disappearing", exfmt.Duration(disappear.Timer)), - }, - }, time.UnixMilli(int64(dataMsg.GetTimestamp()))) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to send notice about disappearing message timer changing implicitly") - } + disappear.DisappearAt = dataMsgTS.Add(disappear.Timer) } + portal.UpdateDisappearingSetting(ctx, disappear, nil, dataMsgTS, true, true) } return &bridgev2.ConvertedMessage{ ReplyTo: replyTo, From 9121a0c29f50755bda14b13d4c5489243562454c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Jun 2024 19:08:19 +0300 Subject: [PATCH 225/718] v2/legacymigrate: copy revision in portals --- cmd/mautrix-signal-v2/legacymigrate.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index ba91f9c..8aac4db 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -29,8 +29,8 @@ SELECT false, -- in_space CAST( CASE WHEN expiration_time = 0 - THEN '{}' - ELSE '{"disappear_type": "after_read", "disappear_timer": "' || (expiration_time * 1000000000) || '"}' + THEN '{"revision":"' || revision || '"}' + ELSE '{"disappear_type": "after_read", "disappear_timer": "' || (expiration_time * 1000000000) || '","revision":"' || revision || '"}' END -- only: postgres AS jsonb From 7b538502f157c619141f7029b51db63a2587cf61 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Jun 2024 18:50:37 +0300 Subject: [PATCH 226/718] v2: bridge all member states and permissions --- go.mod | 2 +- go.sum | 4 +- pkg/connector/chatinfo.go | 20 +++- pkg/connector/groupinfo.go | 220 +++++++++++++++++++++++++++++++++++-- 4 files changed, 231 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 7edae3d..b4f8e16 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240627155110-35f8d837b5f5 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240628154312-d7251a4c6950 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 476c3d9..8ae9f4b 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240627155110-35f8d837b5f5 h1:dJBtUNpc9G0IKq1uRU6kZetBmgMtcmh1F/sMiyDpbDc= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240627155110-35f8d837b5f5/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240628154312-d7251a4c6950 h1:A43PQ5ltou4KhcCMxZz1gb3QXrhOjVKweYDW5YQ/Gok= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240628154312-d7251a4c6950/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index aa5c7c8..79b253d 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -27,6 +27,7 @@ import ( "github.com/rs/zerolog" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" @@ -195,7 +196,16 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev isSpace := false name := "" topic := PrivateChatTopic - members := []networkid.UserID{makeUserID(s.Client.Store.ACI)} + members := &bridgev2.ChatMemberList{ + IsFull: true, + Members: []bridgev2.ChatMember{ + { + EventSender: s.makeEventSender(s.Client.Store.ACI), + Membership: event.MembershipJoin, + PowerLevel: moderatorPL, + }, + }, + } if s.Main.Config.NumberInTopic && recipient.E164 != "" { topic = fmt.Sprintf("%s with %s", PrivateChatTopic, recipient.E164) } @@ -215,13 +225,17 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev } } else { // The other user is only present if their ACI is known - members = append(members, makeUserID(recipient.ACI)) + members.Members = append(members.Members, bridgev2.ChatMember{ + EventSender: s.makeEventSender(recipient.ACI), + Membership: event.MembershipJoin, + PowerLevel: moderatorPL, + }) } serviceID = libsignalgo.NewACIServiceID(recipient.ACI) } return &bridgev2.CreateChatResponse{ PortalID: s.makeDMPortalKey(serviceID), - PortalInfo: &bridgev2.PortalInfo{ + PortalInfo: &bridgev2.ChatInfo{ Name: &name, Avatar: avatar, Topic: &topic, diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index e436412..65cbab2 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -23,24 +23,128 @@ import ( "github.com/rs/zerolog" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" - "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32) (*bridgev2.PortalInfo, error) { +var defaultPL = 0 +var moderatorPL = 50 + +func roleToPL(role signalmeow.GroupMemberRole) int { + switch role { + case signalmeow.GroupMember_ADMINISTRATOR: + return moderatorPL + case signalmeow.GroupMember_DEFAULT: + fallthrough + default: + return defaultPL + } +} + +func applyAnnouncementsOnly(plc *bridgev2.PowerLevelChanges, announcementsOnly bool) { + if announcementsOnly { + plc.EventsDefault = &moderatorPL + } else { + plc.EventsDefault = &defaultPL + } +} + +func applyAttributesAccess(plc *bridgev2.PowerLevelChanges, attributeAccess signalmeow.AccessControl) { + attributePL := defaultPL + if attributeAccess == signalmeow.AccessControl_ADMINISTRATOR { + attributePL = moderatorPL + } + plc.Events[event.StateRoomName] = attributePL + plc.Events[event.StateRoomAvatar] = attributePL + plc.Events[event.StateTopic] = attributePL +} + +func applyMembersAccess(plc *bridgev2.PowerLevelChanges, memberAccess signalmeow.AccessControl) { + if memberAccess == signalmeow.AccessControl_ADMINISTRATOR { + plc.Invite = &moderatorPL + } else { + plc.Invite = &defaultPL + } +} + +func inviteLinkToJoinRule(inviteLinkAccess signalmeow.AccessControl) event.JoinRule { + switch inviteLinkAccess { + case signalmeow.AccessControl_UNSATISFIABLE: + return event.JoinRuleInvite + case signalmeow.AccessControl_ADMINISTRATOR: + return event.JoinRuleKnock + case signalmeow.AccessControl_ANY: + // TODO allow public portals? + publicPortals := false + if publicPortals { + return event.JoinRulePublic + } else { + return event.JoinRuleKnock + } + default: + return event.JoinRuleInvite + } +} + +func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32) (*bridgev2.ChatInfo, error) { groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, minRevision) if err != nil { return nil, err } isDM := false isSpace := false - members := make([]networkid.UserID, len(groupInfo.Members)) - for i, member := range groupInfo.Members { - members[i] = makeUserID(member.ACI) + members := &bridgev2.ChatMemberList{ + IsFull: true, + Members: make([]bridgev2.ChatMember, len(groupInfo.Members), len(groupInfo.Members)+len(groupInfo.PendingMembers)+len(groupInfo.RequestingMembers)+len(groupInfo.BannedMembers)), + PowerLevels: &bridgev2.PowerLevelChanges{ + Events: map[event.Type]int{ + event.StatePowerLevels: moderatorPL, + }, + }, } - return &bridgev2.PortalInfo{ + applyAnnouncementsOnly(members.PowerLevels, groupInfo.AnnouncementsOnly) + joinRule := event.JoinRuleInvite + if groupInfo.AccessControl != nil { + applyAttributesAccess(members.PowerLevels, groupInfo.AccessControl.Attributes) + applyMembersAccess(members.PowerLevels, groupInfo.AccessControl.Members) + joinRule = inviteLinkToJoinRule(groupInfo.AccessControl.AddFromInviteLink) + } + for i, member := range groupInfo.Members { + members.Members[i] = bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipJoin, + } + } + for _, member := range groupInfo.PendingMembers { + if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + continue + } + members.Members = append(members.Members, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ServiceID.UUID), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipInvite, + }) + } + for _, member := range groupInfo.RequestingMembers { + members.Members = append(members.Members, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipKnock, + }) + } + for _, member := range groupInfo.BannedMembers { + if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + continue + } + members.Members = append(members.Members, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ServiceID.UUID), + Membership: event.MembershipBan, + }) + } + return &bridgev2.ChatInfo{ Name: &groupInfo.Title, Topic: &groupInfo.Description, Avatar: s.makeGroupAvatar(groupInfo), @@ -51,6 +155,7 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden Members: members, IsDirectChat: &isDM, IsSpace: &isSpace, + JoinRule: &event.JoinRulesEventContent{JoinRule: joinRule}, ExtraUpdates: makeRevisionUpdater(groupInfo.Revision), }, nil } @@ -82,7 +187,7 @@ func makeRevisionUpdater(rev uint32) func(ctx context.Context, portal *bridgev2. func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint32, groupChange *signalmeow.GroupChange) *bridgev2.ChatInfoChange { ic := &bridgev2.ChatInfoChange{ - PortalInfo: &bridgev2.PortalInfo{ + ChatInfo: &bridgev2.ChatInfo{ ExtraUpdates: makeRevisionUpdater(rev), Name: groupChange.ModifyTitle, Topic: groupChange.ModifyDescription, @@ -90,12 +195,109 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint }, } if groupChange.ModifyDisappearingMessagesDuration != nil { - ic.PortalInfo.Disappear = &database.DisappearingSetting{ + ic.ChatInfo.Disappear = &database.DisappearingSetting{ Type: database.DisappearingTypeAfterRead, Timer: time.Duration(*groupChange.ModifyDisappearingMessagesDuration) * time.Second, } } - // TODO handle member/permission/etc changes + + var pls *bridgev2.PowerLevelChanges + if groupChange.ModifyAnnouncementsOnly != nil || + groupChange.ModifyAttributesAccess != nil || + groupChange.ModifyMemberAccess != nil { + pls = &bridgev2.PowerLevelChanges{Events: make(map[event.Type]int)} + if groupChange.ModifyAnnouncementsOnly != nil { + applyAnnouncementsOnly(pls, *groupChange.ModifyAnnouncementsOnly) + } + if groupChange.ModifyAttributesAccess != nil { + applyAttributesAccess(pls, *groupChange.ModifyAttributesAccess) + } + if groupChange.ModifyMemberAccess != nil { + applyMembersAccess(pls, *groupChange.ModifyMemberAccess) + } + } + if groupChange.ModifyAddFromInviteLinkAccess != nil { + ic.ChatInfo.JoinRule = &event.JoinRulesEventContent{ + JoinRule: inviteLinkToJoinRule(*groupChange.ModifyAddFromInviteLinkAccess), + } + } + var mc []bridgev2.ChatMember + for _, member := range groupChange.AddMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipJoin, + }) + } + for _, member := range groupChange.ModifyMemberRoles { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipJoin, + }) + } + for _, memberACI := range groupChange.DeleteMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(*memberACI), + Membership: event.MembershipLeave, + PrevMembership: event.MembershipJoin, + }) + } + for _, member := range groupChange.AddPendingMembers { + if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + continue + } + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ServiceID.UUID), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipInvite, + }) + } + for _, memberServiceID := range groupChange.DeletePendingMembers { + if memberServiceID.Type != libsignalgo.ServiceIDTypeACI { + continue + } + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(memberServiceID.UUID), + Membership: event.MembershipLeave, + PrevMembership: event.MembershipInvite, + }) + } + for _, member := range groupChange.AddRequestingMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipKnock, + }) + } + for _, memberACI := range groupChange.DeleteRequestingMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(*memberACI), + Membership: event.MembershipLeave, + PrevMembership: event.MembershipKnock, + }) + } + for _, member := range groupChange.AddBannedMembers { + if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + continue + } + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ServiceID.UUID), + Membership: event.MembershipBan, + }) + } + for _, memberServiceID := range groupChange.DeleteBannedMembers { + if memberServiceID.Type != libsignalgo.ServiceIDTypeACI { + continue + } + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(memberServiceID.UUID), + Membership: event.MembershipLeave, + PrevMembership: event.MembershipBan, + }) + } + if len(mc) > 0 || pls != nil { + ic.MemberChanges = &bridgev2.ChatMemberList{Members: mc, PowerLevels: pls} + } return ic } From 7196535e29a20a116144a2673ca15142ccdf0576 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Jun 2024 19:34:18 +0300 Subject: [PATCH 227/718] v2: add call start/end notices --- pkg/connector/chatinfo.go | 2 +- pkg/connector/handlematrix.go | 4 ++-- pkg/connector/handlesignal.go | 40 +++++++++++++++++++++++++++++++++++ pkg/connector/id.go | 2 +- pkg/connector/msgconvproxy.go | 2 +- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 79b253d..30dc546 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -49,7 +49,7 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( } func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { - userID, groupID, err := s.parsePortalID(portal.ID) + userID, groupID, err := parsePortalID(portal.ID) if err != nil { return nil, err } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 052428f..a3203cc 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -36,7 +36,7 @@ import ( ) func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { - userID, groupID, err := s.parsePortalID(portalID) + userID, groupID, err := parsePortalID(portalID) if err != nil { return err } @@ -277,7 +277,7 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri } func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2.MatrixTyping) error { - userID, _, err := s.parsePortalID(typing.Portal.ID) + userID, _, err := parsePortalID(typing.Portal.ID) if err != nil { return err } diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 768b69c..f4e4cb0 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -27,6 +27,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -42,6 +43,7 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { case *events.ReadSelf: s.handleSignalReadSelf(evt) case *events.Call: + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapCallEvent(evt)) case *events.ContactList: s.handleSignalContactList(evt) case *events.ACIFound: @@ -49,6 +51,44 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { } } +func (s *SignalClient) wrapCallEvent(evt *events.Call) bridgev2.RemoteMessage { + return &bridgev2.SimpleRemoteEvent[*events.Call]{ + Type: bridgev2.RemoteEventMessage, + LogContext: func(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Info.Sender) + c = c.Uint64("message_ts", evt.Timestamp) + return c + }, + PortalKey: s.makePortalKey(evt.Info.ChatID), + Data: evt, + CreatePortal: true, + ID: makeMessageID(evt.Info.Sender, evt.Timestamp), + Sender: s.makeEventSender(evt.Info.Sender), + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + ConvertMessageFunc: convertCallEvent, + } +} + +func convertCallEvent(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data *events.Call) (*bridgev2.ConvertedMessage, error) { + content := &event.MessageEventContent{ + MsgType: event.MsgNotice, + } + if data.IsRinging { + content.Body = "Incoming call" + if userID, _, _ := parsePortalID(portal.ID); !userID.IsEmpty() { + content.MsgType = event.MsgText + } + } else { + content.Body = "Call ended" + } + return &bridgev2.ConvertedMessage{ + Parts: []*bridgev2.ConvertedMessagePart{{ + Type: event.EventMessage, + Content: content, + }}, + }, nil +} + type Bv2ChatEvent struct { *events.ChatEvent s *SignalClient diff --git a/pkg/connector/id.go b/pkg/connector/id.go index 147b21f..6aa4f82 100644 --- a/pkg/connector/id.go +++ b/pkg/connector/id.go @@ -44,7 +44,7 @@ func parseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, err return libsignalgo.ServiceIDFromString(string(userID)) } -func (s *SignalClient) parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { +func parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { if len(portalID) == 44 { groupID = types.GroupIdentifier(portalID) } else { diff --git a/pkg/connector/msgconvproxy.go b/pkg/connector/msgconvproxy.go index 8ffeb6f..c8d97a4 100644 --- a/pkg/connector/msgconvproxy.go +++ b/pkg/connector/msgconvproxy.go @@ -85,7 +85,7 @@ func (mpm *msgconvPortalMethods) GetClient(ctx context.Context) *signalmeow.Clie func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) portal := mcCtx.Portal - userID, groupID, _ := mcCtx.Client.parsePortalID(portal.ID) + userID, groupID, _ := parsePortalID(portal.ID) chatID := string(groupID) if chatID == "" { chatID = userID.String() From 5883ade9d881015902ec001fce5b0d5178f9f897 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Jun 2024 23:13:52 +0300 Subject: [PATCH 228/718] v2: add support for changing group name/avatar/topic from Matrix --- go.mod | 2 +- go.sum | 4 +- pkg/connector/client.go | 3 ++ pkg/connector/handlematrix.go | 78 ++++++++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b4f8e16..16d31e0 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240628154312-d7251a4c6950 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240628200158-86ac5c340b35 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 8ae9f4b..6a6b6f9 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240628154312-d7251a4c6950 h1:A43PQ5ltou4KhcCMxZz1gb3QXrhOjVKweYDW5YQ/Gok= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240628154312-d7251a4c6950/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240628200158-86ac5c340b35 h1:ghI1MLQc4JS0ov31rpjuHrCwqVP7b+4wZfwXsD/5i0k= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240628200158-86ac5c340b35/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 285e207..0b92901 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -53,6 +53,9 @@ var ( _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) ) var pushCfg = &bridgev2.PushConfig{ diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index a3203cc..41b5ecd 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -18,6 +18,7 @@ package connector import ( "context" + "crypto/sha256" "errors" "fmt" "time" @@ -286,8 +287,81 @@ func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2. if !userID.IsEmpty() && userID.Type == libsignalgo.ServiceIDTypeACI { typingMessage := signalmeow.TypingMessage(typing.IsTyping) result := s.Client.SendMessage(ctx, userID, typingMessage) - fmt.Println(result) - // TODO check result + if !result.WasSuccessful { + return result.Error + } } return nil } + +func (s *SignalClient) handleMatrixRoomMeta(ctx context.Context, portal *bridgev2.Portal, gc *signalmeow.GroupChange, postUpdatePortal func()) (bool, error) { + _, groupID, err := parsePortalID(portal.ID) + if err != nil || groupID == "" { + return false, err + } + rev, ok := database.GetNumberFromMap[uint32](portal.Metadata.Extra, "revision") + if !ok { + return false, fmt.Errorf("missing revision in portal metadata") + } + gc.Revision = rev + 1 + revision, err := s.Client.UpdateGroup(ctx, gc, groupID) + if err != nil { + return false, err + } + if gc.ModifyTitle != nil { + portal.Name = *gc.ModifyTitle + portal.NameSet = true + } + if gc.ModifyDescription != nil { + portal.Topic = *gc.ModifyDescription + portal.TopicSet = true + } + if gc.ModifyAvatar != nil { + portal.AvatarID = makeAvatarPathID(*gc.ModifyAvatar) + portal.AvatarSet = true + } + if postUpdatePortal != nil { + postUpdatePortal() + } + portal.Metadata.Extra["revision"] = revision + return true, nil +} + +func (s *SignalClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2.MatrixRoomName) (bool, error) { + return s.handleMatrixRoomMeta(ctx, msg.Portal, &signalmeow.GroupChange{ + ModifyTitle: &msg.Content.Name, + }, nil) +} + +func (s *SignalClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2.MatrixRoomAvatar) (bool, error) { + _, groupID, err := parsePortalID(msg.Portal.ID) + if err != nil || groupID == "" { + return false, err + } + var avatarPath string + var avatarHash [32]byte + if msg.Content.URL != "" { + data, err := s.Main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, nil) + if err != nil { + return false, fmt.Errorf("failed to download avatar: %w", err) + } + avatarHash = sha256.Sum256(data) + avatarPathPtr, err := s.Client.UploadGroupAvatar(ctx, data, groupID) + if err != nil { + return false, fmt.Errorf("failed to reupload avatar: %w", err) + } + avatarPath = *avatarPathPtr + } + return s.handleMatrixRoomMeta(ctx, msg.Portal, &signalmeow.GroupChange{ + ModifyAvatar: &avatarPath, + }, func() { + msg.Portal.AvatarMXC = msg.Content.URL + msg.Portal.AvatarHash = avatarHash + }) +} + +func (s *SignalClient) HandleMatrixRoomTopic(ctx context.Context, msg *bridgev2.MatrixRoomTopic) (bool, error) { + return s.handleMatrixRoomMeta(ctx, msg.Portal, &signalmeow.GroupChange{ + ModifyDescription: &msg.Content.Topic, + }, nil) +} From 1bc7b100ee1a341b12ef483e52cd9c14292673d3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Jun 2024 23:17:39 +0300 Subject: [PATCH 229/718] pre-commit: add local imports flag --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 064e948..b22a061 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,6 +13,10 @@ repos: hooks: - id: go-imports exclude: "pb\\.go$" + args: + - "-local" + - "go.mau.fi/mautrix-signal" + - "-w" - id: go-vet-mod #- id: go-staticcheck-repo-mod # TODO: reenable this and fix all the problems From 96724bd9dcdb476fc5a6003fd3b6dbe2e2d7db78 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Jun 2024 23:48:52 +0300 Subject: [PATCH 230/718] libsignalgo: update libsignal to v0.52.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 56 ++++++++++++++++----------------- pkg/libsignalgo/version.go | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 95bf4e7..e13e3de 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 95bf4e77155b5110e80a8d140cce7adaef8aa0ac +Subproject commit e13e3de8b25c8204b9bb5f04cc50dd12e7f40fc3 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index bd99f60..0e5e893 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1228,6 +1228,18 @@ SignalFfiError *signal_device_transfer_generate_certificate(SignalOwnedBuffer *o SignalFfiError *signal_cds2_client_state_new(SignalSgxClientState **out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); +SignalFfiError *signal_hsm_enclave_client_destroy(SignalHsmEnclaveClient *p); + +SignalFfiError *signal_hsm_enclave_client_new(SignalHsmEnclaveClient **out, SignalBorrowedBuffer trusted_public_key, SignalBorrowedBuffer trusted_code_hashes); + +SignalFfiError *signal_hsm_enclave_client_complete_handshake(SignalHsmEnclaveClient *cli, SignalBorrowedBuffer handshake_received); + +SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer plaintext_to_send); + +SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer received_ciphertext); + +SignalFfiError *signal_hsm_enclave_client_initial_request(SignalOwnedBuffer *out, const SignalHsmEnclaveClient *obj); + SignalFfiError *signal_sgx_client_state_destroy(SignalSgxClientState *p); SignalFfiError *signal_sgx_client_state_initial_request(SignalOwnedBuffer *out, const SignalSgxClientState *obj); @@ -1238,18 +1250,6 @@ SignalFfiError *signal_sgx_client_state_established_send(SignalOwnedBuffer *out, SignalFfiError *signal_sgx_client_state_established_recv(SignalOwnedBuffer *out, SignalSgxClientState *cli, SignalBorrowedBuffer received_ciphertext); -SignalFfiError *signal_hsm_enclave_client_destroy(SignalHsmEnclaveClient *p); - -SignalFfiError *signal_hsm_enclave_client_new(SignalHsmEnclaveClient **out, SignalBorrowedBuffer trusted_public_key, SignalBorrowedBuffer trusted_code_hashes); - -SignalFfiError *signal_hsm_enclave_client_initial_request(SignalOwnedBuffer *out, const SignalHsmEnclaveClient *obj); - -SignalFfiError *signal_hsm_enclave_client_complete_handshake(SignalHsmEnclaveClient *cli, SignalBorrowedBuffer handshake_received); - -SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer plaintext_to_send); - -SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer received_ciphertext); - SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); SignalFfiError *signal_expiring_profile_key_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); @@ -1510,14 +1510,14 @@ SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalFfiError *signal_verify_signature(bool *out, SignalBorrowedBuffer cert_pem, SignalBorrowedBuffer body, SignalBorrowedBuffer signature, uint64_t current_timestamp); +SignalFfiError *signal_connection_manager_destroy(SignalConnectionManager *p); + SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment, const char *user_agent); SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManager *connection_manager, const char *host, int32_t port); SignalFfiError *signal_connection_manager_clear_proxy(const SignalConnectionManager *connection_manager); -SignalFfiError *signal_connection_manager_destroy(SignalConnectionManager *p); - SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); @@ -1528,6 +1528,8 @@ SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalFfiError *signal_svr3_remove(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *enclave_password); +SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); + SignalFfiError *signal_lookup_request_new(SignalLookupRequest **out); SignalFfiError *signal_lookup_request_add_e164(const SignalLookupRequest *request, const char *e164); @@ -1540,8 +1542,6 @@ SignalFfiError *signal_lookup_request_add_aci_and_access_key(const SignalLookupR SignalFfiError *signal_lookup_request_set_return_acis_without_uaks(const SignalLookupRequest *request, bool return_acis_without_uaks); -SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); - SignalFfiError *signal_cdsi_lookup_destroy(SignalCdsiLookup *p); SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request); @@ -1610,10 +1610,10 @@ SignalFfiError *signal_pin_verify_local_hash(bool *out, const char *encoded_hash SignalFfiError *signal_svr2_client_new(SignalSgxClientState **out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); -SignalFfiError *signal_incremental_mac_calculate_chunk_size(uint32_t *out, uint32_t data_size); - SignalFfiError *signal_incremental_mac_destroy(SignalIncrementalMac *p); +SignalFfiError *signal_incremental_mac_calculate_chunk_size(uint32_t *out, uint32_t data_size); + SignalFfiError *signal_incremental_mac_initialize(SignalIncrementalMac **out, SignalBorrowedBuffer key, uint32_t chunk_size); SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalIncrementalMac *mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); @@ -1630,10 +1630,10 @@ SignalFfiError *signal_validating_mac_finalize(int32_t *out, SignalValidatingMac SignalFfiError *signal_message_backup_key_destroy(SignalMessageBackupKey *p); -SignalFfiError *signal_message_backup_key_new(SignalMessageBackupKey **out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); - SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMessageBackupValidationOutcome *p); +SignalFfiError *signal_message_backup_key_new(SignalMessageBackupKey **out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); + SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, const SignalMessageBackupValidationOutcome *outcome); SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, const SignalMessageBackupValidationOutcome *outcome); @@ -1654,6 +1654,14 @@ SignalFfiError *signal_username_link_create(SignalOwnedBuffer *out, const char * SignalFfiError *signal_username_link_decrypt_username(const char **out, SignalBorrowedBuffer entropy, SignalBorrowedBuffer encrypted_username); +#if defined(SIGNAL_MEDIA_SUPPORTED) +SignalFfiError *signal_sanitized_metadata_destroy(SignalSanitizedMetadata *p); +#endif + +#if defined(SIGNAL_MEDIA_SUPPORTED) +SignalFfiError *signal_sanitized_metadata_clone(SignalSanitizedMetadata **new_obj, const SignalSanitizedMetadata *obj); +#endif + #if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_signal_media_check_available(void); #endif @@ -1666,14 +1674,6 @@ SignalFfiError *signal_mp4_sanitizer_sanitize(SignalSanitizedMetadata **out, con SignalFfiError *signal_webp_sanitizer_sanitize(const SignalSyncInputStream *input); #endif -#if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_destroy(SignalSanitizedMetadata *p); -#endif - -#if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_clone(SignalSanitizedMetadata **new_obj, const SignalSanitizedMetadata *obj); -#endif - #if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_get_metadata(SignalOwnedBuffer *out, const SignalSanitizedMetadata *sanitized); #endif diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index cf2f348..8191319 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.51.0" +const Version = "v0.52.0" From 21282c3e6772a73e94077f14f8838779fe53bbe4 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Sat, 29 Jun 2024 06:20:02 +0900 Subject: [PATCH 231/718] Fix example location URL template config for OSM (#516) [skip ci] --- example-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example-config.yaml b/example-config.yaml index 71caa9c..93a7955 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -141,7 +141,7 @@ bridge: caption_in_message: false # Format for generating URLs from location messages for sending to Signal # Google Maps: 'https://www.google.com/maps/place/%[1]s,%[2]s' - # OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]' + # OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]s' location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s' # Whether or not created rooms should have federation enabled. # If false, created portal rooms will never be federated. From 97d87b5160b32079b97034466581c253bb6d919c Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 28 Jun 2024 23:20:30 +0200 Subject: [PATCH 232/718] v1/portal: log more errors for addmember (#475) [skip ci] --- portal.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/portal.go b/portal.go index 0369c04..37fabe6 100644 --- a/portal.go +++ b/portal.go @@ -1018,12 +1018,15 @@ func (portal *Portal) applySignalGroupChange(ctx context.Context, source *User, } } } else { - puppet, _ = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.ACI, event.MembershipInvite, "added") + puppet, err = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.ACI, event.MembershipInvite, "added") } - if puppet != nil { - puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") - } else { - log.Warn().Stringer("signal_user_id", addMember.ACI).Msg("Couldn't get puppet for invite") + if err != nil { + log.Err(err).Stringer("signal_user_id", addMember.ACI).Msg("Couldn't get puppet for invite") + return + } + _, err = puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") + if err != nil { + log.Err(err).Stringer("mxid", puppet.MXID).Msg("Failed to join user") } } bannedMembers := make(map[uuid.UUID]bool) From 10eefaf92897d406949fadd9d13d470f2b4a4583 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 28 Jun 2024 23:21:34 +0200 Subject: [PATCH 233/718] v1: sync groups command (#490) [skip cd] --- commands.go | 73 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/commands.go b/commands.go index e3021c0..7600d66 100644 --- a/commands.go +++ b/commands.go @@ -61,7 +61,7 @@ func (br *SignalBridge) RegisterCommands() { cmdSetDeviceName, cmdPM, cmdResolvePhone, - cmdSyncSpace, + cmdSync, cmdDeleteSession, cmdSetRelay, cmdUnsetRelay, @@ -537,18 +537,26 @@ func fnResolvePhone(ce *WrappedCommandEvent) { } } -var cmdSyncSpace = &commands.FullHandler{ - Func: wrapCommand(fnSyncSpace), - Name: "sync-space", +var cmdSync = &commands.FullHandler{ + Func: wrapCommand(fnSync), + Name: "sync", Help: commands.HelpMeta{ Section: HelpSectionMiscellaneous, - Description: "Synchronize your personal filtering space", + Description: "Synchronize Signal bridge data", + Args: "", }, RequiresLogin: true, } -func fnSyncSpace(ce *WrappedCommandEvent) { - if !ce.Bridge.Config.Bridge.PersonalFilteringSpaces { +func fnSync(ce *WrappedCommandEvent) { + args := strings.ToLower(strings.Join(ce.Args, " ")) + space := strings.Contains(args, "space") + groups := strings.Contains(args, "groups") + if !space && !groups { + ce.Reply("**Usage:** `sync `") + return + } + if !ce.Bridge.Config.Bridge.PersonalFilteringSpaces && space { ce.Reply("Personal filtering spaces are not enabled on this instance of the bridge") return } @@ -559,26 +567,49 @@ func fnSyncSpace(ce *WrappedCommandEvent) { ce.Reply("Failed to get private chat IDs from database") return } - count := 0 allPortals := ce.Bridge.GetAllPortalsWithMXID() - for _, portal := range allPortals { - if portal.IsPrivateChat() { - continue + if space { + count := 0 + for _, portal := range allPortals { + if portal.IsPrivateChat() { + continue + } + if ce.Bridge.StateStore.IsInRoom(ctx, portal.MXID, ce.User.MXID) && portal.addToPersonalSpace(ctx, ce.User) { + count++ + } } - if ce.Bridge.StateStore.IsInRoom(ctx, portal.MXID, ce.User.MXID) && portal.addToPersonalSpace(ctx, ce.User) { + for _, key := range dmKeys { + portal := ce.Bridge.GetPortalByChatID(key) + portal.addToPersonalSpace(ctx, ce.User) count++ } + plural := "s" + if count == 1 { + plural = "" + } + ce.Reply("Added %d room%s to space", count, plural) } - for _, key := range dmKeys { - portal := ce.Bridge.GetPortalByChatID(key) - portal.addToPersonalSpace(ctx, ce.User) - count++ + if groups { + count := 0 + for _, portal := range allPortals { + if portal.IsPrivateChat() { + continue + } + if ce.Bridge.StateStore.IsInRoom(ctx, portal.MXID, ce.User.MXID) { + groupInfo := portal.UpdateGroupInfo(ce.Ctx, ce.User, nil, 0, true) + if groupInfo != nil { + members := portal.SyncParticipants(ctx, ce.User, groupInfo) + portal.updatePowerLevelsAndJoinRule(ctx, groupInfo, members) + count++ + } + } + } + plural := "s" + if count == 1 { + plural = "" + } + ce.Reply("Synced %d group%s", count, plural) } - plural := "s" - if count == 1 { - plural = "" - } - ce.Reply("Added %d room%s to space", count, plural) } var cmdLogin = &commands.FullHandler{ From a3e20a8423e3b1c2f81f399e38d09fe7357a3bbe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 29 Jun 2024 12:22:55 +0300 Subject: [PATCH 234/718] v2: copy relay user ID in legacy migration --- cmd/mautrix-signal-v2/legacymigrate.sql | 43 +++++++++++++------------ cmd/mautrix-signal-v2/main.go | 2 +- go.mod | 2 +- go.sum | 4 +-- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index 8aac4db..5e8c5ba 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -1,5 +1,24 @@ +INSERT INTO "user" (bridge_id, mxid, management_room, access_token) +SELECT '', mxid, management_room, NULL +FROM user_old; + +INSERT INTO user_login (bridge_id, user_mxid, id, space_room, metadata) +SELECT + '', + mxid, + cast(uuid AS TEXT), + space_room, + CAST( + '{"phone":"' || phone || '","remote_name":"' || phone || '"}' + -- only: postgres + AS jsonb + -- only: sqlite (line commented) +-- AS text + ) +FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; + INSERT INTO portal ( - bridge_id, id, receiver, mxid, parent_id, parent_receiver, + bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, name, topic, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, topic_set, in_space, metadata ) @@ -13,6 +32,8 @@ SELECT mxid, NULL, -- parent_id '', -- parent_receiver + CASE WHEN portal_old.relay_user_id<>'' THEN '' END, -- relay_bridge_id + CASE WHEN portal_old.relay_user_id<>'' THEN portal_old.relay_user_id END, -- relay_login_id name, topic, CASE @@ -37,7 +58,6 @@ SELECT -- only: sqlite (line commented) -- AS text ) -- metadata - -- TODO migrate relay user id FROM portal_old; INSERT INTO ghost ( @@ -126,25 +146,6 @@ SELECT ) -- metadata FROM reaction_old; -INSERT INTO "user" (bridge_id, mxid, management_room, access_token) -SELECT '', mxid, management_room, NULL -FROM user_old; - -INSERT INTO user_login (bridge_id, user_mxid, id, space_room, metadata) -SELECT - '', - mxid, - cast(uuid AS TEXT), - space_room, - CAST( - '{"phone":"' || phone || '","remote_name":"' || phone || '"}' - -- only: postgres - AS jsonb - -- only: sqlite (line commented) --- AS text - ) -FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; - INSERT INTO user_portal ( bridge_id, user_mxid, login_id, portal_id, portal_receiver, in_space, preferred, last_read ) diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 0e85c38..80d2efc 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 2), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 4), true, ) } diff --git a/go.mod b/go.mod index 16d31e0..535a7da 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240628200158-86ac5c340b35 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240629130130-2b668652aba5 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 6a6b6f9..30198cf 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240628200158-86ac5c340b35 h1:ghI1MLQc4JS0ov31rpjuHrCwqVP7b+4wZfwXsD/5i0k= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240628200158-86ac5c340b35/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240629130130-2b668652aba5 h1:OtQxTxVhivW4U6VC0UhGZINemqePLigA70ot2p+zp6I= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240629130130-2b668652aba5/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From b2c1efc85c9d90a015d0dc15bba05c0325dc9208 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 30 Jun 2024 00:15:37 +0300 Subject: [PATCH 235/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/handlesignal.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 535a7da..0a81303 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240629130130-2b668652aba5 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240629212545-63c49bf8400d nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 30198cf..af4e6a3 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240629130130-2b668652aba5 h1:OtQxTxVhivW4U6VC0UhGZINemqePLigA70ot2p+zp6I= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240629130130-2b668652aba5/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240629212545-63c49bf8400d h1:hKmeOEHr6woCQCDhq8nzT0ekuCRGelx3k5FDo2+DD34= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240629212545-63c49bf8400d/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index f4e4cb0..993d23f 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -431,7 +431,7 @@ func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { Logger() ctx := log.WithContext(context.TODO()) receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { - return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(s.Client.Store.ACI, msgTS)) + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, makeMessageID(s.Client.Store.ACI, msgTS)) }) s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) } @@ -446,7 +446,7 @@ func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { if err != nil { return nil, err } - return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, makeMessageID(aciUUID, msgInfo.GetTimestamp())) + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, makeMessageID(aciUUID, msgInfo.GetTimestamp())) }) s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) } From 85f3c153767cef5449189e9d01cb93437723b399 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 7 Jul 2024 15:33:41 +0300 Subject: [PATCH 236/718] v2: use improved NewLogin function --- go.mod | 6 +++--- go.sum | 12 +++++------ pkg/connector/login.go | 48 ++++++++++++------------------------------ 3 files changed, 23 insertions(+), 43 deletions(-) diff --git a/go.mod b/go.mod index 0a81303..e7cb76e 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240626184357-b3f4d78c25cf + go.mau.fi/util v0.5.1-0.20240702170310-bd1da3c069eb golang.org/x/crypto v0.24.0 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240629212545-63c49bf8400d + maunium.net/go/mautrix v0.19.0-beta.1.0.20240706124659-b4057a26c3ed nhooyr.io/websocket v1.8.11 ) @@ -40,7 +40,7 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.2 // indirect + github.com/yuin/goldmark v1.7.4 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect golang.org/x/sys v0.21.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index af4e6a3..45caa46 100644 --- a/go.sum +++ b/go.sum @@ -65,10 +65,10 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/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.7.2 h1:NjGd7lO7zrUn/A7eKwn5PEOt4ONYGqpxSEeZuduvgxc= -github.com/yuin/goldmark v1.7.2/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240626184357-b3f4d78c25cf h1:ceXQTB6IqjqGBGhzOTEBGbxQu7xDyuT9YR06gxr9Ncw= -go.mau.fi/util v0.5.1-0.20240626184357-b3f4d78c25cf/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.mau.fi/util v0.5.1-0.20240702170310-bd1da3c069eb h1:VZPo2pvfjNj6fkFv5e9FyTYx96BLwwYNA19WYaY+KN8= +go.mau.fi/util v0.5.1-0.20240702170310-bd1da3c069eb/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240629212545-63c49bf8400d h1:hKmeOEHr6woCQCDhq8nzT0ekuCRGelx3k5FDo2+DD34= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240629212545-63c49bf8400d/go.mod h1:eu/C1dTewrW7yiFNiCKGm4zuWJANyt7zPjaY5g3f3r4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240706124659-b4057a26c3ed h1:3F4YHSFaUJ9N0l4zNGeXZvnTBIHC9PDVOWOFiOvNn3Y= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240706124659-b4057a26c3ed/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 24cbcd7..3a58312 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/google/uuid" - "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -157,42 +156,23 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err return nil, ctx.Err() } - ul, err := qr.Main.Bridge.GetExistingUserLoginByID(ctx, newLoginID) - if err != nil { - return nil, fmt.Errorf("failed to get existing login: %w", err) - } - if ul != nil && ul.UserMXID != qr.User.MXID { - ul.Delete(ctx, status.BridgeState{StateEvent: status.StateLoggedOut, Error: "overridden-by-another-user"}, false) - ul = nil - } - if ul == nil { - ul, err = qr.User.NewLogin(ctx, &database.UserLogin{ - ID: newLoginID, - Metadata: database.UserLoginMetadata{ - StandardUserLoginMetadata: database.StandardUserLoginMetadata{ - RemoteName: qr.ProvData.Number, - }, - Extra: map[string]any{ - "phone": qr.ProvData.Number, - }, + ul, err := qr.User.NewLogin(ctx, &database.UserLogin{ + ID: newLoginID, + Metadata: database.UserLoginMetadata{ + StandardUserLoginMetadata: database.StandardUserLoginMetadata{ + RemoteName: qr.ProvData.Number, }, - }, nil) - if err != nil { - return nil, fmt.Errorf("failed to save new login: %w", err) - } - } else { - ul.Metadata.Extra["phone"] = qr.ProvData.Number - ul.Metadata.RemoteName = qr.ProvData.Number - err = ul.Save(ctx) - if err != nil { - return nil, fmt.Errorf("failed to update existing login: %w", err) - } + Extra: map[string]any{ + "phone": qr.ProvData.Number, + }, + }, + }, &bridgev2.NewLoginParams{ + DeleteOnConflict: true, + }) + if err != nil { + return nil, fmt.Errorf("failed to create user login: %w", err) } backgroundCtx := ul.Log.WithContext(context.Background()) - err = qr.Main.LoadUserLogin(backgroundCtx, ul) - if err != nil { - return nil, fmt.Errorf("failed to prepare connection after login: %w", err) - } err = ul.Client.Connect(backgroundCtx) if err != nil { return nil, fmt.Errorf("failed to connect after login: %w", err) From c5c12135c5a87388a3b78fc8583ecc1a708b0c88 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Jul 2024 21:25:42 +0300 Subject: [PATCH 237/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/handlesignal.go | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e7cb76e..8d62958 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240706124659-b4057a26c3ed + maunium.net/go/mautrix v0.19.0-beta.1.0.20240709160900-fc7ed77e2630 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 45caa46..094f2d1 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240706124659-b4057a26c3ed h1:3F4YHSFaUJ9N0l4zNGeXZvnTBIHC9PDVOWOFiOvNn3Y= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240706124659-b4057a26c3ed/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240709160900-fc7ed77e2630 h1:X+IuVExANBr0gfFQ22vpecvDzkiSCVAnFAYvyIZ+uOI= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240709160900-fc7ed77e2630/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 993d23f..0618957 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -386,6 +386,10 @@ func (b *Bv2Receipt) GetReceiptTargets() []networkid.MessageID { return b.IDs } +func (b *Bv2Receipt) GetReadUpTo() time.Time { + return time.Time{} +} + var _ bridgev2.RemoteReceipt = (*Bv2Receipt)(nil) func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt { From fe389bf65a5869f99c2a1b4d22a4012b9f7227be Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Jul 2024 20:36:07 +0300 Subject: [PATCH 238/718] signalmeow: update registration capabilities --- pkg/signalmeow/provisioning.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 88f8485..1aff0cd 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -384,7 +384,7 @@ func confirmDevice( "registrationId": aciRegistrationID, "pniRegistrationId": pniRegistrationID, "capabilities": map[string]any{ - "pni": true, + "deleteSync": true, }, }, "aciSignedPreKey": aciSignedPreKeyJson, From 4fd377707026dd803611c8684a3ee8e1f86998bb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Jul 2024 20:40:07 +0300 Subject: [PATCH 239/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/Groups.pb.go | 661 ++++++++++------ pkg/signalmeow/protobuf/Groups.proto | 13 +- pkg/signalmeow/protobuf/SignalService.pb.go | 822 ++++++++++++-------- pkg/signalmeow/protobuf/SignalService.proto | 18 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 5 files changed, 935 insertions(+), 583 deletions(-) diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 8ec4a97..ae4b64b 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -761,18 +761,74 @@ func (x *GroupChange) GetChangeEpoch() uint32 { return 0 } +type GroupResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` +} + +func (x *GroupResponse) Reset() { + *x = GroupResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_Groups_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupResponse) ProtoMessage() {} + +func (x *GroupResponse) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupResponse.ProtoReflect.Descriptor instead. +func (*GroupResponse) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{8} +} + +func (x *GroupResponse) GetGroup() *Group { + if x != nil { + return x.Group + } + return nil +} + +func (x *GroupResponse) GetGroupSendEndorsementsResponse() []byte { + if x != nil { + return x.GroupSendEndorsementsResponse + } + return nil +} + type GroupChanges struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - GroupChanges []*GroupChanges_GroupChangeState `protobuf:"bytes,1,rep,name=groupChanges,proto3" json:"groupChanges,omitempty"` + GroupChanges []*GroupChanges_GroupChangeState `protobuf:"bytes,1,rep,name=groupChanges,proto3" json:"groupChanges,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` } func (x *GroupChanges) Reset() { *x = GroupChanges{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[8] + mi := &file_Groups_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -785,7 +841,7 @@ func (x *GroupChanges) String() string { func (*GroupChanges) ProtoMessage() {} func (x *GroupChanges) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[8] + mi := &file_Groups_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -798,7 +854,7 @@ func (x *GroupChanges) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChanges.ProtoReflect.Descriptor instead. func (*GroupChanges) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{8} + return file_Groups_proto_rawDescGZIP(), []int{9} } func (x *GroupChanges) GetGroupChanges() []*GroupChanges_GroupChangeState { @@ -808,6 +864,68 @@ func (x *GroupChanges) GetGroupChanges() []*GroupChanges_GroupChangeState { return nil } +func (x *GroupChanges) GetGroupSendEndorsementsResponse() []byte { + if x != nil { + return x.GroupSendEndorsementsResponse + } + return nil +} + +type GroupChangeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` +} + +func (x *GroupChangeResponse) Reset() { + *x = GroupChangeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_Groups_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GroupChangeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChangeResponse) ProtoMessage() {} + +func (x *GroupChangeResponse) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupChangeResponse.ProtoReflect.Descriptor instead. +func (*GroupChangeResponse) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10} +} + +func (x *GroupChangeResponse) GetGroupChange() *GroupChange { + if x != nil { + return x.GroupChange + } + return nil +} + +func (x *GroupChangeResponse) GetGroupSendEndorsementsResponse() []byte { + if x != nil { + return x.GroupSendEndorsementsResponse + } + return nil +} + type GroupAttributeBlob struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -825,7 +943,7 @@ type GroupAttributeBlob struct { func (x *GroupAttributeBlob) Reset() { *x = GroupAttributeBlob{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[9] + mi := &file_Groups_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -838,7 +956,7 @@ func (x *GroupAttributeBlob) String() string { func (*GroupAttributeBlob) ProtoMessage() {} func (x *GroupAttributeBlob) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[9] + mi := &file_Groups_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -851,7 +969,7 @@ func (x *GroupAttributeBlob) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupAttributeBlob.ProtoReflect.Descriptor instead. func (*GroupAttributeBlob) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{9} + return file_Groups_proto_rawDescGZIP(), []int{11} } func (m *GroupAttributeBlob) GetContent() isGroupAttributeBlob_Content { @@ -931,7 +1049,7 @@ type GroupInviteLink struct { func (x *GroupInviteLink) Reset() { *x = GroupInviteLink{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[10] + mi := &file_Groups_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -944,7 +1062,7 @@ func (x *GroupInviteLink) String() string { func (*GroupInviteLink) ProtoMessage() {} func (x *GroupInviteLink) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[10] + mi := &file_Groups_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -957,7 +1075,7 @@ func (x *GroupInviteLink) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLink.ProtoReflect.Descriptor instead. func (*GroupInviteLink) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{10} + return file_Groups_proto_rawDescGZIP(), []int{12} } func (m *GroupInviteLink) GetContents() isGroupInviteLink_Contents { @@ -1002,7 +1120,7 @@ type GroupJoinInfo struct { func (x *GroupJoinInfo) Reset() { *x = GroupJoinInfo{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[11] + mi := &file_Groups_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1015,7 +1133,7 @@ func (x *GroupJoinInfo) String() string { func (*GroupJoinInfo) ProtoMessage() {} func (x *GroupJoinInfo) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[11] + mi := &file_Groups_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1028,7 +1146,7 @@ func (x *GroupJoinInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinInfo.ProtoReflect.Descriptor instead. func (*GroupJoinInfo) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{11} + return file_Groups_proto_rawDescGZIP(), []int{13} } func (x *GroupJoinInfo) GetPublicKey() []byte { @@ -1098,7 +1216,7 @@ type GroupExternalCredential struct { func (x *GroupExternalCredential) Reset() { *x = GroupExternalCredential{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[12] + mi := &file_Groups_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1111,7 +1229,7 @@ func (x *GroupExternalCredential) String() string { func (*GroupExternalCredential) ProtoMessage() {} func (x *GroupExternalCredential) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[12] + mi := &file_Groups_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1124,7 +1242,7 @@ func (x *GroupExternalCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupExternalCredential.ProtoReflect.Descriptor instead. func (*GroupExternalCredential) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{12} + return file_Groups_proto_rawDescGZIP(), []int{14} } func (x *GroupExternalCredential) GetToken() string { @@ -1168,7 +1286,7 @@ type GroupChange_Actions struct { func (x *GroupChange_Actions) Reset() { *x = GroupChange_Actions{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[13] + mi := &file_Groups_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1181,7 +1299,7 @@ func (x *GroupChange_Actions) String() string { func (*GroupChange_Actions) ProtoMessage() {} func (x *GroupChange_Actions) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[13] + mi := &file_Groups_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1377,7 +1495,7 @@ type GroupChange_Actions_AddMemberAction struct { func (x *GroupChange_Actions_AddMemberAction) Reset() { *x = GroupChange_Actions_AddMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[14] + mi := &file_Groups_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1390,7 +1508,7 @@ func (x *GroupChange_Actions_AddMemberAction) String() string { func (*GroupChange_Actions_AddMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[14] + mi := &file_Groups_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1431,7 +1549,7 @@ type GroupChange_Actions_DeleteMemberAction struct { func (x *GroupChange_Actions_DeleteMemberAction) Reset() { *x = GroupChange_Actions_DeleteMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[15] + mi := &file_Groups_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1444,7 +1562,7 @@ func (x *GroupChange_Actions_DeleteMemberAction) String() string { func (*GroupChange_Actions_DeleteMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[15] + mi := &file_Groups_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1479,7 +1597,7 @@ type GroupChange_Actions_ModifyMemberRoleAction struct { func (x *GroupChange_Actions_ModifyMemberRoleAction) Reset() { *x = GroupChange_Actions_ModifyMemberRoleAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[16] + mi := &file_Groups_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1492,7 +1610,7 @@ func (x *GroupChange_Actions_ModifyMemberRoleAction) String() string { func (*GroupChange_Actions_ModifyMemberRoleAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMemberRoleAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[16] + mi := &file_Groups_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1535,7 +1653,7 @@ type GroupChange_Actions_ModifyMemberProfileKeyAction struct { func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) Reset() { *x = GroupChange_Actions_ModifyMemberProfileKeyAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[17] + mi := &file_Groups_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1548,7 +1666,7 @@ func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) String() string { func (*GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[17] + mi := &file_Groups_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1596,7 +1714,7 @@ type GroupChange_Actions_AddPendingMemberAction struct { func (x *GroupChange_Actions_AddPendingMemberAction) Reset() { *x = GroupChange_Actions_AddPendingMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[18] + mi := &file_Groups_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1609,7 +1727,7 @@ func (x *GroupChange_Actions_AddPendingMemberAction) String() string { func (*GroupChange_Actions_AddPendingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddPendingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[18] + mi := &file_Groups_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1643,7 +1761,7 @@ type GroupChange_Actions_DeletePendingMemberAction struct { func (x *GroupChange_Actions_DeletePendingMemberAction) Reset() { *x = GroupChange_Actions_DeletePendingMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[19] + mi := &file_Groups_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1656,7 +1774,7 @@ func (x *GroupChange_Actions_DeletePendingMemberAction) String() string { func (*GroupChange_Actions_DeletePendingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeletePendingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[19] + mi := &file_Groups_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1692,7 +1810,7 @@ type GroupChange_Actions_PromotePendingMemberAction struct { func (x *GroupChange_Actions_PromotePendingMemberAction) Reset() { *x = GroupChange_Actions_PromotePendingMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[20] + mi := &file_Groups_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1705,7 +1823,7 @@ func (x *GroupChange_Actions_PromotePendingMemberAction) String() string { func (*GroupChange_Actions_PromotePendingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_PromotePendingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[20] + mi := &file_Groups_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1756,7 +1874,7 @@ type GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction struct { func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) Reset() { *x = GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[21] + mi := &file_Groups_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1769,7 +1887,7 @@ func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) String( func (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoMessage() {} func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[21] + mi := &file_Groups_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1824,7 +1942,7 @@ type GroupChange_Actions_AddRequestingMemberAction struct { func (x *GroupChange_Actions_AddRequestingMemberAction) Reset() { *x = GroupChange_Actions_AddRequestingMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[22] + mi := &file_Groups_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1837,7 +1955,7 @@ func (x *GroupChange_Actions_AddRequestingMemberAction) String() string { func (*GroupChange_Actions_AddRequestingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddRequestingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[22] + mi := &file_Groups_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1871,7 +1989,7 @@ type GroupChange_Actions_DeleteRequestingMemberAction struct { func (x *GroupChange_Actions_DeleteRequestingMemberAction) Reset() { *x = GroupChange_Actions_DeleteRequestingMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[23] + mi := &file_Groups_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1884,7 +2002,7 @@ func (x *GroupChange_Actions_DeleteRequestingMemberAction) String() string { func (*GroupChange_Actions_DeleteRequestingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteRequestingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[23] + mi := &file_Groups_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1919,7 +2037,7 @@ type GroupChange_Actions_PromoteRequestingMemberAction struct { func (x *GroupChange_Actions_PromoteRequestingMemberAction) Reset() { *x = GroupChange_Actions_PromoteRequestingMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[24] + mi := &file_Groups_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1932,7 +2050,7 @@ func (x *GroupChange_Actions_PromoteRequestingMemberAction) String() string { func (*GroupChange_Actions_PromoteRequestingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_PromoteRequestingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[24] + mi := &file_Groups_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1973,7 +2091,7 @@ type GroupChange_Actions_AddBannedMemberAction struct { func (x *GroupChange_Actions_AddBannedMemberAction) Reset() { *x = GroupChange_Actions_AddBannedMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[25] + mi := &file_Groups_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1986,7 +2104,7 @@ func (x *GroupChange_Actions_AddBannedMemberAction) String() string { func (*GroupChange_Actions_AddBannedMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddBannedMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[25] + mi := &file_Groups_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2020,7 +2138,7 @@ type GroupChange_Actions_DeleteBannedMemberAction struct { func (x *GroupChange_Actions_DeleteBannedMemberAction) Reset() { *x = GroupChange_Actions_DeleteBannedMemberAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[26] + mi := &file_Groups_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2033,7 +2151,7 @@ func (x *GroupChange_Actions_DeleteBannedMemberAction) String() string { func (*GroupChange_Actions_DeleteBannedMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteBannedMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[26] + mi := &file_Groups_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2067,7 +2185,7 @@ type GroupChange_Actions_ModifyTitleAction struct { func (x *GroupChange_Actions_ModifyTitleAction) Reset() { *x = GroupChange_Actions_ModifyTitleAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[27] + mi := &file_Groups_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2080,7 +2198,7 @@ func (x *GroupChange_Actions_ModifyTitleAction) String() string { func (*GroupChange_Actions_ModifyTitleAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyTitleAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[27] + mi := &file_Groups_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2114,7 +2232,7 @@ type GroupChange_Actions_ModifyDescriptionAction struct { func (x *GroupChange_Actions_ModifyDescriptionAction) Reset() { *x = GroupChange_Actions_ModifyDescriptionAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[28] + mi := &file_Groups_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2127,7 +2245,7 @@ func (x *GroupChange_Actions_ModifyDescriptionAction) String() string { func (*GroupChange_Actions_ModifyDescriptionAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyDescriptionAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[28] + mi := &file_Groups_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2161,7 +2279,7 @@ type GroupChange_Actions_ModifyAvatarAction struct { func (x *GroupChange_Actions_ModifyAvatarAction) Reset() { *x = GroupChange_Actions_ModifyAvatarAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[29] + mi := &file_Groups_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2174,7 +2292,7 @@ func (x *GroupChange_Actions_ModifyAvatarAction) String() string { func (*GroupChange_Actions_ModifyAvatarAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAvatarAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[29] + mi := &file_Groups_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2208,7 +2326,7 @@ type GroupChange_Actions_ModifyDisappearingMessagesTimerAction struct { func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) Reset() { *x = GroupChange_Actions_ModifyDisappearingMessagesTimerAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[30] + mi := &file_Groups_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2221,7 +2339,7 @@ func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) String() str func (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[30] + mi := &file_Groups_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2255,7 +2373,7 @@ type GroupChange_Actions_ModifyAttributesAccessControlAction struct { func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyAttributesAccessControlAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[31] + mi := &file_Groups_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2268,7 +2386,7 @@ func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) String() strin func (*GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[31] + mi := &file_Groups_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2302,7 +2420,7 @@ type GroupChange_Actions_ModifyMembersAccessControlAction struct { func (x *GroupChange_Actions_ModifyMembersAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyMembersAccessControlAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[32] + mi := &file_Groups_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2315,7 +2433,7 @@ func (x *GroupChange_Actions_ModifyMembersAccessControlAction) String() string { func (*GroupChange_Actions_ModifyMembersAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMembersAccessControlAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[32] + mi := &file_Groups_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2349,7 +2467,7 @@ type GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction struct { func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[33] + mi := &file_Groups_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2362,7 +2480,7 @@ func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) String( func (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[33] + mi := &file_Groups_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2396,7 +2514,7 @@ type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() { *x = GroupChange_Actions_ModifyInviteLinkPasswordAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[34] + mi := &file_Groups_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2409,7 +2527,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) String() string { func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[34] + mi := &file_Groups_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2443,7 +2561,7 @@ type GroupChange_Actions_ModifyAnnouncementsOnlyAction struct { func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() { *x = GroupChange_Actions_ModifyAnnouncementsOnlyAction{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[35] + mi := &file_Groups_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2456,7 +2574,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) String() string { func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[35] + mi := &file_Groups_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2491,7 +2609,7 @@ type GroupChanges_GroupChangeState struct { func (x *GroupChanges_GroupChangeState) Reset() { *x = GroupChanges_GroupChangeState{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[36] + mi := &file_Groups_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2504,7 +2622,7 @@ func (x *GroupChanges_GroupChangeState) String() string { func (*GroupChanges_GroupChangeState) ProtoMessage() {} func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[36] + mi := &file_Groups_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2517,7 +2635,7 @@ func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChanges_GroupChangeState.ProtoReflect.Descriptor instead. func (*GroupChanges_GroupChangeState) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{8, 0} + return file_Groups_proto_rawDescGZIP(), []int{9, 0} } func (x *GroupChanges_GroupChangeState) GetGroupChange() *GroupChange { @@ -2546,7 +2664,7 @@ type GroupInviteLink_GroupInviteLinkContentsV1 struct { func (x *GroupInviteLink_GroupInviteLinkContentsV1) Reset() { *x = GroupInviteLink_GroupInviteLinkContentsV1{} if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[37] + mi := &file_Groups_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2559,7 +2677,7 @@ func (x *GroupInviteLink_GroupInviteLinkContentsV1) String() string { func (*GroupInviteLink_GroupInviteLinkContentsV1) ProtoMessage() {} func (x *GroupInviteLink_GroupInviteLinkContentsV1) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[37] + mi := &file_Groups_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2572,7 +2690,7 @@ func (x *GroupInviteLink_GroupInviteLinkContentsV1) ProtoReflect() protoreflect. // Deprecated: Use GroupInviteLink_GroupInviteLinkContentsV1.ProtoReflect.Descriptor instead. func (*GroupInviteLink_GroupInviteLinkContentsV1) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{10, 0} + return file_Groups_proto_rawDescGZIP(), []int{12, 0} } func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetGroupMasterKey() []byte { @@ -2964,71 +3082,92 @@ var file_Groups_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, - 0x79, 0x22, 0xbe, 0x01, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x1a, 0x6a, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x0b, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0c, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0a, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x12, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x69, 0x74, - 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x12, 0x18, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x48, 0x00, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x44, 0x0a, 0x1c, 0x64, - 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x48, 0x00, 0x52, 0x1c, 0x64, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, - 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x22, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x22, 0xe0, 0x01, 0x0a, 0x0f, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x4c, 0x0a, 0x0a, 0x76, 0x31, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0a, 0x76, 0x31, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x1a, 0x73, 0x0a, 0x19, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, - 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x56, 0x31, 0x12, - 0x26, 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, - 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, - 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42, 0x0a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x73, 0x22, 0xbc, 0x02, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a, 0x6f, 0x69, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, - 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, - 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x11, 0x61, - 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, - 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x14, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x72, - 0x6f, 0x76, 0x61, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, - 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0x2f, 0x0a, 0x17, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x45, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x42, 0x2b, 0x0a, 0x27, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x50, 0x01, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x79, 0x22, 0x73, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x06, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x12, 0x44, 0x0a, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, + 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, + 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2e, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x1d, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, + 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x1a, 0x6a, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x8b, 0x01, + 0x0a, 0x13, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, + 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x12, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x42, 0x6c, + 0x6f, 0x62, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x61, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x61, 0x76, + 0x61, 0x74, 0x61, 0x72, 0x12, 0x44, 0x0a, 0x1c, 0x64, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, + 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x1c, 0x64, 0x69, + 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x73, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, + 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xe0, 0x01, 0x0a, 0x0f, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x4c, 0x0a, + 0x0a, 0x76, 0x31, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, + 0x69, 0x6e, 0x6b, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, + 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x56, 0x31, 0x48, 0x00, 0x52, + 0x0a, 0x76, 0x31, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x73, 0x0a, 0x19, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x56, 0x31, 0x12, 0x26, 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, + 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x42, 0x0a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xbc, 0x02, 0x0a, + 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, + 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x69, 0x74, + 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, + 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, + 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x11, 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2f, 0x0a, 0x17, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x2b, 0x0a, 0x27, + 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x50, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -3044,48 +3183,50 @@ func file_Groups_proto_rawDescGZIP() []byte { } var file_Groups_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 38) +var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 40) var file_Groups_proto_goTypes = []interface{}{ - (Member_Role)(0), // 0: Member.Role - (AccessControl_AccessRequired)(0), // 1: AccessControl.AccessRequired - (*AvatarUploadAttributes)(nil), // 2: AvatarUploadAttributes - (*Member)(nil), // 3: Member - (*PendingMember)(nil), // 4: PendingMember - (*RequestingMember)(nil), // 5: RequestingMember - (*BannedMember)(nil), // 6: BannedMember - (*AccessControl)(nil), // 7: AccessControl - (*Group)(nil), // 8: Group - (*GroupChange)(nil), // 9: GroupChange - (*GroupChanges)(nil), // 10: GroupChanges - (*GroupAttributeBlob)(nil), // 11: GroupAttributeBlob - (*GroupInviteLink)(nil), // 12: GroupInviteLink - (*GroupJoinInfo)(nil), // 13: GroupJoinInfo - (*GroupExternalCredential)(nil), // 14: GroupExternalCredential - (*GroupChange_Actions)(nil), // 15: GroupChange.Actions - (*GroupChange_Actions_AddMemberAction)(nil), // 16: GroupChange.Actions.AddMemberAction - (*GroupChange_Actions_DeleteMemberAction)(nil), // 17: GroupChange.Actions.DeleteMemberAction - (*GroupChange_Actions_ModifyMemberRoleAction)(nil), // 18: GroupChange.Actions.ModifyMemberRoleAction - (*GroupChange_Actions_ModifyMemberProfileKeyAction)(nil), // 19: GroupChange.Actions.ModifyMemberProfileKeyAction - (*GroupChange_Actions_AddPendingMemberAction)(nil), // 20: GroupChange.Actions.AddPendingMemberAction - (*GroupChange_Actions_DeletePendingMemberAction)(nil), // 21: GroupChange.Actions.DeletePendingMemberAction - (*GroupChange_Actions_PromotePendingMemberAction)(nil), // 22: GroupChange.Actions.PromotePendingMemberAction - (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction)(nil), // 23: GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction - (*GroupChange_Actions_AddRequestingMemberAction)(nil), // 24: GroupChange.Actions.AddRequestingMemberAction - (*GroupChange_Actions_DeleteRequestingMemberAction)(nil), // 25: GroupChange.Actions.DeleteRequestingMemberAction - (*GroupChange_Actions_PromoteRequestingMemberAction)(nil), // 26: GroupChange.Actions.PromoteRequestingMemberAction - (*GroupChange_Actions_AddBannedMemberAction)(nil), // 27: GroupChange.Actions.AddBannedMemberAction - (*GroupChange_Actions_DeleteBannedMemberAction)(nil), // 28: GroupChange.Actions.DeleteBannedMemberAction - (*GroupChange_Actions_ModifyTitleAction)(nil), // 29: GroupChange.Actions.ModifyTitleAction - (*GroupChange_Actions_ModifyDescriptionAction)(nil), // 30: GroupChange.Actions.ModifyDescriptionAction - (*GroupChange_Actions_ModifyAvatarAction)(nil), // 31: GroupChange.Actions.ModifyAvatarAction - (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction)(nil), // 32: GroupChange.Actions.ModifyDisappearingMessagesTimerAction - (*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 33: GroupChange.Actions.ModifyAttributesAccessControlAction - (*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 34: GroupChange.Actions.ModifyMembersAccessControlAction - (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 35: GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 36: GroupChange.Actions.ModifyInviteLinkPasswordAction - (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 37: GroupChange.Actions.ModifyAnnouncementsOnlyAction - (*GroupChanges_GroupChangeState)(nil), // 38: GroupChanges.GroupChangeState - (*GroupInviteLink_GroupInviteLinkContentsV1)(nil), // 39: GroupInviteLink.GroupInviteLinkContentsV1 + (Member_Role)(0), // 0: Member.Role + (AccessControl_AccessRequired)(0), // 1: AccessControl.AccessRequired + (*AvatarUploadAttributes)(nil), // 2: AvatarUploadAttributes + (*Member)(nil), // 3: Member + (*PendingMember)(nil), // 4: PendingMember + (*RequestingMember)(nil), // 5: RequestingMember + (*BannedMember)(nil), // 6: BannedMember + (*AccessControl)(nil), // 7: AccessControl + (*Group)(nil), // 8: Group + (*GroupChange)(nil), // 9: GroupChange + (*GroupResponse)(nil), // 10: GroupResponse + (*GroupChanges)(nil), // 11: GroupChanges + (*GroupChangeResponse)(nil), // 12: GroupChangeResponse + (*GroupAttributeBlob)(nil), // 13: GroupAttributeBlob + (*GroupInviteLink)(nil), // 14: GroupInviteLink + (*GroupJoinInfo)(nil), // 15: GroupJoinInfo + (*GroupExternalCredential)(nil), // 16: GroupExternalCredential + (*GroupChange_Actions)(nil), // 17: GroupChange.Actions + (*GroupChange_Actions_AddMemberAction)(nil), // 18: GroupChange.Actions.AddMemberAction + (*GroupChange_Actions_DeleteMemberAction)(nil), // 19: GroupChange.Actions.DeleteMemberAction + (*GroupChange_Actions_ModifyMemberRoleAction)(nil), // 20: GroupChange.Actions.ModifyMemberRoleAction + (*GroupChange_Actions_ModifyMemberProfileKeyAction)(nil), // 21: GroupChange.Actions.ModifyMemberProfileKeyAction + (*GroupChange_Actions_AddPendingMemberAction)(nil), // 22: GroupChange.Actions.AddPendingMemberAction + (*GroupChange_Actions_DeletePendingMemberAction)(nil), // 23: GroupChange.Actions.DeletePendingMemberAction + (*GroupChange_Actions_PromotePendingMemberAction)(nil), // 24: GroupChange.Actions.PromotePendingMemberAction + (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction)(nil), // 25: GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction + (*GroupChange_Actions_AddRequestingMemberAction)(nil), // 26: GroupChange.Actions.AddRequestingMemberAction + (*GroupChange_Actions_DeleteRequestingMemberAction)(nil), // 27: GroupChange.Actions.DeleteRequestingMemberAction + (*GroupChange_Actions_PromoteRequestingMemberAction)(nil), // 28: GroupChange.Actions.PromoteRequestingMemberAction + (*GroupChange_Actions_AddBannedMemberAction)(nil), // 29: GroupChange.Actions.AddBannedMemberAction + (*GroupChange_Actions_DeleteBannedMemberAction)(nil), // 30: GroupChange.Actions.DeleteBannedMemberAction + (*GroupChange_Actions_ModifyTitleAction)(nil), // 31: GroupChange.Actions.ModifyTitleAction + (*GroupChange_Actions_ModifyDescriptionAction)(nil), // 32: GroupChange.Actions.ModifyDescriptionAction + (*GroupChange_Actions_ModifyAvatarAction)(nil), // 33: GroupChange.Actions.ModifyAvatarAction + (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction)(nil), // 34: GroupChange.Actions.ModifyDisappearingMessagesTimerAction + (*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 35: GroupChange.Actions.ModifyAttributesAccessControlAction + (*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 36: GroupChange.Actions.ModifyMembersAccessControlAction + (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 37: GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction + (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 38: GroupChange.Actions.ModifyInviteLinkPasswordAction + (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 39: GroupChange.Actions.ModifyAnnouncementsOnlyAction + (*GroupChanges_GroupChangeState)(nil), // 40: GroupChanges.GroupChangeState + (*GroupInviteLink_GroupInviteLinkContentsV1)(nil), // 41: GroupInviteLink.GroupInviteLinkContentsV1 } var file_Groups_proto_depIdxs = []int32{ 0, // 0: Member.role:type_name -> Member.Role @@ -3098,47 +3239,49 @@ var file_Groups_proto_depIdxs = []int32{ 4, // 7: Group.pendingMembers:type_name -> PendingMember 5, // 8: Group.requestingMembers:type_name -> RequestingMember 6, // 9: Group.bannedMembers:type_name -> BannedMember - 38, // 10: GroupChanges.groupChanges:type_name -> GroupChanges.GroupChangeState - 39, // 11: GroupInviteLink.v1Contents:type_name -> GroupInviteLink.GroupInviteLinkContentsV1 - 1, // 12: GroupJoinInfo.addFromInviteLink:type_name -> AccessControl.AccessRequired - 16, // 13: GroupChange.Actions.addMembers:type_name -> GroupChange.Actions.AddMemberAction - 17, // 14: GroupChange.Actions.deleteMembers:type_name -> GroupChange.Actions.DeleteMemberAction - 18, // 15: GroupChange.Actions.modifyMemberRoles:type_name -> GroupChange.Actions.ModifyMemberRoleAction - 19, // 16: GroupChange.Actions.modifyMemberProfileKeys:type_name -> GroupChange.Actions.ModifyMemberProfileKeyAction - 20, // 17: GroupChange.Actions.addPendingMembers:type_name -> GroupChange.Actions.AddPendingMemberAction - 21, // 18: GroupChange.Actions.deletePendingMembers:type_name -> GroupChange.Actions.DeletePendingMemberAction - 22, // 19: GroupChange.Actions.promotePendingMembers:type_name -> GroupChange.Actions.PromotePendingMemberAction - 29, // 20: GroupChange.Actions.modifyTitle:type_name -> GroupChange.Actions.ModifyTitleAction - 31, // 21: GroupChange.Actions.modifyAvatar:type_name -> GroupChange.Actions.ModifyAvatarAction - 32, // 22: GroupChange.Actions.modifyDisappearingMessagesTimer:type_name -> GroupChange.Actions.ModifyDisappearingMessagesTimerAction - 33, // 23: GroupChange.Actions.modifyAttributesAccess:type_name -> GroupChange.Actions.ModifyAttributesAccessControlAction - 34, // 24: GroupChange.Actions.modifyMemberAccess:type_name -> GroupChange.Actions.ModifyMembersAccessControlAction - 35, // 25: GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - 24, // 26: GroupChange.Actions.addRequestingMembers:type_name -> GroupChange.Actions.AddRequestingMemberAction - 25, // 27: GroupChange.Actions.deleteRequestingMembers:type_name -> GroupChange.Actions.DeleteRequestingMemberAction - 26, // 28: GroupChange.Actions.promoteRequestingMembers:type_name -> GroupChange.Actions.PromoteRequestingMemberAction - 36, // 29: GroupChange.Actions.modifyInviteLinkPassword:type_name -> GroupChange.Actions.ModifyInviteLinkPasswordAction - 30, // 30: GroupChange.Actions.modifyDescription:type_name -> GroupChange.Actions.ModifyDescriptionAction - 37, // 31: GroupChange.Actions.modifyAnnouncementsOnly:type_name -> GroupChange.Actions.ModifyAnnouncementsOnlyAction - 27, // 32: GroupChange.Actions.addBannedMembers:type_name -> GroupChange.Actions.AddBannedMemberAction - 28, // 33: GroupChange.Actions.deleteBannedMembers:type_name -> GroupChange.Actions.DeleteBannedMemberAction - 23, // 34: GroupChange.Actions.promotePendingPniAciMembers:type_name -> GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction - 3, // 35: GroupChange.Actions.AddMemberAction.added:type_name -> Member - 0, // 36: GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> Member.Role - 4, // 37: GroupChange.Actions.AddPendingMemberAction.added:type_name -> PendingMember - 5, // 38: GroupChange.Actions.AddRequestingMemberAction.added:type_name -> RequestingMember - 0, // 39: GroupChange.Actions.PromoteRequestingMemberAction.role:type_name -> Member.Role - 6, // 40: GroupChange.Actions.AddBannedMemberAction.added:type_name -> BannedMember - 1, // 41: GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> AccessControl.AccessRequired - 1, // 42: GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> AccessControl.AccessRequired - 1, // 43: GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> AccessControl.AccessRequired - 9, // 44: GroupChanges.GroupChangeState.groupChange:type_name -> GroupChange - 8, // 45: GroupChanges.GroupChangeState.groupState:type_name -> Group - 46, // [46:46] is the sub-list for method output_type - 46, // [46:46] is the sub-list for method input_type - 46, // [46:46] is the sub-list for extension type_name - 46, // [46:46] is the sub-list for extension extendee - 0, // [0:46] is the sub-list for field type_name + 8, // 10: GroupResponse.group:type_name -> Group + 40, // 11: GroupChanges.groupChanges:type_name -> GroupChanges.GroupChangeState + 9, // 12: GroupChangeResponse.groupChange:type_name -> GroupChange + 41, // 13: GroupInviteLink.v1Contents:type_name -> GroupInviteLink.GroupInviteLinkContentsV1 + 1, // 14: GroupJoinInfo.addFromInviteLink:type_name -> AccessControl.AccessRequired + 18, // 15: GroupChange.Actions.addMembers:type_name -> GroupChange.Actions.AddMemberAction + 19, // 16: GroupChange.Actions.deleteMembers:type_name -> GroupChange.Actions.DeleteMemberAction + 20, // 17: GroupChange.Actions.modifyMemberRoles:type_name -> GroupChange.Actions.ModifyMemberRoleAction + 21, // 18: GroupChange.Actions.modifyMemberProfileKeys:type_name -> GroupChange.Actions.ModifyMemberProfileKeyAction + 22, // 19: GroupChange.Actions.addPendingMembers:type_name -> GroupChange.Actions.AddPendingMemberAction + 23, // 20: GroupChange.Actions.deletePendingMembers:type_name -> GroupChange.Actions.DeletePendingMemberAction + 24, // 21: GroupChange.Actions.promotePendingMembers:type_name -> GroupChange.Actions.PromotePendingMemberAction + 31, // 22: GroupChange.Actions.modifyTitle:type_name -> GroupChange.Actions.ModifyTitleAction + 33, // 23: GroupChange.Actions.modifyAvatar:type_name -> GroupChange.Actions.ModifyAvatarAction + 34, // 24: GroupChange.Actions.modifyDisappearingMessagesTimer:type_name -> GroupChange.Actions.ModifyDisappearingMessagesTimerAction + 35, // 25: GroupChange.Actions.modifyAttributesAccess:type_name -> GroupChange.Actions.ModifyAttributesAccessControlAction + 36, // 26: GroupChange.Actions.modifyMemberAccess:type_name -> GroupChange.Actions.ModifyMembersAccessControlAction + 37, // 27: GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction + 26, // 28: GroupChange.Actions.addRequestingMembers:type_name -> GroupChange.Actions.AddRequestingMemberAction + 27, // 29: GroupChange.Actions.deleteRequestingMembers:type_name -> GroupChange.Actions.DeleteRequestingMemberAction + 28, // 30: GroupChange.Actions.promoteRequestingMembers:type_name -> GroupChange.Actions.PromoteRequestingMemberAction + 38, // 31: GroupChange.Actions.modifyInviteLinkPassword:type_name -> GroupChange.Actions.ModifyInviteLinkPasswordAction + 32, // 32: GroupChange.Actions.modifyDescription:type_name -> GroupChange.Actions.ModifyDescriptionAction + 39, // 33: GroupChange.Actions.modifyAnnouncementsOnly:type_name -> GroupChange.Actions.ModifyAnnouncementsOnlyAction + 29, // 34: GroupChange.Actions.addBannedMembers:type_name -> GroupChange.Actions.AddBannedMemberAction + 30, // 35: GroupChange.Actions.deleteBannedMembers:type_name -> GroupChange.Actions.DeleteBannedMemberAction + 25, // 36: GroupChange.Actions.promotePendingPniAciMembers:type_name -> GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction + 3, // 37: GroupChange.Actions.AddMemberAction.added:type_name -> Member + 0, // 38: GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> Member.Role + 4, // 39: GroupChange.Actions.AddPendingMemberAction.added:type_name -> PendingMember + 5, // 40: GroupChange.Actions.AddRequestingMemberAction.added:type_name -> RequestingMember + 0, // 41: GroupChange.Actions.PromoteRequestingMemberAction.role:type_name -> Member.Role + 6, // 42: GroupChange.Actions.AddBannedMemberAction.added:type_name -> BannedMember + 1, // 43: GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> AccessControl.AccessRequired + 1, // 44: GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> AccessControl.AccessRequired + 1, // 45: GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> AccessControl.AccessRequired + 9, // 46: GroupChanges.GroupChangeState.groupChange:type_name -> GroupChange + 8, // 47: GroupChanges.GroupChangeState.groupState:type_name -> Group + 48, // [48:48] is the sub-list for method output_type + 48, // [48:48] is the sub-list for method input_type + 48, // [48:48] is the sub-list for extension type_name + 48, // [48:48] is the sub-list for extension extendee + 0, // [0:48] is the sub-list for field type_name } func init() { file_Groups_proto_init() } @@ -3244,7 +3387,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChanges); i { + switch v := v.(*GroupResponse); i { case 0: return &v.state case 1: @@ -3256,7 +3399,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupAttributeBlob); i { + switch v := v.(*GroupChanges); i { case 0: return &v.state case 1: @@ -3268,7 +3411,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupInviteLink); i { + switch v := v.(*GroupChangeResponse); i { case 0: return &v.state case 1: @@ -3280,7 +3423,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupJoinInfo); i { + switch v := v.(*GroupAttributeBlob); i { case 0: return &v.state case 1: @@ -3292,7 +3435,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupExternalCredential); i { + switch v := v.(*GroupInviteLink); i { case 0: return &v.state case 1: @@ -3304,7 +3447,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions); i { + switch v := v.(*GroupJoinInfo); i { case 0: return &v.state case 1: @@ -3316,7 +3459,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_AddMemberAction); i { + switch v := v.(*GroupExternalCredential); i { case 0: return &v.state case 1: @@ -3328,7 +3471,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_DeleteMemberAction); i { + switch v := v.(*GroupChange_Actions); i { case 0: return &v.state case 1: @@ -3340,7 +3483,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyMemberRoleAction); i { + switch v := v.(*GroupChange_Actions_AddMemberAction); i { case 0: return &v.state case 1: @@ -3352,7 +3495,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyMemberProfileKeyAction); i { + switch v := v.(*GroupChange_Actions_DeleteMemberAction); i { case 0: return &v.state case 1: @@ -3364,7 +3507,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_AddPendingMemberAction); i { + switch v := v.(*GroupChange_Actions_ModifyMemberRoleAction); i { case 0: return &v.state case 1: @@ -3376,7 +3519,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_DeletePendingMemberAction); i { + switch v := v.(*GroupChange_Actions_ModifyMemberProfileKeyAction); i { case 0: return &v.state case 1: @@ -3388,7 +3531,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_PromotePendingMemberAction); i { + switch v := v.(*GroupChange_Actions_AddPendingMemberAction); i { case 0: return &v.state case 1: @@ -3400,7 +3543,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction); i { + switch v := v.(*GroupChange_Actions_DeletePendingMemberAction); i { case 0: return &v.state case 1: @@ -3412,7 +3555,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_AddRequestingMemberAction); i { + switch v := v.(*GroupChange_Actions_PromotePendingMemberAction); i { case 0: return &v.state case 1: @@ -3424,7 +3567,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_DeleteRequestingMemberAction); i { + switch v := v.(*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction); i { case 0: return &v.state case 1: @@ -3436,7 +3579,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_PromoteRequestingMemberAction); i { + switch v := v.(*GroupChange_Actions_AddRequestingMemberAction); i { case 0: return &v.state case 1: @@ -3448,7 +3591,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_AddBannedMemberAction); i { + switch v := v.(*GroupChange_Actions_DeleteRequestingMemberAction); i { case 0: return &v.state case 1: @@ -3460,7 +3603,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_DeleteBannedMemberAction); i { + switch v := v.(*GroupChange_Actions_PromoteRequestingMemberAction); i { case 0: return &v.state case 1: @@ -3472,7 +3615,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyTitleAction); i { + switch v := v.(*GroupChange_Actions_AddBannedMemberAction); i { case 0: return &v.state case 1: @@ -3484,7 +3627,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyDescriptionAction); i { + switch v := v.(*GroupChange_Actions_DeleteBannedMemberAction); i { case 0: return &v.state case 1: @@ -3496,7 +3639,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyAvatarAction); i { + switch v := v.(*GroupChange_Actions_ModifyTitleAction); i { case 0: return &v.state case 1: @@ -3508,7 +3651,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyDisappearingMessagesTimerAction); i { + switch v := v.(*GroupChange_Actions_ModifyDescriptionAction); i { case 0: return &v.state case 1: @@ -3520,7 +3663,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyAttributesAccessControlAction); i { + switch v := v.(*GroupChange_Actions_ModifyAvatarAction); i { case 0: return &v.state case 1: @@ -3532,7 +3675,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyMembersAccessControlAction); i { + switch v := v.(*GroupChange_Actions_ModifyDisappearingMessagesTimerAction); i { case 0: return &v.state case 1: @@ -3544,7 +3687,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction); i { + switch v := v.(*GroupChange_Actions_ModifyAttributesAccessControlAction); i { case 0: return &v.state case 1: @@ -3556,7 +3699,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyInviteLinkPasswordAction); i { + switch v := v.(*GroupChange_Actions_ModifyMembersAccessControlAction); i { case 0: return &v.state case 1: @@ -3568,7 +3711,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChange_Actions_ModifyAnnouncementsOnlyAction); i { + switch v := v.(*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction); i { case 0: return &v.state case 1: @@ -3580,7 +3723,7 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupChanges_GroupChangeState); i { + switch v := v.(*GroupChange_Actions_ModifyInviteLinkPasswordAction); i { case 0: return &v.state case 1: @@ -3592,6 +3735,30 @@ func file_Groups_proto_init() { } } file_Groups_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupChange_Actions_ModifyAnnouncementsOnlyAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_Groups_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupChanges_GroupChangeState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_Groups_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GroupInviteLink_GroupInviteLinkContentsV1); i { case 0: return &v.state @@ -3604,13 +3771,13 @@ func file_Groups_proto_init() { } } } - file_Groups_proto_msgTypes[9].OneofWrappers = []interface{}{ + file_Groups_proto_msgTypes[11].OneofWrappers = []interface{}{ (*GroupAttributeBlob_Title)(nil), (*GroupAttributeBlob_Avatar)(nil), (*GroupAttributeBlob_DisappearingMessagesDuration)(nil), (*GroupAttributeBlob_Description)(nil), } - file_Groups_proto_msgTypes[10].OneofWrappers = []interface{}{ + file_Groups_proto_msgTypes[12].OneofWrappers = []interface{}{ (*GroupInviteLink_V1Contents)(nil), } type x struct{} @@ -3619,7 +3786,7 @@ func file_Groups_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_Groups_proto_rawDesc, NumEnums: 2, - NumMessages: 38, + NumMessages: 40, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/Groups.proto b/pkg/signalmeow/protobuf/Groups.proto index 3f0b730..63970c7 100644 --- a/pkg/signalmeow/protobuf/Groups.proto +++ b/pkg/signalmeow/protobuf/Groups.proto @@ -213,13 +213,24 @@ message GroupChange { uint32 changeEpoch = 3; } +message GroupResponse { + Group group = 1; + bytes groupSendEndorsementsResponse = 2; +} + message GroupChanges { message GroupChangeState { GroupChange groupChange = 1; Group groupState = 2; } - repeated GroupChangeState groupChanges = 1; + repeated GroupChangeState groupChanges = 1; + bytes groupSendEndorsementsResponse = 2; +} + +message GroupChangeResponse { + GroupChange groupChange = 1; + bytes groupSendEndorsementsResponse = 2; } message GroupAttributeBlob { diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index 1ff1228..7987d7c 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -1403,6 +1403,7 @@ const ( SyncMessage_CallEvent_ACCEPTED SyncMessage_CallEvent_Event = 1 SyncMessage_CallEvent_NOT_ACCEPTED SyncMessage_CallEvent_Event = 2 SyncMessage_CallEvent_DELETE SyncMessage_CallEvent_Event = 3 + SyncMessage_CallEvent_OBSERVED SyncMessage_CallEvent_Event = 4 ) // Enum value maps for SyncMessage_CallEvent_Event. @@ -1412,12 +1413,14 @@ var ( 1: "ACCEPTED", 2: "NOT_ACCEPTED", 3: "DELETE", + 4: "OBSERVED", } SyncMessage_CallEvent_Event_value = map[string]int32{ "UNKNOWN_ACTION": 0, "ACCEPTED": 1, "NOT_ACCEPTED": 2, "DELETE": 3, + "OBSERVED": 4, } ) @@ -3119,7 +3122,8 @@ type AttachmentPointer struct { Caption *string `protobuf:"bytes,11,opt,name=caption" json:"caption,omitempty"` BlurHash *string `protobuf:"bytes,12,opt,name=blurHash" json:"blurHash,omitempty"` UploadTimestamp *uint64 `protobuf:"varint,13,opt,name=uploadTimestamp" json:"uploadTimestamp,omitempty"` - CdnNumber *uint32 `protobuf:"varint,14,opt,name=cdnNumber" json:"cdnNumber,omitempty"` // Next ID: 19 + CdnNumber *uint32 `protobuf:"varint,14,opt,name=cdnNumber" json:"cdnNumber,omitempty"` + Uuid []byte `protobuf:"bytes,20,opt,name=uuid" json:"uuid,omitempty"` // Next ID: 21 } func (x *AttachmentPointer) Reset() { @@ -3280,6 +3284,13 @@ func (x *AttachmentPointer) GetCdnNumber() uint32 { return 0 } +func (x *AttachmentPointer) GetUuid() []byte { + if x != nil { + return x.Uuid + } + return nil +} + type isAttachmentPointer_AttachmentIdentifier interface { isAttachmentPointer_AttachmentIdentifier() } @@ -6844,6 +6855,7 @@ type SyncMessage_DeleteForMe struct { MessageDeletes []*SyncMessage_DeleteForMe_MessageDeletes `protobuf:"bytes,1,rep,name=messageDeletes" json:"messageDeletes,omitempty"` ConversationDeletes []*SyncMessage_DeleteForMe_ConversationDelete `protobuf:"bytes,2,rep,name=conversationDeletes" json:"conversationDeletes,omitempty"` LocalOnlyConversationDeletes []*SyncMessage_DeleteForMe_LocalOnlyConversationDelete `protobuf:"bytes,3,rep,name=localOnlyConversationDeletes" json:"localOnlyConversationDeletes,omitempty"` + AttachmentDeletes []*SyncMessage_DeleteForMe_AttachmentDelete `protobuf:"bytes,4,rep,name=attachmentDeletes" json:"attachmentDeletes,omitempty"` } func (x *SyncMessage_DeleteForMe) Reset() { @@ -6899,6 +6911,13 @@ func (x *SyncMessage_DeleteForMe) GetLocalOnlyConversationDeletes() []*SyncMessa return nil } +func (x *SyncMessage_DeleteForMe) GetAttachmentDeletes() []*SyncMessage_DeleteForMe_AttachmentDelete { + if x != nil { + return x.AttachmentDeletes + } + return nil +} + type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -7138,7 +7157,7 @@ type SyncMessage_DeleteForMe_ConversationIdentifier struct { // Types that are assignable to Identifier: // - // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci + // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 Identifier isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier `protobuf_oneof:"identifier"` @@ -7183,9 +7202,9 @@ func (m *SyncMessage_DeleteForMe_ConversationIdentifier) GetIdentifier() isSyncM return nil } -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadAci() string { - if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci); ok { - return x.ThreadAci +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadServiceId() string { + if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId); ok { + return x.ThreadServiceId } return "" } @@ -7208,8 +7227,8 @@ type isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier interface { isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() } -type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci struct { - ThreadAci string `protobuf:"bytes,1,opt,name=threadAci,oneof"` +type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId struct { + ThreadServiceId string `protobuf:"bytes,1,opt,name=threadServiceId,oneof"` } type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId struct { @@ -7220,7 +7239,7 @@ type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 struct { ThreadE164 string `protobuf:"bytes,3,opt,name=threadE164,oneof"` } -func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { +func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { } func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { @@ -7236,7 +7255,7 @@ type SyncMessage_DeleteForMe_AddressableMessage struct { // Types that are assignable to Author: // - // *SyncMessage_DeleteForMe_AddressableMessage_AuthorAci + // *SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId // *SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 Author isSyncMessage_DeleteForMe_AddressableMessage_Author `protobuf_oneof:"author"` SentTimestamp *uint64 `protobuf:"varint,3,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` @@ -7281,9 +7300,9 @@ func (m *SyncMessage_DeleteForMe_AddressableMessage) GetAuthor() isSyncMessage_D return nil } -func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorAci() string { - if x, ok := x.GetAuthor().(*SyncMessage_DeleteForMe_AddressableMessage_AuthorAci); ok { - return x.AuthorAci +func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorServiceId() string { + if x, ok := x.GetAuthor().(*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId); ok { + return x.AuthorServiceId } return "" } @@ -7306,15 +7325,15 @@ type isSyncMessage_DeleteForMe_AddressableMessage_Author interface { isSyncMessage_DeleteForMe_AddressableMessage_Author() } -type SyncMessage_DeleteForMe_AddressableMessage_AuthorAci struct { - AuthorAci string `protobuf:"bytes,1,opt,name=authorAci,oneof"` +type SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId struct { + AuthorServiceId string `protobuf:"bytes,1,opt,name=authorServiceId,oneof"` } type SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 struct { AuthorE164 string `protobuf:"bytes,2,opt,name=authorE164,oneof"` } -func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorAci) isSyncMessage_DeleteForMe_AddressableMessage_Author() { +func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId) isSyncMessage_DeleteForMe_AddressableMessage_Author() { } func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164) isSyncMessage_DeleteForMe_AddressableMessage_Author() { @@ -7375,20 +7394,100 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) GetMessages() []*SyncMessage_De return nil } +type SyncMessage_DeleteForMe_AttachmentDelete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + TargetMessage *SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,opt,name=targetMessage" json:"targetMessage,omitempty"` + Uuid []byte `protobuf:"bytes,3,opt,name=uuid" json:"uuid,omitempty"` // The `uuid` from the `Attachment`. + FallbackDigest []byte `protobuf:"bytes,4,opt,name=fallbackDigest" json:"fallbackDigest,omitempty"` + FallbackPlaintextHash []byte `protobuf:"bytes,5,opt,name=fallbackPlaintextHash" json:"fallbackPlaintextHash,omitempty"` +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { + *x = SyncMessage_DeleteForMe_AttachmentDelete{} + if protoimpl.UnsafeEnabled { + mi := &file_SignalService_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[73] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SyncMessage_DeleteForMe_AttachmentDelete.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeleteForMe_AttachmentDelete) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 3} +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { + if x != nil { + return x.Conversation + } + return nil +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetTargetMessage() *SyncMessage_DeleteForMe_AddressableMessage { + if x != nil { + return x.TargetMessage + } + return nil +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetUuid() []byte { + if x != nil { + return x.Uuid + } + return nil +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetFallbackDigest() []byte { + if x != nil { + return x.FallbackDigest + } + return nil +} + +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetFallbackPlaintextHash() []byte { + if x != nil { + return x.FallbackPlaintextHash + } + return nil +} + type SyncMessage_DeleteForMe_ConversationDelete struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` - MostRecentMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=mostRecentMessages" json:"mostRecentMessages,omitempty"` - IsFullDelete *bool `protobuf:"varint,3,opt,name=isFullDelete" json:"isFullDelete,omitempty"` + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + MostRecentMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=mostRecentMessages" json:"mostRecentMessages,omitempty"` + MostRecentNonExpiringMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,4,rep,name=mostRecentNonExpiringMessages" json:"mostRecentNonExpiringMessages,omitempty"` + IsFullDelete *bool `protobuf:"varint,3,opt,name=isFullDelete" json:"isFullDelete,omitempty"` } func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7401,7 +7500,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7414,7 +7513,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect // Deprecated: Use SyncMessage_DeleteForMe_ConversationDelete.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe_ConversationDelete) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 3} + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 4} } func (x *SyncMessage_DeleteForMe_ConversationDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { @@ -7431,6 +7530,13 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentMessages() []* return nil } +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentNonExpiringMessages() []*SyncMessage_DeleteForMe_AddressableMessage { + if x != nil { + return x.MostRecentNonExpiringMessages + } + return nil +} + func (x *SyncMessage_DeleteForMe_ConversationDelete) GetIsFullDelete() bool { if x != nil && x.IsFullDelete != nil { return *x.IsFullDelete @@ -7449,7 +7555,7 @@ type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7462,7 +7568,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7475,7 +7581,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() pro // Deprecated: Use SyncMessage_DeleteForMe_LocalOnlyConversationDelete.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 4} + return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 5} } func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { @@ -7496,7 +7602,7 @@ type GroupContext_Member struct { func (x *GroupContext_Member) Reset() { *x = GroupContext_Member{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7509,7 +7615,7 @@ func (x *GroupContext_Member) String() string { func (*GroupContext_Member) ProtoMessage() {} func (x *GroupContext_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7544,7 +7650,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7557,7 +7663,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7599,7 +7705,7 @@ type GroupDetails_Avatar struct { func (x *GroupDetails_Avatar) Reset() { *x = GroupDetails_Avatar{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7612,7 +7718,7 @@ func (x *GroupDetails_Avatar) String() string { func (*GroupDetails_Avatar) ProtoMessage() {} func (x *GroupDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7653,7 +7759,7 @@ type GroupDetails_Member struct { func (x *GroupDetails_Member) Reset() { *x = GroupDetails_Member{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7666,7 +7772,7 @@ func (x *GroupDetails_Member) String() string { func (*GroupDetails_Member) ProtoMessage() {} func (x *GroupDetails_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7701,7 +7807,7 @@ type PaymentAddress_MobileCoinAddress struct { func (x *PaymentAddress_MobileCoinAddress) Reset() { *x = PaymentAddress_MobileCoinAddress{} if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7714,7 +7820,7 @@ func (x *PaymentAddress_MobileCoinAddress) String() string { func (*PaymentAddress_MobileCoinAddress) ProtoMessage() {} func (x *PaymentAddress_MobileCoinAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8301,7 +8407,7 @@ var file_SignalService_proto_rawDesc = []byte{ 0x67, 0x65, 0x22, 0x32, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x97, 0x36, 0x0a, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xf0, 0x3a, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, @@ -8596,7 +8702,7 @@ var file_SignalService_proto_rawDesc = []byte{ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0x94, 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, + 0x07, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x1a, 0xa2, 0x04, 0x0a, 0x09, 0x43, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x0e, @@ -8625,232 +8731,242 @@ var file_SignalService_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x55, 0x54, 0x47, - 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x47, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x4f, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x55, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, - 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x1a, - 0xb2, 0x01, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, - 0x12, 0x42, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, - 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x1e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, - 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, - 0x54, 0x45, 0x10, 0x01, 0x1a, 0xf9, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, - 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, - 0x06, 0x63, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, - 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x22, 0x49, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, - 0x05, 0x43, 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x52, 0x4b, - 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, - 0x4d, 0x41, 0x52, 0x4b, 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x49, - 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, - 0x1a, 0xd7, 0x09, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, - 0x12, 0x5d, 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, - 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, - 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, - 0x6b, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, + 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x12, + 0x0c, 0x0a, 0x08, 0x4f, 0x42, 0x53, 0x45, 0x52, 0x56, 0x45, 0x44, 0x10, 0x04, 0x1a, 0xb2, 0x01, + 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x42, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, - 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, - 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, 0x86, 0x01, 0x0a, - 0x1c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, - 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, - 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x1c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, - 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x73, 0x1a, 0x90, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, - 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x12, 0x1e, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x41, 0x63, 0x69, - 0x12, 0x26, 0x0a, 0x0d, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x68, 0x72, 0x65, 0x61, - 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0a, 0x74, 0x68, 0x72, 0x65, - 0x61, 0x64, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, - 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x45, 0x31, 0x36, 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x86, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1e, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x41, 0x63, 0x69, 0x12, - 0x20, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x31, 0x36, - 0x34, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x1a, 0xca, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, 0x67, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x69, 0x6e, + 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x1e, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, + 0x44, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, + 0x10, 0x01, 0x1a, 0xf9, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x61, + 0x6c, 0x6c, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x63, + 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x61, 0x6c, + 0x6c, 0x49, 0x64, 0x22, 0x49, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x43, + 0x4c, 0x45, 0x41, 0x52, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x52, 0x4b, 0x45, 0x44, + 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x4d, 0x41, + 0x52, 0x4b, 0x45, 0x44, 0x5f, 0x41, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x49, 0x4e, 0x5f, + 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x1a, 0xa2, + 0x0e, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x12, 0x5d, + 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x0e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, 0x6b, 0x0a, + 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, - 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, - 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, - 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x1a, 0x86, - 0x02, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, - 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, - 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x69, 0x0a, 0x12, 0x6d, 0x6f, 0x73, 0x74, - 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x12, 0x6d, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x46, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x46, 0x75, 0x6c, - 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x80, 0x01, 0x0a, 0x1b, 0x4c, 0x6f, 0x63, 0x61, - 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, - 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, - 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, - 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, - 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x22, 0xe3, 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, - 0x63, 0x64, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, - 0x64, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, - 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, - 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, - 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x6c, 0x4d, 0x61, 0x63, 0x12, 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, - 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, - 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, - 0x0a, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x05, - 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, - 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, - 0x45, 0x52, 0x4c, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, - 0x04, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x42, 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0xf0, 0x02, 0x0a, - 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, - 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, - 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, - 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, - 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, - 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x55, 0x49, 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, - 0x0c, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, - 0x6c, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, - 0x32, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, - 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xa5, 0x03, - 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, - 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, - 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, - 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, - 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, - 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4a, - 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, - 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, + 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, 0x86, 0x01, 0x0a, 0x1c, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x42, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, + 0x6e, 0x6c, 0x79, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x1c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, 0x6c, 0x79, + 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x73, 0x12, 0x65, 0x0a, 0x11, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x11, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, + 0x65, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x1a, 0x9c, 0x01, 0x0a, 0x16, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x0f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x26, 0x0a, 0x0d, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x68, 0x72, 0x65, + 0x61, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0a, 0x74, 0x68, 0x72, + 0x65, 0x61, 0x64, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x0a, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x45, 0x31, 0x36, 0x34, 0x42, 0x0c, 0x0a, 0x0a, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0x92, 0x01, 0x0a, 0x12, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x2a, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0a, + 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x45, 0x31, 0x36, 0x34, 0x12, 0x24, + 0x0a, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x1a, 0xca, + 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x73, 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, + 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x1a, 0xc8, 0x02, 0x0a, 0x10, + 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, + 0x4d, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x66, 0x61, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0e, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x12, 0x34, 0x0a, 0x15, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x50, 0x6c, 0x61, 0x69, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x15, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x87, 0x03, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x61, 0x0a, + 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x69, 0x0a, 0x12, 0x6d, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, + 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, + 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x12, 0x6d, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x63, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x7f, 0x0a, 0x1d, 0x6d, + 0x6f, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, + 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x1d, 0x6d, + 0x6f, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, + 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, + 0x69, 0x73, 0x46, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x46, 0x75, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x1a, 0x80, 0x01, 0x0a, 0x1b, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4f, 0x6e, 0x6c, 0x79, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x12, 0x61, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x2e, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x22, + 0xf7, 0x04, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x06, 0x48, 0x00, 0x52, 0x05, 0x63, 0x64, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, + 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x06, 0x63, 0x64, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x09, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, + 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, + 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x12, 0x38, 0x0a, + 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, + 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, + 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x63, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, + 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x28, 0x0a, + 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x64, 0x6e, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x63, 0x64, 0x6e, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x14, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x39, 0x0a, 0x05, 0x46, 0x6c, 0x61, + 0x67, 0x73, 0x12, 0x11, 0x0a, 0x0d, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, + 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x42, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x4c, + 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x49, 0x46, 0x10, 0x04, 0x22, 0x04, + 0x08, 0x03, 0x10, 0x03, 0x42, 0x17, 0x0a, 0x15, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x4a, 0x04, 0x08, + 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x22, 0xf0, 0x02, 0x0a, 0x0c, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, + 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x22, + 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x22, 0x48, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, + 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x10, 0x02, + 0x12, 0x08, 0x0a, 0x04, 0x51, 0x55, 0x49, 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, + 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x22, 0x6c, 0x0a, 0x0e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x56, 0x32, 0x12, 0x1c, + 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xa5, 0x03, 0x0a, 0x0e, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x61, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, + 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, + 0x33, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x08, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, + 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, @@ -8858,46 +8974,75 @@ var file_SignalService_proto_rawDesc = []byte{ 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, - 0x22, 0xc9, 0x01, 0x0a, 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x5f, 0x0a, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, - 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, - 0x00, 0x52, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x1a, 0x4b, 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, - 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x42, 0x09, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, - 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, - 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x22, 0x45, 0x0a, 0x13, 0x50, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, - 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x75, 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4a, 0x04, 0x08, 0x07, + 0x10, 0x08, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x31, 0x36, 0x34, 0x12, 0x3c, 0x0a, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x44, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x52, 0x06, 0x61, 0x76, 0x61, + 0x74, 0x61, 0x72, 0x12, 0x1c, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x3a, 0x04, 0x74, 0x72, 0x75, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x62, 0x6f, 0x78, 0x50, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x69, 0x6e, 0x62, 0x6f, + 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x64, 0x1a, 0x42, 0x0a, 0x06, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, + 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x1a, 0x22, 0x0a, 0x06, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xc9, 0x01, + 0x0a, 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x5f, 0x0a, 0x11, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x11, + 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x1a, 0x4b, 0x0a, 0x11, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x09, + 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x72, 0x0a, 0x16, 0x44, 0x65, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x4b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, + 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x45, 0x0a, + 0x13, 0x50, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x64, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3c, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x42, 0x45, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, + 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x70, 0x75, 0x73, 0x68, 0x42, 0x13, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, } var ( @@ -8913,7 +9058,7 @@ func file_SignalService_proto_rawDescGZIP() []byte { } var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 27) -var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 80) +var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 81) var file_SignalService_proto_goTypes = []interface{}{ (Envelope_Type)(0), // 0: signalservice.Envelope.Type (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type @@ -9015,13 +9160,14 @@ var file_SignalService_proto_goTypes = []interface{}{ (*SyncMessage_DeleteForMe_ConversationIdentifier)(nil), // 97: signalservice.SyncMessage.DeleteForMe.ConversationIdentifier (*SyncMessage_DeleteForMe_AddressableMessage)(nil), // 98: signalservice.SyncMessage.DeleteForMe.AddressableMessage (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 99: signalservice.SyncMessage.DeleteForMe.MessageDeletes - (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 100: signalservice.SyncMessage.DeleteForMe.ConversationDelete - (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 101: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - (*GroupContext_Member)(nil), // 102: signalservice.GroupContext.Member - (*ContactDetails_Avatar)(nil), // 103: signalservice.ContactDetails.Avatar - (*GroupDetails_Avatar)(nil), // 104: signalservice.GroupDetails.Avatar - (*GroupDetails_Member)(nil), // 105: signalservice.GroupDetails.Member - (*PaymentAddress_MobileCoinAddress)(nil), // 106: signalservice.PaymentAddress.MobileCoinAddress + (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 100: signalservice.SyncMessage.DeleteForMe.AttachmentDelete + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 101: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 102: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*GroupContext_Member)(nil), // 103: signalservice.GroupContext.Member + (*ContactDetails_Avatar)(nil), // 104: signalservice.ContactDetails.Avatar + (*GroupDetails_Avatar)(nil), // 105: signalservice.GroupDetails.Avatar + (*GroupDetails_Member)(nil), // 106: signalservice.GroupDetails.Member + (*PaymentAddress_MobileCoinAddress)(nil), // 107: signalservice.PaymentAddress.MobileCoinAddress } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type @@ -9085,13 +9231,13 @@ var file_SignalService_proto_depIdxs = []int32{ 92, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent 93, // 59: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe 26, // 60: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type - 102, // 61: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member + 103, // 61: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member 40, // 62: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer - 103, // 63: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 104, // 63: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar 38, // 64: signalservice.ContactDetails.verified:type_name -> signalservice.Verified - 105, // 65: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member - 104, // 66: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar - 106, // 67: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress + 106, // 65: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member + 105, // 66: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar + 107, // 67: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress 31, // 68: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage 1, // 69: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type 2, // 70: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type @@ -9132,18 +9278,22 @@ var file_SignalService_proto_depIdxs = []int32{ 23, // 105: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type 24, // 106: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type 99, // 107: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes - 100, // 108: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete - 101, // 109: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - 97, // 110: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 98, // 111: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 97, // 112: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 98, // 113: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 97, // 114: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 115, // [115:115] is the sub-list for method output_type - 115, // [115:115] is the sub-list for method input_type - 115, // [115:115] is the sub-list for extension type_name - 115, // [115:115] is the sub-list for extension extendee - 0, // [0:115] is the sub-list for field type_name + 101, // 108: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 102, // 109: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 100, // 110: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete + 97, // 111: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 98, // 112: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 97, // 113: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 98, // 114: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 97, // 115: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 98, // 116: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 98, // 117: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 97, // 118: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 119, // [119:119] is the sub-list for method output_type + 119, // [119:119] is the sub-list for method input_type + 119, // [119:119] is the sub-list for extension type_name + 119, // [119:119] is the sub-list for extension extendee + 0, // [0:119] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -10029,7 +10179,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SyncMessage_DeleteForMe_ConversationDelete); i { + switch v := v.(*SyncMessage_DeleteForMe_AttachmentDelete); i { case 0: return &v.state case 1: @@ -10041,7 +10191,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SyncMessage_DeleteForMe_LocalOnlyConversationDelete); i { + switch v := v.(*SyncMessage_DeleteForMe_ConversationDelete); i { case 0: return &v.state case 1: @@ -10053,7 +10203,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupContext_Member); i { + switch v := v.(*SyncMessage_DeleteForMe_LocalOnlyConversationDelete); i { case 0: return &v.state case 1: @@ -10065,7 +10215,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ContactDetails_Avatar); i { + switch v := v.(*GroupContext_Member); i { case 0: return &v.state case 1: @@ -10077,7 +10227,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupDetails_Avatar); i { + switch v := v.(*ContactDetails_Avatar); i { case 0: return &v.state case 1: @@ -10089,7 +10239,7 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GroupDetails_Member); i { + switch v := v.(*GroupDetails_Avatar); i { case 0: return &v.state case 1: @@ -10101,6 +10251,18 @@ func file_SignalService_proto_init() { } } file_SignalService_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GroupDetails_Member); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_SignalService_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PaymentAddress_MobileCoinAddress); i { case 0: return &v.state @@ -10146,12 +10308,12 @@ func file_SignalService_proto_init() { (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } file_SignalService_proto_msgTypes[70].OneofWrappers = []interface{}{ - (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadAci)(nil), + (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId)(nil), (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId)(nil), (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164)(nil), } file_SignalService_proto_msgTypes[71].OneofWrappers = []interface{}{ - (*SyncMessage_DeleteForMe_AddressableMessage_AuthorAci)(nil), + (*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId)(nil), (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164)(nil), } type x struct{} @@ -10160,7 +10322,7 @@ func file_SignalService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_SignalService_proto_rawDesc, NumEnums: 27, - NumMessages: 80, + NumMessages: 81, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index dceaf0a..30127a1 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -614,6 +614,7 @@ message SyncMessage { ACCEPTED = 1; NOT_ACCEPTED = 2; DELETE = 3; + OBSERVED = 4; } optional bytes conversationId = 1; @@ -656,7 +657,7 @@ message SyncMessage { message DeleteForMe { message ConversationIdentifier { oneof identifier { - string threadAci = 1; + string threadServiceId = 1; bytes threadGroupId = 2; string threadE164 = 3; } @@ -664,7 +665,7 @@ message SyncMessage { message AddressableMessage { oneof author { - string authorAci = 1; + string authorServiceId = 1; string authorE164 = 2; } optional uint64 sentTimestamp = 3; @@ -675,9 +676,18 @@ message SyncMessage { repeated AddressableMessage messages = 2; } + message AttachmentDelete { + optional ConversationIdentifier conversation = 1; + optional AddressableMessage targetMessage = 2; + optional bytes uuid = 3; // The `uuid` from the `Attachment`. + optional bytes fallbackDigest = 4; + optional bytes fallbackPlaintextHash = 5; + } + message ConversationDelete { optional ConversationIdentifier conversation = 1; repeated AddressableMessage mostRecentMessages = 2; + repeated AddressableMessage mostRecentNonExpiringMessages = 4; optional bool isFullDelete = 3; } @@ -688,6 +698,7 @@ message SyncMessage { repeated MessageDeletes messageDeletes = 1; repeated ConversationDelete conversationDeletes = 2; repeated LocalOnlyConversationDelete localOnlyConversationDeletes = 3; + repeated AttachmentDelete attachmentDeletes = 4; } optional Sent sent = 1; @@ -743,7 +754,8 @@ message AttachmentPointer { optional string blurHash = 12; optional uint64 uploadTimestamp = 13; optional uint32 cdnNumber = 14; - // Next ID: 19 + optional bytes uuid = 20; + // Next ID: 21 } message GroupContext { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index dac087b..e6d0ea3 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-c4805126008977827f8ee08e016568fc9a374b4d} -DESKTOP_GIT_REVISION=${1:-af1c593fef4e485127ea356b3b592f3c781c2a16} +ANDROID_GIT_REVISION=${1:-6c302b708a6980041ff57271f800c0b092e74ef9} +DESKTOP_GIT_REVISION=${1:-b34f2fbb99d68bd462715f8519524100580fb372} update_proto() { case "$1" in From fdacfc2f677b9a00b53a31ece44bbd2826023816 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Jul 2024 23:50:41 +0300 Subject: [PATCH 240/718] v2: update mautrix-go --- cmd/mautrix-signal-v2/legacymigrate.sql | 3 +-- cmd/mautrix-signal-v2/main.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/handlematrix.go | 7 ++----- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index 5e8c5ba..eec7101 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -90,7 +90,7 @@ FROM puppet_old; INSERT INTO message ( bridge_id, id, part_id, mxid, room_id, room_receiver, - sender_id, timestamp, relates_to, metadata + sender_id, timestamp, metadata ) SELECT '', -- bridge_id @@ -104,7 +104,6 @@ SELECT END, -- room_receiver cast(sender AS TEXT), -- sender_id timestamp * 1000000, - NULL, -- relates_to '{}' -- metadata FROM message_old; diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 80d2efc..39a3496 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 4), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 7), true, ) } diff --git a/go.mod b/go.mod index 8d62958..3f068ba 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240709160900-fc7ed77e2630 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240710204602-dd16a8d1d90b nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 094f2d1..a7c534e 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240709160900-fc7ed77e2630 h1:X+IuVExANBr0gfFQ22vpecvDzkiSCVAnFAYvyIZ+uOI= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240709160900-fc7ed77e2630/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240710204602-dd16a8d1d90b h1:xYEIkM0OzirvHPpTwYiDQrh6PHjDny5Ox84SIkD2aXc= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240710204602-dd16a8d1d90b/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 41b5ecd..ea3475e 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -101,9 +101,6 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma dbMsg.Metadata.Extra = map[string]any{ "contains_attachments": len(converted.Attachments) > 0, } - if msg.ReplyTo != nil { - dbMsg.RelatesToRowID = msg.ReplyTo.RowID - } return &bridgev2.MatrixMessageResponse{ DB: dbMsg, }, nil @@ -122,9 +119,9 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri Client: s, Portal: msg.Portal, } - if msg.EditTarget.RelatesToRowID != 0 { + if msg.EditTarget.ReplyTo.MessageID != "" { var err error - mcCtx.ReplyTo, err = s.Main.Bridge.DB.Message.GetByRowID(ctx, msg.EditTarget.RelatesToRowID) + mcCtx.ReplyTo, err = s.Main.Bridge.DB.Message.GetFirstOrSpecificPartByID(ctx, msg.Portal.Receiver, msg.EditTarget.ReplyTo) if err != nil { return fmt.Errorf("failed to get message reply target: %w", err) } From 76462a7938f077479c27f4925df3d99e502938da Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 12 Jul 2024 15:01:31 +0300 Subject: [PATCH 241/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3f068ba..f2c0b50 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240710204602-dd16a8d1d90b + maunium.net/go/mautrix v0.19.0-beta.1.0.20240712120058-0f9f923378c5 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index a7c534e..bf5118a 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240710204602-dd16a8d1d90b h1:xYEIkM0OzirvHPpTwYiDQrh6PHjDny5Ox84SIkD2aXc= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240710204602-dd16a8d1d90b/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240712120058-0f9f923378c5 h1:trHMeTOodR/JvlYiy6xGgGnXcy/VAuJp9eeP816S6yw= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240712120058-0f9f923378c5/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 0e46919ace5f63f5ef6a1991d49aaef022a3abf0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 12 Jul 2024 16:54:37 +0300 Subject: [PATCH 242/718] v2: update mautrix-go to support appservice websockets --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f2c0b50..18c1c10 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240712120058-0f9f923378c5 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240712135340-7c9b8cb28773 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index bf5118a..72bf004 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240712120058-0f9f923378c5 h1:trHMeTOodR/JvlYiy6xGgGnXcy/VAuJp9eeP816S6yw= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240712120058-0f9f923378c5/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240712135340-7c9b8cb28773 h1:4rpBbhsdOkRF3bZ6VscH+yTbk3sDV1w+Bkr+J9XLHeU= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240712135340-7c9b8cb28773/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From b853d1756f8fee1c873a294a07a724f1aed8e5f8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 12 Jul 2024 19:55:55 +0300 Subject: [PATCH 243/718] main: update dependencies --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 18c1c10..18a5606 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240702170310-bd1da3c069eb - golang.org/x/crypto v0.24.0 - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 - golang.org/x/net v0.26.0 + go.mau.fi/util v0.5.1-0.20240710154926-931b33d6d530 + golang.org/x/crypto v0.25.0 + golang.org/x/exp v0.0.0-20240707233637-46b078467d37 + golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240712135340-7c9b8cb28773 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240712164309-85e0664cb441 nhooyr.io/websocket v1.8.11 ) @@ -42,7 +42,7 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.4 // indirect go.mau.fi/zeroconfig v0.1.2 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index 72bf004..e7f09ae 100644 --- a/go.sum +++ b/go.sum @@ -67,21 +67,21 @@ 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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240702170310-bd1da3c069eb h1:VZPo2pvfjNj6fkFv5e9FyTYx96BLwwYNA19WYaY+KN8= -go.mau.fi/util v0.5.1-0.20240702170310-bd1da3c069eb/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/util v0.5.1-0.20240710154926-931b33d6d530 h1:ZWMrLC+Fn2AmKL8HM04YY0zyMDMOagQZVukpxp0rmic= +go.mau.fi/util v0.5.1-0.20240710154926-931b33d6d530/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240712135340-7c9b8cb28773 h1:4rpBbhsdOkRF3bZ6VscH+yTbk3sDV1w+Bkr+J9XLHeU= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240712135340-7c9b8cb28773/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240712164309-85e0664cb441 h1:k2yoj2UiUX4X1csGiXpyxkN3hWR4kmzlCseY0iznVb4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240712164309-85e0664cb441/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 1e093d6dc6840ed99aedd79c1a1ddd3a16af30e7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 13 Jul 2024 14:11:28 +0300 Subject: [PATCH 244/718] v2: update mautrix-go and use new typed metadata structs --- cmd/mautrix-signal-v2/legacymigrate.sql | 38 ++++++++++-------- cmd/mautrix-signal-v2/legacyprovision.go | 2 +- cmd/mautrix-signal-v2/main.go | 2 +- go.mod | 2 +- go.sum | 4 +- pkg/connector/chatinfo.go | 15 ++++---- pkg/connector/connector.go | 6 +-- pkg/connector/dbmeta.go | 49 ++++++++++++++++++++++++ pkg/connector/groupinfo.go | 12 +++--- pkg/connector/handlematrix.go | 20 ++++------ pkg/connector/handlesignal.go | 13 ++++--- pkg/connector/login.go | 12 ++---- pkg/connector/msgconvproxy.go | 6 +-- 13 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 pkg/connector/dbmeta.go diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index eec7101..952dc4d 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -2,14 +2,15 @@ INSERT INTO "user" (bridge_id, mxid, management_room, access_token) SELECT '', mxid, management_room, NULL FROM user_old; -INSERT INTO user_login (bridge_id, user_mxid, id, space_room, metadata) +INSERT INTO user_login (bridge_id, user_mxid, id, remote_name, space_room, metadata) SELECT '', mxid, cast(uuid AS TEXT), + phone, -- remote_name space_room, CAST( - '{"phone":"' || phone || '","remote_name":"' || phone || '"}' + '{"phone":"' || phone || '"}' -- only: postgres AS jsonb -- only: sqlite (line commented) @@ -20,7 +21,8 @@ FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; INSERT INTO portal ( bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, name, topic, avatar_id, avatar_hash, avatar_mxc, - name_set, avatar_set, topic_set, in_space, metadata + name_set, avatar_set, topic_set, in_space, + room_type, disappear_type, disappear_timer, metadata ) SELECT '', -- bridge_id @@ -48,11 +50,11 @@ SELECT avatar_set, topic_set, false, -- in_space + CASE WHEN LENGTH(chat_id)=44 THEN '' ELSE 'dm' END, -- room_type + CASE WHEN expiration_time<>0 THEN 'after_read' END, + CASE WHEN expiration_time<>0 THEN expiration_time * 1000000000 END, CAST( - CASE WHEN expiration_time = 0 - THEN '{"revision":"' || revision || '"}' - ELSE '{"disappear_type": "after_read", "disappear_timer": "' || (expiration_time * 1000000000) || '","revision":"' || revision || '"}' - END + '{"revision":' || revision || '}' -- only: postgres AS jsonb -- only: sqlite (line commented) @@ -61,7 +63,9 @@ SELECT FROM portal_old; INSERT INTO ghost ( - bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, metadata + bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, + name_set, avatar_set, contact_info_set, + is_bot, identifiers, metadata ) SELECT '', -- bridge_id @@ -76,6 +80,9 @@ SELECT avatar_url, -- avatar_mxc name_set, avatar_set, + contact_info_set, + false, -- is_bot + '[]', -- identifiers CAST( CASE WHEN profile_fetched_at IS NOT NULL THEN ('{"profile_fetched_at":' || profile_fetched_at || '}') @@ -90,7 +97,7 @@ FROM puppet_old; INSERT INTO message ( bridge_id, id, part_id, mxid, room_id, room_receiver, - sender_id, timestamp, metadata + sender_id, sender_mxid, timestamp, edit_count, metadata ) SELECT '', -- bridge_id @@ -103,7 +110,9 @@ SELECT ELSE cast(signal_receiver AS TEXT) END, -- room_receiver cast(sender AS TEXT), -- sender_id + '', -- sender_mxid timestamp * 1000000, + 0, -- edit_count '{}' -- metadata FROM message_old; @@ -120,7 +129,7 @@ SELECT FROM disappearing_message_old; INSERT INTO reaction ( - bridge_id, message_id, message_part_id, sender_id, emoji_id, + bridge_id, message_id, message_part_id, sender_id, emoji_id, emoji, room_id, room_receiver, mxid, timestamp, metadata ) SELECT @@ -129,6 +138,7 @@ SELECT '', -- message_part_id cast(author AS TEXT), -- sender_id '', -- emoji_id + emoji, signal_chat_id, -- room_id CASE WHEN signal_receiver='00000000-0000-0000-0000-000000000000' THEN '' @@ -136,13 +146,7 @@ SELECT END, -- room_receiver mxid, msg_timestamp * 1000000, -- timestamp (actual reaction timestamp not available) - CAST( - '{"emoji":"' || emoji || '"}' - -- only: postgres - AS jsonb - -- only: sqlite (line commented) --- AS text - ) -- metadata + '{}' -- metadata FROM reaction_old; INSERT INTO user_portal ( diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal-v2/legacyprovision.go index 0eef485..48a9c5f 100644 --- a/cmd/mautrix-signal-v2/legacyprovision.go +++ b/cmd/mautrix-signal-v2/legacyprovision.go @@ -186,7 +186,7 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { Success: true, Status: "prekeys_registered", UUID: string(res.CompleteParams.UserLogin.ID), - Number: res.CompleteParams.UserLogin.Metadata.RemoteName, + Number: res.CompleteParams.UserLogin.RemoteName, }) } login.Delete() diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 39a3496..cc1f0bf 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 7), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 9), true, ) } diff --git a/go.mod b/go.mod index 18a5606..42b930a 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240712164309-85e0664cb441 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240713090952-9fdf94132a3d nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index e7f09ae..2fc2c90 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240712164309-85e0664cb441 h1:k2yoj2UiUX4X1csGiXpyxkN3hWR4kmzlCseY0iznVb4= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240712164309-85e0664cb441/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240713090952-9fdf94132a3d h1:Fxpvg1sOmkKKsYqbTLEIf6La9+qeBFKmnwkZfcxa8eM= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240713090952-9fdf94132a3d/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 30dc546..36daecb 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -25,7 +25,9 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" @@ -192,8 +194,6 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI } func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { - isDirectChat := true - isSpace := false name := "" topic := PrivateChatTopic members := &bridgev2.ChatMemberList{ @@ -236,12 +236,11 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev return &bridgev2.CreateChatResponse{ PortalID: s.makeDMPortalKey(serviceID), PortalInfo: &bridgev2.ChatInfo{ - Name: &name, - Avatar: avatar, - Topic: &topic, - Members: members, - IsDirectChat: &isDirectChat, - IsSpace: &isSpace, + Name: &name, + Avatar: avatar, + Topic: &topic, + Members: members, + Type: ptr.Ptr(database.RoomTypeDM), }, } } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index dcb7ada..4c36674 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -129,11 +129,11 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { LocationFormat: s.Config.LocationFormat, UpdateDisappearing: func(ctx context.Context, newTimer time.Duration) { portal := ctx.Value(msgconvContextKey).(*msgconvContext).Portal - portal.Metadata.DisappearTimer = newTimer + portal.Disappear.Timer = newTimer if newTimer == 0 { - portal.Metadata.DisappearType = "" + portal.Disappear.Type = "" } else { - portal.Metadata.DisappearType = database.DisappearingTypeAfterRead + portal.Disappear.Type = database.DisappearingTypeAfterRead } err := portal.Save(ctx) if err != nil { diff --git a/pkg/connector/dbmeta.go b/pkg/connector/dbmeta.go new file mode 100644 index 0000000..18de885 --- /dev/null +++ b/pkg/connector/dbmeta.go @@ -0,0 +1,49 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "maunium.net/go/mautrix/bridgev2/database" +) + +func (s *SignalConnector) GetDBMetaTypes() database.MetaTypes { + return database.MetaTypes{ + Portal: func() any { + return &PortalMetadata{} + }, + Ghost: nil, + Message: func() any { + return &MessageMetadata{} + }, + Reaction: nil, + UserLogin: func() any { + return &UserLoginMetadata{} + }, + } +} + +type PortalMetadata struct { + Revision uint32 `json:"revision"` +} + +type MessageMetadata struct { + ContainsAttachments bool `json:"contains_attachments,omitempty"` +} + +type UserLoginMetadata struct { + Phone string `json:"phone"` +} diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 65cbab2..333ed7c 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -21,6 +21,7 @@ import ( "time" "github.com/rs/zerolog" + "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/event" @@ -94,8 +95,6 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden if err != nil { return nil, err } - isDM := false - isSpace := false members := &bridgev2.ChatMemberList{ IsFull: true, Members: make([]bridgev2.ChatMember, len(groupInfo.Members), len(groupInfo.Members)+len(groupInfo.PendingMembers)+len(groupInfo.RequestingMembers)+len(groupInfo.BannedMembers)), @@ -153,8 +152,7 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden Timer: time.Duration(groupInfo.DisappearingMessagesDuration) * time.Second, }, Members: members, - IsDirectChat: &isDM, - IsSpace: &isSpace, + Type: ptr.Ptr(database.RoomTypeDefault), JoinRule: &event.JoinRulesEventContent{JoinRule: joinRule}, ExtraUpdates: makeRevisionUpdater(groupInfo.Revision), }, nil @@ -176,9 +174,9 @@ func (s *SignalClient) makeGroupAvatar(meta signalmeow.GroupAvatarMeta) *bridgev func makeRevisionUpdater(rev uint32) func(ctx context.Context, portal *bridgev2.Portal) bool { return func(ctx context.Context, portal *bridgev2.Portal) bool { - currentRev, _ := database.GetNumberFromMap[uint32](portal.Metadata.Extra, "revision") - if currentRev < rev { - portal.Metadata.Extra["revision"] = rev + meta := portal.Metadata.(*PortalMetadata) + if meta.Revision < rev { + meta.Revision = rev return true } return false diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index ea3475e..2f36ae7 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -97,9 +97,9 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), SenderID: makeUserID(s.Client.Store.ACI), Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), - } - dbMsg.Metadata.Extra = map[string]any{ - "contains_attachments": len(converted.Attachments) > 0, + Metadata: &MessageMetadata{ + ContainsAttachments: len(converted.Attachments) > 0, + }, } return &bridgev2.MatrixMessageResponse{ DB: dbMsg, @@ -139,8 +139,8 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri return err } msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) - msg.EditTarget.Metadata.Extra["contains_attachments"] = len(converted.Attachments) > 0 - msg.EditTarget.Metadata.EditCount++ + msg.EditTarget.Metadata = &MessageMetadata{ContainsAttachments: len(converted.Attachments) > 0} + msg.EditTarget.EditCount++ return nil } @@ -186,7 +186,7 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.TargetReaction.Metadata.Emoji), + Emoji: proto.String(msg.TargetReaction.Emoji), Remove: proto.Bool(true), TargetAuthorAci: proto.String(targetAuthorACI.String()), TargetSentTimestamp: proto.Uint64(targetSentTimestamp), @@ -296,11 +296,7 @@ func (s *SignalClient) handleMatrixRoomMeta(ctx context.Context, portal *bridgev if err != nil || groupID == "" { return false, err } - rev, ok := database.GetNumberFromMap[uint32](portal.Metadata.Extra, "revision") - if !ok { - return false, fmt.Errorf("missing revision in portal metadata") - } - gc.Revision = rev + 1 + gc.Revision = portal.Metadata.(*PortalMetadata).Revision + 1 revision, err := s.Client.UpdateGroup(ctx, gc, groupID) if err != nil { return false, err @@ -320,7 +316,7 @@ func (s *SignalClient) handleMatrixRoomMeta(ctx context.Context, portal *bridgev if postUpdatePortal != nil { postUpdatePortal() } - portal.Metadata.Extra["revision"] = revision + portal.Metadata.(*PortalMetadata).Revision = revision return true, nil } diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 0618957..500ec96 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -151,7 +151,7 @@ func (evt *Bv2ChatEvent) PreHandle(ctx context.Context, portal *bridgev2.Portal) if !ok || dataMsg.GroupV2 == nil { return } - portalRev, _ := database.GetNumberFromMap[uint32](portal.Metadata.Extra, "revision") + portalRev := portal.Metadata.(*PortalMetadata).Revision if evt.Info.GroupRevision > portalRev { toRevision := evt.Info.GroupRevision if dataMsg.GetGroupV2().GetGroupChange() != nil { @@ -289,10 +289,11 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po convertedParts := make([]*bridgev2.ConvertedMessagePart, len(converted.Parts)) for i, part := range converted.Parts { convertedParts[i] = &bridgev2.ConvertedMessagePart{ - ID: makeMessagePartID(i), - Type: part.Type, - Content: part.Content, - Extra: part.Extra, + ID: makeMessagePartID(i), + Type: part.Type, + Content: part.Content, + Extra: part.Extra, + DBMetadata: &MessageMetadata{ContainsAttachments: len(dataMsg.GetAttachments()) > 0}, } } var disappear database.DisappearingSetting @@ -338,7 +339,7 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta Content: lastPart.Content, Extra: lastPart.Extra, }) - convertedEdit.ModifiedParts[0].Part.Metadata.EditCount++ + convertedEdit.ModifiedParts[0].Part.EditCount++ return convertedEdit, nil } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 3a58312..82ddac5 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -157,14 +157,10 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err } ul, err := qr.User.NewLogin(ctx, &database.UserLogin{ - ID: newLoginID, - Metadata: database.UserLoginMetadata{ - StandardUserLoginMetadata: database.StandardUserLoginMetadata{ - RemoteName: qr.ProvData.Number, - }, - Extra: map[string]any{ - "phone": qr.ProvData.Number, - }, + ID: newLoginID, + RemoteName: qr.ProvData.Number, + Metadata: &UserLoginMetadata{ + Phone: qr.ProvData.Number, }, }, &bridgev2.NewLoginParams{ DeleteOnConflict: true, diff --git a/pkg/connector/msgconvproxy.go b/pkg/connector/msgconvproxy.go index c8d97a4..87ebbb9 100644 --- a/pkg/connector/msgconvproxy.go +++ b/pkg/connector/msgconvproxy.go @@ -72,7 +72,7 @@ func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *ev AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), Type: signalpb.DataMessage_Quote_NORMAL.Enum(), } - if mcCtx.ReplyTo.Metadata.Extra["contains_attachments"] != false { + if mcCtx.ReplyTo.Metadata.(*MessageMetadata).ContainsAttachments { quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) } return quote @@ -107,9 +107,9 @@ func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { NameSet: portal.NameSet, AvatarSet: portal.AvatarSet, TopicSet: portal.TopicSet, - //Revision: portal.Metadata["revision"].(uint32), + Revision: portal.Metadata.(*PortalMetadata).Revision, Encrypted: true, //RelayUserID: portal.Relay.UserMXID, - ExpirationTime: uint32(portal.Metadata.DisappearTimer.Seconds()), + ExpirationTime: uint32(portal.Disappear.Timer.Seconds()), } } From ca21d467de314fac2b644d52c0e7c21ece5b382f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jul 2024 11:13:08 +0300 Subject: [PATCH 245/718] v2: update mautrix-go --- cmd/mautrix-signal-v2/legacyprovision.go | 2 +- cmd/mautrix-signal-v2/main.go | 2 +- database/upgrades/upgrades.go | 4 ++-- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/connector/chatinfo.go | 2 +- pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal-v2/legacyprovision.go index 48a9c5f..b3c3f80 100644 --- a/cmd/mautrix-signal-v2/legacyprovision.go +++ b/cmd/mautrix-signal-v2/legacyprovision.go @@ -237,7 +237,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, } if resp.Chat != nil { if resp.Chat.Portal == nil { - resp.Chat.Portal, err = m.Bridge.GetPortalByID(r.Context(), resp.Chat.PortalID) + resp.Chat.Portal, err = m.Bridge.GetPortalByKey(r.Context(), resp.Chat.PortalKey) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to get portal") legacyprovision.JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index cc1f0bf..55ef75c 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 9), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 11), true, ) } diff --git a/database/upgrades/upgrades.go b/database/upgrades/upgrades.go index 895be62..20f60f4 100644 --- a/database/upgrades/upgrades.go +++ b/database/upgrades/upgrades.go @@ -30,10 +30,10 @@ var Table dbutil.UpgradeTable var rawUpgrades embed.FS func init() { - Table.Register(-1, 12, 0, "Unsupported version", false, func(ctx context.Context, database *dbutil.Database) error { + Table.Register(-1, 12, 0, "Unsupported version", dbutil.TxnModeOff, func(ctx context.Context, database *dbutil.Database) error { return errors.New("please upgrade to mautrix-signal v0.4.3 before upgrading to a newer version") }) - Table.Register(1, 13, 0, "Jump to version 13", false, func(ctx context.Context, database *dbutil.Database) error { + Table.Register(1, 13, 0, "Jump to version 13", dbutil.TxnModeOff, func(ctx context.Context, database *dbutil.Database) error { return nil }) Table.RegisterFS(rawUpgrades) diff --git a/go.mod b/go.mod index 42b930a..a0cb89d 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240710154926-931b33d6d530 + go.mau.fi/util v0.5.1-0.20240714080209-e8e8154ce82a golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240713090952-9fdf94132a3d + maunium.net/go/mautrix v0.19.0-beta.1.0.20240714080619-d1905f623215 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 2fc2c90..92dabd2 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240710154926-931b33d6d530 h1:ZWMrLC+Fn2AmKL8HM04YY0zyMDMOagQZVukpxp0rmic= -go.mau.fi/util v0.5.1-0.20240710154926-931b33d6d530/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/util v0.5.1-0.20240714080209-e8e8154ce82a h1:m9QJacb5JfXDCdYoi/DvG4/FaHGketCSGzqys3Wyr10= +go.mau.fi/util v0.5.1-0.20240714080209-e8e8154ce82a/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240713090952-9fdf94132a3d h1:Fxpvg1sOmkKKsYqbTLEIf6La9+qeBFKmnwkZfcxa8eM= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240713090952-9fdf94132a3d/go.mod h1:bNQrvIftiwJ+7OjSh+Gza5xcncq1ooHk6oyDWq4B4sg= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240714080619-d1905f623215 h1:cy3Ge8DMOQj+a6G8QhWEcg8FWsx2wEwTgSATHzg3wIE= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240714080619-d1905f623215/go.mod h1:ldNVOQXaljMk4YLzlohp+DniMQtCSzTVcwjEFBlYQLM= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 36daecb..984a4ef 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -234,7 +234,7 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev serviceID = libsignalgo.NewACIServiceID(recipient.ACI) } return &bridgev2.CreateChatResponse{ - PortalID: s.makeDMPortalKey(serviceID), + PortalKey: s.makeDMPortalKey(serviceID), PortalInfo: &bridgev2.ChatInfo{ Name: &name, Avatar: avatar, diff --git a/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go b/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go index 9a5b011..5046abf 100644 --- a/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go +++ b/pkg/signalmeow/store/upgrades/16-remove-extra-prekeys.go @@ -59,7 +59,7 @@ func deleteExtraPrekeys(ctx context.Context, db *dbutil.Database, selectQuery, d } func init() { - Table.Register(-1, 16, 13, "Remove extra prekeys", true, func(ctx context.Context, db *dbutil.Database) error { + Table.Register(-1, 16, 13, "Remove extra prekeys", dbutil.TxnModeOn, func(ctx context.Context, db *dbutil.Database) error { err := deleteExtraPrekeys(ctx, db, ` SELECT account_id, service_id, COUNT(*), MAX(key_id) FROM signalmeow_pre_keys WHERE is_signed=false GROUP BY 1, 2 `, ` From 41a7187dff34f8568ff5af26852c67d62010c193 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jul 2024 14:47:58 +0300 Subject: [PATCH 246/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a0cb89d..be6c9f1 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240714080619-d1905f623215 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240714114557-edf1a8d8d022 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 92dabd2..0fdbe27 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240714080619-d1905f623215 h1:cy3Ge8DMOQj+a6G8QhWEcg8FWsx2wEwTgSATHzg3wIE= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240714080619-d1905f623215/go.mod h1:ldNVOQXaljMk4YLzlohp+DniMQtCSzTVcwjEFBlYQLM= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240714114557-edf1a8d8d022 h1:YOc5Ulfjd4Iw9unao18rXcy/nhrHMWZwutBT3bcc/3I= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240714114557-edf1a8d8d022/go.mod h1:ldNVOQXaljMk4YLzlohp+DniMQtCSzTVcwjEFBlYQLM= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From e627ad878e4b7b69de7bf3216ec694f8159eb2af Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Jul 2024 19:19:02 +0300 Subject: [PATCH 247/718] signalmeow/receiving: handle sync messages sent to PNIs properly * store destination E.164 numbers received in sync messages * fetch PNI identity from server if it isn't found in database when handling PNI signature message --- pkg/connector/chatinfo.go | 12 ++---------- pkg/libsignalgo/serviceid.go | 8 ++++++++ pkg/signalmeow/receiving.go | 20 +++++++++++++++++++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 984a4ef..a851260 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -50,7 +50,7 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( return s.contactToUserInfo(contact), nil } -func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.PortalInfo, error) { +func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { userID, groupID, err := parsePortalID(portal.ID) if err != nil { return nil, err @@ -58,7 +58,7 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) if groupID != "" { return s.getGroupInfo(ctx, groupID, 0) } else { - aci, pni := serviceIDToACIAndPNI(userID) + aci, pni := userID.ToACIAndPNI() contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) if err != nil { return nil, err @@ -251,11 +251,3 @@ func makeAvatarPathID(avatarPath string) networkid.AvatarID { } return networkid.AvatarID("path:" + avatarPath) } - -func serviceIDToACIAndPNI(serviceID libsignalgo.ServiceID) (aci, pni uuid.UUID) { - if serviceID.Type == libsignalgo.ServiceIDTypeACI { - return serviceID.UUID, uuid.Nil - } else { - return uuid.Nil, serviceID.UUID - } -} diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index cd08f4d..5308af1 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -81,6 +81,14 @@ func NewACIServiceID(uuid uuid.UUID) ServiceID { } } +func (s ServiceID) ToACIAndPNI() (aci, pni uuid.UUID) { + if s.Type == ServiceIDTypeACI { + return s.UUID, uuid.Nil + } else { + return uuid.Nil, s.UUID + } +} + func (s ServiceID) IsEmpty() bool { return s.UUID == uuid.Nil } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 96d066a..b28a992 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -734,6 +734,13 @@ func (cli *Client) handleDecryptedResult( log.Err(err).Msg("Sync message destination parse error") return err } + if syncSent.GetDestinationE164() != "" { + aci, pni := syncDestinationServiceID.ToACIAndPNI() + _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) + if err != nil { + log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") + } + } } if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { log.Warn().Msg("sync message sent destination is nil") @@ -913,7 +920,18 @@ func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsign if err != nil { return fmt.Errorf("failed to get identity for PNI %s: %w", pni, err) } else if pniIdentity == nil { - return fmt.Errorf("identity not found for PNI %s", pni) + zerolog.Ctx(ctx).Debug(). + Stringer("aci", sender.UUID). + Stringer("pni", pni). + Msg("Fetching PNI identity for signature verification as it wasn't found in store") + err = cli.FetchAndProcessPreKey(ctx, pniServiceID, 0) + if err != nil { + return fmt.Errorf("failed to fetch prekey for PNI %s after identity wasn't found in store: %w", pni, err) + } else if pniIdentity, err = cli.Store.IdentityKeyStore.GetIdentityKey(ctx, pniServiceID); err != nil { + return fmt.Errorf("failed to get identity for PNI %s after fetching: %w", pni, err) + } else if pniIdentity == nil { + return fmt.Errorf("identity not found for PNI %s even after fetching", pni) + } } aciIdentity, err := cli.Store.IdentityKeyStore.GetIdentityKey(ctx, sender) if err != nil { From b42164a6f5c30d2cd3394bb4fba5262b7d02d358 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 15 Jul 2024 15:40:31 +0300 Subject: [PATCH 248/718] dependencies: update --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index be6c9f1..c3e796a 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240714080209-e8e8154ce82a + go.mau.fi/util v0.5.1-0.20240714204302-8d7c8742a899 golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240714114557-edf1a8d8d022 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240715123557-cb850e3f0293 nhooyr.io/websocket v1.8.11 ) @@ -41,7 +41,7 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.4 // indirect - go.mau.fi/zeroconfig v0.1.2 // indirect + go.mau.fi/zeroconfig v0.1.3 // indirect golang.org/x/sys v0.22.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 0fdbe27..e8999e7 100644 --- a/go.sum +++ b/go.sum @@ -67,10 +67,10 @@ 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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240714080209-e8e8154ce82a h1:m9QJacb5JfXDCdYoi/DvG4/FaHGketCSGzqys3Wyr10= -go.mau.fi/util v0.5.1-0.20240714080209-e8e8154ce82a/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= -go.mau.fi/zeroconfig v0.1.2 h1:DKOydWnhPMn65GbXZOafgkPm11BvFashZWLct0dGFto= -go.mau.fi/zeroconfig v0.1.2/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= +go.mau.fi/util v0.5.1-0.20240714204302-8d7c8742a899 h1:6/4XgDIvH2/4+aQ1WADo7UOmQCiHjx7wd0jjezew7JE= +go.mau.fi/util v0.5.1-0.20240714204302-8d7c8742a899/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= +go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240714114557-edf1a8d8d022 h1:YOc5Ulfjd4Iw9unao18rXcy/nhrHMWZwutBT3bcc/3I= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240714114557-edf1a8d8d022/go.mod h1:ldNVOQXaljMk4YLzlohp+DniMQtCSzTVcwjEFBlYQLM= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240715123557-cb850e3f0293 h1:/9nLAfETGuy4juesa+XYfM0fl2v2DgSVrYjlcG9CB2o= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240715123557-cb850e3f0293/go.mod h1:ji+Od74MtqQk7KYWKmfZ8L6/z+DKNnZafFYvEJHkDEk= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From d94864d1f9dcba2b00c32fdf72299eba364c4450 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 16 Jul 2024 11:50:19 +0300 Subject: [PATCH 249/718] Bump version to v0.6.3 --- CHANGELOG.md | 13 +++++++++++++ go.mod | 4 ++-- go.sum | 8 ++++---- main.go | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f31a4c2..f00f374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# v0.6.3 (2024-07-16) + +* Updated to libsignal v0.52.0. +* Fixed bridge losing track of user phone numbers in some cases. +* Fixed edge cases in handling new outgoing DMs started from other devices. +* Added `sync groups` command (thanks to [@maltee1] in [#490]). +* Fixed typo in location bridging example config + (thanks to [@AndrewFerr] in [#516]). + +[#490]: https://github.com/mautrix/signal/pull/490 +[#516]: https://github.com/mautrix/signal/pull/516 +[@AndrewFerr]: https://github.com/mautrix/signal/pull/516 + # v0.6.2 (2024-06-16) * Updated to libsignal v0.51.0. diff --git a/go.mod b/go.mod index c3e796a..147ab5c 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.5.1-0.20240714204302-8d7c8742a899 + go.mau.fi/util v0.6.0 golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1.0.20240715123557-cb850e3f0293 + maunium.net/go/mautrix v0.19.0 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index e8999e7..00314ae 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.5.1-0.20240714204302-8d7c8742a899 h1:6/4XgDIvH2/4+aQ1WADo7UOmQCiHjx7wd0jjezew7JE= -go.mau.fi/util v0.5.1-0.20240714204302-8d7c8742a899/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4= +go.mau.fi/util v0.6.0 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg= +go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= @@ -93,7 +93,7 @@ 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.19.0-beta.1.0.20240715123557-cb850e3f0293 h1:/9nLAfETGuy4juesa+XYfM0fl2v2DgSVrYjlcG9CB2o= -maunium.net/go/mautrix v0.19.0-beta.1.0.20240715123557-cb850e3f0293/go.mod h1:ji+Od74MtqQk7KYWKmfZ8L6/z+DKNnZafFYvEJHkDEk= +maunium.net/go/mautrix v0.19.0 h1:67eSJWam93mw44Q0/1SiOG7zQzXMUknUv5UaWkrODDU= +maunium.net/go/mautrix v0.19.0/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/main.go b/main.go index 16dbd05..eb24aa0 100644 --- a/main.go +++ b/main.go @@ -331,7 +331,7 @@ func main() { Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.6.2", + Version: "0.6.3", ProtocolName: "Signal", BeeperServiceName: "signal", BeeperNetworkName: "signal", From ef4d776730001e87c6ac281d79c05d5c0cb7831f Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Tue, 16 Jul 2024 19:16:23 -0600 Subject: [PATCH 250/718] flake: remove Signed-off-by: Sumner Evans --- .envrc | 8 ------- flake.lock | 61 ------------------------------------------------------ flake.nix | 33 ----------------------------- 3 files changed, 102 deletions(-) delete mode 100644 .envrc delete mode 100644 flake.lock delete mode 100644 flake.nix diff --git a/.envrc b/.envrc deleted file mode 100644 index 4520fd1..0000000 --- a/.envrc +++ /dev/null @@ -1,8 +0,0 @@ -if [[ $(uname -s) == "Linux" && $(uname --kernel-version | grep "NixOS") ]]; then - echo "The best OS (NixOS) has been detected. Using nice tools." - if ! has nix_direnv_version || ! nix_direnv_version 3.0.0; then - source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.0/direnvrc" "sha256-21TMnI2xWX7HkSTjFFri2UaohXVj854mgvWapWrxRXg=" - fi - - use flake -fi diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 80c5341..0000000 --- a/flake.lock +++ /dev/null @@ -1,61 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1703255338, - "narHash": "sha256-Z6wfYJQKmDN9xciTwU3cOiOk+NElxdZwy/FiHctCzjU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "6df37dc6a77654682fe9f071c62b4242b5342e04", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index cbb2b61..0000000 --- a/flake.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ - description = "mautrix-signal development environment"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, flake-utils }: - (flake-utils.lib.eachDefaultSystem (system: - let pkgs = import nixpkgs { inherit system; }; - in { - devShells.default = pkgs.mkShell { - LIBCLANG_PATH = "${pkgs.llvmPackages_11.libclang.lib}/lib"; - - buildInputs = with pkgs; [ - clang - cmake - gnumake - protobuf - rust-cbindgen - rustup - olm - - go_1_20 - go-tools - gotools - - pre-commit - ]; - }; - })); -} From fd3ef2ebc3b417097a0bfe82418e96ee4d18a806 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Jul 2024 11:58:30 +0300 Subject: [PATCH 251/718] v2: fix edit time limits --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 11 +++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 147ab5c..1288396 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0 + maunium.net/go/mautrix v0.19.1-0.20240717085751-0d81a91c9feb nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 00314ae..174319f 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.0 h1:67eSJWam93mw44Q0/1SiOG7zQzXMUknUv5UaWkrODDU= -maunium.net/go/mautrix v0.19.0/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= +maunium.net/go/mautrix v0.19.1-0.20240717085751-0d81a91c9feb h1:acwViarBwsMMnDRLMNylAfWj9wsrpmMI39O8o0bOXww= +maunium.net/go/mautrix v0.19.1-0.20240717085751-0d81a91c9feb/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 0b92901..2293a33 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -6,6 +6,7 @@ import ( "time" "github.com/rs/zerolog" + "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" @@ -38,7 +39,17 @@ var signalCaps = &bridgev2.NetworkRoomCapabilities{ ReactionCount: 1, } +var signalCapsNoteToSelf *bridgev2.NetworkRoomCapabilities + +func init() { + signalCapsNoteToSelf = ptr.Clone(signalCaps) + signalCapsNoteToSelf.EditMaxAge = 0 +} + func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *bridgev2.NetworkRoomCapabilities { + if portal.Receiver == s.UserLogin.ID && portal.ID == networkid.PortalID(s.UserLogin.ID) { + return signalCapsNoteToSelf + } return signalCaps } From ca460d8021434fb4df804ac48cc214bc810053cb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Jul 2024 12:18:42 +0300 Subject: [PATCH 252/718] v2: fill other user ID in DM portals --- cmd/mautrix-signal-v2/legacymigrate.sql | 3 ++- cmd/mautrix-signal-v2/main.go | 2 +- pkg/connector/chatinfo.go | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index 952dc4d..6ad95b0 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -19,7 +19,7 @@ SELECT FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; INSERT INTO portal ( - bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, + bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, other_user_id, name, topic, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, topic_set, in_space, room_type, disappear_type, disappear_timer, metadata @@ -36,6 +36,7 @@ SELECT '', -- parent_receiver CASE WHEN portal_old.relay_user_id<>'' THEN '' END, -- relay_bridge_id CASE WHEN portal_old.relay_user_id<>'' THEN portal_old.relay_user_id END, -- relay_login_id + CASE WHEN LENGTH(chat_id)=44 THEN NULL ELSE chat_id END, -- other_user_id name, topic, CASE diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 55ef75c..8d7a1c2 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 11), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 12), true, ) } diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index a851260..85758c7 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -215,6 +215,7 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev name = s.Main.Config.FormatDisplayname(recipient) serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) } else { + members.OtherUserID = makeUserID(recipient.ACI) if recipient.ACI == s.Client.Store.ACI { name = NoteToSelfName avatar = &bridgev2.Avatar{ From dc109a254e8e69bed170efe6cfa17561e0ed90b0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 19 Jul 2024 14:10:05 +0300 Subject: [PATCH 253/718] v2: update mautrix-go to get post-migration handling for rooms --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1288396..faa4cee 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240717085751-0d81a91c9feb + maunium.net/go/mautrix v0.19.1-0.20240719110719-b881a7d45511 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 174319f..235a78f 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.1-0.20240717085751-0d81a91c9feb h1:acwViarBwsMMnDRLMNylAfWj9wsrpmMI39O8o0bOXww= -maunium.net/go/mautrix v0.19.1-0.20240717085751-0d81a91c9feb/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= +maunium.net/go/mautrix v0.19.1-0.20240719110719-b881a7d45511 h1:Qbpe6EdaZn4YzNsJTrowWv34afbc1c8OYij58e7Vl70= +maunium.net/go/mautrix v0.19.1-0.20240719110719-b881a7d45511/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 1f3558032237c9987705a9733cc89ddb35925920 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 19 Jul 2024 21:21:39 +0300 Subject: [PATCH 254/718] v2/legacymigrate: add name_is_custom field --- cmd/mautrix-signal-v2/legacymigrate.sql | 3 ++- cmd/mautrix-signal-v2/main.go | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal-v2/legacymigrate.sql index 6ad95b0..9266e9d 100644 --- a/cmd/mautrix-signal-v2/legacymigrate.sql +++ b/cmd/mautrix-signal-v2/legacymigrate.sql @@ -21,7 +21,7 @@ FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; INSERT INTO portal ( bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, other_user_id, name, topic, avatar_id, avatar_hash, avatar_mxc, - name_set, avatar_set, topic_set, in_space, + name_set, avatar_set, topic_set, name_is_custom, in_space, room_type, disappear_type, disappear_timer, metadata ) SELECT @@ -50,6 +50,7 @@ SELECT name_set, avatar_set, topic_set, + CASE WHEN LENGTH(chat_id)=44 THEN true ELSE false END, -- name_is_custom false, -- in_space CASE WHEN LENGTH(chat_id)=44 THEN '' ELSE 'dm' END, -- room_type CASE WHEN expiration_time<>0 THEN 'after_read' END, diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal-v2/main.go index 8d7a1c2..5fe7117 100644 --- a/cmd/mautrix-signal-v2/main.go +++ b/cmd/mautrix-signal-v2/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 12), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 14), true, ) } diff --git a/go.mod b/go.mod index faa4cee..7ab4c53 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.6.0 + go.mau.fi/util v0.6.1-0.20240719175439-20a6073e1dd4 golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240719110719-b881a7d45511 + maunium.net/go/mautrix v0.19.1-0.20240719181800-ea591b0a2e23 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 235a78f..3c2192b 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.6.0 h1:W6SyB3Bm/GjenQ5iq8Z8WWdN85Gy2xS6L0wmnR7SVjg= -go.mau.fi/util v0.6.0/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= +go.mau.fi/util v0.6.1-0.20240719175439-20a6073e1dd4 h1:CYKYs5jwJ0bFJqh6pRoWtC9NIJ0lz0/6i2SC4qEBFaU= +go.mau.fi/util v0.6.1-0.20240719175439-20a6073e1dd4/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= @@ -93,7 +93,7 @@ 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.19.1-0.20240719110719-b881a7d45511 h1:Qbpe6EdaZn4YzNsJTrowWv34afbc1c8OYij58e7Vl70= -maunium.net/go/mautrix v0.19.1-0.20240719110719-b881a7d45511/go.mod h1:UE+mSQ4sDUuJMbjN0aB9EjQSGgXd48AzMvZ6+QJV1k8= +maunium.net/go/mautrix v0.19.1-0.20240719181800-ea591b0a2e23 h1:F3LI6273WRwlpgkjY/5646XAm0xTnCtyZ5BgIqcfVIg= +maunium.net/go/mautrix v0.19.1-0.20240719181800-ea591b0a2e23/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 1978a73888e014d72c99c94337919d60ed2054c0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 22 Jul 2024 21:02:54 +0300 Subject: [PATCH 255/718] docker: fix typo in docker-run.sh --- docker-run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-run.sh b/docker-run.sh index bcc6bc4..fdb22b2 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -18,7 +18,7 @@ function fixperms { if [[ ! -f /data/config.yaml ]]; then if [[ "$BRIDGEV2" == "1" ]]; then - $BINARY_NAME -c /data/config -e + $BINARY_NAME -c /data/config.yaml -e else cp /opt/mautrix-signal/example-config.yaml /data/config.yaml fi From 5027cb591b2c1c673d0c29fbfb52a525f25aca54 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 22 Jul 2024 21:03:02 +0300 Subject: [PATCH 256/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7ab4c53..a6350d2 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240719181800-ea591b0a2e23 + maunium.net/go/mautrix v0.19.1-0.20240722162239-edb026c8a35c nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 3c2192b..aff2e47 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.1-0.20240719181800-ea591b0a2e23 h1:F3LI6273WRwlpgkjY/5646XAm0xTnCtyZ5BgIqcfVIg= -maunium.net/go/mautrix v0.19.1-0.20240719181800-ea591b0a2e23/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= +maunium.net/go/mautrix v0.19.1-0.20240722162239-edb026c8a35c h1:oSYl9jldWBocSwO3yUe0vXxzrV9DeOsa1adisM5nbfc= +maunium.net/go/mautrix v0.19.1-0.20240722162239-edb026c8a35c/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 5d2163056a8fb00556eff5580bad26e6dfdb1bd5 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Mon, 22 Jul 2024 19:14:13 -0400 Subject: [PATCH 257/718] Disable encryption for local bridges (#525) --- pkg/connector/msgconvproxy.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/connector/msgconvproxy.go b/pkg/connector/msgconvproxy.go index 87ebbb9..8dc2db8 100644 --- a/pkg/connector/msgconvproxy.go +++ b/pkg/connector/msgconvproxy.go @@ -18,6 +18,7 @@ package connector import ( "context" + "strings" "google.golang.org/protobuf/proto" "maunium.net/go/mautrix/bridgev2" @@ -108,7 +109,8 @@ func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { AvatarSet: portal.AvatarSet, TopicSet: portal.TopicSet, Revision: portal.Metadata.(*PortalMetadata).Revision, - Encrypted: true, + // Hack to prevent encryption while using the bridge as a "local bridge" + Encrypted: !strings.HasSuffix(portal.Bridge.Matrix.ServerName(), ".localhost"), //RelayUserID: portal.Relay.UserMXID, ExpirationTime: uint32(portal.Disappear.Timer.Seconds()), } From 478a3f14b9bf67cf920f4d9f26a3755729913ec2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 29 Jul 2024 16:41:08 +0300 Subject: [PATCH 258/718] v2: fix message ID when handling incoming edits --- pkg/connector/handlesignal.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 500ec96..ba3f6ff 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -340,6 +340,7 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta Extra: lastPart.Extra, }) convertedEdit.ModifiedParts[0].Part.EditCount++ + convertedEdit.ModifiedParts[0].Part.ID = makeMessageID(evt.Info.Sender, editMsg.GetDataMessage().GetTimestamp()) return convertedEdit, nil } From 570d0542b8f165aea360f8a26f315197ea6b15e7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 30 Jul 2024 16:46:41 +0300 Subject: [PATCH 259/718] dependencies: update --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- pkg/connector/chatinfo.go | 4 ++-- pkg/connector/groupinfo.go | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index a6350d2..a501f5f 100644 --- a/go.mod +++ b/go.mod @@ -13,13 +13,13 @@ require ( github.com/rs/zerolog v1.33.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 - github.com/tidwall/gjson v1.17.1 - go.mau.fi/util v0.6.1-0.20240719175439-20a6073e1dd4 + github.com/tidwall/gjson v1.17.3 + go.mau.fi/util v0.6.1-0.20240722085753-2d7945696c9b golang.org/x/crypto v0.25.0 - golang.org/x/exp v0.0.0-20240707233637-46b078467d37 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240722162239-edb026c8a35c + maunium.net/go/mautrix v0.19.1-0.20240730133608-779f61ac9c69 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index aff2e47..374199d 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= -github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -67,14 +67,14 @@ 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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.6.1-0.20240719175439-20a6073e1dd4 h1:CYKYs5jwJ0bFJqh6pRoWtC9NIJ0lz0/6i2SC4qEBFaU= -go.mau.fi/util v0.6.1-0.20240719175439-20a6073e1dd4/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= +go.mau.fi/util v0.6.1-0.20240722085753-2d7945696c9b h1:8s3uTMPZts03evXLqdTJ0WXB0YWZDNSovpd6oFfCFvY= +go.mau.fi/util v0.6.1-0.20240722085753-2d7945696c9b/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= -golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -93,7 +93,7 @@ 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.19.1-0.20240722162239-edb026c8a35c h1:oSYl9jldWBocSwO3yUe0vXxzrV9DeOsa1adisM5nbfc= -maunium.net/go/mautrix v0.19.1-0.20240722162239-edb026c8a35c/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= +maunium.net/go/mautrix v0.19.1-0.20240730133608-779f61ac9c69 h1:bKO9y6moTiKWBYry5KwhiGmdyZR1xfIX4ujAWt7KuUU= +maunium.net/go/mautrix v0.19.1-0.20240730133608-779f61ac9c69/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 85758c7..732b0ae 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -202,7 +202,7 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev { EventSender: s.makeEventSender(s.Client.Store.ACI), Membership: event.MembershipJoin, - PowerLevel: moderatorPL, + PowerLevel: &moderatorPL, }, }, } @@ -229,7 +229,7 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev members.Members = append(members.Members, bridgev2.ChatMember{ EventSender: s.makeEventSender(recipient.ACI), Membership: event.MembershipJoin, - PowerLevel: moderatorPL, + PowerLevel: &moderatorPL, }) } serviceID = libsignalgo.NewACIServiceID(recipient.ACI) diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 333ed7c..6bea361 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -34,14 +34,14 @@ import ( var defaultPL = 0 var moderatorPL = 50 -func roleToPL(role signalmeow.GroupMemberRole) int { +func roleToPL(role signalmeow.GroupMemberRole) *int { switch role { case signalmeow.GroupMember_ADMINISTRATOR: - return moderatorPL + return &moderatorPL case signalmeow.GroupMember_DEFAULT: fallthrough default: - return defaultPL + return &defaultPL } } From 03995c219ca2c3f71a9884e2e7d46bb489ad73ed Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 30 Jul 2024 16:51:40 +0300 Subject: [PATCH 260/718] libsignal: update to v0.54.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 13 ++++++++++--- pkg/libsignalgo/version.go | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index e13e3de..b86d58e 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit e13e3de8b25c8204b9bb5f04cc50dd12e7f40fc3 +Subproject commit b86d58e8d61e2d6f1687bfd30bd143e3eeeaaf6f diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 0e5e893..0292867 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -196,6 +196,7 @@ typedef enum { SignalErrorCodeSvrRestoreFailed = 151, SignalErrorCodeAppExpired = 160, SignalErrorCodeDeviceDeregistered = 161, + SignalErrorCodeBackupValidation = 170, } SignalErrorCode; /** @@ -376,6 +377,8 @@ typedef struct { SignalOwnedBufferOfusize lengths; } SignalBytestringArray; +typedef SignalBytestringArray SignalStringArray; + typedef struct { const unsigned char *base; size_t length; @@ -660,8 +663,6 @@ typedef struct { typedef SignalFfiChatListenerStruct SignalFfiMakeChatListenerStruct; -typedef SignalBytestringArray SignalStringArray; - typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); typedef int (*SignalSkip)(void *ctx, uint64_t amount); @@ -760,6 +761,8 @@ SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_unknown_fields(const SignalFfiError *err, SignalStringArray *out); + void signal_error_free(SignalFfiError *err); SignalFfiError *signal_identitykeypair_deserialize(SignalPrivateKey **private_key, SignalPublicKey **public_key, SignalBorrowedBuffer input); @@ -1524,6 +1527,8 @@ SignalFfiError *signal_create_otp_from_base64(const char **out, const char *user SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); +SignalFfiError *signal_svr3_migrate(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); + SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); SignalFfiError *signal_svr3_remove(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *enclave_password); @@ -1560,7 +1565,7 @@ SignalFfiError *signal_http_request_new_without_body(SignalHttpRequest **out, co SignalFfiError *signal_http_request_add_header(const SignalHttpRequest *request, const char *name, const char *value); -SignalFfiError *signal_chat_service_new(SignalChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password); +SignalFfiError *signal_chat_service_new(SignalChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password, bool receive_stories); SignalFfiError *signal_chat_service_disconnect(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); @@ -1748,6 +1753,8 @@ SignalFfiError *signal_testing_return_string_array(SignalStringArray *out); SignalFfiError *signal_testing_process_bytestring_array(SignalBytestringArray *out, SignalBorrowedSliceOfBuffers input); +SignalFfiError *signal_testing_input_stream_read_into_zero_length_slice(SignalOwnedBuffer *out, const SignalInputStream *caps_alphabet_input); + SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime); SignalFfiError *signal_testing_only_completes_by_cancellation(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 8191319..59cbbd7 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.52.0" +const Version = "v0.54.0" From 5d2dfa48c7121ca34e8e6ae67d19b69abfa0c33a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 1 Aug 2024 18:20:57 +0300 Subject: [PATCH 261/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a501f5f..b55a072 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240730133608-779f61ac9c69 + maunium.net/go/mautrix v0.19.1-0.20240801151952-a1a245be10db nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 374199d..9088583 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.1-0.20240730133608-779f61ac9c69 h1:bKO9y6moTiKWBYry5KwhiGmdyZR1xfIX4ujAWt7KuUU= -maunium.net/go/mautrix v0.19.1-0.20240730133608-779f61ac9c69/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= +maunium.net/go/mautrix v0.19.1-0.20240801151952-a1a245be10db h1:ouSy8EJgvkopHXPZHaxXDw47wrWLaHOrL6nlcIsvZbA= +maunium.net/go/mautrix v0.19.1-0.20240801151952-a1a245be10db/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 480c2a404e55f2e8a8436a69916d702c4c259636 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 1 Aug 2024 22:15:19 +0300 Subject: [PATCH 262/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b55a072..463bc67 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240801151952-a1a245be10db + maunium.net/go/mautrix v0.19.1-0.20240801191314-7402f5a70501 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 9088583..e22a3ca 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ 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.19.1-0.20240801151952-a1a245be10db h1:ouSy8EJgvkopHXPZHaxXDw47wrWLaHOrL6nlcIsvZbA= -maunium.net/go/mautrix v0.19.1-0.20240801151952-a1a245be10db/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= +maunium.net/go/mautrix v0.19.1-0.20240801191314-7402f5a70501 h1:fikXfFmwO3azwAbBS1Js7MLs657xGZrtyAMFPri9TGc= +maunium.net/go/mautrix v0.19.1-0.20240801191314-7402f5a70501/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 219b3bec1de066d889b802481b6498f522ca05f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 5 Aug 2024 17:36:35 +0300 Subject: [PATCH 263/718] v2: store remote profile info in UserLogin --- go.mod | 5 +-- go.sum | 10 +++--- pkg/connector/client.go | 10 +++--- pkg/connector/dbmeta.go | 10 ++---- pkg/connector/handlesignal.go | 68 ++++++++++++++++++++++++++++------- pkg/connector/login.go | 3 +- 6 files changed, 74 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 463bc67..27964e4 100644 --- a/go.mod +++ b/go.mod @@ -14,12 +14,12 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.6.1-0.20240722085753-2d7945696c9b + go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240801191314-7402f5a70501 + maunium.net/go/mautrix v0.19.1-0.20240804192210-9d6622c29325 nhooyr.io/websocket v1.8.11 ) @@ -43,6 +43,7 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index e22a3ca..054a6be 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.6.1-0.20240722085753-2d7945696c9b h1:8s3uTMPZts03evXLqdTJ0WXB0YWZDNSovpd6oFfCFvY= -go.mau.fi/util v0.6.1-0.20240722085753-2d7945696c9b/go.mod h1:ljYdq3sPfpICc3zMU+/mHV/sa4z0nKxc67hSBwnrk8U= +go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 h1:gJ0peWecBm6TtlxKFVIc1KbooXSCHtPfsfb2Eha5A0A= +go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98/go.mod h1:S1juuPWGau2GctPY3FR/4ec/MDLhAG2QPhdnUwpzWIo= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= @@ -82,6 +82,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -93,7 +95,7 @@ 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.19.1-0.20240801191314-7402f5a70501 h1:fikXfFmwO3azwAbBS1Js7MLs657xGZrtyAMFPri9TGc= -maunium.net/go/mautrix v0.19.1-0.20240801191314-7402f5a70501/go.mod h1:xP3DCXdPBUe1sPiugLbd5mRh/mJQWfGWyED1S8s9V7c= +maunium.net/go/mautrix v0.19.1-0.20240804192210-9d6622c29325 h1:2Ontl4ZDFytmhCKyp5io4HQD+t9bQOZod0lPwtwiXPA= +maunium.net/go/mautrix v0.19.1-0.20240804192210-9d6622c29325/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 2293a33..838c0ee 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -18,6 +18,7 @@ type SignalClient struct { Main *SignalConnector UserLogin *bridgev2.UserLogin Client *signalmeow.Client + Ghost *bridgev2.Ghost } var signalCaps = &bridgev2.NetworkRoomCapabilities{ @@ -218,6 +219,11 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } func (s *SignalClient) Connect(ctx context.Context) error { + if s.Client == nil { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You're not logged into Signal"}) + return nil + } + s.updateRemoteProfile(ctx, false) s.tryConnect(ctx, 0) return nil } @@ -233,10 +239,6 @@ func (s *SignalClient) Disconnect() { } func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { - if s.Client == nil { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You're not logged into Signal"}) - return - } ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") diff --git a/pkg/connector/dbmeta.go b/pkg/connector/dbmeta.go index 18de885..68e21d5 100644 --- a/pkg/connector/dbmeta.go +++ b/pkg/connector/dbmeta.go @@ -29,10 +29,8 @@ func (s *SignalConnector) GetDBMetaTypes() database.MetaTypes { Message: func() any { return &MessageMetadata{} }, - Reaction: nil, - UserLogin: func() any { - return &UserLoginMetadata{} - }, + Reaction: nil, + UserLogin: nil, } } @@ -43,7 +41,3 @@ type PortalMetadata struct { type MessageMetadata struct { ContainsAttachments bool `json:"contains_attachments,omitempty"` } - -type UserLoginMetadata struct { - Phone string `json:"phone"` -} diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index ba3f6ff..169338d 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -19,6 +19,7 @@ package connector import ( "context" "fmt" + "strings" "time" "github.com/google/uuid" @@ -485,19 +486,60 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { log := s.UserLogin.Log.With().Str("action", "handle contact list").Logger() ctx := log.WithContext(context.TODO()) for _, contact := range evt.Contacts { - if contact.ACI != uuid.Nil { - fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) - if err != nil { - log.Err(err).Msg("Failed to get full contact info from store") - continue - } - fullContact.ContactAvatar = contact.ContactAvatar - ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(contact.ACI)) - if err != nil { - log.Err(err).Msg("Failed to get ghost to update contact info") - continue - } - ghost.UpdateInfo(ctx, s.contactToUserInfo(contact)) + if contact.ACI == uuid.Nil { + continue + } + fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) + if err != nil { + log.Err(err).Msg("Failed to get full contact info from store") + continue + } + fullContact.ContactAvatar = contact.ContactAvatar + ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(contact.ACI)) + if err != nil { + log.Err(err).Msg("Failed to get ghost to update contact info") + continue + } + ghost.UpdateInfo(ctx, s.contactToUserInfo(contact)) + if contact.ACI == s.Client.Store.ACI { + s.updateRemoteProfile(ctx, true) + } + } +} + +func (s *SignalClient) updateRemoteProfile(ctx context.Context, resendState bool) { + var err error + if s.Ghost == nil { + s.Ghost, err = s.Main.Bridge.GetGhostByID(ctx, makeUserID(s.Client.Store.ACI)) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get ghost for remote profile update") + return + } + } + changed := false + if s.UserLogin.RemoteProfile.Name != s.Ghost.Name { + s.UserLogin.RemoteProfile.Name = s.Ghost.Name + changed = true + } + if s.UserLogin.RemoteProfile.Avatar != s.Ghost.AvatarMXC { + s.UserLogin.RemoteProfile.Avatar = s.Ghost.AvatarMXC + changed = true + } + if len(s.Ghost.Identifiers) > 0 && strings.HasPrefix(s.Ghost.Identifiers[0], "tel:") { + phone := strings.TrimPrefix(s.Ghost.Identifiers[0], "tel:") + if s.UserLogin.RemoteProfile.Phone != phone { + s.UserLogin.RemoteProfile.Phone = phone + changed = true + } + } + if changed { + err = s.UserLogin.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save updated remote profile") + } + if resendState { + // TODO this has potential race conditions + s.UserLogin.BridgeState.Send(s.UserLogin.BridgeState.GetPrevUnsent()) } } } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 82ddac5..3acd926 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/google/uuid" + "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -159,7 +160,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err ul, err := qr.User.NewLogin(ctx, &database.UserLogin{ ID: newLoginID, RemoteName: qr.ProvData.Number, - Metadata: &UserLoginMetadata{ + RemoteProfile: status.RemoteProfile{ Phone: qr.ProvData.Number, }, }, &bridgev2.NewLoginParams{ From c246473b52533624083635ddb9d623fe5eb2f405 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Aug 2024 00:45:01 +0300 Subject: [PATCH 264/718] v2: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 27964e4..a04e88a 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240804192210-9d6622c29325 + maunium.net/go/mautrix v0.19.1-0.20240806214251-e0f58dccf432 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 054a6be..50a5dcc 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,7 @@ 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.19.1-0.20240804192210-9d6622c29325 h1:2Ontl4ZDFytmhCKyp5io4HQD+t9bQOZod0lPwtwiXPA= -maunium.net/go/mautrix v0.19.1-0.20240804192210-9d6622c29325/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= +maunium.net/go/mautrix v0.19.1-0.20240806214251-e0f58dccf432 h1:Gz1nMg/s4B0VZD4e31wfaghR5cSk2NQVuQkxdCBuI7o= +maunium.net/go/mautrix v0.19.1-0.20240806214251-e0f58dccf432/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 0c9f2c19d22f8d8021748eaaa387d35b0e448247 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Aug 2024 02:14:39 +0300 Subject: [PATCH 265/718] all: delete legacy bridge --- .gitignore | 2 - .gitlab-ci.yml | 7 +- .pre-commit-config.yaml | 6 +- CHANGELOG.md | 6 + Dockerfile.ci | 14 - Makefile | 28 - ROADMAP.md | 14 +- build-go-v2.sh | 9 - build-go.sh | 4 +- build-v2.sh | 6 +- build.sh | 4 - .../legacymigrate.go | 0 .../legacymigrate.sql | 0 .../legacyprovision.go | 118 +- .../main.go | 0 commands.go | 1161 ------- config/bridge.go | 241 -- config/config.go | 44 - config/upgrade.go | 167 - custompuppet.go | 97 - database/database.go | 53 - database/disappearingmessage.go | 125 - database/lostportal.go | 58 - database/message.go | 179 - database/portal.go | 206 -- database/puppet.go | 158 - database/reaction.go | 97 - database/upgrades/00-latest.sql | 116 - .../upgrades/13-upgrade-mx-state-store.sql | 18 - database/upgrades/14-remove-notice-room.sql | 3 - .../15-remove-unused-puppet-columns.sql | 3 - database/upgrades/16-refactor-postgres.sql | 123 - database/upgrades/17-refactor-sqlite.sql | 198 -- database/upgrades/18-spaces.sql | 17 - database/upgrades/19-more-portal-metadata.sql | 5 - .../upgrades/20-puppet-profile-fetch-ts.sql | 2 - database/user.go | 115 - database/userportal.go | 116 - disappearing.go | 156 - docker-run.sh | 6 +- example-config.yaml | 317 -- go.mod | 3 + legacyprovision/types.go | 92 - main.go | 352 -- messagetracking.go | 311 -- metrics.go | 281 -- msgconv/msgconv.go | 65 - pkg/connector/chatinfo.go | 17 +- pkg/connector/client.go | 3 +- pkg/connector/connector.go | 69 +- pkg/connector/dbmeta.go | 14 +- pkg/connector/groupinfo.go | 3 +- pkg/connector/handlematrix.go | 62 +- pkg/connector/handlesignal.go | 92 +- pkg/connector/id.go | 88 +- pkg/connector/login.go | 3 +- pkg/connector/msgconvproxy.go | 117 - {msgconv => pkg/msgconv}/from-matrix.go | 83 +- {msgconv => pkg/msgconv}/from-signal.go | 226 +- {msgconv => pkg/msgconv}/matrixfmt/convert.go | 0 .../msgconv}/matrixfmt/convert_test.go | 4 +- {msgconv => pkg/msgconv}/matrixfmt/html.go | 2 +- pkg/msgconv/msgconv.go | 107 + {msgconv => pkg/msgconv}/signalfmt/convert.go | 0 .../msgconv}/signalfmt/convert_test.go | 2 +- {msgconv => pkg/msgconv}/signalfmt/html.go | 0 {msgconv => pkg/msgconv}/signalfmt/tags.go | 0 {msgconv => pkg/msgconv}/signalfmt/tree.go | 0 {msgconv => pkg/msgconv}/urlpreview.go | 71 +- .../upgrades.go => pkg/signalid/dbmeta.go | 31 +- pkg/signalid/ids.go | 105 + portal.go | 3026 ----------------- provisioning.go | 640 ---- puppet.go | 411 --- user.go | 1020 ------ 75 files changed, 562 insertions(+), 10737 deletions(-) delete mode 100644 Dockerfile.ci delete mode 100644 Makefile delete mode 100755 build-go-v2.sh delete mode 100755 build.sh rename cmd/{mautrix-signal-v2 => mautrix-signal}/legacymigrate.go (100%) rename cmd/{mautrix-signal-v2 => mautrix-signal}/legacymigrate.sql (100%) rename cmd/{mautrix-signal-v2 => mautrix-signal}/legacyprovision.go (69%) rename cmd/{mautrix-signal-v2 => mautrix-signal}/main.go (100%) delete mode 100644 commands.go delete mode 100644 config/bridge.go delete mode 100644 config/config.go delete mode 100644 config/upgrade.go delete mode 100644 custompuppet.go delete mode 100644 database/database.go delete mode 100644 database/disappearingmessage.go delete mode 100644 database/lostportal.go delete mode 100644 database/message.go delete mode 100644 database/portal.go delete mode 100644 database/puppet.go delete mode 100644 database/reaction.go delete mode 100644 database/upgrades/00-latest.sql delete mode 100644 database/upgrades/13-upgrade-mx-state-store.sql delete mode 100644 database/upgrades/14-remove-notice-room.sql delete mode 100644 database/upgrades/15-remove-unused-puppet-columns.sql delete mode 100644 database/upgrades/16-refactor-postgres.sql delete mode 100644 database/upgrades/17-refactor-sqlite.sql delete mode 100644 database/upgrades/18-spaces.sql delete mode 100644 database/upgrades/19-more-portal-metadata.sql delete mode 100644 database/upgrades/20-puppet-profile-fetch-ts.sql delete mode 100644 database/user.go delete mode 100644 database/userportal.go delete mode 100644 disappearing.go delete mode 100644 example-config.yaml delete mode 100644 legacyprovision/types.go delete mode 100644 main.go delete mode 100644 messagetracking.go delete mode 100644 metrics.go delete mode 100644 msgconv/msgconv.go delete mode 100644 pkg/connector/msgconvproxy.go rename {msgconv => pkg/msgconv}/from-matrix.go (74%) rename {msgconv => pkg/msgconv}/from-signal.go (72%) rename {msgconv => pkg/msgconv}/matrixfmt/convert.go (100%) rename {msgconv => pkg/msgconv}/matrixfmt/convert_test.go (97%) rename {msgconv => pkg/msgconv}/matrixfmt/html.go (99%) create mode 100644 pkg/msgconv/msgconv.go rename {msgconv => pkg/msgconv}/signalfmt/convert.go (100%) rename {msgconv => pkg/msgconv}/signalfmt/convert_test.go (99%) rename {msgconv => pkg/msgconv}/signalfmt/html.go (100%) rename {msgconv => pkg/msgconv}/signalfmt/tags.go (100%) rename {msgconv => pkg/msgconv}/signalfmt/tree.go (100%) rename {msgconv => pkg/msgconv}/urlpreview.go (53%) rename database/upgrades/upgrades.go => pkg/signalid/dbmeta.go (54%) create mode 100644 pkg/signalid/ids.go delete mode 100644 portal.go delete mode 100644 provisioning.go delete mode 100644 puppet.go delete mode 100644 user.go diff --git a/.gitignore b/.gitignore index 0031287..ab00deb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,5 @@ *.log* /mautrix-signal -/mautrix-signalgo -/mautrix-signal-v2 /start /libsignal_ffi.a diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 03bd8f5..952dabc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,17 +1,12 @@ include: -- project: 'mautrix/ci' - file: '/go.yml' - project: 'mautrix/ci' file: '/gov2.yml' variables: BUILDER_IMAGE: dock.mau.dev/tulir/gomuks-build-docker/signal + BINARY_NAME_V2: mautrix-signal # 32-bit arm builds aren't supported -build arm: - rules: - - when: never - build arm v2: rules: - when: never diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b22a061..8a667b3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace exclude_types: [markdown] @@ -18,11 +18,11 @@ repos: - "go.mau.fi/mautrix-signal" - "-w" - id: go-vet-mod - #- id: go-staticcheck-repo-mod +# - id: go-staticcheck-repo-mod # TODO: reenable this and fix all the problems - repo: https://github.com/beeper/pre-commit-go - rev: v0.3.0 + rev: v0.3.1 hooks: - id: zerolog-ban-msgf - id: zerolog-use-stringer diff --git a/CHANGELOG.md b/CHANGELOG.md index f00f374..f0c11f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v0.7.0 (unreleased) + +* Updated to libsignal v0.54.0. +* Rewrote bridge using bridgev2 architecture. + * It is recommended to check the config file after upgrading. + # v0.6.3 (2024-07-16) * Updated to libsignal v0.52.0. diff --git a/Dockerfile.ci b/Dockerfile.ci deleted file mode 100644 index e75845e..0000000 --- a/Dockerfile.ci +++ /dev/null @@ -1,14 +0,0 @@ -FROM alpine:3.19 - -ENV UID=1337 \ - GID=1337 - -RUN apk add --no-cache ffmpeg su-exec ca-certificates bash jq curl yq - -ARG EXECUTABLE=./mautrix-signal -COPY $EXECUTABLE /usr/bin/mautrix-signal -COPY ./example-config.yaml /opt/mautrix-signal/example-config.yaml -COPY ./docker-run.sh /docker-run.sh -VOLUME /data - -CMD ["/docker-run.sh"] diff --git a/Makefile b/Makefile deleted file mode 100644 index b497635..0000000 --- a/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -.PHONY: all build_rust copy_library build_go clean - -all: build_rust copy_library build_go - -LIBRARY_FILENAME=libsignal_ffi.a -RUST_DIR=pkg/libsignalgo/libsignal -GO_BINARY=mautrix-signal - -# TODO fix linking with debug library -#ifneq ($(DBG),1) -RUST_TARGET_SUBDIR=release -#else -#RUST_TARGET_SUBDIR=debug -#endif - -build_rust: - ./build-rust.sh - -copy_library: - cp $(RUST_DIR)/target/$(RUST_TARGET_SUBDIR)/$(LIBRARY_FILENAME) . - -build_go: - LIBRARY_PATH="$${LIBRARY_PATH}:." ./build-go.sh - -clean: - rm -f ./$(LIBRARY_FILENAME) - cd $(RUST_DIR) && cargo clean - rm -f $(GO_BINARY) diff --git a/ROADMAP.md b/ROADMAP.md index 85c7494..9c0cedb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,17 +1,17 @@ # Features & roadmap * Matrix → Signal - * [ ] Message content + * [x] Message content * [x] Text * [x] Formatting * [x] Mentions - * [ ] Media + * [x] Media * [x] Images * [x] Audio files * [x] Voice messages * [x] Files * [x] Gifs - * [ ] Locations + * [x] Locations * [x] Stickers * [x] Message edits * [x] Message reactions @@ -22,9 +22,9 @@ * [x] Topic * [ ] Membership actions * [ ] Join (accepting invites) - * [x] Invite - * [x] Leave - * [x] Kick/Ban/Unban + * [ ] Invite + * [ ] Leave + * [ ] Kick/Ban/Unban * [x] Group permissions * [x] Typing notifications * [x] Read receipts @@ -70,5 +70,5 @@ * [x] When receiving message * [x] Linking as secondary device * [ ] Registering as primary device - * [x] Private chat/group creation by inviting Matrix puppet of Signal user to new room + * [ ] Private chat/group creation by inviting Matrix puppet of Signal user to new room * [x] Option to use own Matrix account for messages sent from other Signal clients diff --git a/build-go-v2.sh b/build-go-v2.sh deleted file mode 100755 index 199f474..0000000 --- a/build-go-v2.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -MAUTRIX_VERSION=$(cat go.mod | grep 'maunium.net/go/mautrix ' | awk '{ print $2 }') -GO_LDFLAGS="-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date -Iseconds`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" -if [ "$DBG" = 1 ]; then - GO_GCFLAGS='all=-N -l' -else - GO_LDFLAGS="-s -w ${GO_LDFLAGS}" -fi -go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal-v2 ./cmd/mautrix-signal-v2 "$@" diff --git a/build-go.sh b/build-go.sh index ecf8907..faaac6f 100755 --- a/build-go.sh +++ b/build-go.sh @@ -1,9 +1,9 @@ #!/bin/sh MAUTRIX_VERSION=$(cat go.mod | grep 'maunium.net/go/mautrix ' | awk '{ print $2 }') -GO_LDFLAGS="-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date '+%b %_d %Y, %H:%M:%S'`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" +GO_LDFLAGS="-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=`date -Iseconds`' -X 'maunium.net/go/mautrix.GoModVersion=$MAUTRIX_VERSION'" if [ "$DBG" = 1 ]; then GO_GCFLAGS='all=-N -l' else GO_LDFLAGS="-s -w ${GO_LDFLAGS}" fi -go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal "$@" +go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal ./cmd/mautrix-signal "$@" diff --git a/build-v2.sh b/build-v2.sh index b541932..2b51084 100755 --- a/build-v2.sh +++ b/build-v2.sh @@ -1,4 +1,4 @@ #!/bin/sh -#./build-rust.sh -#cp -f pkg/libsignalgo/libsignal/target/release/libsignal_ffi.a . -LIBRARY_PATH=.:$LIBRARY_PATH ./build-go-v2.sh +./build-rust.sh +cp -f pkg/libsignalgo/libsignal/target/release/libsignal_ffi.a . +LIBRARY_PATH=.:$LIBRARY_PATH ./build-go.sh diff --git a/build.sh b/build.sh deleted file mode 100755 index b17ad4f..0000000 --- a/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -git submodule init -git submodule update -make diff --git a/cmd/mautrix-signal-v2/legacymigrate.go b/cmd/mautrix-signal/legacymigrate.go similarity index 100% rename from cmd/mautrix-signal-v2/legacymigrate.go rename to cmd/mautrix-signal/legacymigrate.go diff --git a/cmd/mautrix-signal-v2/legacymigrate.sql b/cmd/mautrix-signal/legacymigrate.sql similarity index 100% rename from cmd/mautrix-signal-v2/legacymigrate.sql rename to cmd/mautrix-signal/legacymigrate.sql diff --git a/cmd/mautrix-signal-v2/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go similarity index 69% rename from cmd/mautrix-signal-v2/legacyprovision.go rename to cmd/mautrix-signal/legacyprovision.go index b3c3f80..8e8e752 100644 --- a/cmd/mautrix-signal-v2/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -28,8 +28,8 @@ import ( "github.com/rs/zerolog" "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/id" - "go.mau.fi/mautrix-signal/legacyprovision" "go.mau.fi/mautrix-signal/pkg/connector" ) @@ -54,7 +54,7 @@ func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { user := m.Matrix.Provisioning.GetUser(r) defLogin := user.GetDefaultLogin() if defLogin != nil && defLogin.Client != nil && defLogin.Client.IsLoggedIn() { - legacyprovision.JSONResponse(w, http.StatusConflict, &legacyprovision.Error{ + JSONResponse(w, http.StatusConflict, &Error{ Error: "Already logged in", ErrCode: "FI.MAU.ALREADY_LOGGED_IN", }) @@ -64,7 +64,7 @@ func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { login, err := m.Connector.CreateLogin(r.Context(), user, "qr") if err != nil { log.Err(err).Msg("Failed to create login") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, &Error{ Error: "Internal error starting login", ErrCode: "M_UNKNOWN", }) @@ -73,14 +73,14 @@ func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { firstStep, err := login.Start(r.Context()) if err != nil { log.Err(err).Msg("Failed to start login") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, &Error{ Error: "Internal error starting login", ErrCode: "M_UNKNOWN", }) return } else if firstStep.StepID != connector.LoginStepQR || firstStep.Type != bridgev2.LoginStepTypeDisplayAndWait || firstStep.DisplayAndWaitParams.Type != bridgev2.LoginDisplayTypeQR { log.Error().Any("first_step", firstStep).Msg("Unexpected first step") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, &Error{ Error: "Unexpected first login step", ErrCode: "M_UNKNOWN", }) @@ -93,7 +93,7 @@ func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { User: user, } loginSessionsLock.Unlock() - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ + JSONResponse(w, http.StatusOK, Response{ Success: true, Status: "provisioning_url_received", SessionID: strconv.Itoa(int(handleID)), @@ -102,10 +102,10 @@ func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { } func getLoginProcess(w http.ResponseWriter, r *http.Request) *legacyLoginProcess { - var body legacyprovision.LinkWaitForAccountRequest + var body LinkWaitForAccountRequest err := json.NewDecoder(r.Body).Decode(&body) if err != nil { - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ + JSONResponse(w, http.StatusBadRequest, Error{ Success: false, Error: "Error decoding JSON body", ErrCode: mautrix.MBadJSON.ErrCode, @@ -114,7 +114,7 @@ func getLoginProcess(w http.ResponseWriter, r *http.Request) *legacyLoginProcess } sessionID, err := strconv.Atoi(body.SessionID) if err != nil { - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ + JSONResponse(w, http.StatusBadRequest, Error{ Success: false, Error: "Error decoding session ID in JSON body", ErrCode: mautrix.MBadJSON.ErrCode, @@ -124,7 +124,7 @@ func getLoginProcess(w http.ResponseWriter, r *http.Request) *legacyLoginProcess process, ok := loginSessions[uint32(sessionID)] user := m.Matrix.Provisioning.GetUser(r) if !ok || process.User != user { - legacyprovision.JSONResponse(w, http.StatusNotFound, legacyprovision.Error{ + JSONResponse(w, http.StatusNotFound, Error{ Success: false, Error: "No session found", ErrCode: mautrix.MNotFound.ErrCode, @@ -142,7 +142,7 @@ func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to log in") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, Error{ Error: "Failed to log in", ErrCode: "M_UNKNOWN", }) @@ -150,14 +150,14 @@ func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { return } else if res.StepID != connector.LoginStepProcess { zerolog.Ctx(r.Context()).Error().Any("first_step", res).Msg("Unexpected login step") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, Error{ Error: "Unexpected login step", ErrCode: "M_UNKNOWN", }) login.Delete() return } - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ + JSONResponse(w, http.StatusOK, Response{ Success: true, Status: "provisioning_data_received", }) @@ -171,18 +171,18 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to log in") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, Error{ Error: "Failed to log in", ErrCode: "M_UNKNOWN", }) } else if res.StepID != connector.LoginStepComplete || res.Type != bridgev2.LoginStepTypeComplete { zerolog.Ctx(r.Context()).Error().Any("first_step", res).Msg("Unexpected login step") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, Error{ Error: "Unexpected login step", ErrCode: "M_UNKNOWN", }) } else { - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ + JSONResponse(w, http.StatusOK, Response{ Success: true, Status: "prekeys_registered", UUID: string(res.CompleteParams.UserLogin.ID), @@ -194,7 +194,7 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { func legacyProvLogout(w http.ResponseWriter, r *http.Request) { // No-op for backwards compatibility - legacyprovision.JSONResponse(w, http.StatusOK, nil) + JSONResponse(w, http.StatusOK, nil) } func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, create bool) { @@ -206,21 +206,21 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, resp, err := api.ResolveIdentifier(r.Context(), mux.Vars(r)["phonenum"], create) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to resolve identifier") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, &legacyprovision.Error{ + JSONResponse(w, http.StatusInternalServerError, &Error{ Error: fmt.Sprintf("Failed to resolve identifier: %v", err), ErrCode: "M_UNKNOWN", }) return } else if resp == nil { - legacyprovision.JSONResponse(w, http.StatusNotFound, &legacyprovision.Error{ + JSONResponse(w, http.StatusNotFound, &Error{ ErrCode: mautrix.MNotFound.ErrCode, Error: "User not found on Signal", }) return } status := http.StatusOK - apiResp := &legacyprovision.ResolveIdentifierResponse{ - ChatID: legacyprovision.ResolveIdentifierResponseChatID{ + apiResp := &ResolveIdentifierResponse{ + ChatID: ResolveIdentifierResponseChatID{ UUID: string(resp.UserID), Number: "", }, @@ -229,7 +229,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, if resp.UserInfo != nil { resp.Ghost.UpdateInfo(r.Context(), resp.UserInfo) } - apiResp.OtherUser = &legacyprovision.ResolveIdentifierResponseOtherUser{ + apiResp.OtherUser = &ResolveIdentifierResponseOtherUser{ MXID: resp.Ghost.Intent.GetMXID(), DisplayName: resp.Ghost.Name, AvatarURL: resp.Ghost.AvatarMXC.ParseOrIgnore(), @@ -240,7 +240,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, resp.Chat.Portal, err = m.Bridge.GetPortalByKey(r.Context(), resp.Chat.PortalKey) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to get portal") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ + JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ Err: "Failed to get portal", ErrCode: "M_UNKNOWN", }) @@ -253,7 +253,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, err = resp.Chat.Portal.CreateMatrixRoom(r.Context(), login, resp.Chat.PortalInfo) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to create portal room") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ + JSONResponse(w, http.StatusInternalServerError, &mautrix.RespError{ Err: "Failed to create portal room", ErrCode: "M_UNKNOWN", }) @@ -262,7 +262,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, } apiResp.RoomID = resp.Chat.Portal.MXID } - legacyprovision.JSONResponse(w, status, &legacyprovision.Response{ + JSONResponse(w, status, &Response{ Success: true, Status: "ok", ResolveIdentifierResponse: apiResp, @@ -276,3 +276,71 @@ func legacyProvResolveIdentifier(w http.ResponseWriter, r *http.Request) { func legacyProvPM(w http.ResponseWriter, r *http.Request) { legacyResolveIdentifierOrStartChat(w, r, true) } + +func JSONResponse(w http.ResponseWriter, status int, response any) { + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(status) + _ = json.NewEncoder(w).Encode(response) +} + +type Error struct { + Success bool `json:"success"` + Error string `json:"error"` + ErrCode string `json:"errcode"` +} + +type Response struct { + Success bool `json:"success"` + Status string `json:"status"` + + // For response in LinkNew + SessionID string `json:"session_id,omitempty"` + URI string `json:"uri,omitempty"` + + // For response in LinkWaitForAccount + UUID string `json:"uuid,omitempty"` + Number string `json:"number,omitempty"` + + // For response in ResolveIdentifier + *ResolveIdentifierResponse +} + +type WhoAmIResponse struct { + Permissions int `json:"permissions"` + MXID string `json:"mxid"` + Signal *WhoAmIResponseSignal `json:"signal,omitempty"` +} + +type WhoAmIResponseSignal struct { + Number string `json:"number"` + UUID string `json:"uuid"` + Name string `json:"name"` + Ok bool `json:"ok"` +} + +type ResolveIdentifierResponse struct { + RoomID id.RoomID `json:"room_id"` + ChatID ResolveIdentifierResponseChatID `json:"chat_id"` + JustCreated bool `json:"just_created"` + OtherUser *ResolveIdentifierResponseOtherUser `json:"other_user,omitempty"` +} + +type ResolveIdentifierResponseChatID struct { + UUID string `json:"uuid"` + Number string `json:"number"` +} + +type ResolveIdentifierResponseOtherUser struct { + MXID id.UserID `json:"mxid"` + DisplayName string `json:"displayname"` + AvatarURL id.ContentURI `json:"avatar_url"` +} + +type LinkWaitForScanRequest struct { + SessionID string `json:"session_id"` +} + +type LinkWaitForAccountRequest struct { + SessionID string `json:"session_id"` + DeviceName string `json:"device_name"` // TODO this seems to not be used anywhere +} diff --git a/cmd/mautrix-signal-v2/main.go b/cmd/mautrix-signal/main.go similarity index 100% rename from cmd/mautrix-signal-v2/main.go rename to cmd/mautrix-signal/main.go diff --git a/commands.go b/commands.go deleted file mode 100644 index 7600d66..0000000 --- a/commands.go +++ /dev/null @@ -1,1161 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "strconv" - "strings" - - "github.com/google/uuid" - "github.com/rs/zerolog" - "github.com/skip2/go-qrcode" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/bridge/commands" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" -) - -var ( - HelpSectionConnectionManagement = commands.HelpSection{Name: "Connection management", Order: 11} - HelpSectionCreatingPortals = commands.HelpSection{Name: "Creating portals", Order: 15} - HelpSectionPortalManagement = commands.HelpSection{Name: "Portal management", Order: 20} - HelpSectionInvites = commands.HelpSection{Name: "Group invites", Order: 25} - HelpSectionMiscellaneous = commands.HelpSection{Name: "Miscellaneous", Order: 30} -) - -type WrappedCommandEvent struct { - *commands.Event - Bridge *SignalBridge - User *User - Portal *Portal -} - -func (br *SignalBridge) RegisterCommands() { - proc := br.CommandProcessor.(*commands.Processor) - proc.AddHandlers( - cmdPing, - cmdLogin, - cmdSetDeviceName, - cmdPM, - cmdResolvePhone, - cmdSync, - cmdDeleteSession, - cmdSetRelay, - cmdUnsetRelay, - cmdDeletePortal, - cmdDeleteAllPortals, - cmdCleanupLostPortals, - cmdInviteLink, - cmdResetInviteLink, - cmdCreate, - cmdInvite, - cmdListInvited, - cmdRevokeInvite, - ) -} - -func wrapCommand(handler func(*WrappedCommandEvent)) func(*commands.Event) { - return func(ce *commands.Event) { - user := ce.User.(*User) - var portal *Portal - if ce.Portal != nil { - portal = ce.Portal.(*Portal) - } - br := ce.Bridge.Child.(*SignalBridge) - handler(&WrappedCommandEvent{ce, br, user, portal}) - } -} - -var cmdSetRelay = &commands.FullHandler{ - Func: wrapCommand(fnSetRelay), - Name: "set-relay", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Relay messages in this room through your Signal account.", - }, - RequiresPortal: true, - RequiresLogin: true, -} - -func fnSetRelay(ce *WrappedCommandEvent) { - if !ce.Bridge.Config.Bridge.Relay.Enabled { - ce.Reply("Relay mode is not enabled on this instance of the bridge") - } else if ce.Bridge.Config.Bridge.Relay.AdminOnly && !ce.User.Admin { - ce.Reply("Only bridge admins are allowed to enable relay mode on this instance of the bridge") - } else { - ce.Portal.RelayUserID = ce.User.MXID - ce.Portal.Update(ce.Ctx) - ce.Reply("Messages from non-logged-in users in this room will now be bridged through your Signal account") - } -} - -var cmdUnsetRelay = &commands.FullHandler{ - Func: wrapCommand(fnUnsetRelay), - Name: "unset-relay", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Stop relaying messages in this room.", - }, - RequiresPortal: true, -} - -func fnUnsetRelay(ce *WrappedCommandEvent) { - if !ce.Bridge.Config.Bridge.Relay.Enabled { - ce.Reply("Relay mode is not enabled on this instance of the bridge") - } else if ce.Bridge.Config.Bridge.Relay.AdminOnly && !ce.User.Admin { - ce.Reply("Only bridge admins are allowed to enable relay mode on this instance of the bridge") - } else { - ce.Portal.RelayUserID = "" - ce.Portal.Update(ce.Ctx) - ce.Reply("Messages from non-logged-in users will no longer be bridged in this room") - } -} - -var cmdDeleteSession = &commands.FullHandler{ - Func: wrapCommand(fnDeleteSession), - Name: "delete-session", - Help: commands.HelpMeta{ - Section: HelpSectionConnectionManagement, - Description: "Disconnect from Signal, clearing sessions but keeping other data. Reconnect with `login`", - }, -} - -func fnDeleteSession(ce *WrappedCommandEvent) { - if !ce.User.IsLoggedIn() { - ce.Reply("You're not logged in") - return - } - ce.User.Client.ClearKeysAndDisconnect(ce.Ctx) - ce.Reply("Disconnected from Signal") -} - -var cmdPing = &commands.FullHandler{ - Func: wrapCommand(fnPing), - Name: "ping", - Help: commands.HelpMeta{ - Section: commands.HelpSectionAuth, - Description: "Check your connection to Signal", - }, -} - -func fnPing(ce *WrappedCommandEvent) { - if ce.User.SignalID == uuid.Nil { - ce.Reply("You're not logged in") - } else if !ce.User.IsLoggedIn() { - ce.Reply("You were logged in at some point, but are not anymore") - } else if !ce.User.Client.IsConnected() { - ce.Reply("You're logged into Signal, but not connected to the server") - } else { - ce.Reply("You're logged into Signal and probably connected to the server") - } -} - -var cmdSetDeviceName = &commands.FullHandler{ - Func: wrapCommand(fnSetDeviceName), - Name: "set-device-name", - Help: commands.HelpMeta{ - Section: HelpSectionConnectionManagement, - Description: "Set the name of this device in Signal", - Args: "", - }, - RequiresLogin: true, -} - -func fnSetDeviceName(ce *WrappedCommandEvent) { - if len(ce.Args) == 0 { - ce.Reply("**Usage:** `set-device-name `") - return - } - - name := strings.Join(ce.Args, " ") - err := ce.User.Client.UpdateDeviceName(ce.Ctx, name) - if err != nil { - ce.Reply("Error setting device name: %v", err) - return - } - ce.Reply("Device name updated") -} - -var cmdPM = &commands.FullHandler{ - Func: wrapCommand(fnPM), - Name: "pm", - Help: commands.HelpMeta{ - Section: HelpSectionCreatingPortals, - Description: "Open a private chat with the given phone number.", - Args: "<_international phone number_>", - }, - RequiresLogin: true, -} - -var numberCleaner = strings.NewReplacer("-", "", " ", "", "(", "", ")", "", "+", "") - -func fnPM(ce *WrappedCommandEvent) { - if len(ce.Args) == 0 { - ce.Reply("**Usage:** `pm `") - return - } - number, err := strconv.ParseUint(numberCleaner.Replace(strings.Join(ce.Args, "")), 10, 64) - if err != nil { - ce.Reply("Failed to parse number") - return - } - - user := ce.User - var aci, pni uuid.UUID - e164 := fmt.Sprintf("+%d", number) - var recipient *types.Recipient - - if recipient, err = user.Client.ContactByE164(ce.Ctx, e164); err != nil { - ce.Reply("Error looking up number in local contact list: %v", err) - return - } else if recipient != nil && (recipient.ACI != uuid.Nil || recipient.PNI != uuid.Nil) { - // TODO maybe lookup PNI if there's only ACI and E164 stored? - aci = recipient.ACI - pni = recipient.PNI - } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { - ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") - ce.Reply("Error looking up number on server: %v", err) - return - } else { - aci = resp[number].ACI - pni = resp[number].PNI - if aci == uuid.Nil && pni == uuid.Nil { - ce.Reply("+%d doesn't seem to be on Signal", number) - return - } - recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ce.Ctx, aci, pni, e164) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to save recipient entry after looking up phone") - } - aci, pni = recipient.ACI, recipient.PNI - } - ce.ZLog.Debug(). - Uint64("e164", number). - Stringer("aci", aci). - Stringer("pni", pni). - Msg("Found DM target user") - - var targetServiceID libsignalgo.ServiceID - if aci != uuid.Nil { - targetServiceID = libsignalgo.NewACIServiceID(aci) - } else { - targetServiceID = libsignalgo.NewPNIServiceID(pni) - } - portal := user.GetPortalByChatID(targetServiceID.String()) - if portal == nil { - ce.Reply("Couldn't get portal with %s/+%d", targetServiceID, number) - return - } else if portal.MXID != "" { - ok := portal.ensureUserInvited(ce.Ctx, ce.User) - if ok { - ce.Reply("You already have a portal with +%d at [%s](%s)", number, portal.MXID, portal.MXID.URI(portal.bridge.Config.Homeserver.Domain).MatrixToURL()) - return - } - ce.ZLog.Warn().Stringer("existing_room_id", portal.MXID).Msg("Ensuring user is invited to existing room failed, creating new room") - portal.Cleanup(ce.Ctx, false) - portal.MXID = "" - } - - if err = portal.CreateMatrixRoom(ce.Ctx, user, 0); err != nil { - ce.ZLog.Err(err).Msg("Failed to create portal room") - ce.Reply("Error creating Matrix room for portal to +%d", number) - } else { - ce.Reply("Created portal room [%s](%s) with +%d and invited you to it.", portal.MXID, portal.MXID.URI(portal.bridge.Config.Homeserver.Domain).MatrixToURL(), number) - } -} - -var cmdInvite = &commands.FullHandler{ - Func: wrapCommand(fnInvite), - Name: "invite", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Invite a user by phone number.", - Args: "<_international phone number_>", - }, - RequiresLogin: true, - RequiresPortal: true, -} - -func fnInvite(ce *WrappedCommandEvent) { - if len(ce.Args) == 0 { - ce.Reply("**Usage:** `invite `") - return - } - number, err := strconv.ParseUint(numberCleaner.Replace(strings.Join(ce.Args, "")), 10, 64) - if err != nil { - ce.Reply("Failed to parse number") - return - } - - user := ce.User - var aci, pni uuid.UUID - e164 := fmt.Sprintf("+%d", number) - var recipient *types.Recipient - - if recipient, err = user.Client.ContactByE164(ce.Ctx, e164); err != nil { - ce.Reply("Error looking up number in local contact list: %v", err) - return - } else if recipient != nil && (recipient.ACI != uuid.Nil || recipient.PNI != uuid.Nil) { - // TODO maybe lookup PNI if there's only ACI and E164 stored? - aci = recipient.ACI - pni = recipient.PNI - } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { - ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") - ce.Reply("Error looking up number on server: %v", err) - return - } else { - aci = resp[number].ACI - pni = resp[number].PNI - if aci == uuid.Nil && pni == uuid.Nil { - ce.Reply("+%d doesn't seem to be on Signal", number) - return - } - recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ce.Ctx, aci, pni, e164) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to save recipient entry after looking up phone") - } - aci, pni = recipient.ACI, recipient.PNI - } - ce.ZLog.Debug(). - Uint64("e164", number). - Stringer("aci", aci). - Stringer("pni", pni). - Msg("Found Invite target user") - - var groupChange signalmeow.GroupChange - if aci != uuid.Nil { - groupChange.AddMembers = []*signalmeow.AddMember{ - { - GroupMember: signalmeow.GroupMember{ - ACI: aci, - Role: signalmeow.GroupMember_DEFAULT, - }, - }, - } - } else { - groupChange.AddPendingMembers = []*signalmeow.PendingMember{ - { - ServiceID: libsignalgo.NewPNIServiceID(pni), - AddedByUserID: ce.User.SignalID, - Role: signalmeow.GroupMember_DEFAULT, - }, - } - } - revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) - if err != nil { - ce.Reply("Failed to update group: %w", err) - return - } - ce.Portal.Revision = revision - if aci != uuid.Nil { - group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), revision) - if err != nil { - ce.Reply("Failed to fetch group after invite: %w", err) - } - ce.Portal.SyncParticipants(ce.Ctx, user, group) - ce.Portal.Update(ce.Ctx) - return - } - ce.Portal.Update(ce.Ctx) - ce.Reply("Invited " + e164) -} - -var cmdListInvited = &commands.FullHandler{ - Func: wrapCommand(fnListInvited), - Name: "list-invited", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "list pending invites", - Args: "<_international phone number_>", - }, - RequiresLogin: true, - RequiresPortal: true, -} - -func fnListInvited(ce *WrappedCommandEvent) { - group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), ce.Portal.Revision) - if err != nil { - ce.Reply("Failed to fetch group info: %w", err) - return - } - var memberList []string - for _, pendingMember := range group.PendingMembers { - recipientString, err := pendingMemberToString(ce.Ctx, ce.User, pendingMember) - if err != nil { - ce.Reply("Failed to fetch recipient for %s: %w", pendingMember.ServiceID, err) - continue - } - memberList = append(memberList, recipientString) - } - if len(memberList) == 0 { - ce.Reply("No pending Invites") - } else { - ce.Reply(strings.Join(memberList, "\n")) - } -} - -func pendingMemberToString(ctx context.Context, user *User, pendingMember *signalmeow.PendingMember) (string, error) { - var pni, aci uuid.UUID - if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypeACI { - aci = pendingMember.ServiceID.UUID - } else { - pni = pendingMember.ServiceID.UUID - } - recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) - if err != nil { - return "", err - } - if recipient.E164 != "" { - return recipient.E164, nil - } else { - return "Unidentified User", nil - } -} - -var cmdRevokeInvite = &commands.FullHandler{ - Func: wrapCommand(fnRevokeInvite), - Name: "revoke-invite", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Revoke an invite by phone number.", - Args: "<_international phone number_>", - }, - RequiresLogin: true, - RequiresPortal: true, -} - -func fnRevokeInvite(ce *WrappedCommandEvent) { - if len(ce.Args) == 0 { - ce.Reply("**Usage:** `RevokeInvite `") - return - } - e164 := "+" + numberCleaner.Replace(strings.Join(ce.Args, "")) - - user := ce.User - var serviceID libsignalgo.ServiceID - group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), ce.Portal.Revision) - if err != nil { - ce.Reply("Failed to fetch group info: %w", err) - return - } - var pni, aci uuid.UUID - for _, pendingMember := range group.PendingMembers { - if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypeACI { - aci = pendingMember.ServiceID.UUID - } else { - pni = pendingMember.ServiceID.UUID - } - recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ce.Ctx, aci, pni, nil) - if err != nil { - continue - } - if recipient.E164 == e164 { - serviceID = pendingMember.ServiceID - break - } - } - if serviceID.UUID == uuid.Nil { - ce.Reply("User not in Group") - return - } - var groupChange signalmeow.GroupChange - groupChange.DeletePendingMembers = []*libsignalgo.ServiceID{&serviceID} - revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) - if err != nil { - ce.Reply("Failed to update group: %w", err) - return - } - if aci != uuid.Nil { - target := ce.Bridge.GetPuppetBySignalID(aci) - if target != nil { - ce.Bot.SendCustomMembershipEvent(ce.Ctx, ce.Portal.MXID, target.IntentFor(ce.Portal).UserID, event.MembershipLeave, "removed by "+user.MXID.String()) - } - } - ce.Portal.Revision = revision - ce.Portal.Update(ce.Ctx) - ce.Reply("Revoked the invitation for " + e164) -} - -var cmdResolvePhone = &commands.FullHandler{ - Func: wrapCommand(fnResolvePhone), - Name: "resolve-phone", - Help: commands.HelpMeta{ - Section: HelpSectionCreatingPortals, - Description: "Look up phone numbers on the Signal servers.", - Args: "", - }, - RequiresLogin: true, -} - -func fnResolvePhone(ce *WrappedCommandEvent) { - numbers := make([]uint64, len(ce.Args)) - for i, arg := range ce.Args { - var err error - numbers[i], err = strconv.ParseUint(numberCleaner.Replace(arg), 10, 64) - if err != nil { - ce.Reply("Failed to parse number %s: %v", arg, err) - return - } - } - resp, err := ce.User.Client.LookupPhone(ce.Ctx, numbers...) - if err != nil { - ce.Reply("Failed to look up: %v", err) - } else { - var out strings.Builder - for _, phone := range numbers { - result, found := resp[phone] - if found { - _, _ = fmt.Fprintf(&out, "+%d: %s / %s\n", phone, result.ACI, result.PNI) - } else { - _, _ = fmt.Fprintf(&out, "+%d: not found\n", phone) - } - } - ce.Reply(strings.TrimSpace(out.String())) - } -} - -var cmdSync = &commands.FullHandler{ - Func: wrapCommand(fnSync), - Name: "sync", - Help: commands.HelpMeta{ - Section: HelpSectionMiscellaneous, - Description: "Synchronize Signal bridge data", - Args: "", - }, - RequiresLogin: true, -} - -func fnSync(ce *WrappedCommandEvent) { - args := strings.ToLower(strings.Join(ce.Args, " ")) - space := strings.Contains(args, "space") - groups := strings.Contains(args, "groups") - if !space && !groups { - ce.Reply("**Usage:** `sync `") - return - } - if !ce.Bridge.Config.Bridge.PersonalFilteringSpaces && space { - ce.Reply("Personal filtering spaces are not enabled on this instance of the bridge") - return - } - ctx := ce.Ctx - dmKeys, err := ce.Bridge.DB.Portal.FindPrivateChatsNotInSpace(ctx, ce.User.SignalID) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to get private chat keys") - ce.Reply("Failed to get private chat IDs from database") - return - } - allPortals := ce.Bridge.GetAllPortalsWithMXID() - if space { - count := 0 - for _, portal := range allPortals { - if portal.IsPrivateChat() { - continue - } - if ce.Bridge.StateStore.IsInRoom(ctx, portal.MXID, ce.User.MXID) && portal.addToPersonalSpace(ctx, ce.User) { - count++ - } - } - for _, key := range dmKeys { - portal := ce.Bridge.GetPortalByChatID(key) - portal.addToPersonalSpace(ctx, ce.User) - count++ - } - plural := "s" - if count == 1 { - plural = "" - } - ce.Reply("Added %d room%s to space", count, plural) - } - if groups { - count := 0 - for _, portal := range allPortals { - if portal.IsPrivateChat() { - continue - } - if ce.Bridge.StateStore.IsInRoom(ctx, portal.MXID, ce.User.MXID) { - groupInfo := portal.UpdateGroupInfo(ce.Ctx, ce.User, nil, 0, true) - if groupInfo != nil { - members := portal.SyncParticipants(ctx, ce.User, groupInfo) - portal.updatePowerLevelsAndJoinRule(ctx, groupInfo, members) - count++ - } - } - } - plural := "s" - if count == 1 { - plural = "" - } - ce.Reply("Synced %d group%s", count, plural) - } -} - -var cmdLogin = &commands.FullHandler{ - Func: wrapCommand(fnLogin), - Name: "login", - Help: commands.HelpMeta{ - Section: commands.HelpSectionAuth, - Description: "Link the bridge to your Signal account as a web client.", - }, -} - -func fnLogin(ce *WrappedCommandEvent) { - if ce.User.IsLoggedIn() { - if ce.User.Client.IsConnected() { - ce.Reply("You're already logged in") - } else { - ce.Reply("You're already logged in, but not connected 🤔") - } - return - } - - var qrEventID, msgEventID id.EventID - var signalID uuid.UUID - var signalPhone string - - // First get the provisioning URL - provChan, err := ce.User.Login() - if err != nil { - ce.ZLog.Err(err).Msg("Failure logging in") - ce.Reply("Failure logging in: %v", err) - return - } - - resp := <-provChan - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - ce.Reply("Error getting provisioning URL: %v", resp.Err) - return - } - if resp.State == signalmeow.StateProvisioningURLReceived { - qrEventID, msgEventID = ce.User.sendQR(ce, resp.ProvisioningURL, qrEventID, msgEventID) - } else { - ce.Reply("Unexpected state: %v", resp.State) - return - } - - // Next, get the results of finishing registration - resp = <-provChan - _, _ = ce.Bot.RedactEvent(ce.Ctx, ce.RoomID, qrEventID) - _, _ = ce.Bot.RedactEvent(ce.Ctx, ce.RoomID, msgEventID) - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - if resp.Err != nil && strings.HasSuffix(resp.Err.Error(), " EOF") { - ce.Reply("Logging in timed out, please try again.") - } else { - ce.Reply("Error finishing registration: %v", resp.Err) - } - return - } - if resp.State == signalmeow.StateProvisioningDataReceived { - signalID = resp.ProvisioningData.ACI - signalPhone = resp.ProvisioningData.Number - } else { - ce.Reply("Unexpected state: %v", resp.State) - return - } - - // Finally, get the results of generating and registering prekeys - resp = <-provChan - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - ce.Reply("Error with prekeys: %v", resp.Err) - return - } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { - ce.Reply("Unexpected state: %v", resp.State) - return - } - - if signalID == uuid.Nil { - ce.Reply("Problem logging in - No SignalID received") - return - } - ce.User.saveSignalID(ce.Ctx, signalID, signalPhone) - - // Connect to Signal - ce.User.Connect() - ce.Reply("Successfully logged in as %s (UUID: %s)", ce.User.SignalUsername, ce.User.SignalID) -} - -func (user *User) sendQR(ce *WrappedCommandEvent, code string, prevQR, prevMsg id.EventID) (qr, msg id.EventID) { - content, ok := user.uploadQR(ce, code) - if !ok { - return prevQR, prevMsg - } - if len(prevQR) != 0 { - content.SetEdit(prevQR) - } - resp, err := ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to send QR code to user") - } else if len(prevQR) == 0 { - prevQR = resp.EventID - } - content = event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: fmt.Sprintf("Raw linking URI: %s", code), - Format: event.FormatHTML, - FormattedBody: fmt.Sprintf("Raw linking URI: %s", code), - } - if len(prevMsg) != 0 { - content.SetEdit(prevMsg) - } - resp, err = ce.Bot.SendMessageEvent(ce.Ctx, ce.RoomID, event.EventMessage, &content) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to send raw code to user") - } else if len(prevMsg) == 0 { - prevMsg = resp.EventID - } - return prevQR, prevMsg -} - -func (user *User) uploadQR(ce *WrappedCommandEvent, code string) (event.MessageEventContent, bool) { - const size = 512 - qrCode, err := qrcode.Encode(code, qrcode.Low, size) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to encode QR code") - ce.Reply("Failed to encode QR code: %v", err) - return event.MessageEventContent{}, false - } - - bot := user.bridge.AS.BotClient() - - resp, err := bot.UploadBytes(ce.Ctx, qrCode, "image/png") - if err != nil { - ce.ZLog.Err(err).Msg("Failed to upload QR code") - ce.Reply("Failed to upload QR code: %v", err) - return event.MessageEventContent{}, false - } - return event.MessageEventContent{ - MsgType: event.MsgImage, - Info: &event.FileInfo{ - MimeType: "image/png", - Width: size, - Height: size, - Size: len(qrCode), - }, - Body: "qr.png", - URL: resp.ContentURI.CUString(), - }, true -} - -func canDeletePortal(ctx context.Context, portal *Portal, userID id.UserID) bool { - if len(portal.MXID) == 0 { - return false - } - - members, err := portal.MainIntent().JoinedMembers(ctx, portal.MXID) - if err != nil { - portal.log.Err(err). - Stringer("user_id", userID). - Msg("Failed to get joined members to check if user can delete portal") - return false - } - for otherUser := range members.Joined { - _, isPuppet := portal.bridge.ParsePuppetMXID(otherUser) - if isPuppet || otherUser == portal.bridge.Bot.UserID || otherUser == userID { - continue - } - user := portal.bridge.GetUserByMXID(otherUser) - if user != nil && user.IsLoggedIn() { - return false - } - } - return true -} - -var cmdDeletePortal = &commands.FullHandler{ - Func: wrapCommand(fnDeletePortal), - Name: "delete-portal", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Delete the current portal. If the portal is used by other people, this is limited to bridge admins.", - }, - RequiresPortal: true, -} - -func fnDeletePortal(ce *WrappedCommandEvent) { - if !ce.User.Admin && !canDeletePortal(ce.Ctx, ce.Portal, ce.User.MXID) { - ce.Reply("Only bridge admins can delete portals with other Matrix users") - return - } - - ce.Portal.log.Info().Stringer("user_id", ce.User.MXID).Msg("User requested deletion of portal") - ce.Portal.Delete() - ce.Portal.Cleanup(ce.Ctx, false) -} - -var cmdDeleteAllPortals = &commands.FullHandler{ - Func: wrapCommand(fnDeleteAllPortals), - Name: "delete-all-portals", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Delete all portals.", - }, -} - -func fnDeleteAllPortals(ce *WrappedCommandEvent) { - portals := ce.Bridge.GetAllPortalsWithMXID() - var portalsToDelete []*Portal - - if ce.User.Admin { - portalsToDelete = portals - } else { - portalsToDelete = portals[:0] - for _, portal := range portals { - if canDeletePortal(ce.Ctx, portal, ce.User.MXID) { - portalsToDelete = append(portalsToDelete, portal) - } - } - } - if len(portalsToDelete) == 0 { - ce.Reply("Didn't find any portals to delete") - return - } - - leave := func(portal *Portal) { - if len(portal.MXID) > 0 { - _, _ = portal.MainIntent().KickUser(ce.Ctx, portal.MXID, &mautrix.ReqKickUser{ - Reason: "Deleting portal", - UserID: ce.User.MXID, - }) - } - } - customPuppet := ce.Bridge.GetPuppetByCustomMXID(ce.User.MXID) - if customPuppet != nil && customPuppet.CustomIntent() != nil { - intent := customPuppet.CustomIntent() - leave = func(portal *Portal) { - if len(portal.MXID) > 0 { - _, _ = intent.LeaveRoom(ce.Ctx, portal.MXID) - _, _ = intent.ForgetRoom(ce.Ctx, portal.MXID) - } - } - } - ce.Reply("Found %d portals, deleting...", len(portalsToDelete)) - for _, portal := range portalsToDelete { - portal.Delete() - leave(portal) - } - ce.Reply("Finished deleting portal info. Now cleaning up rooms in background.") - - backgroundCtx := context.TODO() - go func() { - for _, portal := range portalsToDelete { - portal.Cleanup(backgroundCtx, false) - } - ce.Reply("Finished background cleanup of deleted portal rooms.") - }() -} - -var cmdCleanupLostPortals = &commands.FullHandler{ - Func: wrapCommand(fnCleanupLostPortals), - Name: "cleanup-lost-portals", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Clean up portals that were discarded due to the receiver not being logged into the bridge", - }, - RequiresAdmin: true, -} - -func fnCleanupLostPortals(ce *WrappedCommandEvent) { - portals, err := ce.Bridge.DB.LostPortal.GetAll(ce.Ctx) - if err != nil { - ce.Reply("Failed to get portals: %v", err) - return - } else if len(portals) == 0 { - ce.Reply("No lost portals found") - return - } - - ce.Reply("Found %d lost portals, deleting...", len(portals)) - for _, portal := range portals { - dmUUID, err := uuid.Parse(portal.ChatID) - intent := ce.Bot - if err == nil { - intent = ce.Bridge.GetPuppetBySignalID(dmUUID).DefaultIntent() - } - ce.Bridge.CleanupRoom(ce.Ctx, ce.ZLog, intent, portal.MXID, false) - err = portal.Delete(ce.Ctx) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to delete lost portal from database after cleanup") - } - } - ce.Reply("Finished cleaning up portals") -} - -var cmdInviteLink = &commands.FullHandler{ - Func: wrapCommand(fnInviteLink), - Name: "invite-link", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Get the invite link for the corresponding Signal Group", - }, - RequiresLogin: true, -} - -func fnInviteLink(ce *WrappedCommandEvent) { - if ce.Portal == nil { - ce.Reply("This is not a portal room") - return - } - if ce.Portal.IsPrivateChat() { - ce.Reply("Invite Links are not available for private chats") - return - } - inviteLinkPassword, err := ce.Portal.GetInviteLink(ce.Ctx, ce.User) - if err != nil { - ce.Reply("Error getting invite link %w", err) - return - } - ce.Reply(inviteLinkPassword) -} - -var cmdResetInviteLink = &commands.FullHandler{ - Func: wrapCommand(fnResetInviteLink), - Name: "reset-invite-link", - Help: commands.HelpMeta{ - Section: HelpSectionPortalManagement, - Description: "Generate a new invite link password", - }, - RequiresLogin: true, -} - -func fnResetInviteLink(ce *WrappedCommandEvent) { - if ce.Portal == nil { - ce.Reply("This is not a portal room") - return - } - if ce.Portal.IsPrivateChat() { - ce.Reply("Invite Links are not available for private chats") - return - } - err := ce.Portal.ResetInviteLink(ce.Ctx, ce.User) - if err != nil { - ce.Reply("Error setting new invite link %w", err) - } - inviteLink, err := ce.Portal.GetInviteLink(ce.Ctx, ce.User) - if err != nil { - ce.Reply("Error getting new invite link %w", err) - return - } - ce.Reply(inviteLink) -} - -var cmdCreate = &commands.FullHandler{ - Func: wrapCommand(fnCreate), - Name: "create", - Help: commands.HelpMeta{ - Section: HelpSectionCreatingPortals, - Description: "Create a Signal group chat for the current Matrix room.", - }, - RequiresLogin: true, -} - -func fnCreate(ce *WrappedCommandEvent) { - if ce.Portal != nil { - ce.Reply("This is already a portal room") - return - } - - roomState, err := ce.Bot.State(ce.Ctx, ce.RoomID) - if err != nil { - ce.Reply("Failed to get room state: %w", err) - return - } - members := roomState[event.StateMember] - powerLevelsRaw, ok := roomState[event.StatePowerLevels][""] - if !ok { - ce.Reply("Failed to get room power levels") - return - } - powerLevelsRaw.Content.ParseRaw(event.StatePowerLevels) - powerLevels := powerLevelsRaw.Content.AsPowerLevels() - joinRulesRaw, ok := roomState[event.StateJoinRules][""] - if !ok { - ce.Reply("Failed to get join rules") - return - } - joinRulesRaw.Content.ParseRaw(event.StateJoinRules) - joinRule := joinRulesRaw.Content.AsJoinRules().JoinRule - roomNameEventRaw, ok := roomState[event.StateRoomName][""] - if !ok { - ce.Reply("Failed to get room name") - return - } - roomNameEventRaw.Content.ParseRaw(event.StateRoomName) - roomName := roomNameEventRaw.Content.AsRoomName().Name - if len(roomName) == 0 { - ce.Reply("Please set a name for the room first") - return - } - roomTopic := "" - roomTopicEvent, ok := roomState[event.StateTopic][""] - if ok { - roomTopicEvent.Content.ParseRaw(event.StateTopic) - roomTopic = roomTopicEvent.Content.AsTopic().Topic - } - roomAvatarEvent, ok := roomState[event.StateRoomAvatar][""] - var avatarHash string - var avatarURL id.ContentURI - var avatarBytes []byte - avatarSet := false - if ok { - roomAvatarEvent.Content.ParseRaw(event.StateRoomAvatar) - avatarURL = roomAvatarEvent.Content.AsRoomAvatar().URL.ParseOrIgnore() - if !avatarURL.IsEmpty() { - avatarBytes, err = ce.Bot.DownloadBytes(ce.Ctx, avatarURL) - if err != nil { - ce.ZLog.Err(err).Stringer("Failed to download updated avatar %s", avatarURL) - return - } - hash := sha256.Sum256(avatarBytes) - avatarHash = hex.EncodeToString(hash[:]) - ce.ZLog.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{ce.User.MXID, avatarURL}) - avatarSet = true - } - } - var encryptionEvent *event.EncryptionEventContent - encryptionEventContent, ok := roomState[event.StateEncryption][""] - if ok { - encryptionEventContent.Content.ParseRaw(event.StateEncryption) - encryptionEvent = encryptionEventContent.Content.AsEncryption() - } - var participants []*signalmeow.GroupMember - var bannedMembers []*signalmeow.BannedMember - participantDedup := make(map[uuid.UUID]bool) - participantDedup[uuid.Nil] = true - for key, member := range members { - mxid := id.UserID(key) - member.Content.ParseRaw(event.StateMember) - content := member.Content.AsMember() - membership := content.Membership - var uuid uuid.UUID - puppet := ce.Bridge.GetPuppetByMXID(mxid) - if puppet != nil { - uuid = puppet.SignalID - } else { - user := ce.Bridge.GetUserByMXID(mxid) - if user != nil && user.IsLoggedIn() { - uuid = user.SignalID - } - } - role := signalmeow.GroupMember_DEFAULT - if powerLevels.GetUserLevel(mxid) >= 50 { - role = signalmeow.GroupMember_ADMINISTRATOR - } - if !participantDedup[uuid] { - participantDedup[uuid] = true - // invites should be added on signal and then auto-joined - // joined members that need to be pending-Members should have their signal invite auto-accepted - if membership == event.MembershipJoin || membership == event.MembershipInvite { - participants = append(participants, &signalmeow.GroupMember{ - ACI: uuid, - Role: role, - }) - } else if membership == event.MembershipBan { - bannedMembers = append(bannedMembers, &signalmeow.BannedMember{ - ServiceID: libsignalgo.NewACIServiceID(uuid), - }) - } - } - } - addFromInviteLinkAccess := signalmeow.AccessControl_UNSATISFIABLE - if joinRule == event.JoinRulePublic { - addFromInviteLinkAccess = signalmeow.AccessControl_ANY - } else if joinRule == event.JoinRuleKnock { - addFromInviteLinkAccess = signalmeow.AccessControl_ADMINISTRATOR - } - var inviteLinkPassword types.SerializedInviteLinkPassword - if addFromInviteLinkAccess != signalmeow.AccessControl_UNSATISFIABLE { - inviteLinkPassword = signalmeow.GenerateInviteLinkPassword() - } - membersAccess := signalmeow.AccessControl_MEMBER - if powerLevels.Invite() >= 50 { - membersAccess = signalmeow.AccessControl_ADMINISTRATOR - } - attributesAccess := signalmeow.AccessControl_MEMBER - if powerLevels.StateDefault() >= 50 { - attributesAccess = signalmeow.AccessControl_ADMINISTRATOR - } - announcementsOnly := false - if powerLevels.EventsDefault >= 50 { - announcementsOnly = true - } - ce.ZLog.Info(). - Str("room_name", roomName). - Any("participants", participants). - Msg("Creating Signal group for Matrix room") - group, err := ce.User.Client.CreateGroup(ce.Ctx, &signalmeow.Group{ - Title: roomName, - Description: roomTopic, - Members: participants, - AccessControl: &signalmeow.GroupAccessControl{ - Members: membersAccess, - Attributes: attributesAccess, - AddFromInviteLink: addFromInviteLinkAccess, - }, - InviteLinkPassword: &inviteLinkPassword, - BannedMembers: bannedMembers, - AnnouncementsOnly: announcementsOnly, - }, avatarBytes) - if err != nil { - ce.Reply("Failed to create group: %v", err) - return - } - gid := group.GroupIdentifier - ce.ZLog.UpdateContext(func(c zerolog.Context) zerolog.Context { - return c.Stringer("group_id", gid) - }) - portal := ce.User.GetPortalByChatID(gid.String()) - portal.roomCreateLock.Lock() - defer portal.roomCreateLock.Unlock() - if len(portal.MXID) != 0 { - ce.ZLog.Warn().Msg("Detected race condition in room creation") - // TODO race condition, clean up the old room - } - portal.MXID = ce.RoomID - portal.Name = roomName - portal.Encrypted = encryptionEvent != nil && encryptionEvent.Algorithm == id.AlgorithmMegolmV1 - if !portal.Encrypted && ce.Bridge.Config.Bridge.Encryption.Default { - _, err = portal.MainIntent().SendStateEvent(ce.Ctx, portal.MXID, event.StateEncryption, "", portal.GetEncryptionEventContent()) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to enable encryption in room") - if errors.Is(err, mautrix.MForbidden) { - ce.Reply("I don't seem to have permission to enable encryption in this room.") - } else { - ce.Reply("Failed to enable encryption in room: %v", err) - } - } - portal.Encrypted = true - } - portal.Revision = group.Revision - portal.AvatarHash = avatarHash - portal.AvatarURL = avatarURL - portal.AvatarPath = group.AvatarPath - portal.AvatarSet = avatarSet - err = portal.Update(ce.Ctx) - if err != nil { - ce.ZLog.Err(err).Msg("Failed to save portal after creating group") - } - portal.UpdateBridgeInfo(ce.Ctx) - ce.Reply("Successfully created Signal group %s", gid.String()) -} diff --git a/config/bridge.go b/config/bridge.go deleted file mode 100644 index e3e756c..0000000 --- a/config/bridge.go +++ /dev/null @@ -1,241 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2022 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package config - -import ( - "errors" - "fmt" - "strings" - "text/template" - "time" - - "maunium.net/go/mautrix/bridge/bridgeconfig" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" -) - -type BridgeConfig struct { - UsernameTemplate string `yaml:"username_template"` - DisplaynameTemplate string `yaml:"displayname_template"` - PrivateChatPortalMeta string `yaml:"private_chat_portal_meta"` - UseContactAvatars bool `yaml:"use_contact_avatars"` - UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` - NumberInTopic bool `yaml:"number_in_topic"` - - NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` - - PortalMessageBuffer int `yaml:"portal_message_buffer"` - - PersonalFilteringSpaces bool `yaml:"personal_filtering_spaces"` - BridgeNotices bool `yaml:"bridge_notices"` - DeliveryReceipts bool `yaml:"delivery_receipts"` - MessageStatusEvents bool `yaml:"message_status_events"` - MessageErrorNotices bool `yaml:"message_error_notices"` - SyncDirectChatList bool `yaml:"sync_direct_chat_list"` - ResendBridgeInfo bool `yaml:"resend_bridge_info"` - PublicPortals bool `yaml:"public_portals"` - CaptionInMessage bool `yaml:"caption_in_message"` - LocationFormat string `yaml:"location_format"` - FederateRooms bool `yaml:"federate_rooms"` - BridgeMatrixLeave bool `yaml:"bridge_matrix_leave"` - - DoublePuppetConfig bridgeconfig.DoublePuppetConfig `yaml:",inline"` - - MessageHandlingTimeout struct { - ErrorAfterStr string `yaml:"error_after"` - DeadlineStr string `yaml:"deadline"` - - ErrorAfter time.Duration `yaml:"-"` - Deadline time.Duration `yaml:"-"` - } `yaml:"message_handling_timeout"` - - CommandPrefix string `yaml:"command_prefix"` - ManagementRoomText bridgeconfig.ManagementRoomTexts `yaml:"management_room_text"` - - Encryption bridgeconfig.EncryptionConfig `yaml:"encryption"` - - Provisioning struct { - Prefix string `yaml:"prefix"` - SharedSecret string `yaml:"shared_secret"` - DebugEndpoints bool `yaml:"debug_endpoints"` - } `yaml:"provisioning"` - - Permissions bridgeconfig.PermissionConfig `yaml:"permissions"` - - Relay RelaybotConfig `yaml:"relay"` - - usernameTemplate *template.Template `yaml:"-"` - displaynameTemplate *template.Template `yaml:"-"` -} - -func (bc *BridgeConfig) GetResendBridgeInfo() bool { - return bc.ResendBridgeInfo -} - -func (bc *BridgeConfig) EnableMessageStatusEvents() bool { - return bc.MessageStatusEvents -} - -func (bc *BridgeConfig) EnableMessageErrorNotices() bool { - return bc.MessageErrorNotices -} - -func boolToInt(val bool) int { - if val { - return 1 - } - return 0 -} - -func (bc *BridgeConfig) Validate() error { - _, hasWildcard := bc.Permissions["*"] - _, hasExampleDomain := bc.Permissions["example.com"] - _, hasExampleUser := bc.Permissions["@admin:example.com"] - exampleLen := boolToInt(hasWildcard) + boolToInt(hasExampleUser) + boolToInt(hasExampleDomain) - if len(bc.Permissions) <= exampleLen { - return errors.New("bridge.permissions not configured") - } - return nil -} - -type umBridgeConfig BridgeConfig - -func (bc *BridgeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - err := unmarshal((*umBridgeConfig)(bc)) - if err != nil { - return err - } - - bc.usernameTemplate, err = template.New("username").Parse(bc.UsernameTemplate) - if err != nil { - return err - } else if !strings.Contains(bc.FormatUsername("1234567890"), "1234567890") { - return fmt.Errorf("username template is missing user ID placeholder") - } - bc.displaynameTemplate, err = template.New("displayname").Parse(bc.DisplaynameTemplate) - if err != nil { - return err - } - - return nil -} - -var _ bridgeconfig.BridgeConfig = (*BridgeConfig)(nil) - -func (bc BridgeConfig) GetDoublePuppetConfig() bridgeconfig.DoublePuppetConfig { - return bc.DoublePuppetConfig -} - -func (bc BridgeConfig) GetEncryptionConfig() bridgeconfig.EncryptionConfig { - return bc.Encryption -} - -func (bc BridgeConfig) GetCommandPrefix() string { - return bc.CommandPrefix -} - -func (bc BridgeConfig) GetManagementRoomTexts() bridgeconfig.ManagementRoomTexts { - return bc.ManagementRoomText -} - -func (bc BridgeConfig) FormatUsername(userID string) string { - var buffer strings.Builder - _ = bc.usernameTemplate.Execute(&buffer, userID) - return buffer.String() -} - -type DisplaynameParams struct { - ProfileName string - ContactName string - Username string - PhoneNumber string - UUID string - ACI string - PNI string - AboutEmoji string -} - -func (bc BridgeConfig) FormatDisplayname(contact *types.Recipient) string { - var buffer strings.Builder - _ = bc.displaynameTemplate.Execute(&buffer, DisplaynameParams{ - ProfileName: contact.Profile.Name, - ContactName: contact.ContactName, - //Username: contact.Username, - PhoneNumber: contact.E164, - UUID: contact.ACI.String(), - ACI: contact.ACI.String(), - PNI: contact.PNI.String(), - AboutEmoji: contact.Profile.AboutEmoji, - }) - return buffer.String() -} - -type RelaybotConfig struct { - Enabled bool `yaml:"enabled"` - AdminOnly bool `yaml:"admin_only"` - MessageFormats map[event.MessageType]string `yaml:"message_formats"` - messageTemplates *template.Template `yaml:"-"` -} - -type umRelaybotConfig RelaybotConfig - -func (rc *RelaybotConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - err := unmarshal((*umRelaybotConfig)(rc)) - if err != nil { - return err - } - - rc.messageTemplates = template.New("messageTemplates") - for key, format := range rc.MessageFormats { - _, err := rc.messageTemplates.New(string(key)).Parse(format) - if err != nil { - return err - } - } - - return nil -} - -type Sender struct { - UserID string - event.MemberEventContent -} - -type formatData struct { - Sender Sender - Message string - Content *event.MessageEventContent -} - -func (rc *RelaybotConfig) FormatMessage(content *event.MessageEventContent, sender id.UserID, member event.MemberEventContent) (string, error) { - if len(member.Displayname) == 0 { - member.Displayname = sender.String() - } - member.Displayname = template.HTMLEscapeString(member.Displayname) - var output strings.Builder - err := rc.messageTemplates.ExecuteTemplate(&output, string(content.MsgType), formatData{ - Sender: Sender{ - UserID: template.HTMLEscapeString(sender.String()), - MemberEventContent: member, - }, - Content: content, - Message: content.FormattedBody, - }) - return output.String(), err -} diff --git a/config/config.go b/config/config.go deleted file mode 100644 index de62c82..0000000 --- a/config/config.go +++ /dev/null @@ -1,44 +0,0 @@ -// mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2022 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package config - -import ( - "maunium.net/go/mautrix/bridge/bridgeconfig" - "maunium.net/go/mautrix/id" -) - -type Config struct { - *bridgeconfig.BaseConfig `yaml:",inline"` - - Metrics struct { - Enabled bool `yaml:"enabled"` - Listen string `yaml:"listen"` - } `yaml:"metrics"` - - Signal struct { - DeviceName string `yaml:"device_name"` - } `yaml:"signal"` - - Bridge BridgeConfig `yaml:"bridge"` -} - -func (config *Config) CanAutoDoublePuppet(userID id.UserID) bool { - _, homeserver, _ := userID.Parse() - _, hasSecret := config.Bridge.DoublePuppetConfig.SharedSecretMap[homeserver] - - return hasSecret -} diff --git a/config/upgrade.go b/config/upgrade.go deleted file mode 100644 index 219b7fc..0000000 --- a/config/upgrade.go +++ /dev/null @@ -1,167 +0,0 @@ -// mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2022 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package config - -import ( - "net/url" - "strings" - - up "go.mau.fi/util/configupgrade" - "go.mau.fi/util/random" - "maunium.net/go/mautrix/bridge/bridgeconfig" -) - -func DoUpgrade(helper up.Helper) { - bridgeconfig.Upgrader.DoUpgrade(helper) - - legacyDB, ok := helper.Get(up.Str, "appservice", "database") - if ok { - if strings.HasPrefix(legacyDB, "postgres") { - parsedDB, err := url.Parse(legacyDB) - if err != nil { - panic(err) - } - q := parsedDB.Query() - if parsedDB.Host == "" && !q.Has("host") { - q.Set("host", "/var/run/postgresql") - } else if !q.Has("sslmode") { - q.Set("sslmode", "disable") - } - parsedDB.RawQuery = q.Encode() - helper.Set(up.Str, parsedDB.String(), "appservice", "database", "uri") - helper.Set(up.Str, "postgres", "appservice", "database", "type") - } else { - dbPath := strings.TrimPrefix(strings.TrimPrefix(legacyDB, "sqlite:"), "///") - helper.Set(up.Str, dbPath, "appservice", "database", "uri") - helper.Set(up.Str, "sqlite3-fk-wal", "appservice", "database", "type") - } - } - if legacyDBMinSize, ok := helper.Get(up.Int, "appservice", "database_opts", "min_size"); ok { - helper.Set(up.Int, legacyDBMinSize, "appservice", "database", "max_idle_conns") - } - if legacyDBMaxSize, ok := helper.Get(up.Int, "appservice", "database_opts", "max_size"); ok { - helper.Set(up.Int, legacyDBMaxSize, "appservice", "database", "max_open_conns") - } - if legacyBotUsername, ok := helper.Get(up.Str, "appservice", "bot_username"); ok { - helper.Set(up.Str, legacyBotUsername, "appservice", "bot", "username") - } - if legacyBotDisplayname, ok := helper.Get(up.Str, "appservice", "bot_displayname"); ok { - helper.Set(up.Str, legacyBotDisplayname, "appservice", "bot", "displayname") - } - if legacyBotAvatar, ok := helper.Get(up.Str, "appservice", "bot_avatar"); ok { - helper.Set(up.Str, legacyBotAvatar, "appservice", "bot", "avatar") - } - - helper.Copy(up.Bool, "metrics", "enabled") - helper.Copy(up.Str, "metrics", "listen") - - helper.Copy(up.Str, "signal", "device_name") - - if usernameTemplate, ok := helper.Get(up.Str, "bridge", "username_template"); ok && strings.Contains(usernameTemplate, "{userid}") { - helper.Set(up.Str, strings.ReplaceAll(usernameTemplate, "{userid}", "{{.}}"), "bridge", "username_template") - } else { - helper.Copy(up.Str, "bridge", "username_template") - } - if displaynameTemplate, ok := helper.Get(up.Str, "bridge", "displayname_template"); ok && strings.Contains(displaynameTemplate, "{displayname}") { - helper.Set(up.Str, strings.ReplaceAll(displaynameTemplate, "{displayname}", `{{or .ProfileName .PhoneNumber "Unknown user"}}`), "bridge", "displayname_template") - } else { - helper.Copy(up.Str, "bridge", "displayname_template") - } - helper.Copy(up.Str, "bridge", "private_chat_portal_meta") - helper.Copy(up.Bool, "bridge", "use_contact_avatars") - helper.Copy(up.Bool, "bridge", "use_outdated_profiles") - helper.Copy(up.Bool, "bridge", "number_in_topic") - helper.Copy(up.Str, "bridge", "note_to_self_avatar") - helper.Copy(up.Int, "bridge", "portal_message_buffer") - helper.Copy(up.Bool, "bridge", "personal_filtering_spaces") - helper.Copy(up.Bool, "bridge", "bridge_notices") - helper.Copy(up.Bool, "bridge", "delivery_receipts") - helper.Copy(up.Bool, "bridge", "message_status_events") - helper.Copy(up.Bool, "bridge", "message_error_notices") - helper.Copy(up.Bool, "bridge", "sync_direct_chat_list") - helper.Copy(up.Bool, "bridge", "resend_bridge_info") - helper.Copy(up.Bool, "bridge", "public_portals") - helper.Copy(up.Bool, "bridge", "caption_in_message") - helper.Copy(up.Str, "bridge", "location_format") - helper.Copy(up.Bool, "bridge", "federate_rooms") - helper.Copy(up.Map, "bridge", "double_puppet_server_map") - helper.Copy(up.Bool, "bridge", "double_puppet_allow_discovery") - helper.Copy(up.Map, "bridge", "login_shared_secret_map") - helper.Copy(up.Str, "bridge", "command_prefix") - helper.Copy(up.Str, "bridge", "management_room_text", "welcome") - helper.Copy(up.Str, "bridge", "management_room_text", "welcome_connected") - helper.Copy(up.Str, "bridge", "management_room_text", "welcome_unconnected") - helper.Copy(up.Str|up.Null, "bridge", "management_room_text", "additional_help") - helper.Copy(up.Bool, "bridge", "encryption", "allow") - helper.Copy(up.Bool, "bridge", "encryption", "default") - helper.Copy(up.Bool, "bridge", "encryption", "require") - helper.Copy(up.Bool, "bridge", "encryption", "appservice") - helper.Copy(up.Bool, "bridge", "encryption", "allow_key_sharing") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "delete_outbound_on_ack") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "dont_store_outbound") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "ratchet_on_decrypt") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "delete_fully_used_on_decrypt") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "delete_prev_on_new_session") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "delete_on_device_delete") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "periodically_delete_expired") - helper.Copy(up.Bool, "bridge", "encryption", "delete_keys", "delete_outdated_inbound") - helper.Copy(up.Str, "bridge", "encryption", "verification_levels", "receive") - helper.Copy(up.Str, "bridge", "encryption", "verification_levels", "send") - helper.Copy(up.Str, "bridge", "encryption", "verification_levels", "share") - helper.Copy(up.Bool, "bridge", "encryption", "rotation", "enable_custom") - helper.Copy(up.Int, "bridge", "encryption", "rotation", "milliseconds") - helper.Copy(up.Int, "bridge", "encryption", "rotation", "messages") - helper.Copy(up.Bool, "bridge", "encryption", "rotation", "disable_device_change_key_rotation") - helper.Copy(up.Bool, "bridge", "bridge_matrix_leave") - - helper.Copy(up.Str, "bridge", "provisioning", "prefix") - if secret, ok := helper.Get(up.Str, "bridge", "provisioning", "shared_secret"); !ok || secret == "generate" { - sharedSecret := random.String(64) - helper.Set(up.Str, sharedSecret, "bridge", "provisioning", "shared_secret") - } else { - helper.Copy(up.Str, "bridge", "provisioning", "shared_secret") - } - helper.Copy(up.Bool, "bridge", "provisioning", "debug_endpoints") - - helper.Copy(up.Map, "bridge", "permissions") - helper.Copy(up.Bool, "bridge", "relay", "enabled") - helper.Copy(up.Bool, "bridge", "relay", "admin_only") - if textRelayFormat, ok := helper.Get(up.Str, "bridge", "relay", "message_formats", "m.text"); ok && strings.Contains(textRelayFormat, "$message") && !strings.Contains(textRelayFormat, ".Message") { - // don't copy legacy message formats - } else { - helper.Copy(up.Map, "bridge", "relay", "message_formats") - } -} - -var SpacedBlocks = [][]string{ - {"homeserver", "software"}, - {"appservice"}, - {"appservice", "hostname"}, - {"appservice", "database"}, - {"appservice", "id"}, - {"appservice", "as_token"}, - {"metrics"}, - {"signal"}, - {"bridge"}, - {"bridge", "personal_filtering_spaces"}, - {"bridge", "command_prefix"}, - {"bridge", "management_room_text"}, - {"bridge", "encryption"}, - {"bridge", "provisioning"}, - {"bridge", "permissions"}, - {"logging"}, -} diff --git a/custompuppet.go b/custompuppet.go deleted file mode 100644 index cde3059..0000000 --- a/custompuppet.go +++ /dev/null @@ -1,97 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "fmt" - - "maunium.net/go/mautrix/id" -) - -func (puppet *Puppet) SwitchCustomMXID(accessToken string, mxid id.UserID) error { - puppet.CustomMXID = mxid - puppet.AccessToken = accessToken - err := puppet.Update(context.TODO()) - if err != nil { - return fmt.Errorf("failed to save access token: %w", err) - } - err = puppet.StartCustomMXID(false) - if err != nil { - return err - } - // TODO leave rooms with default puppet - return nil -} - -func (puppet *Puppet) ClearCustomMXID() { - save := puppet.CustomMXID != "" || puppet.AccessToken != "" - puppet.bridge.puppetsLock.Lock() - if puppet.CustomMXID != "" && puppet.bridge.puppetsByCustomMXID[puppet.CustomMXID] == puppet { - delete(puppet.bridge.puppetsByCustomMXID, puppet.CustomMXID) - } - puppet.bridge.puppetsLock.Unlock() - puppet.CustomMXID = "" - puppet.AccessToken = "" - puppet.customIntent = nil - puppet.customUser = nil - if save { - err := puppet.Update(context.TODO()) - if err != nil { - puppet.log.Err(err).Msg("Failed to clear custom MXID") - } - } -} - -func (puppet *Puppet) StartCustomMXID(reloginOnFail bool) error { - newIntent, newAccessToken, err := puppet.bridge.DoublePuppet.Setup(context.TODO(), puppet.CustomMXID, puppet.AccessToken, reloginOnFail) - if err != nil { - puppet.ClearCustomMXID() - return err - } - puppet.bridge.puppetsLock.Lock() - puppet.bridge.puppetsByCustomMXID[puppet.CustomMXID] = puppet - puppet.bridge.puppetsLock.Unlock() - if puppet.AccessToken != newAccessToken { - puppet.AccessToken = newAccessToken - err = puppet.Update(context.TODO()) - } - puppet.customIntent = newIntent - puppet.customUser = puppet.bridge.GetUserByMXID(puppet.CustomMXID) - return err -} - -func (user *User) tryAutomaticDoublePuppeting() { - if !user.bridge.Config.CanAutoDoublePuppet(user.MXID) { - return - } - user.log.Debug().Msg("Checking if double puppeting needs to be enabled") - puppet := user.bridge.GetPuppetBySignalID(user.SignalID) - if puppet.CustomMXID == user.MXID { - user.log.Debug().Msg("User already has double-puppeting enabled") - // Custom puppet already enabled - return - } - puppet.CustomMXID = user.MXID - err := puppet.StartCustomMXID(true) - if err != nil { - user.log.Warn().Err(err).Msg("Failed to login with shared secret") - } else { - // TODO leave rooms with default puppet - user.log.Debug().Msg("Successfully automatically enabled custom puppet") - } -} diff --git a/database/database.go b/database/database.go deleted file mode 100644 index daa365f..0000000 --- a/database/database.go +++ /dev/null @@ -1,53 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - _ "embed" - - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" - "go.mau.fi/util/dbutil" - - "go.mau.fi/mautrix-signal/database/upgrades" -) - -type Database struct { - *dbutil.Database - - User *UserQuery - Portal *PortalQuery - LostPortal *LostPortalQuery - Puppet *PuppetQuery - Message *MessageQuery - Reaction *ReactionQuery - DisappearingMessage *DisappearingMessageQuery -} - -func New(db *dbutil.Database) *Database { - db.UpgradeTable = upgrades.Table - return &Database{ - Database: db, - User: &UserQuery{dbutil.MakeQueryHelper(db, newUser)}, - Portal: &PortalQuery{dbutil.MakeQueryHelper(db, newPortal)}, - LostPortal: &LostPortalQuery{dbutil.MakeQueryHelper(db, newLostPortal)}, - Puppet: &PuppetQuery{dbutil.MakeQueryHelper(db, newPuppet)}, - Message: &MessageQuery{dbutil.MakeQueryHelper(db, newMessage)}, - Reaction: &ReactionQuery{dbutil.MakeQueryHelper(db, newReaction)}, - DisappearingMessage: &DisappearingMessageQuery{dbutil.MakeQueryHelper(db, newDisappearingMessage)}, - } -} diff --git a/database/disappearingmessage.go b/database/disappearingmessage.go deleted file mode 100644 index b32a8ee..0000000 --- a/database/disappearingmessage.go +++ /dev/null @@ -1,125 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - "database/sql" - "time" - - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" -) - -const ( - getUnscheduledDisappearingMessagesForRoomQuery = ` - SELECT room_id, mxid, expiration_seconds, expiration_ts - FROM disappearing_message WHERE expiration_ts IS NULL AND room_id = $1 - ` - getExpiredDisappearingMessagesQuery = ` - SELECT room_id, mxid, expiration_seconds, expiration_ts - FROM disappearing_message WHERE expiration_ts IS NOT NULL AND expiration_ts <= $1 - ` - getNextDisappearingMessageQuery = ` - SELECT room_id, mxid, expiration_seconds, expiration_ts - FROM disappearing_message WHERE expiration_ts IS NOT NULL ORDER BY expiration_ts ASC LIMIT 1 - ` - insertDisappearingMessageQuery = ` - INSERT INTO disappearing_message (room_id, mxid, expiration_seconds, expiration_ts) VALUES ($1, $2, $3, $4) - ` - updateDisappearingMessageQuery = ` - UPDATE disappearing_message SET expiration_ts=$2 WHERE mxid=$1 - ` - deleteDisappearingMessageQuery = ` - DELETE FROM disappearing_message WHERE mxid=$1 - ` -) - -type DisappearingMessageQuery struct { - *dbutil.QueryHelper[*DisappearingMessage] -} - -type DisappearingMessage struct { - qh *dbutil.QueryHelper[*DisappearingMessage] - - RoomID id.RoomID - EventID id.EventID - ExpireIn time.Duration - ExpireAt time.Time -} - -func newDisappearingMessage(qh *dbutil.QueryHelper[*DisappearingMessage]) *DisappearingMessage { - return &DisappearingMessage{qh: qh} -} - -func (dmq *DisappearingMessageQuery) NewWithValues(roomID id.RoomID, eventID id.EventID, expireIn time.Duration, expireAt time.Time) *DisappearingMessage { - return &DisappearingMessage{ - qh: dmq.QueryHelper, - RoomID: roomID, - EventID: eventID, - ExpireIn: expireIn, - ExpireAt: expireAt, - } -} - -func (dmq *DisappearingMessageQuery) GetUnscheduledForRoom(ctx context.Context, roomID id.RoomID) ([]*DisappearingMessage, error) { - return dmq.QueryMany(ctx, getUnscheduledDisappearingMessagesForRoomQuery, roomID) -} - -func (dmq *DisappearingMessageQuery) GetExpiredMessages(ctx context.Context) ([]*DisappearingMessage, error) { - return dmq.QueryMany(ctx, getExpiredDisappearingMessagesQuery, time.Now().Unix()+1) -} - -func (dmq *DisappearingMessageQuery) GetNextScheduledMessage(ctx context.Context) (*DisappearingMessage, error) { - return dmq.QueryOne(ctx, getNextDisappearingMessageQuery) -} - -func (msg *DisappearingMessage) Scan(row dbutil.Scannable) (*DisappearingMessage, error) { - var expireIn int64 - var expireAt sql.NullInt64 - err := row.Scan(&msg.RoomID, &msg.EventID, &expireIn, &expireAt) - if err != nil { - return nil, err - } - msg.ExpireIn = time.Duration(expireIn) * time.Second - if expireAt.Valid { - msg.ExpireAt = time.Unix(expireAt.Int64, 0) - } - return msg, nil -} - -func (msg *DisappearingMessage) sqlVariables() []any { - var expireAt sql.NullInt64 - if !msg.ExpireAt.IsZero() { - expireAt.Valid = true - expireAt.Int64 = msg.ExpireAt.Unix() - } - return []any{msg.RoomID, msg.EventID, int64(msg.ExpireIn.Seconds()), expireAt} -} - -func (msg *DisappearingMessage) Insert(ctx context.Context) error { - return msg.qh.Exec(ctx, insertDisappearingMessageQuery, msg.sqlVariables()...) -} - -func (msg *DisappearingMessage) StartExpirationTimer(ctx context.Context) error { - msg.ExpireAt = time.Now().Add(msg.ExpireIn) - return msg.qh.Exec(ctx, updateDisappearingMessageQuery, msg.EventID, msg.ExpireAt.Unix()) -} - -func (msg *DisappearingMessage) Delete(ctx context.Context) error { - return msg.qh.Exec(ctx, deleteDisappearingMessageQuery, msg.EventID) -} diff --git a/database/lostportal.go b/database/lostportal.go deleted file mode 100644 index 29779b8..0000000 --- a/database/lostportal.go +++ /dev/null @@ -1,58 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" -) - -const ( - getLostPortalsQuery = `SELECT chat_id, receiver, mxid FROM lost_portals` - deleteLostPortalQuery = `DELETE FROM lost_portals WHERE mxid=$1` -) - -type LostPortalQuery struct { - *dbutil.QueryHelper[*LostPortal] -} - -func (lpq *LostPortalQuery) GetAll(ctx context.Context) ([]*LostPortal, error) { - return lpq.QueryMany(ctx, getLostPortalsQuery) -} - -type LostPortal struct { - qh *dbutil.QueryHelper[*LostPortal] - - ChatID string - Receiver string - MXID id.RoomID -} - -func newLostPortal(qh *dbutil.QueryHelper[*LostPortal]) *LostPortal { - return &LostPortal{qh: qh} -} - -func (l *LostPortal) Scan(row dbutil.Scannable) (*LostPortal, error) { - err := row.Scan(&l.ChatID, &l.Receiver, &l.MXID) - return l, err -} - -func (l *LostPortal) Delete(ctx context.Context) error { - return l.qh.Exec(ctx, deleteLostPortalQuery, l.MXID) -} diff --git a/database/message.go b/database/message.go deleted file mode 100644 index 5184bd8..0000000 --- a/database/message.go +++ /dev/null @@ -1,179 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - "fmt" - "strings" - - "github.com/google/uuid" - "github.com/lib/pq" - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" -) - -const ( - getMessageByMXIDQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE mxid=$1 - ` - getMessagePartBySignalIDQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE sender=$1 AND timestamp=$2 AND part_index=$3 AND signal_receiver=$4 - ` - getLastMessagePartBySignalIDQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE sender=$1 AND timestamp=$2 AND signal_receiver=$3 - ORDER BY part_index DESC LIMIT 1 - ` - getAllMessagePartsBySignalIDQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE sender=$1 AND timestamp=$2 AND signal_receiver=$3 - ` - getMessageLastPartBySignalIDWithUnknownReceiverQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE sender=$1 AND timestamp=$2 AND (signal_receiver=$3 OR signal_receiver='00000000-0000-0000-0000-000000000000') - ORDER BY part_index DESC LIMIT 1 - ` - getManyMessagesBySignalIDQueryPostgres = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE sender=$1 AND (signal_receiver=$2 OR signal_receiver=$3) AND timestamp=ANY($4) - ORDER BY timestamp DESC, part_index DESC - ` - getManyMessagesBySignalIDQuerySQLite = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE sender=?1 AND (signal_receiver=?2 OR signal_receiver=?3) AND timestamp IN (?4) - ORDER BY timestamp DESC, part_index DESC - ` - getFirstBeforeQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE mx_room=$1 AND timestamp <= $2 - ORDER BY timestamp DESC - LIMIT 1 - ` - getMessagesBetweenTimeQuery = ` - SELECT sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room FROM message - WHERE signal_chat_id=$1 AND signal_receiver=$2 AND timestamp>$3 AND timestamp<=$4 AND part_index=0 - ORDER BY timestamp ASC - ` - insertMessageQuery = ` - INSERT INTO message (sender, timestamp, part_index, signal_chat_id, signal_receiver, mxid, mx_room) - VALUES ($1, $2, $3, $4, $5, $6, $7) - ` - deleteMessageQuery = ` - DELETE FROM message - WHERE sender=$1 AND timestamp=$2 AND part_index=$3 AND signal_receiver=$4 - ` - updateMessageTimestampQuery = ` - UPDATE message SET timestamp=$4 WHERE sender=$1 AND timestamp=$2 AND signal_receiver=$3 - ` -) - -type MessageQuery struct { - *dbutil.QueryHelper[*Message] -} - -type Message struct { - qh *dbutil.QueryHelper[*Message] - - Sender uuid.UUID - Timestamp uint64 - PartIndex int - - SignalChatID string - SignalReceiver uuid.UUID - - MXID id.EventID - RoomID id.RoomID -} - -func newMessage(qh *dbutil.QueryHelper[*Message]) *Message { - return &Message{qh: qh} -} - -func (mq *MessageQuery) GetByMXID(ctx context.Context, mxid id.EventID) (*Message, error) { - return mq.QueryOne(ctx, getMessageByMXIDQuery, mxid) -} - -func (mq *MessageQuery) GetBySignalID(ctx context.Context, sender uuid.UUID, timestamp uint64, partIndex int, receiver uuid.UUID) (*Message, error) { - return mq.QueryOne(ctx, getMessagePartBySignalIDQuery, sender, timestamp, partIndex, receiver) -} - -func (mq *MessageQuery) GetLastPartBySignalID(ctx context.Context, sender uuid.UUID, timestamp uint64, receiver uuid.UUID) (*Message, error) { - return mq.QueryOne(ctx, getLastMessagePartBySignalIDQuery, sender, timestamp, receiver) -} - -func (mq *MessageQuery) GetAllPartsBySignalID(ctx context.Context, sender uuid.UUID, timestamp uint64, receiver uuid.UUID) ([]*Message, error) { - return mq.QueryMany(ctx, getAllMessagePartsBySignalIDQuery, sender, timestamp, receiver) -} - -func (mq *MessageQuery) GetAllBetweenTimestamps(ctx context.Context, key PortalKey, min, max uint64) ([]*Message, error) { - return mq.QueryMany(ctx, getMessagesBetweenTimeQuery, key.ChatID, key.Receiver, int64(min), int64(max)) -} - -func (mq *MessageQuery) GetLastPartBySignalIDWithUnknownReceiver(ctx context.Context, sender uuid.UUID, timestamp uint64, receiver uuid.UUID) (*Message, error) { - return mq.QueryOne(ctx, getMessageLastPartBySignalIDWithUnknownReceiverQuery, sender, timestamp, receiver) -} - -func (mq *MessageQuery) GetManyBySignalID(ctx context.Context, sender uuid.UUID, timestamps []uint64, receiver uuid.UUID, strictReceiver bool) ([]*Message, error) { - receiver2 := uuid.Nil - if strictReceiver { - receiver2 = receiver - } - if mq.GetDB().Dialect == dbutil.Postgres { - int64Array := make([]int64, len(timestamps)) - for i, timestamp := range timestamps { - int64Array[i] = int64(timestamp) - } - return mq.QueryMany(ctx, getManyMessagesBySignalIDQueryPostgres, sender, receiver, receiver2, pq.Array(int64Array)) - } else { - const varargIndex = 3 - arguments := make([]any, len(timestamps)+varargIndex) - placeholders := make([]string, len(timestamps)) - arguments[0] = sender - arguments[1] = receiver - arguments[2] = receiver2 - for i, timestamp := range timestamps { - arguments[i+varargIndex] = timestamp - placeholders[i] = fmt.Sprintf("?%d", i+varargIndex+1) - } - return mq.QueryMany(ctx, strings.Replace(getManyMessagesBySignalIDQuerySQLite, fmt.Sprintf("?%d", varargIndex+1), strings.Join(placeholders, ", "), 1), arguments...) - } -} - -func (msg *Message) Scan(row dbutil.Scannable) (*Message, error) { - return dbutil.ValueOrErr(msg, row.Scan( - &msg.Sender, &msg.Timestamp, &msg.PartIndex, &msg.SignalChatID, &msg.SignalReceiver, &msg.MXID, &msg.RoomID, - )) -} - -func (msg *Message) sqlVariables() []any { - return []any{msg.Sender, msg.Timestamp, msg.PartIndex, msg.SignalChatID, msg.SignalReceiver, msg.MXID, msg.RoomID} -} - -func (msg *Message) Insert(ctx context.Context) error { - return msg.qh.Exec(ctx, insertMessageQuery, msg.sqlVariables()...) -} - -func (msg *Message) Delete(ctx context.Context) error { - return msg.qh.Exec(ctx, deleteMessageQuery, msg.Sender, msg.Timestamp, msg.PartIndex, msg.SignalReceiver) -} - -func (msg *Message) SetTimestamp(ctx context.Context, editTime uint64) error { - return msg.qh.Exec(ctx, updateMessageTimestampQuery, msg.Sender, msg.Timestamp, msg.SignalReceiver, editTime) -} diff --git a/database/portal.go b/database/portal.go deleted file mode 100644 index 786f084..0000000 --- a/database/portal.go +++ /dev/null @@ -1,206 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - "database/sql" - - "github.com/google/uuid" - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" -) - -const ( - portalBaseSelect = ` - SELECT chat_id, receiver, mxid, name, topic, avatar_path, avatar_hash, avatar_url, - name_set, avatar_set, topic_set, revision, encrypted, relay_user_id, expiration_time - FROM portal - ` - getPortalByMXIDQuery = portalBaseSelect + `WHERE mxid=$1` - getPortalByChatIDQuery = portalBaseSelect + `WHERE chat_id=$1 AND receiver=$2` - getPortalsByReceiver = portalBaseSelect + `WHERE receiver=$1` - getPortalsByUser = portalBaseSelect + `WHERE chat_id=$1` - getAllPortalsWithMXIDQuery = portalBaseSelect + `WHERE mxid IS NOT NULL` - getChatsNotInSpaceQuery = ` - SELECT chat_id FROM portal - LEFT JOIN user_portal ON portal.chat_id=user_portal.portal_chat_id AND portal.receiver=user_portal.portal_receiver - WHERE mxid<>'' AND receiver=$1 AND (user_portal.in_space=false OR user_portal.in_space IS NULL) - ` - insertPortalQuery = ` - INSERT INTO portal ( - chat_id, receiver, mxid, name, topic, avatar_path, avatar_hash, avatar_url, - name_set, avatar_set, topic_set, revision, encrypted, relay_user_id, expiration_time - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) - ` - updatePortalQuery = ` - UPDATE portal SET - mxid=$3, name=$4, topic=$5, avatar_path=$6, avatar_hash=$7, avatar_url=$8, - name_set=$9, avatar_set=$10, topic_set=$11, revision=$12, encrypted=$13, relay_user_id=$14, expiration_time=$15 - WHERE chat_id=$1 AND receiver=$2 - ` - deletePortalQuery = `DELETE FROM portal WHERE chat_id=$1 AND receiver=$2` - reIDPortalQuery = `UPDATE portal SET chat_id=$2 WHERE chat_id=$1 AND receiver=$3` -) - -type PortalQuery struct { - *dbutil.QueryHelper[*Portal] -} - -type PortalKey struct { - ChatID string - Receiver uuid.UUID -} - -func (pk *PortalKey) UserID() libsignalgo.ServiceID { - parsed, _ := libsignalgo.ServiceIDFromString(pk.ChatID) - return parsed -} - -func (pk *PortalKey) GroupID() types.GroupIdentifier { - if len(pk.ChatID) == 44 { - return types.GroupIdentifier(pk.ChatID) - } - return "" -} - -func NewPortalKey(chatID string, receiver uuid.UUID) PortalKey { - return PortalKey{ - ChatID: chatID, - Receiver: receiver, - } -} - -type Portal struct { - qh *dbutil.QueryHelper[*Portal] - - PortalKey - MXID id.RoomID - Name string - Topic string - AvatarPath string - AvatarHash string - AvatarURL id.ContentURI - NameSet bool - AvatarSet bool - TopicSet bool - Revision uint32 - Encrypted bool - RelayUserID id.UserID - ExpirationTime uint32 -} - -func newPortal(qh *dbutil.QueryHelper[*Portal]) *Portal { - return &Portal{qh: qh} -} - -func (pq *PortalQuery) GetByMXID(ctx context.Context, mxid id.RoomID) (*Portal, error) { - return pq.QueryOne(ctx, getPortalByMXIDQuery, mxid) -} - -func (pq *PortalQuery) GetByChatID(ctx context.Context, pk PortalKey) (*Portal, error) { - return pq.QueryOne(ctx, getPortalByChatIDQuery, pk.ChatID, pk.Receiver) -} - -func (pq *PortalQuery) FindPrivateChatsWith(ctx context.Context, userID uuid.UUID) ([]*Portal, error) { - return pq.QueryMany(ctx, getPortalsByUser, userID.String()) -} - -func (pq *PortalQuery) FindPrivateChatsOf(ctx context.Context, receiver uuid.UUID) ([]*Portal, error) { - return pq.QueryMany(ctx, getPortalsByReceiver, receiver) -} - -func (pq *PortalQuery) GetAllWithMXID(ctx context.Context) ([]*Portal, error) { - return pq.QueryMany(ctx, getAllPortalsWithMXIDQuery) -} - -func (pq *PortalQuery) FindPrivateChatsNotInSpace(ctx context.Context, receiver uuid.UUID) ([]PortalKey, error) { - rows, err := pq.GetDB().Query(ctx, getChatsNotInSpaceQuery, receiver) - if err != nil { - return nil, err - } - return dbutil.NewRowIter(rows, func(rows dbutil.Scannable) (key PortalKey, err error) { - err = rows.Scan(&key.ChatID) - key.Receiver = receiver - return - }).AsList() -} - -func (p *Portal) Scan(row dbutil.Scannable) (*Portal, error) { - var mxid sql.NullString - err := row.Scan( - &p.ChatID, - &p.Receiver, - &mxid, - &p.Name, - &p.Topic, - &p.AvatarPath, - &p.AvatarHash, - &p.AvatarURL, - &p.NameSet, - &p.AvatarSet, - &p.TopicSet, - &p.Revision, - &p.Encrypted, - &p.RelayUserID, - &p.ExpirationTime, - ) - if err != nil { - return nil, err - } - p.MXID = id.RoomID(mxid.String) - return p, nil -} - -func (p *Portal) sqlVariables() []any { - return []any{ - p.ChatID, - p.Receiver, - dbutil.StrPtr(p.MXID), - p.Name, - p.Topic, - p.AvatarPath, - p.AvatarHash, - &p.AvatarURL, - p.NameSet, - p.AvatarSet, - p.TopicSet, - p.Revision, - p.Encrypted, - p.RelayUserID, - p.ExpirationTime, - } -} - -func (p *Portal) Insert(ctx context.Context) error { - return p.qh.Exec(ctx, insertPortalQuery, p.sqlVariables()...) -} - -func (p *Portal) Update(ctx context.Context) error { - return p.qh.Exec(ctx, updatePortalQuery, p.sqlVariables()...) -} - -func (p *Portal) Delete(ctx context.Context) error { - return p.qh.Exec(ctx, deletePortalQuery, p.ChatID, p.Receiver) -} - -func (p *Portal) ReID(ctx context.Context, newID string) error { - return p.qh.Exec(ctx, reIDPortalQuery, p.ChatID, newID, p.Receiver) -} diff --git a/database/puppet.go b/database/puppet.go deleted file mode 100644 index 99a65ff..0000000 --- a/database/puppet.go +++ /dev/null @@ -1,158 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - "database/sql" - "time" - - "github.com/google/uuid" - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" -) - -const ( - puppetBaseSelect = ` - SELECT uuid, number, name, name_quality, avatar_path, avatar_hash, avatar_url, name_set, avatar_set, - contact_info_set, is_registered, profile_fetched_at, custom_mxid, access_token - FROM puppet - ` - getPuppetBySignalIDQuery = puppetBaseSelect + `WHERE uuid=$1` - getPuppetByNumberQuery = puppetBaseSelect + `WHERE number=$1` - getPuppetByCustomMXIDQuery = puppetBaseSelect + `WHERE custom_mxid=$1` - getPuppetsWithCustomMXID = puppetBaseSelect + `WHERE custom_mxid<>''` - updatePuppetQuery = ` - UPDATE puppet SET - number=$2, name=$3, name_quality=$4, avatar_path=$5, avatar_hash=$6, avatar_url=$7, - name_set=$8, avatar_set=$9, contact_info_set=$10, is_registered=$11, profile_fetched_at=$12, - custom_mxid=$13, access_token=$14 - WHERE uuid=$1 - ` - insertPuppetQuery = ` - INSERT INTO puppet ( - uuid, number, name, name_quality, avatar_path, avatar_hash, avatar_url, - name_set, avatar_set, contact_info_set, is_registered, profile_fetched_at, - custom_mxid, access_token - ) - VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14 - ) - ` -) - -type PuppetQuery struct { - *dbutil.QueryHelper[*Puppet] -} - -type Puppet struct { - qh *dbutil.QueryHelper[*Puppet] - - SignalID uuid.UUID - Number string - Name string - NameQuality int - AvatarPath string - AvatarHash string - AvatarURL id.ContentURI - NameSet bool - AvatarSet bool - - IsRegistered bool - ContactInfoSet bool - ProfileFetchedAt time.Time - - CustomMXID id.UserID - AccessToken string -} - -func newPuppet(qh *dbutil.QueryHelper[*Puppet]) *Puppet { - return &Puppet{qh: qh} -} - -func (pq *PuppetQuery) GetBySignalID(ctx context.Context, signalID uuid.UUID) (*Puppet, error) { - return pq.QueryOne(ctx, getPuppetBySignalIDQuery, signalID) -} - -func (pq *PuppetQuery) GetByNumber(ctx context.Context, number string) (*Puppet, error) { - return pq.QueryOne(ctx, getPuppetByNumberQuery, number) -} - -func (pq *PuppetQuery) GetByCustomMXID(ctx context.Context, mxid id.UserID) (*Puppet, error) { - return pq.QueryOne(ctx, getPuppetByCustomMXIDQuery, mxid) -} - -func (pq *PuppetQuery) GetAllWithCustomMXID(ctx context.Context) ([]*Puppet, error) { - return pq.QueryMany(ctx, getPuppetsWithCustomMXID) -} - -func (p *Puppet) Scan(row dbutil.Scannable) (*Puppet, error) { - var number, customMXID sql.NullString - var profileFetchedAt sql.NullInt64 - err := row.Scan( - &p.SignalID, - &number, - &p.Name, - &p.NameQuality, - &p.AvatarPath, - &p.AvatarHash, - &p.AvatarURL, - &p.NameSet, - &p.AvatarSet, - &p.ContactInfoSet, - &p.IsRegistered, - &profileFetchedAt, - &customMXID, - &p.AccessToken, - ) - if err != nil { - return nil, err - } - p.Number = number.String - p.CustomMXID = id.UserID(customMXID.String) - if profileFetchedAt.Valid { - p.ProfileFetchedAt = time.UnixMilli(profileFetchedAt.Int64) - } - return p, nil -} - -func (p *Puppet) sqlVariables() []any { - return []any{ - p.SignalID, - dbutil.StrPtr(p.Number), - p.Name, - p.NameQuality, - p.AvatarPath, - p.AvatarHash, - &p.AvatarURL, - p.NameSet, - p.AvatarSet, - p.ContactInfoSet, - p.IsRegistered, - dbutil.UnixMilliPtr(p.ProfileFetchedAt), - dbutil.StrPtr(p.CustomMXID), - p.AccessToken, - } -} - -func (p *Puppet) Insert(ctx context.Context) error { - return p.qh.Exec(ctx, insertPuppetQuery, p.sqlVariables()...) -} - -func (p *Puppet) Update(ctx context.Context) error { - return p.qh.Exec(ctx, updatePuppetQuery, p.sqlVariables()...) -} diff --git a/database/reaction.go b/database/reaction.go deleted file mode 100644 index fc5228e..0000000 --- a/database/reaction.go +++ /dev/null @@ -1,97 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - - "github.com/google/uuid" - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" -) - -const ( - getReactionByMXIDQuery = `SELECT msg_author, msg_timestamp, author, emoji, signal_chat_id, signal_receiver, mxid, mx_room FROM reaction WHERE mxid=$1` - getReactionBySignalIDQuery = `SELECT msg_author, msg_timestamp, author, emoji, signal_chat_id, signal_receiver, mxid, mx_room FROM reaction WHERE msg_author=$1 AND msg_timestamp=$2 AND author=$3 AND signal_receiver=$4` - insertReactionQuery = ` - INSERT INTO reaction (msg_author, msg_timestamp, author, emoji, signal_chat_id, signal_receiver, mxid, mx_room) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8) - ` - updateReactionQuery = ` - UPDATE reaction - SET mxid=$1, emoji=$2 - WHERE msg_author=$3 AND msg_timestamp=$4 AND author=$5 AND signal_receiver=$6 - ` - deleteReactionQuery = ` - DELETE FROM reaction WHERE msg_author=$1 AND msg_timestamp=$2 AND author=$3 AND signal_receiver=$4 - ` -) - -type ReactionQuery struct { - *dbutil.QueryHelper[*Reaction] -} - -func newReaction(qh *dbutil.QueryHelper[*Reaction]) *Reaction { - return &Reaction{qh: qh} -} - -type Reaction struct { - qh *dbutil.QueryHelper[*Reaction] - - MsgAuthor uuid.UUID - MsgTimestamp uint64 - Author uuid.UUID - Emoji string - - SignalChatID string - SignalReceiver uuid.UUID - - MXID id.EventID - RoomID id.RoomID -} - -func (rq *ReactionQuery) GetByMXID(ctx context.Context, mxid id.EventID) (*Reaction, error) { - return rq.QueryOne(ctx, getReactionByMXIDQuery, mxid) -} - -func (rq *ReactionQuery) GetBySignalID(ctx context.Context, msgAuthor uuid.UUID, msgTimestamp uint64, author, signalReceiver uuid.UUID) (*Reaction, error) { - return rq.QueryOne(ctx, getReactionBySignalIDQuery, msgAuthor, msgTimestamp, author, signalReceiver) -} - -func (r *Reaction) Scan(row dbutil.Scannable) (*Reaction, error) { - return dbutil.ValueOrErr(r, row.Scan( - &r.MsgAuthor, &r.MsgTimestamp, &r.Author, &r.Emoji, &r.SignalChatID, &r.SignalReceiver, &r.MXID, &r.RoomID, - )) -} - -func (r *Reaction) sqlVariables() []any { - return []any{ - r.MsgAuthor, r.MsgTimestamp, r.Author, r.Emoji, r.SignalChatID, r.SignalReceiver, r.MXID, r.RoomID, - } -} - -func (r *Reaction) Insert(ctx context.Context) error { - return r.qh.Exec(ctx, insertReactionQuery, r.sqlVariables()...) -} - -func (r *Reaction) Update(ctx context.Context) error { - return r.qh.Exec(ctx, updateReactionQuery, r.MXID, r.Emoji, r.MsgAuthor, r.MsgTimestamp, r.Author, r.SignalReceiver) -} - -func (r *Reaction) Delete(ctx context.Context) error { - return r.qh.Exec(ctx, deleteReactionQuery, r.MsgAuthor, r.MsgTimestamp, r.Author, r.SignalReceiver) -} diff --git a/database/upgrades/00-latest.sql b/database/upgrades/00-latest.sql deleted file mode 100644 index 4dec3ff..0000000 --- a/database/upgrades/00-latest.sql +++ /dev/null @@ -1,116 +0,0 @@ --- v0 -> v20 (compatible with v17+): Latest revision - -CREATE TABLE portal ( - chat_id TEXT NOT NULL, - receiver uuid NOT NULL, - mxid TEXT, - name TEXT NOT NULL, - topic TEXT NOT NULL, - encrypted BOOLEAN NOT NULL DEFAULT false, - avatar_path TEXT NOT NULL DEFAULT '', - avatar_hash TEXT NOT NULL, - avatar_url TEXT NOT NULL, - name_set BOOLEAN NOT NULL DEFAULT false, - avatar_set BOOLEAN NOT NULL DEFAULT false, - topic_set BOOLEAN NOT NULL DEFAULT false, - revision INTEGER NOT NULL DEFAULT 0, - - expiration_time BIGINT NOT NULL, - relay_user_id TEXT NOT NULL, - - PRIMARY KEY (chat_id, receiver), - CONSTRAINT portal_mxid_unique UNIQUE(mxid) -); - -CREATE TABLE puppet ( - uuid uuid PRIMARY KEY, - number TEXT UNIQUE, - name TEXT NOT NULL, - name_quality INTEGER NOT NULL, - avatar_path TEXT NOT NULL, - avatar_hash TEXT NOT NULL, - avatar_url TEXT NOT NULL, - name_set BOOLEAN NOT NULL DEFAULT false, - avatar_set BOOLEAN NOT NULL DEFAULT false, - - is_registered BOOLEAN NOT NULL DEFAULT false, - contact_info_set BOOLEAN NOT NULL DEFAULT false, - profile_fetched_at BIGINT, - - custom_mxid TEXT, - access_token TEXT NOT NULL, - - CONSTRAINT puppet_custom_mxid_unique UNIQUE(custom_mxid) -); - -CREATE TABLE "user" ( - mxid TEXT PRIMARY KEY, - uuid uuid, - phone TEXT, - - management_room TEXT, - space_room TEXT, - - CONSTRAINT user_uuid_unique UNIQUE(uuid) -); - -CREATE TABLE user_portal ( - user_mxid TEXT, - portal_chat_id TEXT, - portal_receiver uuid, - last_read_ts BIGINT NOT NULL DEFAULT 0, - in_space BOOLEAN NOT NULL DEFAULT false, - - PRIMARY KEY (user_mxid, portal_chat_id, portal_receiver), - CONSTRAINT user_portal_user_fkey FOREIGN KEY (user_mxid) - REFERENCES "user"(mxid) ON UPDATE CASCADE ON DELETE CASCADE, - CONSTRAINT user_portal_portal_fkey FOREIGN KEY (portal_chat_id, portal_receiver) - REFERENCES portal(chat_id, receiver) ON UPDATE CASCADE ON DELETE CASCADE -); - -CREATE TABLE message ( - sender uuid NOT NULL, - timestamp BIGINT NOT NULL, - part_index INTEGER NOT NULL, - - signal_chat_id TEXT NOT NULL, - signal_receiver uuid NOT NULL, - - mxid TEXT NOT NULL, - mx_room TEXT NOT NULL, - - PRIMARY KEY (sender, timestamp, part_index, signal_receiver), - CONSTRAINT message_portal_fkey FOREIGN KEY (signal_chat_id, signal_receiver) - REFERENCES portal(chat_id, receiver) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (sender) REFERENCES puppet(uuid) ON DELETE CASCADE, - CONSTRAINT message_mxid_unique UNIQUE (mxid) -); - -CREATE TABLE reaction ( - msg_author uuid NOT NULL, - msg_timestamp BIGINT NOT NULL, - -- part_index is not used in reactions, but is required for the foreign key. - _part_index INTEGER NOT NULL DEFAULT 0, - - author uuid NOT NULL, - emoji TEXT NOT NULL, - - signal_chat_id TEXT NOT NULL, - signal_receiver uuid NOT NULL, - - mxid TEXT NOT NULL, - mx_room TEXT NOT NULL, - - PRIMARY KEY (msg_author, msg_timestamp, author, signal_receiver), - CONSTRAINT reaction_message_fkey FOREIGN KEY (msg_author, msg_timestamp, _part_index, signal_receiver) - REFERENCES message (sender, timestamp, part_index, signal_receiver) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (author) REFERENCES puppet(uuid) ON DELETE CASCADE, - CONSTRAINT reaction_mxid_unique UNIQUE (mxid) -); - -CREATE TABLE disappearing_message ( - mxid TEXT NOT NULL PRIMARY KEY, - room_id TEXT NOT NULL, - expiration_seconds BIGINT NOT NULL, - expiration_ts BIGINT -); diff --git a/database/upgrades/13-upgrade-mx-state-store.sql b/database/upgrades/13-upgrade-mx-state-store.sql deleted file mode 100644 index ec1b6c2..0000000 --- a/database/upgrades/13-upgrade-mx-state-store.sql +++ /dev/null @@ -1,18 +0,0 @@ --- v13: Switch mx_room_state from Python to Go format -ALTER TABLE mx_room_state DROP COLUMN is_encrypted; -ALTER TABLE mx_room_state DROP COLUMN has_full_member_list; - --- only: postgres for next 2 lines -ALTER TABLE mx_room_state ALTER COLUMN power_levels TYPE jsonb USING power_levels::jsonb; -ALTER TABLE mx_room_state ALTER COLUMN encryption TYPE jsonb USING encryption::jsonb; - -ALTER TABLE "user" ADD COLUMN management_room TEXT; - -UPDATE mx_user_profile SET displayname='' WHERE displayname IS NULL; -UPDATE mx_user_profile SET avatar_url='' WHERE avatar_url IS NULL; - -CREATE TABLE mx_registrations ( - user_id TEXT PRIMARY KEY -); - -UPDATE mx_version SET version=5; diff --git a/database/upgrades/14-remove-notice-room.sql b/database/upgrades/14-remove-notice-room.sql deleted file mode 100644 index 9ad0692..0000000 --- a/database/upgrades/14-remove-notice-room.sql +++ /dev/null @@ -1,3 +0,0 @@ --- v14: Remove redundant notice_room column from users -UPDATE "user" SET management_room = COALESCE(management_room, notice_room); -ALTER TABLE "user" DROP COLUMN notice_room; diff --git a/database/upgrades/15-remove-unused-puppet-columns.sql b/database/upgrades/15-remove-unused-puppet-columns.sql deleted file mode 100644 index 925c3a8..0000000 --- a/database/upgrades/15-remove-unused-puppet-columns.sql +++ /dev/null @@ -1,3 +0,0 @@ --- v15: Remove unused columns in puppet table -ALTER TABLE puppet DROP COLUMN next_batch; -ALTER TABLE puppet DROP COLUMN base_url; diff --git a/database/upgrades/16-refactor-postgres.sql b/database/upgrades/16-refactor-postgres.sql deleted file mode 100644 index 9ab94e8..0000000 --- a/database/upgrades/16-refactor-postgres.sql +++ /dev/null @@ -1,123 +0,0 @@ --- v16: Refactor types (Postgres) --- only: postgres - -DROP TABLE IF EXISTS user_portal; - --- Drop constraints so we can fix timestamps. -ALTER TABLE reaction DROP CONSTRAINT reaction_message_fkey; -ALTER TABLE message DROP CONSTRAINT message_pkey; - --- Add part index to message and fix the hacky timestamps -ALTER TABLE message ADD COLUMN part_index INTEGER; -UPDATE message - SET timestamp=CASE WHEN timestamp > 1500000000000000 THEN timestamp / 1000 ELSE timestamp END, - part_index=CASE WHEN timestamp > 1500000000000000 THEN timestamp % 1000 ELSE 0 END; --- If the bridge users have reacted to message parts, forget about those, not worth trying to deal with potential conflicts. -DELETE FROM reaction WHERE msg_timestamp > 1500000000000000; -ALTER TABLE message ALTER COLUMN part_index SET NOT NULL; -ALTER TABLE reaction ADD COLUMN _part_index INTEGER NOT NULL DEFAULT 0; - --- Re-add the dropped constraints (but with part index and no chat) -DELETE FROM message - WHERE (sender, timestamp, part_index, signal_receiver) - IN (SELECT DISTINCT sender, timestamp, part_index, signal_receiver FROM message GROUP BY (sender, timestamp, part_index, signal_receiver) HAVING COUNT(*)>1); -ALTER TABLE message ADD PRIMARY KEY (sender, timestamp, part_index, signal_receiver); -ALTER TABLE message DROP CONSTRAINT IF EXISTS message_signal_chat_id_signal_receiver_fkey; -ALTER TABLE message DROP CONSTRAINT IF EXISTS message_signal_chat_id_fkey; --- Also update the reaction primary key -ALTER TABLE reaction DROP CONSTRAINT reaction_pkey; -ALTER TABLE reaction ADD PRIMARY KEY (author, msg_author, msg_timestamp, signal_receiver); - --- Change unique constraint from (mxid, mx_room) to just mxid. -ALTER TABLE message DROP CONSTRAINT message_mxid_mx_room_key; -ALTER TABLE message ADD CONSTRAINT message_mxid_unique UNIQUE (mxid); -ALTER TABLE reaction DROP CONSTRAINT reaction_mxid_mx_room_key; -ALTER TABLE reaction ADD CONSTRAINT reaction_mxid_unique UNIQUE (mxid); - -CREATE TABLE lost_portals ( - mxid TEXT PRIMARY KEY, - chat_id TEXT, - receiver TEXT -); -INSERT INTO lost_portals SELECT mxid, chat_id, receiver FROM portal WHERE mxid<>''; - --- Make mxid column unique (requires using nulls for missing values) -UPDATE portal SET mxid=NULL WHERE mxid=''; -ALTER TABLE portal ADD CONSTRAINT portal_mxid_unique UNIQUE(mxid); --- Delete any portals that aren't associated with logged-in users. -DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE username IS NOT NULL AND uuid IS NOT NULL); --- CASCADE manually -DELETE FROM message - WHERE (signal_chat_id, signal_receiver) - NOT IN (SELECT DISTINCT signal_chat_id, signal_receiver FROM message WHERE (signal_chat_id, signal_receiver) IN (SELECT DISTINCT chat_id, receiver FROM portal)); -DELETE FROM reaction - WHERE (author, msg_author, msg_timestamp, signal_receiver) - NOT IN (SELECT DISTINCT author, msg_author, msg_timestamp, signal_receiver FROM reaction WHERE (msg_author, msg_timestamp, _part_index, signal_receiver) IN (SELECT DISTINCT sender, timestamp, part_index, signal_receiver FROM message)); --- Change receiver to uuid instead of phone number, also add nil uuid for groups. -UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver AND uuid IS NOT NULL LIMIT 1) WHERE receiver<>''; -UPDATE portal SET receiver='00000000-0000-0000-0000-000000000000' WHERE receiver=''; --- CASCADE manually -UPDATE message SET signal_receiver=(SELECT uuid FROM "user" WHERE username=signal_receiver AND uuid IS NOT NULL LIMIT 1) WHERE signal_receiver<>''; -UPDATE message SET signal_receiver='00000000-0000-0000-0000-000000000000' WHERE signal_receiver=''; -UPDATE reaction SET signal_receiver=(SELECT uuid FROM "user" WHERE username=signal_receiver AND uuid IS NOT NULL LIMIT 1) WHERE signal_receiver<>''; -UPDATE reaction SET signal_receiver='00000000-0000-0000-0000-000000000000' WHERE signal_receiver=''; --- Change column types -ALTER TABLE portal ALTER COLUMN receiver TYPE uuid USING receiver::uuid; -ALTER TABLE message ALTER COLUMN signal_receiver TYPE uuid USING signal_receiver::uuid; -ALTER TABLE reaction ALTER COLUMN signal_receiver TYPE uuid USING signal_receiver::uuid; --- Re-add the dropped constraints again -ALTER TABLE message ADD CONSTRAINT message_portal_fkey - FOREIGN KEY (signal_chat_id, signal_receiver) - REFERENCES portal (chat_id, receiver) - ON DELETE CASCADE ON UPDATE CASCADE; -ALTER TABLE reaction ADD CONSTRAINT reaction_message_fkey FOREIGN KEY (msg_author, msg_timestamp, _part_index, signal_receiver) - REFERENCES message (sender, timestamp, part_index, signal_receiver) ON DELETE CASCADE ON UPDATE CASCADE; --- Delete group v1 portal entries -DELETE FROM portal WHERE chat_id NOT LIKE '________-____-____-____-____________' AND LENGTH(chat_id) <> 44; -DELETE FROM lost_portals WHERE mxid IN (SELECT mxid FROM portal WHERE mxid<>''); - --- Remove unnecessary nullables in portal -UPDATE portal SET name='' WHERE name IS NULL; -UPDATE portal SET topic='' WHERE topic IS NULL; -UPDATE portal SET avatar_hash='' WHERE avatar_hash IS NULL; -UPDATE portal SET avatar_url='' WHERE avatar_url IS NULL; -UPDATE portal SET expiration_time=0 WHERE expiration_time IS NULL; -UPDATE portal SET relay_user_id='' WHERE relay_user_id IS NULL; -ALTER TABLE portal ALTER COLUMN name SET NOT NULL; -ALTER TABLE portal ALTER COLUMN topic SET NOT NULL; -ALTER TABLE portal ALTER COLUMN avatar_hash SET NOT NULL; -ALTER TABLE portal ALTER COLUMN avatar_url SET NOT NULL; -ALTER TABLE portal ALTER COLUMN expiration_time SET NOT NULL; -ALTER TABLE portal ALTER COLUMN relay_user_id SET NOT NULL; - --- Add unique constraint to custom_mxid -UPDATE puppet - SET custom_mxid=NULL, access_token='' - WHERE custom_mxid<>'' - AND uuid<>COALESCE((SELECT uuid FROM "user" WHERE mxid=custom_mxid), '00000000-0000-0000-0000-000000000000'); -UPDATE puppet SET custom_mxid=NULL WHERE custom_mxid=''; -ALTER TABLE puppet ADD CONSTRAINT puppet_custom_mxid_unique UNIQUE(custom_mxid); --- Remove unnecessary nullables in puppet -UPDATE puppet SET name='' WHERE name IS NULL; -UPDATE puppet SET avatar_hash='' WHERE avatar_hash IS NULL; -UPDATE puppet SET avatar_url='' WHERE avatar_url IS NULL; -UPDATE puppet SET access_token='' WHERE access_token IS NULL; -ALTER TABLE puppet ALTER COLUMN name SET NOT NULL; -ALTER TABLE puppet ALTER COLUMN avatar_hash SET NOT NULL; -ALTER TABLE puppet ALTER COLUMN avatar_url SET NOT NULL; -ALTER TABLE puppet ALTER COLUMN access_token SET NOT NULL; -ALTER TABLE puppet ALTER COLUMN name_quality DROP DEFAULT; - -UPDATE "user" - SET uuid=NULL - WHERE uuid IN (SELECT DISTINCT uuid FROM "user" WHERE uuid IS NOT NULL GROUP BY uuid HAVING COUNT(*)>1); -ALTER TABLE "user" ADD CONSTRAINT user_uuid_unique UNIQUE(uuid); -ALTER TABLE "user" RENAME COLUMN username TO phone; - --- Drop room_id from disappearing message primary key -ALTER TABLE disappearing_message DROP CONSTRAINT disappearing_message_pkey; -ALTER TABLE disappearing_message ADD PRIMARY KEY (mxid); --- Remove unnecessary nullables in disappearing_message -ALTER TABLE disappearing_message ALTER COLUMN room_id SET NOT NULL; -UPDATE disappearing_message SET expiration_seconds=0 WHERE expiration_seconds IS NULL; -ALTER TABLE disappearing_message ALTER COLUMN expiration_seconds SET NOT NULL; diff --git a/database/upgrades/17-refactor-sqlite.sql b/database/upgrades/17-refactor-sqlite.sql deleted file mode 100644 index f55dc0b..0000000 --- a/database/upgrades/17-refactor-sqlite.sql +++ /dev/null @@ -1,198 +0,0 @@ --- v17: Refactor types (SQLite) --- transaction: off --- only: sqlite - --- This is separate from v16 so that postgres can run with transaction: on --- (split upgrades by dialect don't currently allow disabling transaction in only one dialect) - -DROP TABLE IF EXISTS user_portal; - -PRAGMA foreign_keys = OFF; -BEGIN; - -CREATE TABLE message_new ( - sender uuid NOT NULL, - timestamp BIGINT NOT NULL, - part_index INTEGER NOT NULL, - - signal_chat_id TEXT NOT NULL, - signal_receiver TEXT NOT NULL, - - mxid TEXT NOT NULL, - mx_room TEXT NOT NULL, - - PRIMARY KEY (sender, timestamp, part_index, signal_receiver), - CONSTRAINT message_portal_fkey FOREIGN KEY (signal_chat_id, signal_receiver) REFERENCES portal(chat_id, receiver) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (sender) REFERENCES puppet(uuid) ON DELETE CASCADE, - CONSTRAINT message_mxid_unique UNIQUE (mxid) -); - -CREATE TABLE reaction_new ( - msg_author uuid NOT NULL, - msg_timestamp BIGINT NOT NULL, - -- part_index is not used in reactions, but is required for the foreign key. - _part_index INTEGER NOT NULL DEFAULT 0, - - author uuid NOT NULL, - emoji TEXT NOT NULL, - - signal_chat_id TEXT NOT NULL, - signal_receiver TEXT NOT NULL, - - mxid TEXT NOT NULL, - mx_room TEXT NOT NULL, - - PRIMARY KEY (msg_author, msg_timestamp, author, signal_receiver), - CONSTRAINT reaction_message_fkey FOREIGN KEY (msg_author, msg_timestamp, _part_index, signal_receiver) - REFERENCES message (sender, timestamp, part_index, signal_receiver) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (author) REFERENCES puppet(uuid) ON DELETE CASCADE, - CONSTRAINT reaction_mxid_unique UNIQUE (mxid) -); - - -DELETE FROM message - WHERE (sender, timestamp, signal_receiver) - IN (SELECT sender, timestamp, signal_receiver FROM message GROUP BY sender, timestamp, signal_receiver HAVING COUNT(*)>1); - -INSERT INTO message_new -SELECT sender, - CASE WHEN timestamp > 1500000000000000 THEN timestamp / 1000 ELSE timestamp END, - CASE WHEN timestamp > 1500000000000000 THEN timestamp % 1000 ELSE 0 END, - COALESCE(signal_chat_id, ''), - COALESCE(signal_receiver, ''), - mxid, - mx_room -FROM message; - -INSERT INTO reaction_new -SELECT msg_author, - msg_timestamp, - 0, -- _part_index - author, - emoji, - COALESCE(signal_chat_id, ''), - COALESCE(signal_receiver, ''), - mxid, - mx_room -FROM reaction -WHERE msg_timestamp<1500000000000000; - -DROP TABLE message; -DROP TABLE reaction; -ALTER TABLE message_new RENAME TO message; -ALTER TABLE reaction_new RENAME TO reaction; - -PRAGMA foreign_key_check; -COMMIT; - -PRAGMA foreign_keys = ON; - -BEGIN; -CREATE TABLE lost_portals ( - mxid TEXT PRIMARY KEY, - chat_id TEXT, - receiver TEXT -); -INSERT INTO lost_portals SELECT mxid, chat_id, receiver FROM portal WHERE mxid<>''; -DELETE FROM portal WHERE receiver<>'' AND receiver NOT IN (SELECT username FROM "user" WHERE username IS NOT NULL AND uuid<>''); -UPDATE portal SET receiver=(SELECT uuid FROM "user" WHERE username=receiver AND uuid<>'' LIMIT 1) WHERE receiver<>''; -UPDATE portal SET receiver='00000000-0000-0000-0000-000000000000' WHERE receiver=''; -DELETE FROM portal WHERE chat_id NOT LIKE '________-____-____-____-____________' AND LENGTH(chat_id) <> 44; -DELETE FROM lost_portals WHERE mxid IN (SELECT mxid FROM portal WHERE mxid<>''); -COMMIT; - -PRAGMA foreign_keys = OFF; - -BEGIN; - -CREATE TABLE portal_new ( - chat_id TEXT NOT NULL, - receiver uuid NOT NULL, - mxid TEXT, - name TEXT NOT NULL, - topic TEXT NOT NULL, - encrypted BOOLEAN NOT NULL DEFAULT false, - avatar_hash TEXT NOT NULL, - avatar_url TEXT NOT NULL, - name_set BOOLEAN NOT NULL DEFAULT false, - avatar_set BOOLEAN NOT NULL DEFAULT false, - revision INTEGER NOT NULL DEFAULT 0, - - expiration_time BIGINT NOT NULL, - relay_user_id TEXT NOT NULL, - - PRIMARY KEY (chat_id, receiver), - CONSTRAINT portal_mxid_unique UNIQUE(mxid) -); - -INSERT INTO portal_new - SELECT chat_id, receiver, CASE WHEN mxid='' THEN NULL ELSE mxid END, - COALESCE(name, ''), COALESCE(topic, ''), encrypted, COALESCE(avatar_hash, ''), COALESCE(avatar_url, ''), - name_set, avatar_set, revision, COALESCE(expiration_time, 0), COALESCE(relay_user_id, '') - FROM portal; -DROP TABLE portal; -ALTER TABLE portal_new RENAME TO portal; - -CREATE TABLE puppet_new ( - uuid uuid PRIMARY KEY, - number TEXT UNIQUE, - name TEXT NOT NULL, - name_quality INTEGER NOT NULL, - avatar_hash TEXT NOT NULL, - avatar_url TEXT NOT NULL, - name_set BOOLEAN NOT NULL DEFAULT false, - avatar_set BOOLEAN NOT NULL DEFAULT false, - - is_registered BOOLEAN NOT NULL DEFAULT false, - contact_info_set BOOLEAN NOT NULL DEFAULT false, - - custom_mxid TEXT, - access_token TEXT NOT NULL, - - CONSTRAINT puppet_custom_mxid_unique UNIQUE(custom_mxid) -); - -UPDATE puppet - SET custom_mxid=NULL, access_token='' - WHERE custom_mxid<>'' - AND uuid<>COALESCE((SELECT uuid FROM "user" WHERE mxid=custom_mxid), '00000000-0000-0000-0000-000000000000'); -INSERT INTO puppet_new - SELECT uuid, number, COALESCE(name, ''), COALESCE(name_quality, 0), COALESCE(avatar_hash, ''), - COALESCE(avatar_url, ''), name_set, avatar_set, is_registered, contact_info_set, - CASE WHEN custom_mxid='' THEN NULL ELSE custom_mxid END, COALESCE(access_token, '') - FROM puppet; -DROP TABLE puppet; -ALTER TABLE puppet_new RENAME TO puppet; - -CREATE TABLE user_new ( - mxid TEXT PRIMARY KEY, - uuid uuid, - phone TEXT, - - management_room TEXT, - - CONSTRAINT user_uuid_unique UNIQUE(uuid) -); - -INSERT INTO user_new - SELECT mxid, uuid, username, management_room - FROM user; -DROP TABLE user; -ALTER TABLE user_new RENAME TO user; - -CREATE TABLE disappearing_message_new ( - mxid TEXT NOT NULL PRIMARY KEY, - room_id TEXT NOT NULL, - expiration_seconds BIGINT NOT NULL, - expiration_ts BIGINT -); - -INSERT INTO disappearing_message_new - SELECT mxid, room_id, COALESCE(expiration_seconds, 0), expiration_ts - FROM disappearing_message; -DROP TABLE disappearing_message; -ALTER TABLE disappearing_message_new RENAME TO disappearing_message; - -PRAGMA foreign_key_check; -COMMIT; -PRAGMA foreign_keys = ON; diff --git a/database/upgrades/18-spaces.sql b/database/upgrades/18-spaces.sql deleted file mode 100644 index 24248ba..0000000 --- a/database/upgrades/18-spaces.sql +++ /dev/null @@ -1,17 +0,0 @@ --- v18 (compatible with v17+): Add columns for personal filtering space info -ALTER TABLE "user" ADD COLUMN space_room TEXT; - -DROP TABLE IF EXISTS user_portal; -CREATE TABLE user_portal ( - user_mxid TEXT, - portal_chat_id TEXT, - portal_receiver uuid, - last_read_ts BIGINT NOT NULL DEFAULT 0, - in_space BOOLEAN NOT NULL DEFAULT false, - - PRIMARY KEY (user_mxid, portal_chat_id, portal_receiver), - CONSTRAINT user_portal_user_fkey FOREIGN KEY (user_mxid) - REFERENCES "user"(mxid) ON UPDATE CASCADE ON DELETE CASCADE, - CONSTRAINT user_portal_portal_fkey FOREIGN KEY (portal_chat_id, portal_receiver) - REFERENCES portal(chat_id, receiver) ON UPDATE CASCADE ON DELETE CASCADE -); diff --git a/database/upgrades/19-more-portal-metadata.sql b/database/upgrades/19-more-portal-metadata.sql deleted file mode 100644 index 6230b21..0000000 --- a/database/upgrades/19-more-portal-metadata.sql +++ /dev/null @@ -1,5 +0,0 @@ --- v19 (compatible with v17+): Add more metadata for portals -ALTER TABLE portal ADD COLUMN topic_set BOOLEAN NOT NULL DEFAULT false; -UPDATE portal SET topic_set=true WHERE topic<>''; -ALTER TABLE portal ADD COLUMN avatar_path TEXT NOT NULL DEFAULT ''; -ALTER TABLE puppet ADD COLUMN avatar_path TEXT NOT NULL DEFAULT ''; diff --git a/database/upgrades/20-puppet-profile-fetch-ts.sql b/database/upgrades/20-puppet-profile-fetch-ts.sql deleted file mode 100644 index b398b2f..0000000 --- a/database/upgrades/20-puppet-profile-fetch-ts.sql +++ /dev/null @@ -1,2 +0,0 @@ --- v20 (compatible with v17+): Add profile fetch timestamp for puppets -ALTER TABLE puppet ADD profile_fetched_at BIGINT; diff --git a/database/user.go b/database/user.go deleted file mode 100644 index aa90686..0000000 --- a/database/user.go +++ /dev/null @@ -1,115 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - "database/sql" - "sync" - - "github.com/google/uuid" - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix/id" -) - -const ( - getUserByMXIDQuery = `SELECT mxid, phone, uuid, management_room, space_room FROM "user" WHERE mxid=$1` - getUserByPhoneQuery = `SELECT mxid, phone, uuid, management_room, space_room FROM "user" WHERE phone=$1` - getUserByUUIDQuery = `SELECT mxid, phone, uuid, management_room, space_room FROM "user" WHERE uuid=$1` - getAllLoggedInUsersQuery = `SELECT mxid, phone, uuid, management_room, space_room FROM "user" WHERE phone IS NOT NULL` - insertUserQuery = `INSERT INTO "user" (mxid, phone, uuid, management_room, space_room) VALUES ($1, $2, $3, $4, $5)` - updateUserQuery = `UPDATE "user" SET phone=$2, uuid=$3, management_room=$4, space_room=$5 WHERE mxid=$1` -) - -type UserQuery struct { - *dbutil.QueryHelper[*User] -} - -type User struct { - qh *dbutil.QueryHelper[*User] - - MXID id.UserID - SignalUsername string - SignalID uuid.UUID - ManagementRoom id.RoomID - SpaceRoom id.RoomID - - lastReadCache map[PortalKey]uint64 - lastReadCacheLock sync.Mutex - inSpaceCache map[PortalKey]bool - inSpaceCacheLock sync.Mutex -} - -func newUser(qh *dbutil.QueryHelper[*User]) *User { - return &User{ - qh: qh, - - lastReadCache: make(map[PortalKey]uint64), - inSpaceCache: make(map[PortalKey]bool), - } -} - -func (uq *UserQuery) GetByMXID(ctx context.Context, mxid id.UserID) (*User, error) { - return uq.QueryOne(ctx, getUserByMXIDQuery, mxid) -} - -func (uq *UserQuery) GetByPhone(ctx context.Context, phone string) (*User, error) { - return uq.QueryOne(ctx, getUserByPhoneQuery, phone) -} - -func (uq *UserQuery) GetBySignalID(ctx context.Context, uuid uuid.UUID) (*User, error) { - return uq.QueryOne(ctx, getUserByUUIDQuery, uuid) -} - -func (uq *UserQuery) GetAllLoggedIn(ctx context.Context) ([]*User, error) { - return uq.QueryMany(ctx, getAllLoggedInUsersQuery) -} - -func (u *User) sqlVariables() []any { - var nu uuid.NullUUID - nu.UUID = u.SignalID - nu.Valid = u.SignalID != uuid.Nil - return []any{u.MXID, dbutil.StrPtr(u.SignalUsername), nu, dbutil.StrPtr(u.ManagementRoom), dbutil.StrPtr(u.SpaceRoom)} -} - -func (u *User) Insert(ctx context.Context) error { - return u.qh.Exec(ctx, insertUserQuery, u.sqlVariables()...) -} - -func (u *User) Update(ctx context.Context) error { - return u.qh.Exec(ctx, updateUserQuery, u.sqlVariables()...) -} - -func (u *User) Scan(row dbutil.Scannable) (*User, error) { - var phone, managementRoom, spaceRoom sql.NullString - var signalID uuid.NullUUID - err := row.Scan( - &u.MXID, - &phone, - &signalID, - &managementRoom, - &spaceRoom, - ) - if err != nil { - return nil, err - } - u.SignalUsername = phone.String - u.SignalID = signalID.UUID - u.ManagementRoom = id.RoomID(managementRoom.String) - u.SpaceRoom = id.RoomID(spaceRoom.String) - return u, nil -} diff --git a/database/userportal.go b/database/userportal.go deleted file mode 100644 index 6081ee8..0000000 --- a/database/userportal.go +++ /dev/null @@ -1,116 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package database - -import ( - "context" - "database/sql" - "errors" - - "github.com/rs/zerolog" -) - -const ( - getLastReadTSQuery = `SELECT last_read_ts FROM user_portal WHERE user_mxid=$1 AND portal_chat_id=$2 AND portal_receiver=$3` - setLastReadTSQuery = ` - INSERT INTO user_portal (user_mxid, portal_chat_id, portal_receiver, last_read_ts) VALUES ($1, $2, $3, $4) - ON CONFLICT (user_mxid, portal_chat_id, portal_receiver) DO UPDATE - SET last_read_ts=excluded.last_read_ts WHERE user_portal.last_read_ts. - -package main - -import ( - "context" - "fmt" - "time" - - "github.com/rs/zerolog" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/database" -) - -type DisappearingMessagesManager struct { - DB *database.Database - Log zerolog.Logger - Bridge *SignalBridge - checkMessagesChan chan struct{} -} - -func (dmm *DisappearingMessagesManager) ScheduleDisappearingForRoom(ctx context.Context, roomID id.RoomID) { - log := dmm.Log.With().Stringer("room_id", roomID).Logger() - disappearingMessages, err := dmm.DB.DisappearingMessage.GetUnscheduledForRoom(ctx, roomID) - if err != nil { - log.Err(err).Msg("Failed to get unscheduled disappearing messages") - return - } - for _, disappearingMessage := range disappearingMessages { - err = disappearingMessage.StartExpirationTimer(ctx) - if err != nil { - log.Err(err).Msg("Failed to schedule disappearing message") - } else { - log.Debug(). - Stringer("event_id", disappearingMessage.EventID). - Time("expire_at", disappearingMessage.ExpireAt). - Msg("Scheduling disappearing message") - } - } - - // Tell the disappearing messages loop to check again - dmm.checkMessagesChan <- struct{}{} -} - -func (dmm *DisappearingMessagesManager) StartDisappearingLoop(ctx context.Context) { - dmm.checkMessagesChan = make(chan struct{}, 1) - go func() { - log := dmm.Log.With().Str("action", "loop").Logger() - ctx = log.WithContext(ctx) - for { - dmm.redactExpiredMessages(ctx) - - duration := 10 * time.Minute // Check again in 10 minutes just in case - nextMsg, err := dmm.DB.DisappearingMessage.GetNextScheduledMessage(ctx) - if err != nil { - if ctx.Err() != nil { - return - } - log.Err(err).Msg("Failed to get next disappearing message") - continue - } else if nextMsg != nil { - duration = time.Until(nextMsg.ExpireAt) - } - - select { - case <-time.After(duration): - case <-dmm.checkMessagesChan: - case <-ctx.Done(): - return - } - } - }() -} - -func (dmm *DisappearingMessagesManager) redactExpiredMessages(ctx context.Context) { - log := zerolog.Ctx(ctx) - expiredMessages, err := dmm.DB.DisappearingMessage.GetExpiredMessages(ctx) - if err != nil { - log.Err(err).Msg("Failed to get expired disappearing messages") - return - } - - for _, msg := range expiredMessages { - portal := dmm.Bridge.GetPortalByMXID(msg.RoomID) - if portal == nil { - log.Warn().Stringer("event_id", msg.EventID).Stringer("room_id", msg.RoomID).Msg("Failed to redact message: portal not found") - err = msg.Delete(ctx) - if err != nil { - log.Err(err). - Stringer("event_id", msg.EventID). - Msg("Failed to delete disappearing message row in database") - } - continue - } - _, err = portal.MainIntent().RedactEvent(ctx, msg.RoomID, msg.EventID, mautrix.ReqRedact{ - Reason: "Message expired", - TxnID: fmt.Sprintf("mxsg_disappear_%s", msg.EventID), - }) - if err != nil { - log.Err(err). - Stringer("event_id", msg.EventID). - Stringer("room_id", msg.RoomID). - Msg("Failed to redact message") - } else { - log.Err(err). - Stringer("event_id", msg.EventID). - Stringer("room_id", msg.RoomID). - Msg("Redacted message") - } - err = msg.Delete(ctx) - if err != nil { - log.Err(err). - Stringer("event_id", msg.EventID). - Msg("Failed to delete disappearing message row in database") - } - } -} - -func (dmm *DisappearingMessagesManager) AddDisappearingMessage(ctx context.Context, eventID id.EventID, roomID id.RoomID, expireIn time.Duration, startTimerNow bool) { - if expireIn == 0 { - return - } - var expireAt time.Time - if startTimerNow { - expireAt = time.Now().Add(expireIn) - } - disappearingMessage := dmm.DB.DisappearingMessage.NewWithValues(roomID, eventID, expireIn, expireAt) - err := disappearingMessage.Insert(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Stringer("event_id", eventID). - Msg("Failed to add disappearing message to database") - return - } - zerolog.Ctx(ctx).Debug().Stringer("event_id", eventID). - Msg("Added disappearing message row to database") - if startTimerNow { - // Tell the disappearing messages loop to check again - dmm.checkMessagesChan <- struct{}{} - } -} diff --git a/docker-run.sh b/docker-run.sh index fdb22b2..5f1ec65 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -17,11 +17,7 @@ function fixperms { } if [[ ! -f /data/config.yaml ]]; then - if [[ "$BRIDGEV2" == "1" ]]; then - $BINARY_NAME -c /data/config.yaml -e - else - cp /opt/mautrix-signal/example-config.yaml /data/config.yaml - fi + $BINARY_NAME -c /data/config.yaml -e echo "Didn't find a config file." echo "Copied default config file to /data/config.yaml" echo "Modify that config file to your liking." diff --git a/example-config.yaml b/example-config.yaml deleted file mode 100644 index 93a7955..0000000 --- a/example-config.yaml +++ /dev/null @@ -1,317 +0,0 @@ -# Homeserver details. -homeserver: - # The address that this appservice can use to connect to the homeserver. - address: https://matrix.example.com - # The domain of the homeserver (also known as server_name, used for MXIDs, etc). - domain: example.com - - # What software is the homeserver running? - # Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here. - software: standard - # The URL to push real-time bridge status to. - # If set, the bridge will make POST requests to this URL whenever a user's Signal connection state changes. - # The bridge will use the appservice as_token to authorize requests. - status_endpoint: null - # Endpoint for reporting per-message status. - message_send_checkpoint_endpoint: null - # Does the homeserver support https://github.com/matrix-org/matrix-spec-proposals/pull/2246? - async_media: false - - # Should the bridge use a websocket for connecting to the homeserver? - # The server side is currently not documented anywhere and is only implemented by mautrix-wsproxy, - # mautrix-asmux (deprecated), and hungryserv (proprietary). - websocket: false - # How often should the websocket be pinged? Pinging will be disabled if this is zero. - ping_interval_seconds: 0 - -# Application service host/registration related details. -# Changing these values requires regeneration of the registration. -appservice: - # The address that the homeserver can use to connect to this appservice. - address: http://localhost:29328 - - # The hostname and port where this appservice should listen. - hostname: 0.0.0.0 - port: 29328 - - # Database config. - database: - # The database type. "sqlite3-fk-wal" and "postgres" are supported. - type: postgres - # The database URI. - # SQLite: A raw file path is supported, but `file:?_txlock=immediate` is recommended. - # https://github.com/mattn/go-sqlite3#connection-string - # Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable - # To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql - uri: postgres://user:password@host/database?sslmode=disable - # Maximum number of connections. Mostly relevant for Postgres. - max_open_conns: 20 - max_idle_conns: 2 - # Maximum connection idle time and lifetime before they're closed. Disabled if null. - # Parsed with https://pkg.go.dev/time#ParseDuration - max_conn_idle_time: null - max_conn_lifetime: null - - # The unique ID of this appservice. - id: signal - # Appservice bot details. - bot: - # Username of the appservice bot. - username: signalbot - # Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty - # to leave display name/avatar as-is. - displayname: Signal bridge bot - avatar: mxc://maunium.net/wPJgTQbZOtpBFmDNkiNEMDUp - - # Whether or not to receive ephemeral events via appservice transactions. - # Requires MSC2409 support (i.e. Synapse 1.22+). - ephemeral_events: true - - # Should incoming events be handled asynchronously? - # This may be necessary for large public instances with lots of messages going through. - # However, messages will not be guaranteed to be bridged in the same order they were sent in. - async_transactions: false - - # Authentication tokens for AS <-> HS communication. Autogenerated; do not modify. - as_token: "This value is generated when generating the registration" - hs_token: "This value is generated when generating the registration" - -# Prometheus config. -metrics: - # Enable prometheus metrics? - enabled: false - # IP and port where the metrics listener should be. The path is always /metrics - listen: 127.0.0.1:8000 - -signal: - # Default device name that shows up in the Signal app. - device_name: mautrix-signal - -# Bridge config -bridge: - # Localpart template of MXIDs for Signal users. - # {{.}} is replaced with the internal ID of the Signal user. - username_template: signal_{{.}} - # Displayname template for Signal users. This is also used as the room name in DMs if private_chat_portal_meta is enabled. - # {{.ProfileName}} - The Signal profile name set by the user. - # {{.ContactName}} - The name for the user from your phone's contact list. This is not safe on multi-user instances. - # {{.PhoneNumber}} - The phone number of the user. - # {{.UUID}} - The UUID of the Signal user. - # {{.AboutEmoji}} - The emoji set by the user in their profile. - displayname_template: '{{or .ProfileName .PhoneNumber "Unknown user"}}' - # Whether to explicitly set the avatar and room name for private chat portal rooms. - # If set to `default`, this will be enabled in encrypted rooms and disabled in unencrypted rooms. - # If set to `always`, all DM rooms will have explicit names and avatars set. - # If set to `never`, DM rooms will never have names and avatars set. - private_chat_portal_meta: default - # Should avatars from the user's contact list be used? This is not safe on multi-user instances. - use_contact_avatars: false - # Should the bridge sync ghost user info even if profile fetching fails? This is not safe on multi-user instances. - use_outdated_profiles: false - # Should the Signal user's phone number be included in the room topic in private chat portal rooms? - number_in_topic: true - # Avatar image for the Note to Self room. - note_to_self_avatar: mxc://maunium.net/REBIVrqjZwmaWpssCZpBlmlL - - portal_message_buffer: 128 - - # Should the bridge create a space for each logged-in user and add bridged rooms to it? - # Users who logged in before turning this on should run `!signal sync-space` to create and fill the space for the first time. - personal_filtering_spaces: false - # Should Matrix m.notice-type messages be bridged? - bridge_notices: true - # Should the bridge send a read receipt from the bridge bot when a message has been sent to Signal? - delivery_receipts: false - # Whether the bridge should send the message status as a custom com.beeper.message_send_status event. - message_status_events: false - # Whether the bridge should send error notices via m.notice events when a message fails to bridge. - message_error_notices: true - # Should the bridge update the m.direct account data event when double puppeting is enabled. - # Note that updating the m.direct event is not atomic (except with mautrix-asmux) - # and is therefore prone to race conditions. - sync_direct_chat_list: false - # Set this to true to tell the bridge to re-send m.bridge events to all rooms on the next run. - # This field will automatically be changed back to false after it, except if the config file is not writable. - resend_bridge_info: false - # Whether or not to make portals of groups that don't need approval of an admin to join by invite - # link publicly joinable on Matrix. - public_portals: false - # Send captions in the same message as images. This will send data compatible with both MSC2530. - # This is currently not supported in most clients. - caption_in_message: false - # Format for generating URLs from location messages for sending to Signal - # Google Maps: 'https://www.google.com/maps/place/%[1]s,%[2]s' - # OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]s' - location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s' - # Whether or not created rooms should have federation enabled. - # If false, created portal rooms will never be federated. - federate_rooms: true - # Servers to always allow double puppeting from - double_puppet_server_map: - example.com: https://example.com - # Allow using double puppeting from any server with a valid client .well-known file. - double_puppet_allow_discovery: false - # Shared secrets for https://github.com/devture/matrix-synapse-shared-secret-auth - # - # If set, double puppeting will be enabled automatically for local users - # instead of users having to find an access token and run `login-matrix` - # manually. - login_shared_secret_map: - example.com: foobar - - # Maximum time for handling Matrix events. Duration strings formatted for https://pkg.go.dev/time#ParseDuration - # Null means there's no enforced timeout. - message_handling_timeout: - # Send an error message after this timeout, but keep waiting for the response until the deadline. - # This is counted from the origin_server_ts, so the warning time is consistent regardless of the source of delay. - # If the message is older than this when it reaches the bridge, the message won't be handled at all. - error_after: null - # Drop messages after this timeout. They may still go through if the message got sent to the servers. - # This is counted from the time the bridge starts handling the message. - deadline: 120s - - # The prefix for commands. Only required in non-management rooms. - command_prefix: '!signal' - # Messages sent upon joining a management room. - # Markdown is supported. The defaults are listed below. - management_room_text: - # Sent when joining a room. - welcome: "Hello, I'm a Signal bridge bot." - # Sent when joining a management room and the user is already logged in. - welcome_connected: "Use `help` for help." - # Sent when joining a management room and the user is not logged in. - welcome_unconnected: "Use `help` for help or `login` to log in." - # Optional extra text sent when joining a management room. - additional_help: "" - - # End-to-bridge encryption support options. - # - # See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info. - encryption: - # Allow encryption, work in group chat rooms with e2ee enabled - allow: false - # Default to encryption, force-enable encryption in all portals the bridge creates - # This will cause the bridge bot to be in private chats for the encryption to work properly. - default: false - # Whether to use MSC2409/MSC3202 instead of /sync long polling for receiving encryption-related data. - appservice: false - # Require encryption, drop any unencrypted messages. - require: false - # Enable key sharing? If enabled, key requests for rooms where users are in will be fulfilled. - # You must use a client that supports requesting keys from other users to use this feature. - allow_key_sharing: false - # Options for deleting megolm sessions from the bridge. - delete_keys: - # Beeper-specific: delete outbound sessions when hungryserv confirms - # that the user has uploaded the key to key backup. - delete_outbound_on_ack: false - # Don't store outbound sessions in the inbound table. - dont_store_outbound: false - # Ratchet megolm sessions forward after decrypting messages. - ratchet_on_decrypt: false - # Delete fully used keys (index >= max_messages) after decrypting messages. - delete_fully_used_on_decrypt: false - # Delete previous megolm sessions from same device when receiving a new one. - delete_prev_on_new_session: false - # Delete megolm sessions received from a device when the device is deleted. - delete_on_device_delete: false - # Periodically delete megolm sessions when 2x max_age has passed since receiving the session. - periodically_delete_expired: false - # Delete inbound megolm sessions that don't have the received_at field used for - # automatic ratcheting and expired session deletion. This is meant as a migration - # to delete old keys prior to the bridge update. - delete_outdated_inbound: false - # What level of device verification should be required from users? - # - # Valid levels: - # unverified - Send keys to all device in the room. - # cross-signed-untrusted - Require valid cross-signing, but trust all cross-signing keys. - # cross-signed-tofu - Require valid cross-signing, trust cross-signing keys on first use (and reject changes). - # cross-signed-verified - Require valid cross-signing, plus a valid user signature from the bridge bot. - # Note that creating user signatures from the bridge bot is not currently possible. - # verified - Require manual per-device verification - # (currently only possible by modifying the `trust` column in the `crypto_device` database table). - verification_levels: - # Minimum level for which the bridge should send keys to when bridging messages from Signal to Matrix. - receive: unverified - # Minimum level that the bridge should accept for incoming Matrix messages. - send: unverified - # Minimum level that the bridge should require for accepting key requests. - share: cross-signed-tofu - # Options for Megolm room key rotation. These options allow you to - # configure the m.room.encryption event content. See: - # https://spec.matrix.org/v1.3/client-server-api/#mroomencryption for - # more information about that event. - rotation: - # Enable custom Megolm room key rotation settings. Note that these - # settings will only apply to rooms created after this option is - # set. - enable_custom: false - # The maximum number of milliseconds a session should be used - # before changing it. The Matrix spec recommends 604800000 (a week) - # as the default. - milliseconds: 604800000 - # The maximum number of messages that should be sent with a given a - # session before changing it. The Matrix spec recommends 100 as the - # default. - messages: 100 - - # Disable rotating keys when a user's devices change? - # You should not enable this option unless you understand all the implications. - disable_device_change_key_rotation: false - # Should leaving the room on Matrix make the user leave on Signal? - bridge_matrix_leave: true - # Settings for provisioning API - provisioning: - # Prefix for the provisioning API paths. - prefix: /_matrix/provision - # Shared secret for authentication. If set to "generate", a random secret will be generated, - # or if set to "disable", the provisioning API will be disabled. - shared_secret: generate - # Enable debug API at /debug with provisioning authentication. - debug_endpoints: false - - # Permissions for using the bridge. - # Permitted values: - # relay - Talk through the relaybot (if enabled), no access otherwise - # user - Access to use the bridge to chat with a Signal account. - # admin - User level and some additional administration tools - # Permitted keys: - # * - All Matrix users - # domain - All users on that homeserver - # mxid - Specific user - permissions: - "*": relay - "example.com": user - "@admin:example.com": admin - - # Settings for relay mode - relay: - # Whether relay mode should be allowed. If allowed, `!signal set-relay` can be used to turn any - # authenticated user into a relaybot for that chat. - enabled: false - # Should only admins be allowed to set themselves as relay users? - admin_only: true - # The formats to use when sending messages to Signal via the relaybot. - message_formats: - m.text: "{{ .Sender.Displayname }}: {{ .Message }}" - m.notice: "{{ .Sender.Displayname }}: {{ .Message }}" - m.emote: "* {{ .Sender.Displayname }} {{ .Message }}" - m.file: "{{ .Sender.Displayname }} sent a file" - m.image: "{{ .Sender.Displayname }} sent an image" - m.audio: "{{ .Sender.Displayname }} sent an audio file" - m.video: "{{ .Sender.Displayname }} sent a video" - m.location: "{{ .Sender.Displayname }} sent a location" - -# Logging config. See https://github.com/tulir/zeroconfig for details. -logging: - min_level: debug - writers: - - type: stdout - format: pretty-colored - - type: file - format: json - filename: ./logs/mautrix-signal.log - max_size: 100 - max_backups: 10 - compress: true diff --git a/go.mod b/go.mod index a04e88a..45187a6 100644 --- a/go.mod +++ b/go.mod @@ -48,3 +48,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect ) + +//replace maunium.net/go/mautrix => ../mautrix-go +//replace go.mau.fi/util => ../../Go/go-util diff --git a/legacyprovision/types.go b/legacyprovision/types.go deleted file mode 100644 index 72f393a..0000000 --- a/legacyprovision/types.go +++ /dev/null @@ -1,92 +0,0 @@ -// mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2024 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 istributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package legacyprovision - -import ( - "encoding/json" - "net/http" - - "maunium.net/go/mautrix/id" -) - -func JSONResponse(w http.ResponseWriter, status int, response any) { - w.Header().Add("Content-Type", "application/json") - w.WriteHeader(status) - _ = json.NewEncoder(w).Encode(response) -} - -type Error struct { - Success bool `json:"success"` - Error string `json:"error"` - ErrCode string `json:"errcode"` -} - -type Response struct { - Success bool `json:"success"` - Status string `json:"status"` - - // For response in LinkNew - SessionID string `json:"session_id,omitempty"` - URI string `json:"uri,omitempty"` - - // For response in LinkWaitForAccount - UUID string `json:"uuid,omitempty"` - Number string `json:"number,omitempty"` - - // For response in ResolveIdentifier - *ResolveIdentifierResponse -} - -type WhoAmIResponse struct { - Permissions int `json:"permissions"` - MXID string `json:"mxid"` - Signal *WhoAmIResponseSignal `json:"signal,omitempty"` -} - -type WhoAmIResponseSignal struct { - Number string `json:"number"` - UUID string `json:"uuid"` - Name string `json:"name"` - Ok bool `json:"ok"` -} - -type ResolveIdentifierResponse struct { - RoomID id.RoomID `json:"room_id"` - ChatID ResolveIdentifierResponseChatID `json:"chat_id"` - JustCreated bool `json:"just_created"` - OtherUser *ResolveIdentifierResponseOtherUser `json:"other_user,omitempty"` -} - -type ResolveIdentifierResponseChatID struct { - UUID string `json:"uuid"` - Number string `json:"number"` -} - -type ResolveIdentifierResponseOtherUser struct { - MXID id.UserID `json:"mxid"` - DisplayName string `json:"displayname"` - AvatarURL id.ContentURI `json:"avatar_url"` -} - -type LinkWaitForScanRequest struct { - SessionID string `json:"session_id"` -} - -type LinkWaitForAccountRequest struct { - SessionID string `json:"session_id"` - DeviceName string `json:"device_name"` // TODO this seems to not be used anywhere -} diff --git a/main.go b/main.go deleted file mode 100644 index eb24aa0..0000000 --- a/main.go +++ /dev/null @@ -1,352 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - _ "embed" - "fmt" - "os" - "sync" - - "github.com/google/uuid" - "github.com/rs/zerolog" - "go.mau.fi/util/configupgrade" - "go.mau.fi/util/dbutil" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/bridge" - "maunium.net/go/mautrix/bridge/commands" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/format" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/config" - "go.mau.fi/mautrix-signal/database" - "go.mau.fi/mautrix-signal/msgconv/matrixfmt" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - "go.mau.fi/mautrix-signal/pkg/signalmeow/store" -) - -//go:embed example-config.yaml -var ExampleConfig string - -// Information to find out exactly which commit the bridge was built from. -// These are filled at build time with the -X linker flag. -var ( - Tag = "unknown" - Commit = "unknown" - BuildTime = "unknown" -) - -type SignalBridge struct { - bridge.Bridge - - Config *config.Config - DB *database.Database - Metrics *MetricsHandler - MeowStore *store.Container - - provisioning *ProvisioningAPI - - usersByMXID map[id.UserID]*User - usersBySignalID map[uuid.UUID]*User - usersLock sync.Mutex - - managementRooms map[id.RoomID]*User - managementRoomsLock sync.Mutex - - portalsByMXID map[id.RoomID]*Portal - portalsByID map[database.PortalKey]*Portal - portalsLock sync.Mutex - - puppets map[uuid.UUID]*Puppet - puppetsByCustomMXID map[id.UserID]*Puppet - puppetsLock sync.Mutex - - disappearingMessagesManager *DisappearingMessagesManager -} - -var _ bridge.ChildOverride = (*SignalBridge)(nil) - -func (br *SignalBridge) GetExampleConfig() string { - return ExampleConfig -} - -func (br *SignalBridge) GetConfigPtr() interface{} { - br.Config = &config.Config{ - BaseConfig: &br.Bridge.Config, - } - br.Config.BaseConfig.Bridge = &br.Config.Bridge - return br.Config -} - -func (br *SignalBridge) Init() { - br.CommandProcessor = commands.NewProcessor(&br.Bridge) - br.RegisterCommands() - - signalmeow.SetLogger(br.ZLog.With().Str("component", "signalmeow").Logger()) - - br.DB = database.New(br.Bridge.DB) - br.MeowStore = store.NewStore(br.Bridge.DB, dbutil.ZeroLogger(br.ZLog.With().Str("db_section", "signalmeow").Logger())) - - ss := br.Config.Bridge.Provisioning.SharedSecret - if len(ss) > 0 && ss != "disable" { - br.provisioning = &ProvisioningAPI{bridge: br, log: br.ZLog.With().Str("component", "provisioning").Logger()} - } - br.disappearingMessagesManager = &DisappearingMessagesManager{ - DB: br.DB, - Log: br.ZLog.With().Str("component", "disappearing messages").Logger(), - Bridge: br, - } - - br.Metrics = NewMetricsHandler(br.Config.Metrics.Listen, br.ZLog.With().Str("component", "metrics").Logger(), br.DB) - br.MatrixHandler.TrackEventDuration = br.Metrics.TrackMatrixEvent - - signalFormatParams = &signalfmt.FormatParams{ - GetUserInfo: func(ctx context.Context, u uuid.UUID) signalfmt.UserInfo { - puppet := br.GetPuppetBySignalID(u) - if puppet == nil { - return signalfmt.UserInfo{} - } - user := br.GetUserBySignalID(u) - if user != nil { - return signalfmt.UserInfo{ - MXID: user.MXID, - Name: puppet.Name, - } - } - return signalfmt.UserInfo{ - MXID: puppet.MXID, - Name: puppet.Name, - } - }, - } - matrixFormatParams = &matrixfmt.HTMLParser{ - GetUUIDFromMXID: func(ctx context.Context, userID id.UserID) uuid.UUID { - parsed, ok := br.ParsePuppetMXID(userID) - if ok { - return parsed - } - user := br.GetUserByMXIDIfExists(userID) - if user != nil && user.SignalID != uuid.Nil { - return user.SignalID - } - return uuid.Nil - }, - } -} - -func (br *SignalBridge) logLostPortals(ctx context.Context) { - exists, err := br.DB.TableExists(ctx, "lost_portals") - if err != nil { - br.ZLog.Err(err).Msg("Failed to check if lost_portals table exists") - } else if !exists { - return - } - lostPortals, err := br.DB.LostPortal.GetAll(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get lost portals") - return - } else if len(lostPortals) == 0 { - return - } - lostCountByReceiver := make(map[string]int) - for _, lost := range lostPortals { - lostCountByReceiver[lost.Receiver]++ - } - br.ZLog.Warn(). - Any("count_by_receiver", lostCountByReceiver). - Msg("Some portals were discarded due to the receiver not being logged into the bridge anymore. " + - "Use `!signal cleanup-lost-portals` to remove them from the database. " + - "Alternatively, you can re-insert the data into the portal table with the appropriate receiver column to restore the portals.") -} - -func (br *SignalBridge) Start() { - go br.logLostPortals(context.TODO()) - err := br.MeowStore.Upgrade(context.TODO()) - if err != nil { - br.ZLog.Fatal().Err(err).Msg("Failed to upgrade signalmeow database") - os.Exit(15) - } - if br.provisioning != nil { - br.ZLog.Debug().Msg("Initializing provisioning API") - br.provisioning.Init() - } - go br.StartUsers() - if br.Config.Metrics.Enabled { - go br.Metrics.Start() - } - go br.disappearingMessagesManager.StartDisappearingLoop(context.TODO()) -} - -func (br *SignalBridge) Stop() { - br.Metrics.Stop() - for _, user := range br.usersByMXID { - br.ZLog.Debug().Stringer("user_id", user.MXID).Msg("Disconnecting user") - user.Disconnect() - } -} - -func (br *SignalBridge) GetIPortal(mxid id.RoomID) bridge.Portal { - p := br.GetPortalByMXID(mxid) - if p == nil { - return nil - } - return p -} - -func (br *SignalBridge) GetIUser(mxid id.UserID, create bool) bridge.User { - p := br.GetUserByMXID(mxid) - if p == nil { - return nil - } - return p -} - -func (br *SignalBridge) IsGhost(mxid id.UserID) bool { - _, isGhost := br.ParsePuppetMXID(mxid) - return isGhost -} - -func (br *SignalBridge) GetIGhost(mxid id.UserID) bridge.Ghost { - p := br.GetPuppetByMXID(mxid) - if p == nil { - return nil - } - return p -} - -func (br *SignalBridge) CreatePrivatePortal(roomID id.RoomID, brInviter bridge.User, brGhost bridge.Ghost) { - inviter := brInviter.(*User) - puppet := brGhost.(*Puppet) - - log := br.ZLog.With(). - Str("action", "create private portal"). - Stringer("target_room_id", roomID). - Stringer("inviter_mxid", brInviter.GetMXID()). - Stringer("invitee_uuid", puppet.SignalID). - Logger() - log.Debug().Msg("Creating private chat portal") - - key := database.NewPortalKey(puppet.SignalID.String(), inviter.SignalID) - portal := br.GetPortalByChatID(key) - ctx := log.WithContext(context.TODO()) - - if len(portal.MXID) == 0 { - br.createPrivatePortalFromInvite(ctx, roomID, inviter, puppet, portal) - return - } - log.Debug(). - Stringer("existing_room_id", portal.MXID). - Msg("Existing private chat portal found, trying to invite user") - - ok := portal.ensureUserInvited(ctx, inviter) - if !ok { - log.Warn().Msg("Failed to invite user to existing private chat portal. Redirecting portal to new room") - br.createPrivatePortalFromInvite(ctx, roomID, inviter, puppet, portal) - return - } - intent := puppet.DefaultIntent() - errorMessage := fmt.Sprintf("You already have a private chat portal with me at [%[1]s](https://matrix.to/#/%[1]s)", portal.MXID) - errorContent := format.RenderMarkdown(errorMessage, true, false) - _, _ = intent.SendMessageEvent(ctx, roomID, event.EventMessage, errorContent) - log.Debug().Msg("Leaving ghost from private chat room after accepting invite because we already have a chat with the user") - _, _ = intent.LeaveRoom(ctx, roomID) -} - -func (br *SignalBridge) createPrivatePortalFromInvite(ctx context.Context, roomID id.RoomID, inviter *User, puppet *Puppet, portal *Portal) { - log := zerolog.Ctx(ctx) - log.Debug().Msg("Creating private portal from invite") - - // Check if room is already encrypted - var existingEncryption event.EncryptionEventContent - var encryptionEnabled bool - err := portal.MainIntent().StateEvent(ctx, roomID, event.StateEncryption, "", &existingEncryption) - if err != nil { - log.Err(err).Msg("Failed to check if encryption is enabled in private chat room") - } else { - encryptionEnabled = existingEncryption.Algorithm == id.AlgorithmMegolmV1 - } - portal.MXID = roomID - br.portalsLock.Lock() - br.portalsByMXID[portal.MXID] = portal - br.portalsLock.Unlock() - intent := puppet.DefaultIntent() - - if br.Config.Bridge.Encryption.Default || encryptionEnabled { - log.Debug().Msg("Adding bridge bot to new private chat portal as encryption is enabled") - _, err = intent.InviteUser(ctx, roomID, &mautrix.ReqInviteUser{UserID: br.Bot.UserID}) - if err != nil { - log.Err(err).Msg("Failed to invite bridge bot to enable e2be") - } - err = br.Bot.EnsureJoined(ctx, roomID) - if err != nil { - log.Err(err).Msg("Failed to join as bridge bot to enable e2be") - } - if !encryptionEnabled { - _, err = intent.SendStateEvent(ctx, roomID, event.StateEncryption, "", portal.getEncryptionEventContent()) - if err != nil { - log.Err(err).Msg("Failed to enable e2be") - } - } - br.AS.StateStore.SetMembership(ctx, roomID, inviter.MXID, event.MembershipJoin) - br.AS.StateStore.SetMembership(ctx, roomID, puppet.MXID, event.MembershipJoin) - br.AS.StateStore.SetMembership(ctx, roomID, br.Bot.UserID, event.MembershipJoin) - portal.Encrypted = true - } - portal.UpdateDMInfo(ctx, true) - _, _ = intent.SendNotice(ctx, roomID, "Private chat portal created") - log.Info().Msg("Created private chat portal after invite") -} - -func main() { - br := &SignalBridge{ - usersByMXID: make(map[id.UserID]*User), - usersBySignalID: make(map[uuid.UUID]*User), - - managementRooms: make(map[id.RoomID]*User), - - portalsByMXID: make(map[id.RoomID]*Portal), - portalsByID: make(map[database.PortalKey]*Portal), - - puppets: make(map[uuid.UUID]*Puppet), - puppetsByCustomMXID: make(map[id.UserID]*Puppet), - } - br.Bridge = bridge.Bridge{ - Name: "mautrix-signal", - URL: "https://github.com/mautrix/signal", - Description: "A Matrix-Signal puppeting bridge.", - Version: "0.6.3", - ProtocolName: "Signal", - BeeperServiceName: "signal", - BeeperNetworkName: "signal", - - CryptoPickleKey: "mautrix.bridge.e2ee", - - ConfigUpgrader: &configupgrade.StructUpgrader{ - SimpleUpgrader: configupgrade.SimpleUpgrader(config.DoUpgrade), - Blocks: config.SpacedBlocks, - Base: ExampleConfig, - }, - - Child: br, - } - br.InitVersion(Tag, Commit, BuildTime) - - br.Main() -} diff --git a/messagetracking.go b/messagetracking.go deleted file mode 100644 index e95abb4..0000000 --- a/messagetracking.go +++ /dev/null @@ -1,311 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "github.com/rs/zerolog" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/bridge/status" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/msgconv" -) - -var ( - errUserNotConnected = errors.New("you are not connected to Signal") - errDifferentUser = errors.New("user is not the recipient of this private chat portal") - errUserNotLoggedIn = errors.New("user is not logged in and chat has no relay bot") - errRelaybotNotLoggedIn = errors.New("neither user nor relay bot of chat are logged in") - errCantRelayReactions = errors.New("user is not logged in and reactions can't be relayed") - errMNoticeDisabled = errors.New("bridging m.notice messages is disabled") - errUnexpectedParsedContentType = errors.New("unexpected parsed content type") - - errRedactionTargetNotFound = errors.New("redaction target message was not found") - errRedactionTargetSentBySomeoneElse = errors.New("redaction target message was sent by someone else") - errUnreactTargetSentBySomeoneElse = errors.New("redaction target reaction was sent by someone else") - errReactionTargetNotFound = errors.New("reaction target message not found") - errEditUnknownTarget = errors.New("unknown edit target message") - errFailedToGetEditTarget = errors.New("failed to get edit target message") - errEditDifferentSender = errors.New("can't edit message sent by another user") - errEditTooOld = errors.New("message is too old to be edited") - - errMessageTakingLong = errors.New("bridging the message is taking longer than usual") - errTimeoutBeforeHandling = errors.New("message timed out before handling was started") -) - -func errorToStatusReason(err error) (reason event.MessageStatusReason, status event.MessageStatus, isCertain, sendNotice bool, humanMessage string) { - switch { - case errors.Is(err, errUnexpectedParsedContentType), - errors.Is(err, msgconv.ErrUnsupportedMsgType), - errors.Is(err, msgconv.ErrInvalidGeoURI): - return event.MessageStatusUnsupported, event.MessageStatusFail, true, true, "" - case errors.Is(err, errMNoticeDisabled): - return event.MessageStatusUnsupported, event.MessageStatusFail, true, false, "" - case errors.Is(err, errEditDifferentSender), - errors.Is(err, errEditTooOld), - errors.Is(err, errEditUnknownTarget): - return event.MessageStatusUnsupported, event.MessageStatusFail, true, true, err.Error() - case errors.Is(err, errTimeoutBeforeHandling): - return event.MessageStatusTooOld, event.MessageStatusRetriable, true, true, "the message was too old when it reached the bridge, so it was not handled" - case errors.Is(err, context.DeadlineExceeded): - return event.MessageStatusTooOld, event.MessageStatusRetriable, false, true, "handling the message took too long and was cancelled" - case errors.Is(err, errMessageTakingLong): - return event.MessageStatusTooOld, event.MessageStatusPending, false, true, err.Error() - case errors.Is(err, errRedactionTargetNotFound), - errors.Is(err, errReactionTargetNotFound), - errors.Is(err, errRedactionTargetSentBySomeoneElse), - errors.Is(err, errUnreactTargetSentBySomeoneElse): - return event.MessageStatusGenericError, event.MessageStatusFail, true, false, "" - case errors.Is(err, errUserNotConnected): - return event.MessageStatusGenericError, event.MessageStatusRetriable, true, true, "" - case errors.Is(err, errUserNotLoggedIn), - errors.Is(err, errDifferentUser), - errors.Is(err, errRelaybotNotLoggedIn): - return event.MessageStatusGenericError, event.MessageStatusRetriable, true, false, "" - default: - return event.MessageStatusGenericError, event.MessageStatusRetriable, false, true, "" - } -} - -func (portal *Portal) sendErrorMessage(ctx context.Context, evt *event.Event, err error, confirmed bool, editID id.EventID) id.EventID { - if !portal.bridge.Config.Bridge.MessageErrorNotices { - return "" - } - certainty := "may not have been" - if confirmed { - certainty = "was not" - } - var msgType string - switch evt.Type { - case event.EventMessage: - msgType = "message" - case event.EventReaction: - msgType = "reaction" - case event.EventRedaction: - msgType = "redaction" - //case TypeMSC3381PollResponse, TypeMSC3381V2PollResponse: - // msgType = "poll response" - //case TypeMSC3381PollStart: - // msgType = "poll start" - default: - msgType = "unknown event" - } - msg := fmt.Sprintf("\u26a0 Your %s %s bridged: %v", msgType, certainty, err) - if errors.Is(err, errMessageTakingLong) { - msg = fmt.Sprintf("\u26a0 Bridging your %s is taking longer than usual", msgType) - } - content := &event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: msg, - } - if editID != "" { - content.SetEdit(editID) - } else { - content.SetReply(evt) - } - resp, err := portal.sendMainIntentMessage(ctx, content) - if err != nil { - portal.log.Err(err).Msg("Failed to send bridging error message") - return "" - } - return resp.EventID -} - -func (portal *Portal) sendStatusEvent(ctx context.Context, evtID, lastRetry id.EventID, err error, deliveredTo *[]id.UserID) { - if !portal.bridge.Config.Bridge.MessageStatusEvents { - return - } - if lastRetry == evtID { - lastRetry = "" - } - intent := portal.bridge.Bot - if !portal.Encrypted { - // Bridge bot isn't present in unencrypted DMs - intent = portal.MainIntent() - } - content := event.BeeperMessageStatusEventContent{ - Network: portal.getBridgeInfoStateKey(), - RelatesTo: event.RelatesTo{ - Type: event.RelReference, - EventID: evtID, - }, - DeliveredToUsers: deliveredTo, - LastRetry: lastRetry, - } - if err == nil { - content.Status = event.MessageStatusSuccess - } else { - content.Reason, content.Status, _, _, content.Message = errorToStatusReason(err) - content.Error = err.Error() - } - _, err = intent.SendMessageEvent(ctx, portal.MXID, event.BeeperMessageStatus, &content) - if err != nil { - portal.log.Err(err).Msg("Failed to send message status event") - } -} - -func (portal *Portal) sendDeliveryReceipt(ctx context.Context, eventID id.EventID) { - if portal.bridge.Config.Bridge.DeliveryReceipts { - err := portal.bridge.Bot.SendReceipt(ctx, portal.MXID, eventID, event.ReceiptTypeRead, nil) - if err != nil { - portal.log.Debug().Err(err).Stringer("event_id", eventID).Msg("Failed to send delivery receipt") - } - } -} - -func (portal *Portal) sendMessageMetrics(ctx context.Context, evt *event.Event, err error, part string, ms *metricSender) { - log := portal.log.With(). - Str("handling_step", part). - Str("event_type", evt.Type.String()). - Stringer("event_id", evt.ID). - Stringer("sender", evt.Sender). - Logger() - if evt.Type == event.EventRedaction { - log = log.With().Stringer("redacts", evt.Redacts).Logger() - } - ctx = log.WithContext(ctx) - - origEvtID := evt.ID - if retryMeta := evt.Content.AsMessage().MessageSendRetry; retryMeta != nil { - origEvtID = retryMeta.OriginalEventID - } - if err != nil { - logEvt := log.Error() - if part == "Ignoring" { - logEvt = log.Debug() - } - logEvt.Err(err).Msg("Sending message metrics for event") - reason, statusCode, isCertain, sendNotice, _ := errorToStatusReason(err) - checkpointStatus := status.ReasonToCheckpointStatus(reason, statusCode) - portal.bridge.SendMessageCheckpoint(evt, status.MsgStepRemote, err, checkpointStatus, ms.getRetryNum()) - if sendNotice { - ms.setNoticeID(portal.sendErrorMessage(ctx, evt, err, isCertain, ms.getNoticeID())) - } - portal.sendStatusEvent(ctx, origEvtID, evt.ID, err, nil) - } else { - log.Debug().Msg("Sending metrics for successfully handled Matrix event") - portal.sendDeliveryReceipt(ctx, evt.ID) - portal.bridge.SendMessageSuccessCheckpoint(evt, status.MsgStepRemote, ms.getRetryNum()) - var deliveredTo *[]id.UserID - if portal.IsPrivateChat() { - deliveredTo = &[]id.UserID{} - } - portal.sendStatusEvent(ctx, origEvtID, evt.ID, nil, deliveredTo) - if prevNotice := ms.popNoticeID(); prevNotice != "" { - _, _ = portal.MainIntent().RedactEvent(ctx, portal.MXID, prevNotice, mautrix.ReqRedact{ - Reason: "error resolved", - }) - } - } - if ms != nil { - log.Debug().Object("timings", ms.timings).Msg("Timings for event") - } -} - -type messageTimings struct { - initReceive time.Duration - decrypt time.Duration - implicitRR time.Duration - portalQueue time.Duration - totalReceive time.Duration - - preproc time.Duration - convert time.Duration - totalSend time.Duration -} - -func niceRound(dur time.Duration) time.Duration { - switch { - case dur < time.Millisecond: - return dur - case dur < time.Second: - return dur.Round(100 * time.Microsecond) - default: - return dur.Round(time.Millisecond) - } -} - -func (mt *messageTimings) MarshalZerologObject(evt *zerolog.Event) { - evt. - Dict("bridge", zerolog.Dict(). - Stringer("init_receive", niceRound(mt.initReceive)). - Stringer("decrypt", niceRound(mt.decrypt)). - Stringer("queue", niceRound(mt.portalQueue)). - Stringer("total_hs_to_portal", niceRound(mt.totalReceive))). - Dict("portal", zerolog.Dict(). - Stringer("implicit_rr", niceRound(mt.implicitRR)). - Stringer("preproc", niceRound(mt.preproc)). - Stringer("convert", niceRound(mt.convert)). - Stringer("total_send", niceRound(mt.totalSend))) -} - -type metricSender struct { - portal *Portal - previousNotice id.EventID - lock sync.Mutex - completed bool - retryNum int - timings *messageTimings - ctx context.Context -} - -func (ms *metricSender) getRetryNum() int { - if ms != nil { - return ms.retryNum - } - return 0 -} - -func (ms *metricSender) getNoticeID() id.EventID { - if ms == nil { - return "" - } - return ms.previousNotice -} - -func (ms *metricSender) popNoticeID() id.EventID { - if ms == nil { - return "" - } - evtID := ms.previousNotice - ms.previousNotice = "" - return evtID -} - -func (ms *metricSender) setNoticeID(evtID id.EventID) { - if ms != nil && ms.previousNotice == "" { - ms.previousNotice = evtID - } -} - -func (ms *metricSender) sendMessageMetrics(evt *event.Event, err error, part string, completed bool) { - ms.lock.Lock() - defer ms.lock.Unlock() - if !completed && ms.completed { - return - } - ms.portal.sendMessageMetrics(ms.ctx, evt, err, part, ms) - ms.retryNum++ - ms.completed = completed -} diff --git a/metrics.go b/metrics.go deleted file mode 100644 index 2e76a04..0000000 --- a/metrics.go +++ /dev/null @@ -1,281 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Element -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "net/http" - "runtime/debug" - "sync" - "time" - - "github.com/google/uuid" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/rs/zerolog" - "maunium.net/go/mautrix/event" - - "go.mau.fi/mautrix-signal/database" -) - -type MetricsHandler struct { - db *database.Database - server *http.Server - log zerolog.Logger - - running bool - ctx context.Context - stopRecorder func() - - matrixEventHandling *prometheus.HistogramVec - signalMessageAge prometheus.Histogram - signalMessageHandling *prometheus.HistogramVec - countCollection prometheus.Histogram - puppetCount prometheus.Gauge - userCount prometheus.Gauge - messageCount prometheus.Gauge - portalCount *prometheus.GaugeVec - encryptedGroupCount prometheus.Gauge - encryptedPrivateCount prometheus.Gauge - unencryptedGroupCount prometheus.Gauge - unencryptedPrivateCount prometheus.Gauge - - connected prometheus.Gauge - connectedState map[uuid.UUID]bool - connectedStateLock sync.Mutex - loggedIn prometheus.Gauge - loggedInState map[uuid.UUID]bool - loggedInStateLock sync.Mutex -} - -func NewMetricsHandler(address string, log zerolog.Logger, db *database.Database) *MetricsHandler { - portalCount := promauto.NewGaugeVec(prometheus.GaugeOpts{ - Name: "signal_portals_total", - Help: "Number of portal rooms on Matrix", - }, []string{"type", "encrypted"}) - return &MetricsHandler{ - db: db, - server: &http.Server{Addr: address, Handler: promhttp.Handler()}, - log: log, - running: false, - - matrixEventHandling: promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "matrix_event", - Help: "Time spent processing Matrix events", - }, []string{"event_type"}), - signalMessageAge: promauto.NewHistogram(prometheus.HistogramOpts{ - Name: "remote_event_age", - Help: "Age of messages received from Signal", - Buckets: []float64{1, 2, 3, 5, 7.5, 10, 20, 30, 60}, - }), - signalMessageHandling: promauto.NewHistogramVec(prometheus.HistogramOpts{ - Name: "remote_event", - Help: "Time spent processing Signal messages", - }, []string{"message_type"}), - countCollection: promauto.NewHistogram(prometheus.HistogramOpts{ - Name: "signal_count_collection", - Help: "Time spent collecting the bridge_*_total metrics", - }), - puppetCount: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "signal_puppets_total", - Help: "Number of Signal users bridged into Matrix", - }), - userCount: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "signal_users_total", - Help: "Number of Matrix users using the bridge", - }), - messageCount: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "signal_messages_total", - Help: "Number of messages bridged", - }), - portalCount: portalCount, - encryptedGroupCount: portalCount.With(prometheus.Labels{"type": "group", "encrypted": "true"}), - encryptedPrivateCount: portalCount.With(prometheus.Labels{"type": "private", "encrypted": "true"}), - unencryptedGroupCount: portalCount.With(prometheus.Labels{"type": "group", "encrypted": "false"}), - unencryptedPrivateCount: portalCount.With(prometheus.Labels{"type": "private", "encrypted": "false"}), - - loggedIn: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "bridge_logged_in", - Help: "Bridge users logged into Signal", - }), - loggedInState: make(map[uuid.UUID]bool), - connected: promauto.NewGauge(prometheus.GaugeOpts{ - Name: "bridge_connected", - Help: "Bridge users connected to Signal", - }), - connectedState: make(map[uuid.UUID]bool), - } -} - -func noop() {} - -func (mh *MetricsHandler) TrackMatrixEvent(eventType event.Type) func() { - if !mh.running { - return noop - } - start := time.Now() - return func() { - duration := time.Since(start) - mh.matrixEventHandling. - With(prometheus.Labels{"event_type": eventType.Type}). - Observe(duration.Seconds()) - } -} - -func (mh *MetricsHandler) TrackSignalMessage(timestamp time.Time, messageType string) func() { - if !mh.running { - return noop - } - - start := time.Now() - return func() { - duration := time.Since(start) - mh.signalMessageHandling. - With(prometheus.Labels{"message_type": messageType}). - Observe(duration.Seconds()) - mh.signalMessageAge.Observe(time.Since(timestamp).Seconds()) - } -} - -func (mh *MetricsHandler) TrackLoginState(signalID uuid.UUID, loggedIn bool) { - if !mh.running { - return - } - mh.loggedInStateLock.Lock() - defer mh.loggedInStateLock.Unlock() - currentVal, ok := mh.loggedInState[signalID] - if !ok || currentVal != loggedIn { - mh.loggedInState[signalID] = loggedIn - if loggedIn { - mh.loggedIn.Inc() - } else if ok { - mh.loggedIn.Dec() - } - } -} - -func (mh *MetricsHandler) TrackConnectionState(signalID uuid.UUID, connected bool) { - if !mh.running { - return - } - mh.connectedStateLock.Lock() - defer mh.connectedStateLock.Unlock() - currentVal, ok := mh.connectedState[signalID] - if !ok || currentVal != connected { - mh.connectedState[signalID] = connected - if connected { - mh.connected.Inc() - } else if ok { - mh.connected.Dec() - } - } -} - -func (mh *MetricsHandler) updateStats() { - start := time.Now() - var puppetCount int - err := mh.db.QueryRow(mh.ctx, "SELECT COUNT(*) FROM puppet").Scan(&puppetCount) - if err != nil { - mh.log.Warn().Err(err).Msg("Failed to scan number of puppets") - } else { - mh.puppetCount.Set(float64(puppetCount)) - } - - var userCount int - err = mh.db.QueryRow(mh.ctx, `SELECT COUNT(*) FROM "user"`).Scan(&userCount) - if err != nil { - mh.log.Warn().Err(err).Msg("Failed to scan number of users:") - } else { - mh.userCount.Set(float64(userCount)) - } - - var messageCount int - err = mh.db.QueryRow(mh.ctx, "SELECT COUNT(*) FROM message").Scan(&messageCount) - if err != nil { - mh.log.Warn().Err(err).Msg("Failed to scan number of messages") - } else { - mh.messageCount.Set(float64(messageCount)) - } - - var encryptedGroupCount, encryptedPrivateCount, unencryptedGroupCount, unencryptedPrivateCount int - // TODO Use a more precise way to check if a chat_id is a UUID. - // It should also be compatible with both SQLite & Postgres. - err = mh.db.QueryRow(mh.ctx, ` - SELECT - COUNT(CASE WHEN chat_id NOT LIKE '%-%-%-%-%' AND encrypted THEN 1 END) AS encrypted_group_portals, - COUNT(CASE WHEN chat_id LIKE '%-%-%-%-%' AND encrypted THEN 1 END) AS encrypted_private_portals, - COUNT(CASE WHEN chat_id NOT LIKE '%-%-%-%-%' AND NOT encrypted THEN 1 END) AS unencrypted_group_portals, - COUNT(CASE WHEN chat_id LIKE '%-%-%-%-%' AND NOT encrypted THEN 1 END) AS unencrypted_private_portals - FROM portal WHERE mxid<>'' - `).Scan(&encryptedGroupCount, &encryptedPrivateCount, &unencryptedGroupCount, &unencryptedPrivateCount) - if err != nil { - mh.log.Warn().Err(err).Msg("Failed to scan number of portals") - } else { - mh.encryptedGroupCount.Set(float64(encryptedGroupCount)) - mh.encryptedPrivateCount.Set(float64(encryptedPrivateCount)) - mh.unencryptedGroupCount.Set(float64(unencryptedGroupCount)) - mh.unencryptedPrivateCount.Set(float64(encryptedPrivateCount)) - } - mh.countCollection.Observe(time.Since(start).Seconds()) -} - -func (mh *MetricsHandler) startUpdatingStats() { - defer func() { - r := recover() - if r != nil { - evt := mh.log.Fatal().Str("stack", string(debug.Stack())) - if err, ok := r.(error); ok { - evt = evt.Err(err) - } else { - evt = evt.Any("error", r) - } - evt.Msg("Panic in metric updater") - } - }() - ticker := time.Tick(10 * time.Second) - for { - mh.updateStats() - select { - case <-mh.ctx.Done(): - return - case <-ticker: - } - } -} - -func (mh *MetricsHandler) Start() { - mh.running = true - mh.ctx, mh.stopRecorder = context.WithCancel(context.Background()) - go mh.startUpdatingStats() - err := mh.server.ListenAndServe() - mh.running = false - if err != nil && err != http.ErrServerClosed { - mh.log.Fatal().Err(err).Msg("Error in metrics listener") - } -} - -func (mh *MetricsHandler) Stop() { - if !mh.running { - return - } - mh.stopRecorder() - err := mh.server.Close() - if err != nil { - mh.log.Err(err).Msg("Error closing metrics listener") - } -} diff --git a/msgconv/msgconv.go b/msgconv/msgconv.go deleted file mode 100644 index ee3ff55..0000000 --- a/msgconv/msgconv.go +++ /dev/null @@ -1,65 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2024 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package msgconv - -import ( - "context" - "time" - - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/database" - "go.mau.fi/mautrix-signal/msgconv/matrixfmt" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" -) - -type PortalMethods interface { - UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) - DownloadMatrixMedia(ctx context.Context, uri id.ContentURIString) ([]byte, error) - GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) - GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote - - GetClient(ctx context.Context) *signalmeow.Client - - GetData(ctx context.Context) *database.Portal -} - -type ExtendedPortalMethods interface { - QueueFileTransfer(ctx context.Context, msgTS uint64, fileName string, ap *signalpb.AttachmentPointer) (id.ContentURIString, error) -} - -type MessageConverter struct { - PortalMethods - - SignalFmtParams *signalfmt.FormatParams - MatrixFmtParams *matrixfmt.HTMLParser - - ConvertVoiceMessages bool - ConvertGIFToAPNG bool - MaxFileSize int64 - AsyncFiles bool - UpdateDisappearing func(ctx context.Context, newTimer time.Duration) - - LocationFormat string -} - -func (mc *MessageConverter) IsPrivateChat(ctx context.Context) bool { - return !mc.GetData(ctx).UserID().IsEmpty() -} diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 732b0ae..a5d99c9 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -32,6 +32,7 @@ import ( "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -39,7 +40,7 @@ const PrivateChatTopic = "Signal private chat" const NoteToSelfName = "Signal Note to Self" func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { - userID, err := parseUserID(ghost.ID) + userID, err := signalid.ParseUserID(ghost.ID) if err != nil { return nil, err } @@ -51,7 +52,7 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( } func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { - userID, groupID, err := parsePortalID(portal.ID) + userID, groupID, err := signalid.ParsePortalID(portal.ID) if err != nil { return nil, err } @@ -143,19 +144,19 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre // createChat is a no-op: chats don't need to be created, and we always return chat info if aci != uuid.Nil { - ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(aci)) + ghost, err := s.Main.Bridge.GetGhostByID(ctx, signalid.MakeUserID(aci)) if err != nil { return nil, fmt.Errorf("failed to get ghost: %w", err) } return &bridgev2.ResolveIdentifierResponse{ - UserID: makeUserID(aci), + UserID: signalid.MakeUserID(aci), UserInfo: s.contactToUserInfo(recipient), Ghost: ghost, Chat: s.makeCreateDMResponse(recipient), }, nil } else { return &bridgev2.ResolveIdentifierResponse{ - UserID: makeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), + UserID: signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), UserInfo: s.contactToUserInfo(recipient), Chat: s.makeCreateDMResponse(recipient), }, nil @@ -179,14 +180,14 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI Chat: s.makeCreateDMResponse(recipient), } if recipient.ACI != uuid.Nil { - recipientResp.UserID = makeUserID(recipient.ACI) + recipientResp.UserID = signalid.MakeUserID(recipient.ACI) ghost, err := s.Main.Bridge.GetGhostByID(ctx, recipientResp.UserID) if err != nil { return nil, fmt.Errorf("failed to get ghost for %s: %w", recipient.ACI, err) } recipientResp.Ghost = ghost } else { - recipientResp.UserID = makeUserIDFromServiceID(libsignalgo.NewPNIServiceID(recipient.PNI)) + recipientResp.UserID = signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(recipient.PNI)) } resp[i] = recipientResp } @@ -215,7 +216,7 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev name = s.Main.Config.FormatDisplayname(recipient) serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) } else { - members.OtherUserID = makeUserID(recipient.ACI) + members.OtherUserID = signalid.MakeUserID(recipient.ACI) if recipient.ACI == s.Client.Store.ACI { name = NoteToSelfName avatar = &bridgev2.Avatar{ diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 838c0ee..56ab59a 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -11,6 +11,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" + "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" ) @@ -112,7 +113,7 @@ func (s *SignalClient) IsThisUser(_ context.Context, userID networkid.UserID) bo if s.Client == nil { return false } - return userID == makeUserID(s.Client.Store.ACI) + return userID == signalid.MakeUserID(s.Client.Store.ACI) } func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnectionStatus) { diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 4c36674..6a4e4dc 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -20,19 +20,12 @@ import ( "context" "fmt" "text/template" - "time" "github.com/google/uuid" - "github.com/rs/zerolog" "go.mau.fi/util/dbutil" "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/database" - "maunium.net/go/mautrix/bridgev2/networkid" - "maunium.net/go/mautrix/id" - "go.mau.fi/mautrix-signal/msgconv" - "go.mau.fi/mautrix-signal/msgconv/matrixfmt" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/msgconv" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" ) @@ -82,65 +75,7 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { } s.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "signalmeow").Logger())) s.Bridge = bridge - s.MsgConv = &msgconv.MessageConverter{ - PortalMethods: &msgconvPortalMethods{}, - SignalFmtParams: &signalfmt.FormatParams{ - GetUserInfo: func(ctx context.Context, uuid uuid.UUID) signalfmt.UserInfo { - ghost, err := s.Bridge.GetGhostByID(ctx, makeUserID(uuid)) - if err != nil { - // TODO log? - return signalfmt.UserInfo{} - } - userInfo := signalfmt.UserInfo{ - MXID: ghost.Intent.GetMXID(), - Name: ghost.Name, - } - userLogin := s.Bridge.GetCachedUserLoginByID(networkid.UserLoginID(uuid.String())) - if userLogin != nil { - userInfo.MXID = userLogin.UserMXID - // TODO find matrix user displayname? - } - return userInfo - }, - }, - MatrixFmtParams: &matrixfmt.HTMLParser{ - GetUUIDFromMXID: func(ctx context.Context, userID id.UserID) uuid.UUID { - parsed, ok := s.Bridge.Matrix.ParseGhostMXID(userID) - if ok { - u, _ := uuid.Parse(string(parsed)) - return u - } - user, _ := s.Bridge.GetExistingUserByMXID(ctx, userID) - // TODO log errors? - if user != nil { - preferredLogin, _, _ := ctx.Value(msgconvContextKey).(*msgconvContext).Portal.FindPreferredLogin(ctx, user, true) - if preferredLogin != nil { - u, _ := uuid.Parse(string(preferredLogin.ID)) - return u - } - } - return uuid.Nil - }, - }, - ConvertVoiceMessages: true, - ConvertGIFToAPNG: true, - MaxFileSize: 50 * 1024 * 1024, - AsyncFiles: true, - LocationFormat: s.Config.LocationFormat, - UpdateDisappearing: func(ctx context.Context, newTimer time.Duration) { - portal := ctx.Value(msgconvContextKey).(*msgconvContext).Portal - portal.Disappear.Timer = newTimer - if newTimer == 0 { - portal.Disappear.Type = "" - } else { - portal.Disappear.Type = database.DisappearingTypeAfterRead - } - err := portal.Save(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") - } - }, - } + s.MsgConv = msgconv.NewMessageConverter(bridge, s.Config.LocationFormat) } func (s *SignalConnector) SetMaxFileSize(maxSize int64) { diff --git a/pkg/connector/dbmeta.go b/pkg/connector/dbmeta.go index 68e21d5..14f59f2 100644 --- a/pkg/connector/dbmeta.go +++ b/pkg/connector/dbmeta.go @@ -18,26 +18,20 @@ package connector import ( "maunium.net/go/mautrix/bridgev2/database" + + "go.mau.fi/mautrix-signal/pkg/signalid" ) func (s *SignalConnector) GetDBMetaTypes() database.MetaTypes { return database.MetaTypes{ Portal: func() any { - return &PortalMetadata{} + return &signalid.PortalMetadata{} }, Ghost: nil, Message: func() any { - return &MessageMetadata{} + return &signalid.MessageMetadata{} }, Reaction: nil, UserLogin: nil, } } - -type PortalMetadata struct { - Revision uint32 `json:"revision"` -} - -type MessageMetadata struct { - ContainsAttachments bool `json:"contains_attachments,omitempty"` -} diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 6bea361..3bf809d 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -27,6 +27,7 @@ import ( "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -174,7 +175,7 @@ func (s *SignalClient) makeGroupAvatar(meta signalmeow.GroupAvatarMeta) *bridgev func makeRevisionUpdater(rev uint32) func(ctx context.Context, portal *bridgev2.Portal) bool { return func(ctx context.Context, portal *bridgev2.Portal) bool { - meta := portal.Metadata.(*PortalMetadata) + meta := portal.Metadata.(*signalid.PortalMetadata) if meta.Revision < rev { meta.Revision = rev return true diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 2f36ae7..9e8c353 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -32,12 +32,13 @@ import ( "maunium.net/go/mautrix/bridgev2/networkid" "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" ) func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { - userID, groupID, err := parsePortalID(portalID) + userID, groupID, err := signalid.ParsePortalID(portalID) if err != nil { return err } @@ -77,15 +78,7 @@ func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.Porta } func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) { - mcCtx := &msgconvContext{ - Connector: s.Main, - Intent: nil, - Client: s, - Portal: msg.Portal, - ReplyTo: msg.ReplyTo, - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) + converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, msg.OrigSender != nil, msg.ReplyTo) if err != nil { return nil, err } @@ -94,10 +87,10 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma return nil, err } dbMsg := &database.Message{ - ID: makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), - SenderID: makeUserID(s.Client.Store.ACI), + ID: signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), + SenderID: signalid.MakeUserID(s.Client.Store.ACI), Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), - Metadata: &MessageMetadata{ + Metadata: &signalid.MessageMetadata{ ContainsAttachments: len(converted.Attachments) > 0, }, } @@ -107,27 +100,20 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma } func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { - _, targetSentTimestamp, err := parseMessageID(msg.EditTarget.ID) + _, targetSentTimestamp, err := signalid.ParseMessageID(msg.EditTarget.ID) if err != nil { return fmt.Errorf("failed to parse target message ID: %w", err) - } else if msg.EditTarget.SenderID != makeUserID(s.Client.Store.ACI) { + } else if msg.EditTarget.SenderID != signalid.MakeUserID(s.Client.Store.ACI) { return fmt.Errorf("cannot edit other people's messages") } - mcCtx := &msgconvContext{ - Connector: s.Main, - Intent: nil, - Client: s, - Portal: msg.Portal, - } + var replyTo *database.Message if msg.EditTarget.ReplyTo.MessageID != "" { - var err error - mcCtx.ReplyTo, err = s.Main.Bridge.DB.Message.GetFirstOrSpecificPartByID(ctx, msg.Portal.Receiver, msg.EditTarget.ReplyTo) + replyTo, err = s.Main.Bridge.DB.Message.GetFirstOrSpecificPartByID(ctx, msg.Portal.Receiver, msg.EditTarget.ReplyTo) if err != nil { return fmt.Errorf("failed to get message reply target: %w", err) } } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) - converted, err := s.Main.MsgConv.ToSignal(ctx, msg.Event, msg.Content, msg.OrigSender != nil) + converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, msg.OrigSender != nil, replyTo) if err != nil { return err } @@ -138,22 +124,22 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri if err != nil { return err } - msg.EditTarget.ID = makeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) - msg.EditTarget.Metadata = &MessageMetadata{ContainsAttachments: len(converted.Attachments) > 0} + msg.EditTarget.ID = signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) + msg.EditTarget.Metadata = &signalid.MessageMetadata{ContainsAttachments: len(converted.Attachments) > 0} msg.EditTarget.EditCount++ return nil } func (s *SignalClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { return bridgev2.MatrixReactionPreResponse{ - SenderID: makeUserID(s.Client.Store.ACI), + SenderID: signalid.MakeUserID(s.Client.Store.ACI), EmojiID: "", Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key), }, nil } func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { - targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) + targetAuthorACI, targetSentTimestamp, err := signalid.ParseMessageID(msg.TargetMessage.ID) if err != nil { return nil, fmt.Errorf("failed to parse target message ID: %w", err) } @@ -177,7 +163,7 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M } func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { - targetAuthorACI, targetSentTimestamp, err := parseMessageID(msg.TargetReaction.MessageID) + targetAuthorACI, targetSentTimestamp, err := signalid.ParseMessageID(msg.TargetReaction.MessageID) if err != nil { return fmt.Errorf("failed to parse target message ID: %w", err) } @@ -201,10 +187,10 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid } func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { - _, targetSentTimestamp, err := parseMessageID(msg.TargetMessage.ID) + _, targetSentTimestamp, err := signalid.ParseMessageID(msg.TargetMessage.ID) if err != nil { return fmt.Errorf("failed to parse target message ID: %w", err) - } else if msg.TargetMessage.SenderID != makeUserID(s.Client.Store.ACI) { + } else if msg.TargetMessage.SenderID != signalid.MakeUserID(s.Client.Store.ACI) { return fmt.Errorf("cannot delete other people's messages") } wrappedContent := &signalpb.Content{ @@ -237,7 +223,7 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri } messagesToRead := map[uuid.UUID][]uint64{} for _, msg := range dbMessages { - userID, timestamp, err := parseMessageID(msg.ID) + userID, timestamp, err := signalid.ParseMessageID(msg.ID) if err != nil { return fmt.Errorf("failed to parse message ID %q: %w", msg.ID, err) } @@ -275,7 +261,7 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri } func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2.MatrixTyping) error { - userID, _, err := parsePortalID(typing.Portal.ID) + userID, _, err := signalid.ParsePortalID(typing.Portal.ID) if err != nil { return err } @@ -292,11 +278,11 @@ func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2. } func (s *SignalClient) handleMatrixRoomMeta(ctx context.Context, portal *bridgev2.Portal, gc *signalmeow.GroupChange, postUpdatePortal func()) (bool, error) { - _, groupID, err := parsePortalID(portal.ID) + _, groupID, err := signalid.ParsePortalID(portal.ID) if err != nil || groupID == "" { return false, err } - gc.Revision = portal.Metadata.(*PortalMetadata).Revision + 1 + gc.Revision = portal.Metadata.(*signalid.PortalMetadata).Revision + 1 revision, err := s.Client.UpdateGroup(ctx, gc, groupID) if err != nil { return false, err @@ -316,7 +302,7 @@ func (s *SignalClient) handleMatrixRoomMeta(ctx context.Context, portal *bridgev if postUpdatePortal != nil { postUpdatePortal() } - portal.Metadata.(*PortalMetadata).Revision = revision + portal.Metadata.(*signalid.PortalMetadata).Revision = revision return true, nil } @@ -327,7 +313,7 @@ func (s *SignalClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2.M } func (s *SignalClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2.MatrixRoomAvatar) (bool, error) { - _, groupID, err := parsePortalID(msg.Portal.ID) + _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) if err != nil || groupID == "" { return false, err } diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 169338d..2f6803d 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -30,6 +30,7 @@ import ( "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" + "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) @@ -63,7 +64,7 @@ func (s *SignalClient) wrapCallEvent(evt *events.Call) bridgev2.RemoteMessage { PortalKey: s.makePortalKey(evt.Info.ChatID), Data: evt, CreatePortal: true, - ID: makeMessageID(evt.Info.Sender, evt.Timestamp), + ID: signalid.MakeMessageID(evt.Info.Sender, evt.Timestamp), Sender: s.makeEventSender(evt.Info.Sender), Timestamp: time.UnixMilli(int64(evt.Timestamp)), ConvertMessageFunc: convertCallEvent, @@ -76,7 +77,7 @@ func convertCallEvent(ctx context.Context, portal *bridgev2.Portal, intent bridg } if data.IsRinging { content.Body = "Incoming call" - if userID, _, _ := parsePortalID(portal.ID); !userID.IsEmpty() { + if userID, _, _ := signalid.ParsePortalID(portal.ID); !userID.IsEmpty() { content.MsgType = event.MsgText } } else { @@ -152,7 +153,7 @@ func (evt *Bv2ChatEvent) PreHandle(ctx context.Context, portal *bridgev2.Portal) if !ok || dataMsg.GroupV2 == nil { return } - portalRev := portal.Metadata.(*PortalMetadata).Revision + portalRev := portal.Metadata.(*signalid.PortalMetadata).Revision if evt.Info.GroupRevision > portalRev { toRevision := evt.Info.GroupRevision if dataMsg.GetGroupV2().GetGroupChange() != nil { @@ -206,7 +207,7 @@ func (evt *Bv2ChatEvent) GetID() networkid.MessageID { if ts == 0 { panic(fmt.Errorf("GetID() called for non-DataMessage event")) } - return makeMessageID(evt.Info.Sender, ts) + return signalid.MakeMessageID(evt.Info.Sender, ts) } func (evt *Bv2ChatEvent) getDataMsgTimestamp() uint64 { @@ -251,7 +252,7 @@ func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { if targetAuthorACI != "" { targetAuthorUUID, _ = uuid.Parse(targetAuthorACI) } - return makeMessageID(targetAuthorUUID, targetSentTS) + return signalid.MakeMessageID(targetAuthorUUID, targetSentTS) } func (evt *Bv2ChatEvent) GetReactionEmoji() (string, networkid.EmojiID) { @@ -267,82 +268,35 @@ func (evt *Bv2ChatEvent) GetRemovedEmojiID() networkid.EmojiID { } func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) { - mcCtx := &msgconvContext{ - Connector: evt.s.Main, - Intent: intent, - Client: evt.s, - Portal: portal, - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) dataMsg, ok := evt.Event.(*signalpb.DataMessage) if !ok { return nil, fmt.Errorf("ConvertMessage() called for non-DataMessage event") } - converted := evt.s.Main.MsgConv.ToMatrix(ctx, dataMsg) - converted.MergeCaption() - var replyTo *networkid.MessageOptionalPartID - if dataMsg.GetQuote() != nil { - quoteAuthor, _ := uuid.Parse(dataMsg.Quote.GetAuthorAci()) - replyTo = &networkid.MessageOptionalPartID{ - MessageID: makeMessageID(quoteAuthor, dataMsg.Quote.GetId()), - } - } - convertedParts := make([]*bridgev2.ConvertedMessagePart, len(converted.Parts)) - for i, part := range converted.Parts { - convertedParts[i] = &bridgev2.ConvertedMessagePart{ - ID: makeMessagePartID(i), - Type: part.Type, - Content: part.Content, - Extra: part.Extra, - DBMetadata: &MessageMetadata{ContainsAttachments: len(dataMsg.GetAttachments()) > 0}, - } - } - var disappear database.DisappearingSetting - if converted.DisappearIn != 0 { - disappear = database.DisappearingSetting{ - Type: database.DisappearingTypeAfterRead, - Timer: time.Duration(converted.DisappearIn) * time.Second, - } - dataMsgTS := time.UnixMilli(int64(dataMsg.GetTimestamp())) + converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, dataMsg) + if converted.Disappear.Type != "" { + evtTS := evt.GetTimestamp() + portal.UpdateDisappearingSetting(ctx, converted.Disappear, nil, evtTS, true, true) if evt.Info.Sender == evt.s.Client.Store.ACI { - disappear.DisappearAt = dataMsgTS.Add(disappear.Timer) + converted.Disappear.DisappearAt = evtTS.Add(converted.Disappear.Timer) } - portal.UpdateDisappearingSetting(ctx, disappear, nil, dataMsgTS, true, true) } - return &bridgev2.ConvertedMessage{ - ReplyTo: replyTo, - Parts: convertedParts, - Disappear: disappear, - }, nil + return converted, nil } func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message) (*bridgev2.ConvertedEdit, error) { - mcCtx := &msgconvContext{ - Connector: evt.s.Main, - Intent: intent, - Client: evt.s, - Portal: portal, - } - ctx = context.WithValue(ctx, msgconvContextKey, mcCtx) editMsg, ok := evt.Event.(*signalpb.EditMessage) if !ok { return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event") } // TODO tell converter about existing parts to avoid reupload? - converted := evt.s.Main.MsgConv.ToMatrix(ctx, editMsg.GetDataMessage()) - converted.MergeCaption() - convertedEdit := &bridgev2.ConvertedEdit{} + converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, editMsg.GetDataMessage()) // TODO can anything other than the text be edited? - lastPart := converted.Parts[len(converted.Parts)-1] - convertedEdit.ModifiedParts = append(convertedEdit.ModifiedParts, &bridgev2.ConvertedEditPart{ - Part: existing[len(existing)-1], - Type: lastPart.Type, - Content: lastPart.Content, - Extra: lastPart.Extra, - }) - convertedEdit.ModifiedParts[0].Part.EditCount++ - convertedEdit.ModifiedParts[0].Part.ID = makeMessageID(evt.Info.Sender, editMsg.GetDataMessage().GetTimestamp()) - return convertedEdit, nil + editPart := converted.Parts[len(converted.Parts)-1].ToEditPart(existing[len(existing)-1]) + editPart.Part.EditCount++ + editPart.Part.ID = signalid.MakeMessageID(evt.Info.Sender, editMsg.GetDataMessage().GetTimestamp()) + return &bridgev2.ConvertedEdit{ + ModifiedParts: []*bridgev2.ConvertedEditPart{editPart}, + }, nil } type Bv2Receipt struct { @@ -438,7 +392,7 @@ func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { Logger() ctx := log.WithContext(context.TODO()) receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { - return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, makeMessageID(s.Client.Store.ACI, msgTS)) + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, signalid.MakeMessageID(s.Client.Store.ACI, msgTS)) }) s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) } @@ -453,7 +407,7 @@ func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { if err != nil { return nil, err } - return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, makeMessageID(aciUUID, msgInfo.GetTimestamp())) + return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, signalid.MakeMessageID(aciUUID, msgInfo.GetTimestamp())) }) s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) } @@ -495,7 +449,7 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { continue } fullContact.ContactAvatar = contact.ContactAvatar - ghost, err := s.Main.Bridge.GetGhostByID(ctx, makeUserID(contact.ACI)) + ghost, err := s.Main.Bridge.GetGhostByID(ctx, signalid.MakeUserID(contact.ACI)) if err != nil { log.Err(err).Msg("Failed to get ghost to update contact info") continue @@ -510,7 +464,7 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { func (s *SignalClient) updateRemoteProfile(ctx context.Context, resendState bool) { var err error if s.Ghost == nil { - s.Ghost, err = s.Main.Bridge.GetGhostByID(ctx, makeUserID(s.Client.Store.ACI)) + s.Ghost, err = s.Main.Bridge.GetGhostByID(ctx, signalid.MakeUserID(s.Client.Store.ACI)) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get ghost for remote profile update") return diff --git a/pkg/connector/id.go b/pkg/connector/id.go index 6aa4f82..49cebe6 100644 --- a/pkg/connector/id.go +++ b/pkg/connector/id.go @@ -17,71 +17,14 @@ package connector import ( - "fmt" - "strconv" - "strings" - "github.com/google/uuid" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" + "go.mau.fi/mautrix-signal/pkg/signalid" ) -func parseUserID(userID networkid.UserID) (uuid.UUID, error) { - serviceID, err := parseUserIDAsServiceID(userID) - if err != nil { - return uuid.Nil, err - } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { - return uuid.Nil, fmt.Errorf("invalid user ID: expected ACI type") - } else { - return serviceID.UUID, nil - } -} - -func parseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { - return libsignalgo.ServiceIDFromString(string(userID)) -} - -func parsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { - if len(portalID) == 44 { - groupID = types.GroupIdentifier(portalID) - } else { - userID, err = libsignalgo.ServiceIDFromString(string(portalID)) - } - return -} - -func parseMessageID(messageID networkid.MessageID) (sender uuid.UUID, timestamp uint64, err error) { - parts := strings.Split(string(messageID), "|") - if len(parts) != 2 { - err = fmt.Errorf("invalid message ID: expected two pipe-separated parts") - return - } - sender, err = uuid.Parse(parts[0]) - if err != nil { - return - } - timestamp, err = strconv.ParseUint(parts[1], 10, 64) - return -} - -func makeGroupPortalID(groupID types.GroupIdentifier) networkid.PortalID { - return networkid.PortalID(groupID) -} - -func makeGroupPortalKey(groupID types.GroupIdentifier) networkid.PortalKey { - return networkid.PortalKey{ - ID: makeGroupPortalID(groupID), - Receiver: "", - } -} - -func makeDMPortalID(serviceID libsignalgo.ServiceID) networkid.PortalID { - return networkid.PortalID(serviceID.String()) -} - func (s *SignalClient) makePortalKey(chatID string) networkid.PortalKey { key := networkid.PortalKey{ID: networkid.PortalID(chatID)} // For non-group chats, add receiver @@ -93,38 +36,15 @@ func (s *SignalClient) makePortalKey(chatID string) networkid.PortalKey { func (s *SignalClient) makeDMPortalKey(serviceID libsignalgo.ServiceID) networkid.PortalKey { return networkid.PortalKey{ - ID: makeDMPortalID(serviceID), + ID: signalid.MakeDMPortalID(serviceID), Receiver: s.UserLogin.ID, } } -func makeMessageID(sender uuid.UUID, timestamp uint64) networkid.MessageID { - return networkid.MessageID(fmt.Sprintf("%s|%d", sender, timestamp)) -} - -func makeUserID(user uuid.UUID) networkid.UserID { - return networkid.UserID(user.String()) -} - -func makeUserIDFromServiceID(user libsignalgo.ServiceID) networkid.UserID { - return networkid.UserID(user.String()) -} - -func makeUserLoginID(user uuid.UUID) networkid.UserLoginID { - return networkid.UserLoginID(user.String()) -} - func (s *SignalClient) makeEventSender(sender uuid.UUID) bridgev2.EventSender { return bridgev2.EventSender{ IsFromMe: sender == s.Client.Store.ACI, - SenderLogin: makeUserLoginID(sender), - Sender: makeUserID(sender), + SenderLogin: signalid.MakeUserLoginID(sender), + Sender: signalid.MakeUserID(sender), } } - -func makeMessagePartID(index int) networkid.PartID { - if index == 0 { - return "" - } - return networkid.PartID(strconv.Itoa(index)) -} diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 3acd926..2e79933 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -25,6 +25,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" + "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" ) @@ -144,7 +145,7 @@ func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, error) { defer qr.cancelChan() - newLoginID := makeUserLoginID(qr.ProvData.ACI) + newLoginID := signalid.MakeUserLoginID(qr.ProvData.ACI) select { case resp := <-qr.ProvChan: diff --git a/pkg/connector/msgconvproxy.go b/pkg/connector/msgconvproxy.go deleted file mode 100644 index 8dc2db8..0000000 --- a/pkg/connector/msgconvproxy.go +++ /dev/null @@ -1,117 +0,0 @@ -// mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2024 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package connector - -import ( - "context" - "strings" - - "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/database" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - legacydb "go.mau.fi/mautrix-signal/database" - "go.mau.fi/mautrix-signal/msgconv" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" -) - -type contextKey int - -var msgconvContextKey contextKey - -type msgconvContext struct { - Connector *SignalConnector - Intent bridgev2.MatrixAPI - Client *SignalClient - Portal *bridgev2.Portal - ReplyTo *database.Message -} - -type msgconvPortalMethods struct{} - -var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) - -func (mpm *msgconvPortalMethods) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { - mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) - uri, _, err := mcCtx.Intent.UploadMedia(ctx, "", data, fileName, contentType) - return uri, err -} - -func (mpm *msgconvPortalMethods) DownloadMatrixMedia(ctx context.Context, uri id.ContentURIString) ([]byte, error) { - return ctx.Value(msgconvContextKey).(*msgconvContext).Connector.Bridge.Bot.DownloadMedia(ctx, uri, nil) -} - -func (mpm *msgconvPortalMethods) GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) { - // Matrix replies are handled in bridgev2 code - return "", "" -} - -func (mpm *msgconvPortalMethods) GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote { - mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) - if mcCtx.ReplyTo == nil { - return nil - } - quote := &signalpb.DataMessage_Quote{ - Id: proto.Uint64(uint64(mcCtx.ReplyTo.Timestamp.UnixMilli())), - AuthorAci: proto.String(string(mcCtx.ReplyTo.SenderID)), - Type: signalpb.DataMessage_Quote_NORMAL.Enum(), - } - if mcCtx.ReplyTo.Metadata.(*MessageMetadata).ContainsAttachments { - quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) - } - return quote -} - -func (mpm *msgconvPortalMethods) GetClient(ctx context.Context) *signalmeow.Client { - return ctx.Value(msgconvContextKey).(*msgconvContext).Client.Client -} - -func (mpm *msgconvPortalMethods) GetData(ctx context.Context) *legacydb.Portal { - mcCtx := ctx.Value(msgconvContextKey).(*msgconvContext) - portal := mcCtx.Portal - userID, groupID, _ := parsePortalID(portal.ID) - chatID := string(groupID) - if chatID == "" { - chatID = userID.String() - } - pk := legacydb.PortalKey{ - ChatID: chatID, - } - if len(chatID) != 44 { - pk.Receiver = mcCtx.Client.Client.Store.ACI - } - return &legacydb.Portal{ - PortalKey: pk, - MXID: portal.MXID, - Name: portal.Name, - Topic: portal.Topic, - //AvatarPath: "", - //AvatarHash: "", - //AvatarURL: id.ContentURI{}, - NameSet: portal.NameSet, - AvatarSet: portal.AvatarSet, - TopicSet: portal.TopicSet, - Revision: portal.Metadata.(*PortalMetadata).Revision, - // Hack to prevent encryption while using the bridge as a "local bridge" - Encrypted: !strings.HasSuffix(portal.Bridge.Matrix.ServerName(), ".localhost"), - //RelayUserID: portal.Relay.UserMXID, - ExpirationTime: uint32(portal.Disappear.Timer.Seconds()), - } -} diff --git a/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go similarity index 74% rename from msgconv/from-matrix.go rename to pkg/msgconv/from-matrix.go index 9a14ead..3b61b9f 100644 --- a/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -18,35 +18,37 @@ package msgconv import ( "context" - "errors" "fmt" "strings" "time" "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - "go.mau.fi/util/exerrors" "go.mau.fi/util/exmime" "go.mau.fi/util/ffmpeg" "go.mau.fi/util/variationselector" "golang.org/x/exp/constraints" "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/event" - "go.mau.fi/mautrix-signal/msgconv/matrixfmt" + "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" ) -var ( - ErrUnsupportedMsgType = errors.New("unsupported msgtype") - ErrMediaDownloadFailed = errors.New("failed to download media") - ErrMediaDecryptFailed = errors.New("failed to decrypt media") - ErrMediaConvertFailed = errors.New("failed to convert") - ErrMediaUploadFailed = errors.New("failed to upload media") - ErrInvalidGeoURI = errors.New("invalid `geo:` URI in message") -) - -func (mc *MessageConverter) ToSignal(ctx context.Context, evt *event.Event, content *event.MessageEventContent, relaybotFormatted bool) (*signalpb.DataMessage, error) { +func (mc *MessageConverter) ToSignal( + ctx context.Context, + client *signalmeow.Client, + portal *bridgev2.Portal, + evt *event.Event, + content *event.MessageEventContent, + relaybotFormatted bool, + replyTo *database.Message, +) (*signalpb.DataMessage, error) { + ctx = context.WithValue(ctx, contextKeyClient, client) + ctx = context.WithValue(ctx, contextKeyPortal, portal) if evt.Type == event.EventSticker { content.MsgType = event.MessageType(event.EventSticker.Type) } @@ -59,11 +61,23 @@ func (mc *MessageConverter) ToSignal(ctx context.Context, evt *event.Event, cont } dm := &signalpb.DataMessage{ Timestamp: &ts, - Quote: mc.GetSignalReply(ctx, content), - Preview: mc.convertURLPreviewToSignal(ctx, evt), + Preview: mc.convertURLPreviewToSignal(ctx, content), } - if expirationTime := mc.GetData(ctx).ExpirationTime; expirationTime != 0 { - dm.ExpireTimer = proto.Uint32(uint32(expirationTime)) + if replyTo != nil { + authorACI, messageID, err := signalid.ParseMessageID(replyTo.ID) + if err == nil { + dm.Quote = &signalpb.DataMessage_Quote{ + Id: proto.Uint64(messageID), + AuthorAci: proto.String(authorACI.String()), + Type: signalpb.DataMessage_Quote_NORMAL.Enum(), + } + if replyTo.Metadata.(*signalid.MessageMetadata).ContainsAttachments { + dm.Quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) + } + } + } + if portal.Disappear.Timer > 0 { + dm.ExpireTimer = proto.Uint32(uint32(portal.Disappear.Timer.Seconds())) } if content.MsgType == event.MsgEmote && !relaybotFormatted { content.Body = "/me " + content.Body @@ -113,13 +127,13 @@ func (mc *MessageConverter) ToSignal(ctx context.Context, evt *event.Event, cont case event.MsgLocation: lat, lon, err := parseGeoURI(content.GeoURI) if err != nil { - log.Err(err).Msg("Invalid geo URI") + zerolog.Ctx(ctx).Err(err).Msg("Invalid geo URI") return nil, err } locationString := fmt.Sprintf(mc.LocationFormat, lat, lon) dm.Body = &locationString default: - return nil, fmt.Errorf("%w %s", ErrUnsupportedMsgType, content.MsgType) + return nil, fmt.Errorf("%w %s", bridgev2.ErrUnsupportedMessageType, content.MsgType) } return dm, nil } @@ -133,44 +147,33 @@ func maybeInt[T constraints.Integer](v T) *T { func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event.Event, content *event.MessageEventContent) (*signalpb.AttachmentPointer, error) { log := zerolog.Ctx(ctx) - mxc := content.URL - if content.File != nil { - mxc = content.File.URL - } - data, err := mc.DownloadMatrixMedia(ctx, mxc) + data, err := mc.Bridge.Bot.DownloadMedia(ctx, content.URL, content.File) if err != nil { - return nil, exerrors.NewDualError(ErrMediaDownloadFailed, err) - } - if content.File != nil { - err = content.File.DecryptInPlace(data) - if err != nil { - return nil, exerrors.NewDualError(ErrMediaDecryptFailed, err) - } + return nil, fmt.Errorf("%w: %w", bridgev2.ErrMediaDownloadFailed, err) } fileName := content.Body if content.FileName != "" { fileName = content.FileName } - _, isVoice := evt.Content.Raw["org.matrix.msc3245.voice"] mime := content.GetInfo().MimeType - if isVoice { + if content.MSC3245Voice != nil && ffmpeg.Supported() { data, err = ffmpeg.ConvertBytes(ctx, data, ".m4a", []string{}, []string{"-c:a", "aac"}, mime) if err != nil { return nil, err } mime = "audio/aac" fileName += ".m4a" - } else if evt.Type == event.EventSticker && mime != "image/webp" && mime != "image/png" && mime != "image/apng" { + } else if evt.Type == event.EventSticker { switch mime { case "image/webp", "image/png", "image/apng": // allowed case "image/gif": - if !mc.ConvertGIFToAPNG { + if !ffmpeg.Supported() { return nil, fmt.Errorf("converting gif stickers is not supported") } data, err = ffmpeg.ConvertBytes(ctx, data, ".apng", []string{}, []string{}, mime) if err != nil { - return nil, fmt.Errorf("%w gif to apng: %w", ErrMediaConvertFailed, err) + return nil, fmt.Errorf("%w (gif to apng): %w", bridgev2.ErrMediaConvertFailed, err) } fileName += ".apng" mime = "image/apng" @@ -178,12 +181,12 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. return nil, fmt.Errorf("unsupported content type for sticker %s", mime) } } - att, err := mc.GetClient(ctx).UploadAttachment(ctx, data) + att, err := getClient(ctx).UploadAttachment(ctx, data) if err != nil { log.Err(err).Msg("Failed to upload file") - return nil, exerrors.NewDualError(ErrMediaUploadFailed, err) + return nil, fmt.Errorf("%w: %w", bridgev2.ErrMediaReuploadFailed, err) } - if isVoice { + if content.MSC3245Voice != nil && mime == "audio/aac" { att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_VOICE_MESSAGE)) } att.ContentType = proto.String(mime) diff --git a/msgconv/from-signal.go b/pkg/msgconv/from-signal.go similarity index 72% rename from msgconv/from-signal.go rename to pkg/msgconv/from-signal.go index 918c749..e4ab6dc 100644 --- a/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -26,49 +26,22 @@ import ( "time" "github.com/emersion/go-vcard" + "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exfmt" "go.mau.fi/util/exmime" "go.mau.fi/util/ffmpeg" - "golang.org/x/exp/slices" - "maunium.net/go/mautrix/crypto/attachment" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "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" ) -type ConvertedMessage struct { - Parts []*ConvertedMessagePart - Timestamp uint64 - DisappearIn uint32 -} - -func (cm *ConvertedMessage) MergeCaption() { - if len(cm.Parts) != 2 || cm.Parts[1].Content.MsgType != event.MsgText { - return - } - switch cm.Parts[0].Content.MsgType { - case event.MsgImage, event.MsgVideo, event.MsgAudio, event.MsgFile: - default: - return - } - mediaContent := cm.Parts[0].Content - textContent := cm.Parts[1].Content - mediaContent.FileName = mediaContent.Body - mediaContent.Body = textContent.Body - mediaContent.Format = textContent.Format - mediaContent.FormattedBody = textContent.FormattedBody - cm.Parts = cm.Parts[:1] -} - -type ConvertedMessagePart struct { - Type event.Type - Content *event.MessageEventContent - Extra map[string]any -} - func calculateLength(dm *signalpb.DataMessage) int { if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { return 1 @@ -96,19 +69,30 @@ func CanConvertSignal(dm *signalpb.DataMessage) bool { return calculateLength(dm) > 0 } -func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessage) *ConvertedMessage { - cm := &ConvertedMessage{ - Timestamp: dm.GetTimestamp(), - DisappearIn: dm.GetExpireTimer(), - Parts: make([]*ConvertedMessagePart, 0, calculateLength(dm)), +func (mc *MessageConverter) ToMatrix( + ctx context.Context, + client *signalmeow.Client, + portal *bridgev2.Portal, + intent bridgev2.MatrixAPI, + dm *signalpb.DataMessage, +) *bridgev2.ConvertedMessage { + ctx = context.WithValue(ctx, contextKeyClient, client) + ctx = context.WithValue(ctx, contextKeyPortal, portal) + ctx = context.WithValue(ctx, contextKeyIntent, intent) + cm := &bridgev2.ConvertedMessage{ + ReplyTo: nil, + ThreadRoot: nil, + Parts: make([]*bridgev2.ConvertedMessagePart, 0, calculateLength(dm)), } if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), true)) - // Don't disappear disappearing timer changes - cm.DisappearIn = 0 // Don't allow any other parts in a disappearing timer change message return cm } + if dm.GetExpireTimer() > 0 { + cm.Disappear.Type = database.DisappearingTypeAfterRead + cm.Disappear.Timer = time.Duration(dm.GetExpireTimer()) * time.Second + } if dm.Sticker != nil { cm.Parts = append(cm.Parts, mc.convertStickerToMatrix(ctx, dm.Sticker)) // Don't allow any other parts in a sticker message @@ -139,7 +123,7 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa cm.Parts = append(cm.Parts, mc.convertTextToMatrix(ctx, dm)) } if len(cm.Parts) == 0 && dm.GetRequiredProtocolVersion() > uint32(signalpb.DataMessage_CURRENT) { - cm.Parts = append(cm.Parts, &ConvertedMessagePart{ + cm.Parts = append(cm.Parts, &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -147,23 +131,28 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, dm *signalpb.DataMessa }, }) } - replyTo, sender := mc.GetMatrixReply(ctx, dm.Quote) - for _, part := range cm.Parts { - if part.Content.Mentions == nil { - part.Content.Mentions = &event.Mentions{} + cm.MergeCaption() + for i, part := range cm.Parts { + part.ID = signalid.MakeMessagePartID(i) + part.DBMetadata = &signalid.MessageMetadata{ + ContainsAttachments: len(dm.GetAttachments()) > 0, } - if replyTo != "" { - part.Content.RelatesTo = (&event.RelatesTo{}).SetReplyTo(replyTo) - if !slices.Contains(part.Content.Mentions.UserIDs, sender) { - part.Content.Mentions.UserIDs = append(part.Content.Mentions.UserIDs, sender) + } + if dm.Quote != nil { + authorACI, err := uuid.Parse(dm.Quote.GetAuthorAci()) + if err != nil { + zerolog.Ctx(ctx).Err(err).Str("author_aci", dm.Quote.GetAuthorAci()).Msg("Failed to parse quote author ACI") + } else { + cm.ReplyTo = &networkid.MessageOptionalPartID{ + MessageID: signalid.MakeMessageID(authorACI, dm.Quote.GetId()), } } } return cm } -func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, updatePortal bool) *ConvertedMessagePart { - part := &ConvertedMessagePart{ +func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, updatePortal bool) *bridgev2.ConvertedMessagePart { + part := &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -174,35 +163,36 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C part.Content.Body = "Disappearing messages disabled" } if updatePortal { - if mc.UpdateDisappearing != nil { - mc.UpdateDisappearing(ctx, time.Duration(timer)*time.Second) + portal := getPortal(ctx) + portal.Disappear.Timer = time.Duration(timer) * time.Second + if timer == 0 { + portal.Disappear.Type = "" } else { - portal := mc.GetData(ctx) - portal.ExpirationTime = timer - err := portal.Update(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") - } + portal.Disappear.Type = database.DisappearingTypeAfterRead + } + err := portal.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") } } return part } -func (mc *MessageConverter) convertTextToMatrix(ctx context.Context, dm *signalpb.DataMessage) *ConvertedMessagePart { +func (mc *MessageConverter) convertTextToMatrix(ctx context.Context, dm *signalpb.DataMessage) *bridgev2.ConvertedMessagePart { content := signalfmt.Parse(ctx, dm.GetBody(), dm.GetBodyRanges(), mc.SignalFmtParams) extra := map[string]any{} if len(dm.Preview) > 0 { - extra["com.beeper.linkpreviews"] = mc.convertURLPreviewsToBeeper(ctx, dm.Preview) + content.BeeperLinkPreviews = mc.convertURLPreviewsToBeeper(ctx, dm.Preview) } - return &ConvertedMessagePart{ + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: content, Extra: extra, } } -func (mc *MessageConverter) convertPaymentToMatrix(_ context.Context, payment *signalpb.DataMessage_Payment) *ConvertedMessagePart { - return &ConvertedMessagePart{ +func (mc *MessageConverter) convertPaymentToMatrix(_ context.Context, payment *signalpb.DataMessage_Payment) *bridgev2.ConvertedMessagePart { + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -214,8 +204,8 @@ func (mc *MessageConverter) convertPaymentToMatrix(_ context.Context, payment *s } } -func (mc *MessageConverter) convertGiftBadgeToMatrix(_ context.Context, giftBadge *signalpb.DataMessage_GiftBadge) *ConvertedMessagePart { - return &ConvertedMessagePart{ +func (mc *MessageConverter) convertGiftBadgeToMatrix(_ context.Context, giftBadge *signalpb.DataMessage_GiftBadge) *bridgev2.ConvertedMessagePart { + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -303,7 +293,7 @@ func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact * return card } -func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact *signalpb.DataMessage_Contact) *ConvertedMessagePart { +func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact *signalpb.DataMessage_Contact) *bridgev2.ConvertedMessagePart { card := mc.convertContactToVCard(ctx, contact) contact.Avatar = nil extraData := map[string]any{ @@ -313,7 +303,7 @@ func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact err := vcard.NewEncoder(&buf).Encode(card) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to encode vCard") - return &ConvertedMessagePart{ + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -323,30 +313,6 @@ func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact } } data := buf.Bytes() - var file *event.EncryptedFileInfo - uploadMime := "text/vcard" - uploadFileName := "contact.vcf" - if mc.GetData(ctx).Encrypted { - file = &event.EncryptedFileInfo{ - EncryptedFile: *attachment.NewEncryptedFile(), - URL: "", - } - file.EncryptInPlace(data) - uploadMime = "application/octet-stream" - uploadFileName = "" - } - mxc, err := mc.UploadMatrixMedia(ctx, data, uploadFileName, uploadMime) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to upload vCard") - return &ConvertedMessagePart{ - Type: event.EventMessage, - Content: &event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: "Failed to upload vCard", - }, - Extra: extraData, - } - } displayName := contact.GetName().GetDisplayName() if displayName == "" { displayName = contact.GetName().GetGivenName() @@ -368,24 +334,30 @@ func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact Size: len(data), }, } - if file != nil { - file.URL = mxc - content.File = file - } else { - content.URL = mxc + content.URL, content.File, err = getIntent(ctx).UploadMedia(ctx, getPortal(ctx).MXID, data, content.Info.MimeType, content.Body) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to upload vCard") + return &bridgev2.ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: "Failed to upload vCard", + }, + Extra: extraData, + } } - return &ConvertedMessagePart{ + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: content, Extra: extraData, } } -func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index int, att *signalpb.AttachmentPointer) *ConvertedMessagePart { +func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index int, att *signalpb.AttachmentPointer) *bridgev2.ConvertedMessagePart { part, err := mc.reuploadAttachment(ctx, att) if err != nil { zerolog.Ctx(ctx).Err(err).Int("attachment_index", index).Msg("Failed to handle attachment") - return &ConvertedMessagePart{ + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -396,11 +368,11 @@ func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index return part } -func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker *signalpb.DataMessage_Sticker) *ConvertedMessagePart { +func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker *signalpb.DataMessage_Sticker) *bridgev2.ConvertedMessagePart { converted, err := mc.reuploadAttachment(ctx, sticker.GetData()) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to handle sticker") - return &ConvertedMessagePart{ + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ MsgType: event.MsgNotice, @@ -437,7 +409,7 @@ func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *sig return &longBody, nil } -func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer) (*ConvertedMessagePart, error) { +func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer) (*bridgev2.ConvertedMessagePart, error) { data, err := signalmeow.DownloadAttachment(ctx, att) if err != nil { return nil, fmt.Errorf("failed to download attachment: %w", err) @@ -447,43 +419,28 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp mimeType = http.DetectContentType(data) } fileName := att.GetFileName() - extra := map[string]any{} - if mc.ConvertVoiceMessages && att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 { + content := &event.MessageEventContent{ + Info: &event.FileInfo{ + Width: int(att.GetWidth()), + Height: int(att.GetHeight()), + Size: len(data), + }, + } + if att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 && ffmpeg.Supported() { data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mimeType) if err != nil { return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err) } fileName += ".ogg" mimeType = "audio/ogg" - extra["org.matrix.msc3245.voice"] = map[string]any{} + content.MSC3245Voice = &event.MSC3245Voice{} // TODO include duration here (and in info) if there's some easy way to extract it with ffmpeg - //extra["org.matrix.msc1767.audio"] = map[string]any{"duration": ???} + //content.MSC1767Audio = &event.MSC1767Audio{} } - var file *event.EncryptedFileInfo - uploadMime := mimeType - uploadFileName := fileName - if mc.GetData(ctx).Encrypted { - file = &event.EncryptedFileInfo{ - EncryptedFile: *attachment.NewEncryptedFile(), - URL: "", - } - file.EncryptInPlace(data) - uploadMime = "application/octet-stream" - uploadFileName = "" - } - mxc, err := mc.UploadMatrixMedia(ctx, data, uploadFileName, uploadMime) + content.URL, content.File, err = getIntent(ctx).UploadMedia(ctx, getPortal(ctx).MXID, data, fileName, mimeType) if err != nil { return nil, err } - content := &event.MessageEventContent{ - Body: fileName, - Info: &event.FileInfo{ - MimeType: mimeType, - Width: int(att.GetWidth()), - Height: int(att.GetHeight()), - Size: len(data), - }, - } if att.GetBlurHash() != "" { content.Info.Blurhash = att.GetBlurHash() content.Info.AnoaBlurhash = att.GetBlurHash() @@ -498,18 +455,13 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp default: content.MsgType = event.MsgFile } + content.Body = fileName + content.Info.MimeType = mimeType if content.Body == "" { content.Body = strings.TrimPrefix(string(content.MsgType), "m.") + exmime.ExtensionFromMimetype(mimeType) } - if file != nil { - file.URL = mxc - content.File = file - } else { - content.URL = mxc - } - return &ConvertedMessagePart{ + return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: content, - Extra: extra, }, nil } diff --git a/msgconv/matrixfmt/convert.go b/pkg/msgconv/matrixfmt/convert.go similarity index 100% rename from msgconv/matrixfmt/convert.go rename to pkg/msgconv/matrixfmt/convert.go diff --git a/msgconv/matrixfmt/convert_test.go b/pkg/msgconv/matrixfmt/convert_test.go similarity index 97% rename from msgconv/matrixfmt/convert_test.go rename to pkg/msgconv/matrixfmt/convert_test.go index 6f9d66e..240ca98 100644 --- a/msgconv/matrixfmt/convert_test.go +++ b/pkg/msgconv/matrixfmt/convert_test.go @@ -10,8 +10,8 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" - "go.mau.fi/mautrix-signal/msgconv/matrixfmt" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/msgconv/matrixfmt" + "go.mau.fi/mautrix-signal/pkg/msgconv/signalfmt" ) var formatParams = &matrixfmt.HTMLParser{ diff --git a/msgconv/matrixfmt/html.go b/pkg/msgconv/matrixfmt/html.go similarity index 99% rename from msgconv/matrixfmt/html.go rename to pkg/msgconv/matrixfmt/html.go index 94571da..1e3d249 100644 --- a/msgconv/matrixfmt/html.go +++ b/pkg/msgconv/matrixfmt/html.go @@ -13,7 +13,7 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/msgconv/signalfmt" ) type EntityString struct { diff --git a/pkg/msgconv/msgconv.go b/pkg/msgconv/msgconv.go new file mode 100644 index 0000000..1d1fee8 --- /dev/null +++ b/pkg/msgconv/msgconv.go @@ -0,0 +1,107 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package msgconv + +import ( + "context" + + "github.com/google/uuid" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/id" + + "go.mau.fi/mautrix-signal/pkg/msgconv/matrixfmt" + "go.mau.fi/mautrix-signal/pkg/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow" +) + +type contextKey int + +const ( + contextKeyPortal contextKey = iota + contextKeyClient + contextKeyIntent +) + +type MessageConverter struct { + Bridge *bridgev2.Bridge + + SignalFmtParams *signalfmt.FormatParams + MatrixFmtParams *matrixfmt.HTMLParser + + MaxFileSize int64 + LocationFormat string +} + +func NewMessageConverter(br *bridgev2.Bridge, locationFormat string) *MessageConverter { + return &MessageConverter{ + Bridge: br, + SignalFmtParams: &signalfmt.FormatParams{ + GetUserInfo: func(ctx context.Context, uuid uuid.UUID) signalfmt.UserInfo { + ghost, err := br.GetGhostByID(ctx, signalid.MakeUserID(uuid)) + if err != nil { + // TODO log? + return signalfmt.UserInfo{} + } + userInfo := signalfmt.UserInfo{ + MXID: ghost.Intent.GetMXID(), + Name: ghost.Name, + } + userLogin := br.GetCachedUserLoginByID(networkid.UserLoginID(uuid.String())) + if userLogin != nil { + userInfo.MXID = userLogin.UserMXID + // TODO find matrix user displayname? + } + return userInfo + }, + }, + MatrixFmtParams: &matrixfmt.HTMLParser{ + GetUUIDFromMXID: func(ctx context.Context, userID id.UserID) uuid.UUID { + parsed, ok := br.Matrix.ParseGhostMXID(userID) + if ok { + u, _ := uuid.Parse(string(parsed)) + return u + } + user, _ := br.GetExistingUserByMXID(ctx, userID) + // TODO log errors? + if user != nil { + preferredLogin, _, _ := getPortal(ctx).FindPreferredLogin(ctx, user, true) + if preferredLogin != nil { + u, _ := uuid.Parse(string(preferredLogin.ID)) + return u + } + } + return uuid.Nil + }, + }, + MaxFileSize: 50 * 1024 * 1024, + LocationFormat: locationFormat, + } +} + +func getClient(ctx context.Context) *signalmeow.Client { + return ctx.Value(contextKeyClient).(*signalmeow.Client) +} + +func getPortal(ctx context.Context) *bridgev2.Portal { + return ctx.Value(contextKeyPortal).(*bridgev2.Portal) +} + +func getIntent(ctx context.Context) bridgev2.MatrixAPI { + return ctx.Value(contextKeyIntent).(bridgev2.MatrixAPI) +} diff --git a/msgconv/signalfmt/convert.go b/pkg/msgconv/signalfmt/convert.go similarity index 100% rename from msgconv/signalfmt/convert.go rename to pkg/msgconv/signalfmt/convert.go diff --git a/msgconv/signalfmt/convert_test.go b/pkg/msgconv/signalfmt/convert_test.go similarity index 99% rename from msgconv/signalfmt/convert_test.go rename to pkg/msgconv/signalfmt/convert_test.go index 1b2d693..eb65542 100644 --- a/msgconv/signalfmt/convert_test.go +++ b/pkg/msgconv/signalfmt/convert_test.go @@ -26,7 +26,7 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" + "go.mau.fi/mautrix-signal/pkg/msgconv/signalfmt" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) diff --git a/msgconv/signalfmt/html.go b/pkg/msgconv/signalfmt/html.go similarity index 100% rename from msgconv/signalfmt/html.go rename to pkg/msgconv/signalfmt/html.go diff --git a/msgconv/signalfmt/tags.go b/pkg/msgconv/signalfmt/tags.go similarity index 100% rename from msgconv/signalfmt/tags.go rename to pkg/msgconv/signalfmt/tags.go diff --git a/msgconv/signalfmt/tree.go b/pkg/msgconv/signalfmt/tree.go similarity index 100% rename from msgconv/signalfmt/tree.go rename to pkg/msgconv/signalfmt/tree.go diff --git a/msgconv/urlpreview.go b/pkg/msgconv/urlpreview.go similarity index 53% rename from msgconv/urlpreview.go rename to pkg/msgconv/urlpreview.go index 168dcb9..d2d3b23 100644 --- a/msgconv/urlpreview.go +++ b/pkg/msgconv/urlpreview.go @@ -18,37 +18,27 @@ package msgconv import ( "context" - "encoding/json" - "regexp" "time" "github.com/rs/zerolog" - "github.com/tidwall/gjson" "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) -type BeeperLinkPreview struct { - mautrix.RespPreviewURL - MatchedURL string `json:"matched_url"` - ImageEncryption *event.EncryptedFileInfo `json:"beeper:image:encryption,omitempty"` -} - -func (mc *MessageConverter) convertURLPreviewsToBeeper(ctx context.Context, preview []*signalpb.Preview) []*BeeperLinkPreview { - output := make([]*BeeperLinkPreview, len(preview)) +func (mc *MessageConverter) convertURLPreviewsToBeeper(ctx context.Context, preview []*signalpb.Preview) []*event.BeeperLinkPreview { + output := make([]*event.BeeperLinkPreview, len(preview)) for i, p := range preview { output[i] = mc.convertURLPreviewToBeeper(ctx, p) } return output } -func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, preview *signalpb.Preview) *BeeperLinkPreview { - output := &BeeperLinkPreview{ +func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, preview *signalpb.Preview) *event.BeeperLinkPreview { + output := &event.BeeperLinkPreview{ MatchedURL: preview.GetUrl(), - RespPreviewURL: mautrix.RespPreviewURL{ + LinkPreview: event.LinkPreview{ CanonicalURL: preview.GetUrl(), Title: preview.GetTitle(), Description: preview.GetDescription(), @@ -70,65 +60,34 @@ func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, previ return output } -var URLRegex = regexp.MustCompile(`https?://[^\s/_*]+(?:/\S*)?`) - -func (mc *MessageConverter) convertURLPreviewToSignal(ctx context.Context, evt *event.Event) []*signalpb.Preview { - var previews []*BeeperLinkPreview - - log := zerolog.Ctx(ctx) - rawPreview := gjson.GetBytes(evt.Content.VeryRaw, `com\.beeper\.linkpreviews`) - if rawPreview.Exists() && rawPreview.IsArray() { - if err := json.Unmarshal([]byte(rawPreview.Raw), &previews); err != nil || len(previews) == 0 { - return nil - } - } /* else if portal.bridge.Config.Bridge.URLPreviews { - if matchedURL := URLRegex.FindString(evt.Content.AsMessage().Body); len(matchedURL) == 0 { - return nil - } else if parsed, err := url.Parse(matchedURL); err != nil { - return nil - } else if parsed.Host, err = idna.ToASCII(parsed.Host); err != nil { - return nil - } else if mxPreview, err := portal.MainIntent().GetURLPreview(parsed.String()); err != nil { - log.Err(err).Str("matched_url", matchedURL).Msg("Failed to fetch preview for URL found in message") - return nil - } else { - previews = []*BeeperLinkPreview{{ - RespPreviewURL: *mxPreview, - MatchedURL: matchedURL, - }} - } - }*/ - if len(previews) == 0 { +func (mc *MessageConverter) convertURLPreviewToSignal(ctx context.Context, content *event.MessageEventContent) []*signalpb.Preview { + if len(content.BeeperLinkPreviews) == 0 { return nil } - output := make([]*signalpb.Preview, len(previews)) - for i, preview := range previews { + output := make([]*signalpb.Preview, len(content.BeeperLinkPreviews)) + for i, preview := range content.BeeperLinkPreviews { output[i] = &signalpb.Preview{ Url: proto.String(preview.MatchedURL), Title: proto.String(preview.Title), Description: proto.String(preview.Description), Date: proto.Uint64(uint64(time.Now().UnixMilli())), } - imageMXC := preview.ImageURL - if preview.ImageEncryption != nil { - imageMXC = preview.ImageEncryption.URL - } - if imageMXC != "" { - data, err := mc.DownloadMatrixMedia(ctx, imageMXC) + if preview.ImageURL != "" || preview.ImageEncryption != nil { + data, err := mc.Bridge.Bot.DownloadMedia(ctx, preview.ImageURL, preview.ImageEncryption) if err != nil { - log.Err(err).Int("preview_index", i).Msg("Failed to download URL preview image") + zerolog.Ctx(ctx).Err(err).Int("preview_index", i).Msg("Failed to download URL preview image") continue } if preview.ImageEncryption != nil { err = preview.ImageEncryption.DecryptInPlace(data) if err != nil { - log.Err(err).Int("preview_index", i).Msg("Failed to decrypt URL preview image") + zerolog.Ctx(ctx).Err(err).Int("preview_index", i).Msg("Failed to decrypt URL preview image") continue } } - uploaded, err := mc.GetClient(ctx).UploadAttachment(ctx, data) + uploaded, err := getClient(ctx).UploadAttachment(ctx, data) if err != nil { - log.Err(err).Int("preview_index", i).Msg("Failed to reupload URL preview image") + zerolog.Ctx(ctx).Err(err).Int("preview_index", i).Msg("Failed to reupload URL preview image") continue } uploaded.ContentType = proto.String(preview.ImageType) diff --git a/database/upgrades/upgrades.go b/pkg/signalid/dbmeta.go similarity index 54% rename from database/upgrades/upgrades.go rename to pkg/signalid/dbmeta.go index 20f60f4..2d85a0c 100644 --- a/database/upgrades/upgrades.go +++ b/pkg/signalid/dbmeta.go @@ -1,5 +1,5 @@ // mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2023 Tulir Asokan +// Copyright (C) 2024 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 @@ -14,27 +14,12 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package upgrades +package signalid -import ( - "context" - "embed" - "errors" - - "go.mau.fi/util/dbutil" -) - -var Table dbutil.UpgradeTable - -//go:embed *.sql -var rawUpgrades embed.FS - -func init() { - Table.Register(-1, 12, 0, "Unsupported version", dbutil.TxnModeOff, func(ctx context.Context, database *dbutil.Database) error { - return errors.New("please upgrade to mautrix-signal v0.4.3 before upgrading to a newer version") - }) - Table.Register(1, 13, 0, "Jump to version 13", dbutil.TxnModeOff, func(ctx context.Context, database *dbutil.Database) error { - return nil - }) - Table.RegisterFS(rawUpgrades) +type PortalMetadata struct { + Revision uint32 `json:"revision"` +} + +type MessageMetadata struct { + ContainsAttachments bool `json:"contains_attachments,omitempty"` } diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go new file mode 100644 index 0000000..f99bf9d --- /dev/null +++ b/pkg/signalid/ids.go @@ -0,0 +1,105 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalid + +import ( + "fmt" + "strconv" + "strings" + + "github.com/google/uuid" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +func ParseUserID(userID networkid.UserID) (uuid.UUID, error) { + serviceID, err := ParseUserIDAsServiceID(userID) + if err != nil { + return uuid.Nil, err + } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return uuid.Nil, fmt.Errorf("invalid user ID: expected ACI type") + } else { + return serviceID.UUID, nil + } +} + +func ParseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { + return libsignalgo.ServiceIDFromString(string(userID)) +} + +func ParsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { + if len(portalID) == 44 { + groupID = types.GroupIdentifier(portalID) + } else { + userID, err = libsignalgo.ServiceIDFromString(string(portalID)) + } + return +} + +func ParseMessageID(messageID networkid.MessageID) (sender uuid.UUID, timestamp uint64, err error) { + parts := strings.Split(string(messageID), "|") + if len(parts) != 2 { + err = fmt.Errorf("invalid message ID: expected two pipe-separated parts") + return + } + sender, err = uuid.Parse(parts[0]) + if err != nil { + return + } + timestamp, err = strconv.ParseUint(parts[1], 10, 64) + return +} + +func MakeGroupPortalID(groupID types.GroupIdentifier) networkid.PortalID { + return networkid.PortalID(groupID) +} + +func MakeGroupPortalKey(groupID types.GroupIdentifier) networkid.PortalKey { + return networkid.PortalKey{ + ID: MakeGroupPortalID(groupID), + Receiver: "", + } +} + +func MakeDMPortalID(serviceID libsignalgo.ServiceID) networkid.PortalID { + return networkid.PortalID(serviceID.String()) +} + +func MakeMessageID(sender uuid.UUID, timestamp uint64) networkid.MessageID { + return networkid.MessageID(fmt.Sprintf("%s|%d", sender, timestamp)) +} + +func MakeUserID(user uuid.UUID) networkid.UserID { + return networkid.UserID(user.String()) +} + +func MakeUserIDFromServiceID(user libsignalgo.ServiceID) networkid.UserID { + return networkid.UserID(user.String()) +} + +func MakeUserLoginID(user uuid.UUID) networkid.UserLoginID { + return networkid.UserLoginID(user.String()) +} + +func MakeMessagePartID(index int) networkid.PartID { + if index == 0 { + return "" + } + return networkid.PartID(strconv.Itoa(index)) +} diff --git a/portal.go b/portal.go deleted file mode 100644 index 37fabe6..0000000 --- a/portal.go +++ /dev/null @@ -1,3026 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber, Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "net/http" - "reflect" - "strings" - "sync" - "time" - - "github.com/google/uuid" - "github.com/rs/zerolog" - "go.mau.fi/util/exfmt" - "go.mau.fi/util/jsontime" - "go.mau.fi/util/variationselector" - "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/appservice" - "maunium.net/go/mautrix/bridge" - "maunium.net/go/mautrix/bridge/bridgeconfig" - "maunium.net/go/mautrix/bridge/status" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/database" - "go.mau.fi/mautrix-signal/msgconv" - "go.mau.fi/mautrix-signal/msgconv/matrixfmt" - "go.mau.fi/mautrix-signal/msgconv/signalfmt" - "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "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/types" -) - -func (br *SignalBridge) GetPortalByMXID(mxid id.RoomID) *Portal { - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - - portal, ok := br.portalsByMXID[mxid] - if !ok { - dbPortal, err := br.DB.Portal.GetByMXID(context.TODO(), mxid) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get portal from database") - return nil - } - return br.loadPortal(context.TODO(), dbPortal, nil) - } - - return portal -} - -func (br *SignalBridge) GetPortalByChatID(key database.PortalKey) *Portal { - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - return br.unlockedGetPortalByChatID(key, true) -} - -func (br *SignalBridge) GetPortalByChatIDIfExists(key database.PortalKey) *Portal { - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - return br.unlockedGetPortalByChatID(key, false) -} - -func (br *SignalBridge) unlockedGetPortalByChatID(key database.PortalKey, createIfNotExists bool) *Portal { - // If this PortalKey is for a group, Receiver should be empty - if key.UserID().IsEmpty() { - key.Receiver = uuid.Nil - } - portal, ok := br.portalsByID[key] - if !ok { - dbPortal, err := br.DB.Portal.GetByChatID(context.TODO(), key) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get portal from database") - return nil - } - keyIfNotExists := &key - if !createIfNotExists { - keyIfNotExists = nil - } - return br.loadPortal(context.TODO(), dbPortal, keyIfNotExists) - } - return portal -} - -func (br *SignalBridge) GetAllPortalsWithMXID() []*Portal { - portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get all portals with mxid") - return nil - } - return portals -} - -func (br *SignalBridge) FindPrivateChatPortalsWith(userID uuid.UUID) []*Portal { - portals, err := br.dbPortalsToPortals(br.DB.Portal.FindPrivateChatsWith(context.TODO(), userID)) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get all DM portals with user") - return nil - } - return portals -} - -func (br *SignalBridge) GetAllIPortals() (iportals []bridge.Portal) { - portals, err := br.dbPortalsToPortals(br.DB.Portal.GetAllWithMXID(context.TODO())) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get all portals with mxid") - return nil - } - iportals = make([]bridge.Portal, len(portals)) - for i, portal := range portals { - iportals[i] = portal - } - return iportals -} - -func (br *SignalBridge) loadPortal(ctx context.Context, dbPortal *database.Portal, key *database.PortalKey) *Portal { - if dbPortal == nil { - if key == nil { - return nil - } - - dbPortal = br.DB.Portal.New() - dbPortal.PortalKey = *key - err := dbPortal.Insert(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Failed to insert new portal") - return nil - } - } - - portal := br.NewPortal(dbPortal) - - br.portalsByID[portal.PortalKey] = portal - if portal.MXID != "" { - br.portalsByMXID[portal.MXID] = portal - } - - return portal -} - -func (br *SignalBridge) dbPortalsToPortals(dbPortals []*database.Portal, err error) ([]*Portal, error) { - if err != nil { - return nil, err - } - br.portalsLock.Lock() - defer br.portalsLock.Unlock() - - output := make([]*Portal, len(dbPortals)) - for index, dbPortal := range dbPortals { - if dbPortal == nil { - continue - } - - portal, ok := br.portalsByID[dbPortal.PortalKey] - if !ok { - portal = br.loadPortal(context.TODO(), dbPortal, nil) - } - - output[index] = portal - } - - return output, nil -} - -type portalSignalMessage struct { - evt *events.ChatEvent - user *User -} - -type portalMatrixMessage struct { - evt *event.Event - user *User -} - -type Portal struct { - *database.Portal - - MsgConv *msgconv.MessageConverter - - bridge *SignalBridge - log zerolog.Logger - - roomCreateLock sync.Mutex - encryptLock sync.Mutex - - signalMessages chan portalSignalMessage - matrixMessages chan portalMatrixMessage - - currentlyTyping []id.UserID - currentlyTypingLock sync.Mutex - - relayUser *User -} - -var signalFormatParams *signalfmt.FormatParams -var matrixFormatParams *matrixfmt.HTMLParser - -func (br *SignalBridge) NewPortal(dbPortal *database.Portal) *Portal { - log := br.ZLog.With().Str("chat_id", dbPortal.ChatID).Logger() - if dbPortal.MXID != "" { - log = log.With().Stringer("room_id", dbPortal.MXID).Logger() - } - - portal := &Portal{ - Portal: dbPortal, - bridge: br, - log: log, - - signalMessages: make(chan portalSignalMessage, br.Config.Bridge.PortalMessageBuffer), - matrixMessages: make(chan portalMatrixMessage, br.Config.Bridge.PortalMessageBuffer), - } - portal.MsgConv = &msgconv.MessageConverter{ - PortalMethods: portal, - SignalFmtParams: signalFormatParams, - MatrixFmtParams: matrixFormatParams, - ConvertVoiceMessages: true, - MaxFileSize: br.MediaConfig.UploadSize, - LocationFormat: br.Config.Bridge.LocationFormat, - } - go portal.messageLoop() - - return portal -} - -func init() { - event.TypeMap[event.StateBridge] = reflect.TypeOf(CustomBridgeInfoContent{}) - event.TypeMap[event.StateHalfShotBridge] = reflect.TypeOf(CustomBridgeInfoContent{}) -} - -var ( - _ bridge.Portal = (*Portal)(nil) - _ bridge.ReadReceiptHandlingPortal = (*Portal)(nil) - _ bridge.TypingPortal = (*Portal)(nil) - _ bridge.DisappearingPortal = (*Portal)(nil) - //_ bridge.MembershipHandlingPortal = (*Portal)(nil) - //_ bridge.MetaHandlingPortal = (*Portal)(nil) -) - -func (portal *Portal) IsEncrypted() bool { - return portal.Encrypted -} - -func (portal *Portal) MarkEncrypted() { - portal.Encrypted = true - err := portal.Update(context.TODO()) - if err != nil { - portal.log.Err(err).Msg("Failed to update portal in database after marking as encrypted") - } -} - -func (portal *Portal) ReceiveMatrixEvent(user bridge.User, evt *event.Event) { - if user.GetPermissionLevel() >= bridgeconfig.PermissionLevelUser || portal.HasRelaybot() { - portal.matrixMessages <- portalMatrixMessage{user: user.(*User), evt: evt} - } -} - -func (portal *Portal) GetRelayUser() *User { - if !portal.HasRelaybot() { - return nil - } else if portal.relayUser == nil { - portal.relayUser = portal.bridge.GetUserByMXID(portal.RelayUserID) - } - return portal.relayUser -} - -func (portal *Portal) IsPrivateChat() bool { - return !portal.UserID().IsEmpty() -} - -func (portal *Portal) IsNoteToSelf() bool { - userID := portal.UserID() - return !userID.IsEmpty() && userID.UUID == portal.Receiver -} - -func (portal *Portal) MainIntent() *appservice.IntentAPI { - dmPuppet := portal.GetDMPuppet() - if dmPuppet != nil { - return dmPuppet.DefaultIntent() - } - - return portal.bridge.Bot -} - -type CustomBridgeInfoContent struct { - event.BridgeEventContent - RoomType string `json:"com.beeper.room_type,omitempty"` -} - -func (portal *Portal) getBridgeInfo() (string, CustomBridgeInfoContent) { - bridgeInfo := event.BridgeEventContent{ - BridgeBot: portal.bridge.Bot.UserID, - Creator: portal.MainIntent().UserID, - Protocol: event.BridgeInfoSection{ - ID: "signal", - DisplayName: "Signal", - AvatarURL: portal.bridge.Config.AppService.Bot.ParsedAvatar.CUString(), - ExternalURL: "https://signal.org/", - }, - Channel: event.BridgeInfoSection{ - ID: portal.ChatID, - DisplayName: portal.Name, - AvatarURL: portal.AvatarURL.CUString(), - }, - } - bridgeInfoStateKey := fmt.Sprintf("fi.mau.signal://signal/%s", portal.ChatID) - bridgeInfo.Channel.ExternalURL = fmt.Sprintf("https://signal.me/#p/%s", portal.ChatID) - var roomType string - if portal.IsPrivateChat() { - roomType = "dm" - } - return bridgeInfoStateKey, CustomBridgeInfoContent{bridgeInfo, roomType} -} - -func (portal *Portal) UpdateBridgeInfo(ctx context.Context) { - if len(portal.MXID) == 0 { - portal.log.Debug().Msg("Not updating bridge info: no Matrix room created") - return - } - portal.log.Debug().Msg("Updating bridge info...") - stateKey, content := portal.getBridgeInfo() - _, err := portal.MainIntent().SendStateEvent(ctx, portal.MXID, event.StateBridge, stateKey, content) - if err != nil { - portal.log.Warn().Err(err).Msg("Failed to update m.bridge") - } - // TODO remove this once https://github.com/matrix-org/matrix-doc/pull/2346 is in spec - _, err = portal.MainIntent().SendStateEvent(ctx, portal.MXID, event.StateHalfShotBridge, stateKey, content) - if err != nil { - portal.log.Warn().Err(err).Msg("Failed to update uk.half-shot.bridge") - } -} - -func (portal *Portal) messageLoop() { - for { - select { - case msg := <-portal.matrixMessages: - portal.handleMatrixMessages(msg) - case msg := <-portal.signalMessages: - portal.handleSignalMessage(msg) - } - } -} - -func (portal *Portal) handleMatrixMessages(msg portalMatrixMessage) { - log := portal.log.With(). - Str("action", "handle matrix event"). - Stringer("event_id", msg.evt.ID). - Str("event_type", msg.evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - - switch msg.evt.Type { - case event.EventMessage, event.EventSticker: - portal.handleMatrixMessage(ctx, msg.user, msg.evt) - case event.EventRedaction: - portal.handleMatrixRedaction(ctx, msg.user, msg.evt) - case event.EventReaction: - portal.handleMatrixReaction(ctx, msg.user, msg.evt) - default: - log.Warn().Str("type", msg.evt.Type.Type).Msg("Unhandled matrix message type") - } -} - -func (portal *Portal) handleMatrixMessage(ctx context.Context, sender *User, evt *event.Event) { - log := zerolog.Ctx(ctx) - evtTS := time.UnixMilli(evt.Timestamp) - timings := messageTimings{ - initReceive: evt.Mautrix.ReceivedAt.Sub(evtTS), - decrypt: evt.Mautrix.DecryptionDuration, - totalReceive: time.Since(evtTS), - } - implicitRRStart := time.Now() - portal.handleMatrixReadReceipt(sender, "", uint64(evt.Timestamp), false) - timings.implicitRR = time.Since(implicitRRStart) - start := time.Now() - - messageAge := timings.totalReceive - ms := metricSender{portal: portal, timings: &timings, ctx: ctx} - log.Debug(). - Stringer("sender", evt.Sender). - Dur("age", messageAge). - Msg("Received message") - - errorAfter := portal.bridge.Config.Bridge.MessageHandlingTimeout.ErrorAfter - deadline := portal.bridge.Config.Bridge.MessageHandlingTimeout.Deadline - isScheduled, _ := evt.Content.Raw["com.beeper.scheduled"].(bool) - if isScheduled { - log.Debug().Msg("Message is a scheduled message, extending handling timeouts") - errorAfter *= 10 - deadline *= 10 - } - - if errorAfter > 0 { - remainingTime := errorAfter - messageAge - if remainingTime < 0 { - go ms.sendMessageMetrics(evt, errTimeoutBeforeHandling, "Timeout handling", true) - return - } else if remainingTime < 1*time.Second { - log.Warn(). - Dur("remaining_time", remainingTime). - Dur("max_timeout", errorAfter). - Msg("Message was delayed before reaching the bridge") - } - go func() { - time.Sleep(remainingTime) - ms.sendMessageMetrics(evt, errMessageTakingLong, "Timeout handling", false) - }() - } - - if deadline > 0 { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, deadline) - defer cancel() - } - - timings.preproc = time.Since(start) - start = time.Now() - - content, ok := evt.Content.Parsed.(*event.MessageEventContent) - if !ok { - log.Error().Type("content_type", content).Msg("Unexpected parsed content type") - go ms.sendMessageMetrics(evt, fmt.Errorf("%w %T", errUnexpectedParsedContentType, evt.Content.Parsed), "Error converting", true) - return - } - - realSenderMXID := sender.MXID - isRelay := false - if !sender.IsLoggedIn() { - sender = portal.GetRelayUser() - if sender == nil { - go ms.sendMessageMetrics(evt, errUserNotLoggedIn, "Ignoring", true) - return - } else if !sender.IsLoggedIn() { - go ms.sendMessageMetrics(evt, errRelaybotNotLoggedIn, "Ignoring", true) - return - } - isRelay = true - } - - var editTargetMsg *database.Message - if editTarget := content.RelatesTo.GetReplaceID(); editTarget != "" { - var err error - editTargetMsg, err = portal.bridge.DB.Message.GetByMXID(ctx, editTarget) - if err != nil { - log.Err(err).Stringer("edit_target_mxid", editTarget).Msg("Failed to get edit target message") - go ms.sendMessageMetrics(evt, errFailedToGetEditTarget, "Error converting", true) - return - } else if editTargetMsg == nil { - log.Err(err).Stringer("edit_target_mxid", editTarget).Msg("Edit target message not found") - go ms.sendMessageMetrics(evt, errEditUnknownTarget, "Error converting", true) - return - } else if editTargetMsg.Sender != sender.SignalID { - go ms.sendMessageMetrics(evt, errEditDifferentSender, "Error converting", true) - return - } - if content.NewContent != nil { - content = content.NewContent - evt.Content.Parsed = content - } - } - - relaybotFormatted := isRelay && portal.addRelaybotFormat(ctx, realSenderMXID, evt, content) - if content.MsgType == event.MsgNotice && !portal.bridge.Config.Bridge.BridgeNotices { - go ms.sendMessageMetrics(evt, errMNoticeDisabled, "Error converting", true) - return - } - ctx = context.WithValue(ctx, msgconvContextKeyClient, sender.Client) - msg, err := portal.MsgConv.ToSignal(ctx, evt, content, relaybotFormatted) - if err != nil { - log.Err(err).Msg("Failed to convert message") - go ms.sendMessageMetrics(evt, err, "Error converting", true) - return - } - var wrappedMsg *signalpb.Content - if editTargetMsg == nil { - wrappedMsg = &signalpb.Content{ - DataMessage: msg, - } - } else { - wrappedMsg = &signalpb.Content{ - EditMessage: &signalpb.EditMessage{ - TargetSentTimestamp: proto.Uint64(editTargetMsg.Timestamp), - DataMessage: msg, - }, - } - } - - timings.convert = time.Since(start) - start = time.Now() - - err = portal.sendSignalMessage(ctx, wrappedMsg, sender, evt.ID) - - timings.totalSend = time.Since(start) - go ms.sendMessageMetrics(evt, err, "Error sending", true) - if err == nil { - if editTargetMsg != nil { - err = editTargetMsg.SetTimestamp(ctx, msg.GetTimestamp()) - if err != nil { - log.Err(err).Msg("Failed to update message timestamp in database after editing") - } - } else { - portal.storeMessageInDB(ctx, evt.ID, sender.SignalID, msg.GetTimestamp(), 0) - if portal.ExpirationTime > 0 { - portal.addDisappearingMessage(ctx, evt.ID, uint32(portal.ExpirationTime), true) - } - } - } -} - -func (portal *Portal) handleMatrixRedaction(ctx context.Context, sender *User, evt *event.Event) { - log := zerolog.Ctx(ctx) - // Find the original signal message based on eventID - dbMessage, err := portal.bridge.DB.Message.GetByMXID(ctx, evt.Redacts) - if err != nil { - log.Err(err).Msg("Failed to get redaction target message") - } - // Might be a reaction redaction, find the original message for the reaction - dbReaction, err := portal.bridge.DB.Reaction.GetByMXID(ctx, evt.Redacts) - if err != nil { - log.Err(err).Msg("Failed to get redaction target reaction") - } - - if !sender.IsLoggedIn() { - sender = portal.GetRelayUser() - if sender == nil { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errUserNotLoggedIn) - return - } else if !sender.IsLoggedIn() { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errRelaybotNotLoggedIn) - return - } - } - - if dbMessage != nil { - if dbMessage.Sender != sender.SignalID { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errRedactionTargetSentBySomeoneElse) - return - } - msg := signalmeow.DataMessageForDelete(dbMessage.Timestamp) - err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) - if err != nil { - portal.sendMessageStatusCheckpointFailed(ctx, evt, err) - log.Err(err).Msg("Failed to send message redaction to Signal") - return - } - err = dbMessage.Delete(ctx) - if err != nil { - log.Err(err).Msg("Failed to delete redacted message from database") - } else if otherParts, err := portal.bridge.DB.Message.GetAllPartsBySignalID(ctx, dbMessage.Sender, dbMessage.Timestamp, portal.Receiver); err != nil { - log.Err(err).Msg("Failed to get other parts of redacted message from database") - } else if len(otherParts) > 0 { - // If there are other parts of the message, send a redaction for each of them - for _, otherPart := range otherParts { - _, err = portal.MainIntent().RedactEvent(ctx, portal.MXID, otherPart.MXID, mautrix.ReqRedact{ - Reason: "Other part of Signal message redacted", - TxnID: "mxsg_partredact_" + otherPart.MXID.String(), - }) - if err != nil { - log.Err(err). - Stringer("part_event_id", otherPart.MXID). - Int("part_index", otherPart.PartIndex). - Msg("Failed to redact other part of redacted message") - } - err = otherPart.Delete(ctx) - if err != nil { - log.Err(err). - Stringer("part_event_id", otherPart.MXID). - Int("part_index", otherPart.PartIndex). - Msg("Failed to delete other part of redacted message from database") - } - } - } - portal.sendMessageStatusCheckpointSuccess(ctx, evt) - } else if dbReaction != nil { - if dbReaction.Author != sender.SignalID { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errUnreactTargetSentBySomeoneElse) - return - } - msg := signalmeow.DataMessageForReaction(dbReaction.Emoji, dbReaction.MsgAuthor, dbReaction.MsgTimestamp, true) - err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) - if err != nil { - portal.sendMessageStatusCheckpointFailed(ctx, evt, err) - log.Err(err).Msg("Failed to send reaction redaction to Signal") - return - } - err = dbReaction.Delete(ctx) - if err != nil { - log.Err(err).Msg("Failed to delete redacted reaction from database") - } - portal.sendMessageStatusCheckpointSuccess(ctx, evt) - } else { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errRedactionTargetNotFound) - } -} - -func (portal *Portal) handleMatrixReaction(ctx context.Context, sender *User, evt *event.Event) { - log := zerolog.Ctx(ctx) - if !sender.IsLoggedIn() { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errCantRelayReactions) - return - } - // Find the original signal message based on eventID - relatedEventID := evt.Content.AsReaction().RelatesTo.EventID - targetMsg, err := portal.bridge.DB.Message.GetByMXID(ctx, relatedEventID) - if err != nil { - portal.sendMessageStatusCheckpointFailed(ctx, evt, err) - log.Err(err).Msg("Failed to get reaction target message") - return - } else if targetMsg == nil { - portal.sendMessageStatusCheckpointFailed(ctx, evt, errReactionTargetNotFound) - log.Warn().Msg("Reaction target message not found") - return - } - emoji := evt.Content.AsReaction().RelatesTo.Key - signalEmoji := variationselector.FullyQualify(emoji) // Signal seems to require fully qualified emojis - msg := signalmeow.DataMessageForReaction(signalEmoji, targetMsg.Sender, targetMsg.Timestamp, false) - err = portal.sendSignalMessage(ctx, msg, sender, evt.ID) - if err != nil { - portal.sendMessageStatusCheckpointFailed(ctx, evt, err) - log.Error().Msg("Failed to send reaction") - return - } - - // Signal only allows one reaction from each user - // Check if there's an existing reaction in the database for this sender and redact/delete it - dbReaction, err := portal.bridge.DB.Reaction.GetBySignalID( - ctx, - targetMsg.Sender, - targetMsg.Timestamp, - sender.SignalID, - portal.Receiver, - ) - if err != nil { - log.Err(err).Msg("Failed to get existing reaction from database") - } else if dbReaction != nil { - log.Debug().Stringer("existing_event_id", dbReaction.MXID).Msg("Redacting existing reaction after sending new one") - _, err = portal.MainIntent().RedactEvent(ctx, portal.MXID, dbReaction.MXID) - if err != nil { - log.Err(err).Msg("Failed to redact existing reaction") - } - } - if dbReaction != nil { - dbReaction.MXID = evt.ID - dbReaction.Emoji = signalEmoji - err = dbReaction.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to update reaction in database") - } - } else { - dbReaction = portal.bridge.DB.Reaction.New() - dbReaction.MXID = evt.ID - dbReaction.RoomID = portal.MXID - dbReaction.SignalChatID = portal.ChatID - dbReaction.SignalReceiver = portal.Receiver - dbReaction.Author = sender.SignalID - dbReaction.MsgAuthor = targetMsg.Sender - dbReaction.MsgTimestamp = targetMsg.Timestamp - dbReaction.Emoji = signalEmoji - err = dbReaction.Insert(ctx) - if err != nil { - log.Err(err).Msg("Failed to insert reaction to database") - } - } - - portal.sendMessageStatusCheckpointSuccess(ctx, evt) -} - -func (portal *Portal) sendSignalMessage(ctx context.Context, msg *signalpb.Content, sender *User, evtID id.EventID) error { - log := zerolog.Ctx(ctx).With(). - Str("action", "send signal message"). - Stringer("event_id", evtID). - Str("portal_chat_id", portal.ChatID). - Logger() - ctx = log.WithContext(ctx) - - log.Debug().Msg("Sending event to Signal") - - // Check to see if portal.ChatID is a standard UUID (with dashes) - if portal.IsPrivateChat() { - // this is a 1:1 chat - result := sender.Client.SendMessage(ctx, portal.UserID(), msg) - if !result.WasSuccessful { - return result.Error - } - } else { - // this is a group chat - groupID := types.GroupIdentifier(portal.ChatID) - result, err := sender.Client.SendGroupMessage(ctx, groupID, msg) - if err != nil { - // check the start of the error string, see if it starts with "No group master key found for group identifier" - if strings.HasPrefix(err.Error(), "No group master key found for group identifier") { - portal.MainIntent().SendNotice(ctx, portal.MXID, "Missing group encryption key. Please ask a group member to send a message in this chat, then retry sending.") - } - log.Err(err).Msg("Error sending event to Signal group") - return err - } - totalRecipients := len(result.FailedToSendTo) + len(result.SuccessfullySentTo) - log = log.With(). - Int("total_recipients", totalRecipients). - Int("failed_to_send_to_count", len(result.FailedToSendTo)). - Int("successfully_sent_to_count", len(result.SuccessfullySentTo)). - Logger() - if len(result.FailedToSendTo) > 0 { - log.Error().Msg("Failed to send event to some members of Signal group") - } - if len(result.SuccessfullySentTo) == 0 && len(result.FailedToSendTo) == 0 { - log.Debug().Msg("No successes or failures - Probably sent to myself") - } else if len(result.SuccessfullySentTo) == 0 { - log.Error().Msg("Failed to send event to all members of Signal group") - return errors.New("failed to send to any members of Signal group") - - } else if len(result.SuccessfullySentTo) < totalRecipients { - log.Warn().Msg("Only sent event to some members of Signal group") - } else { - log.Debug().Msg("Sent event to all members of Signal group") - } - } - return nil -} - -func (portal *Portal) sendMessageStatusCheckpointSuccess(ctx context.Context, evt *event.Event) { - portal.sendDeliveryReceipt(ctx, evt.ID) - portal.bridge.SendMessageSuccessCheckpoint(evt, status.MsgStepRemote, 0) - - var deliveredTo *[]id.UserID - if portal.IsPrivateChat() { - deliveredTo = &[]id.UserID{} - } - portal.sendStatusEvent(ctx, evt.ID, "", nil, deliveredTo) -} - -func (portal *Portal) sendMessageStatusCheckpointFailed(ctx context.Context, evt *event.Event, err error) { - portal.sendDeliveryReceipt(ctx, evt.ID) - portal.bridge.SendMessageErrorCheckpoint(evt, status.MsgStepRemote, err, true, 0) - portal.sendStatusEvent(ctx, evt.ID, "", err, nil) -} - -type msgconvContextKey int - -const ( - msgconvContextKeyIntent msgconvContextKey = iota - msgconvContextKeyClient -) - -func (portal *Portal) UploadMatrixMedia(ctx context.Context, data []byte, fileName, contentType string) (id.ContentURIString, error) { - intent := ctx.Value(msgconvContextKeyIntent).(*appservice.IntentAPI) - req := mautrix.ReqUploadMedia{ - ContentBytes: data, - ContentType: contentType, - FileName: fileName, - } - if portal.bridge.Config.Homeserver.AsyncMedia { - uploaded, err := intent.UploadAsync(ctx, req) - if err != nil { - return "", err - } - return uploaded.ContentURI.CUString(), nil - } else { - uploaded, err := intent.UploadMedia(ctx, req) - if err != nil { - return "", err - } - return uploaded.ContentURI.CUString(), nil - } -} - -func (portal *Portal) DownloadMatrixMedia(ctx context.Context, uriString id.ContentURIString) ([]byte, error) { - parsedURI, err := uriString.Parse() - if err != nil { - return nil, fmt.Errorf("malformed content URI: %w", err) - } - return portal.MainIntent().DownloadBytes(ctx, parsedURI) -} - -func (portal *Portal) GetData(ctx context.Context) *database.Portal { - return portal.Portal -} - -func (portal *Portal) GetClient(ctx context.Context) *signalmeow.Client { - return ctx.Value(msgconvContextKeyClient).(*signalmeow.Client) -} - -func (portal *Portal) GetMatrixReply(ctx context.Context, msg *signalpb.DataMessage_Quote) (replyTo id.EventID, replyTargetSender id.UserID) { - if msg == nil { - return - } - log := zerolog.Ctx(ctx).With(). - Str("reply_target_author", msg.GetAuthorAci()). - Uint64("reply_target_ts", msg.GetId()). - Logger() - if senderUUID, err := uuid.Parse(msg.GetAuthorAci()); err != nil { - log.Err(err).Msg("Failed to parse sender UUID in Signal quote") - } else if message, err := portal.bridge.DB.Message.GetBySignalID(ctx, senderUUID, msg.GetId(), 0, portal.Receiver); err != nil { - log.Err(err).Msg("Failed to get reply target message from database") - } else if message == nil { - log.Warn().Msg("Reply target message not found") - } else { - replyTo = message.MXID - targetUser := portal.bridge.GetUserBySignalID(message.Sender) - if targetUser != nil { - replyTargetSender = targetUser.MXID - } else { - replyTargetSender = portal.bridge.FormatPuppetMXID(message.Sender) - } - } - return -} - -func (portal *Portal) GetSignalReply(ctx context.Context, content *event.MessageEventContent) *signalpb.DataMessage_Quote { - replyToID := content.RelatesTo.GetReplyTo() - if len(replyToID) == 0 { - return nil - } - replyToMsg, err := portal.bridge.DB.Message.GetByMXID(ctx, replyToID) - if err != nil { - zerolog.Ctx(ctx).Err(err). - Stringer("reply_to_mxid", replyToID). - Msg("Failed to get reply target message from database") - } else if replyToMsg == nil { - zerolog.Ctx(ctx).Warn(). - Stringer("reply_to_mxid", replyToID). - Msg("Reply target message not found") - } else { - return &signalpb.DataMessage_Quote{ - Id: proto.Uint64(replyToMsg.Timestamp), - AuthorAci: proto.String(replyToMsg.Sender.String()), - Type: signalpb.DataMessage_Quote_NORMAL.Enum(), - - // This is a hack to make Signal iOS and desktop render replies to file messages. - // Unfortunately it also makes Signal Desktop show a file icon on replies to text messages. - // TODO store file or text flag in database and fill this field only when replying to file messages. - Attachments: make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1), - } - } - return nil -} - -func (portal *Portal) handleSignalMessage(portalMessage portalSignalMessage) { - sender := portal.bridge.GetPuppetBySignalID(portalMessage.evt.Info.Sender) - if sender == nil { - portal.log.Warn(). - Stringer("sender_uuid", portalMessage.evt.Info.Sender). - Msg("Couldn't get puppet for message") - return - } - var msgType string - var timestamp uint64 - switch typedEvt := portalMessage.evt.Event.(type) { - case *signalpb.DataMessage: - msgType = "data" - timestamp = typedEvt.GetTimestamp() - portal.handleSignalDataMessage(portalMessage.user, sender, typedEvt) - case *signalpb.TypingMessage: - msgType = "typing" - timestamp = typedEvt.GetTimestamp() - portal.handleSignalTypingMessage(sender, typedEvt) - case *signalpb.EditMessage: - msgType = "edit" - timestamp = typedEvt.GetTargetSentTimestamp() - portal.handleSignalEditMessage(sender, timestamp, typedEvt.GetDataMessage()) - default: - portal.log.Error(). - Type("data_type", typedEvt). - Msg("Invalid inner event type inside ChatEvent") - } - portal.bridge.Metrics.TrackSignalMessage(time.UnixMilli(int64(timestamp)), msgType) -} - -func (portal *Portal) handleSignalDataMessage(source *User, sender *Puppet, msg *signalpb.DataMessage) { - genericCtx := portal.log.With(). - Str("action", "handle signal data message"). - Uint64("msg_ts", msg.GetTimestamp()). - Logger().WithContext(context.TODO()) - // Always update sender info when we receive a message from them, there's caching inside the function - sender.UpdateInfo(genericCtx, source, nil) - // Handle earlier missed group changes here. - if msg.GetGroupV2() != nil { - requiredRevision := msg.GetGroupV2().GetRevision() - if msg.GetGroupV2().GetGroupChange() != nil { - requiredRevision = requiredRevision - 1 - } - if portal.Revision < requiredRevision { - err := portal.catchUpHistory(source, portal.Revision+1, requiredRevision, msg.GetTimestamp()) - if err != nil { - portal.log.Err(err).Msg("Failed to catch up group history, trying regular update") - portal.UpdateInfo(genericCtx, source, nil, msg.GetGroupV2().GetRevision()) - } - } - } else if portal.IsPrivateChat() && portal.UserID().UUID == portal.Receiver && portal.Name != NoteToSelfName { - // Slightly hacky way to make note to self names backfill - portal.UpdateDMInfo(genericCtx, false) - } - - switch { - case msgconv.CanConvertSignal(msg): - portal.handleSignalNormalDataMessage(source, sender, msg) - case msg.Reaction != nil: - portal.handleSignalReaction(sender, msg.Reaction, msg.GetTimestamp()) - case msg.Delete != nil: - portal.handleSignalDelete(sender, msg.Delete, msg.GetTimestamp()) - case msg.GetGroupV2().GetGroupChange() != nil: - portal.handleSignalGroupChange(source, sender, msg.GroupV2, msg.GetTimestamp()) - case msg.StoryContext != nil, msg.GroupCallUpdate != nil: - // ignore - default: - portal.log.Warn(). - Str("action", "handle signal message"). - Stringer("sender_uuid", sender.SignalID). - Uint64("msg_ts", msg.GetTimestamp()). - Msg("Unrecognized content in message") - } -} - -func (portal *Portal) catchUpHistory(source *User, fromRevision uint32, toRevision uint32, ts uint64) error { - log := portal.log.With(). - Str("action", "catchUpHistory"). - Stringer("source", source.MXID). - Uint32("from_revision", fromRevision). - Uint32("to_revision", toRevision). - Logger() - ctx := log.WithContext(context.TODO()) - groupChanges, err := source.Client.GetGroupHistoryPage(ctx, portal.GroupID(), fromRevision, false) - if err != nil { - log.Err(err).Msg("Failed to get GroupChanges") - return err - } - for _, groupChangeState := range groupChanges { - sender := portal.bridge.GetPuppetBySignalID(groupChangeState.GroupChange.SourceACI) - portal.applySignalGroupChange(ctx, source, sender, groupChangeState.GroupChange, ts) - // for revision > toRevision, we should have received a group change already - if groupChangeState.GroupChange.Revision == toRevision { - break - } - } - return nil -} - -func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, groupMeta *signalpb.GroupContextV2, ts uint64) { - log := portal.log.With(). - Str("action", "handle signal group change"). - Stringer("sender_uuid", sender.SignalID). - Uint64("change_ts", ts). - Uint32("new_revision", groupMeta.GetRevision()). - Logger() - ctx := log.WithContext(context.TODO()) - groupChange, err := source.Client.DecryptGroupChange(ctx, groupMeta) - if err != nil { - log.Err(err).Msg("Handling GroupChange failed") - return - } - portal.applySignalGroupChange(ctx, source, sender, groupChange, ts) -} - -func (portal *Portal) applySignalGroupChange(ctx context.Context, source *User, sender *Puppet, groupChange *signalmeow.GroupChange, ts uint64) { - log := zerolog.Ctx(ctx) - if groupChange.Revision <= portal.Revision { - return - } - portal.Revision = groupChange.Revision - if groupChange.ModifyTitle != nil { - portal.updateName(ctx, *groupChange.ModifyTitle, sender) - } - if groupChange.ModifyDescription != nil { - portal.updateTopic(ctx, *groupChange.ModifyDescription, sender) - } - if groupChange.ModifyAvatar != nil { - portal.updateAvatarWithInfo(ctx, source, groupChange, sender) - } - if groupChange.ModifyDisappearingMessagesDuration != nil { - portal.updateExpirationTimer(ctx, *groupChange.ModifyDisappearingMessagesDuration) - } - intent := sender.IntentFor(portal) - modifyRoles := groupChange.ModifyMemberRoles - var err error - for _, deleteBannedMember := range groupChange.DeleteBannedMembers { - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *&deleteBannedMember.UUID, event.MembershipLeave, "unbanned") - if err != nil { - log.Warn().Stringer("signal_user_id", deleteBannedMember).Msg("Couldn't get puppet for unban") - } - } - for _, addMember := range groupChange.AddMembers { - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: addMember.ACI, Role: addMember.Role}) - var puppet *Puppet - if addMember.JoinFromInviteLink { - puppet = portal.bridge.GetPuppetBySignalID(addMember.ACI) - if puppet != nil { - if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(addMember.ACI) - if user != nil { - portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, user.MXID, event.MembershipInvite, "Joined via invite Link") - } - } - _, err = puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") - if errors.Is(err, mautrix.MForbidden) { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipInvite, "Joined via invite Link") - } else if err == nil { - continue - } - } - } else { - puppet, err = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.ACI, event.MembershipInvite, "added") - } - if err != nil { - log.Err(err).Stringer("signal_user_id", addMember.ACI).Msg("Couldn't get puppet for invite") - return - } - _, err = puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") - if err != nil { - log.Err(err).Stringer("mxid", puppet.MXID).Msg("Failed to join user") - } - } - bannedMembers := make(map[uuid.UUID]bool) - for _, addBannedMember := range groupChange.AddBannedMembers { - if addBannedMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { - continue - } - bannedMembers[addBannedMember.ServiceID.UUID] = true - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addBannedMember.ServiceID.UUID, event.MembershipBan, "banned") - if err != nil { - log.Warn().Stringer("signal_user_id", addBannedMember.ServiceID.UUID).Msg("Couldn't get puppet for ban") - } - } - for _, deleteMember := range groupChange.DeleteMembers { - if bannedMembers[*deleteMember] { - continue - } - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteMember, event.MembershipLeave, "deleted") - if err != nil { - log.Warn().Stringer("signal_user_id", deleteMember).Msg("Couldn't get puppet for removal") - } - } - for _, deletePendingMember := range groupChange.DeletePendingMembers { - if deletePendingMember.Type == libsignalgo.ServiceIDTypePNI { - continue - } - if bannedMembers[deletePendingMember.UUID] { - continue - } - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, deletePendingMember.UUID, event.MembershipLeave, "invite withdrawn") - if err != nil { - log.Warn().Stringer("signal_user_id", deletePendingMember).Msg("Couldn't get puppet for removal") - } - } - for _, deleteRequestingMember := range groupChange.DeleteRequestingMembers { - if bannedMembers[*deleteRequestingMember] { - continue - } - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteRequestingMember, event.MembershipLeave, "request rejected") - if err != nil { - log.Warn().Stringer("signal_user_id", deleteRequestingMember).Msg("Couldn't get puppet for removal") - } - } - for _, promotePendingMember := range groupChange.PromotePendingMembers { - puppet := portal.bridge.GetPuppetBySignalID(promotePendingMember.ACI) - if puppet == nil { - log.Warn().Stringer("signal_user_id", promotePendingMember.ACI).Msg("Couldn't get puppet for invite") - continue - } - puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) - } - for _, promotePendingPniAciMember := range groupChange.PromotePendingPniAciMembers { - puppet := portal.bridge.GetPuppetBySignalID(promotePendingPniAciMember.ACI) - if puppet == nil { - log.Warn().Stringer("signal_user_id", promotePendingPniAciMember.ACI).Msg("Couldn't get puppet for invite") - continue - } - puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) - } - for _, addPendingMember := range groupChange.AddPendingMembers { - if addPendingMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { - continue - } - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addPendingMember.ServiceID.UUID, event.MembershipInvite, "invited") - if err != nil { - log.Warn().Stringer("signal_user_id", addPendingMember.ServiceID).Msg("Couldn't get puppet for invite") - } - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: addPendingMember.ServiceID.UUID, Role: addPendingMember.Role}) - } - for _, promoteRequestingMember := range groupChange.PromoteRequestingMembers { - puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promoteRequestingMember.ACI, event.MembershipInvite, "accepted") - if err == nil { - err = puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) - if err != nil { - log.Warn().Stringer("signal_user_id", promoteRequestingMember.ACI).Msg("failed to join puppet") - } - } else { - log.Warn().Stringer("signal_user_id", promoteRequestingMember.ACI).Msg("Couldn't get puppet for join") - } - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: promoteRequestingMember.ACI, Role: promoteRequestingMember.Role}) - } - for _, addRequestingMember := range groupChange.AddRequestingMembers { - // sender and target should be the same SignalID - puppet := portal.bridge.GetPuppetBySignalID(addRequestingMember.ACI) - if puppet != nil { - portal.sendMembershipWithPuppet(ctx, sender, puppet.IntentFor(portal).UserID, event.MembershipKnock, "knocked") - } - } - - if groupChange.ModifyAttributesAccess != nil || groupChange.ModifyAnnouncementsOnly != nil || groupChange.ModifyMemberAccess != nil || len(modifyRoles) > 0 { - levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) - if err != nil { - log.Err(err).Msg("Couldn't get power levels") - } else { - for _, modifyRole := range modifyRoles { - puppet := portal.bridge.GetPuppetBySignalID(modifyRole.ACI) - if puppet == nil { - log.Warn().Stringer("signal_user_id", modifyRole.ACI).Msg("Couldn't get puppet for power level change") - continue - } - powerLevel := 0 - if modifyRole.Role == signalmeow.GroupMember_ADMINISTRATOR { - powerLevel = 50 - } - levels.EnsureUserLevel(puppet.IntentFor(portal).UserID, powerLevel) - if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(modifyRole.ACI) - if user != nil { - levels.EnsureUserLevel(user.MXID, powerLevel) - } - } - } - if groupChange.ModifyAnnouncementsOnly != nil { - levels.EventsDefault = 0 - if *groupChange.ModifyAnnouncementsOnly { - levels.EventsDefault = 50 - } - } - if groupChange.ModifyAttributesAccess != nil { - level := 0 - if *groupChange.ModifyAttributesAccess == signalmeow.AccessControl_ADMINISTRATOR { - level = 50 - } - levels.StateDefaultPtr = &level - } - if groupChange.ModifyMemberAccess != nil { - level := 0 - if *groupChange.ModifyMemberAccess == signalmeow.AccessControl_ADMINISTRATOR { - level = 50 - } - levels.InvitePtr = &level - } - _, err = intent.SetPowerLevels(ctx, portal.MXID, levels) - if errors.Is(err, mautrix.MForbidden) { - _, err = portal.MainIntent().SetPowerLevels(ctx, portal.MXID, levels) - } - if err != nil { - log.Err(err).Msg("Couldn't set power levels") - } - } - } - if groupChange.ModifyAddFromInviteLinkAccess != nil { - joinRule := event.JoinRuleInvite - if *groupChange.ModifyAddFromInviteLinkAccess == signalmeow.AccessControl_ADMINISTRATOR { - joinRule = event.JoinRuleKnock - } else if *groupChange.ModifyAddFromInviteLinkAccess == signalmeow.AccessControl_ANY && portal.bridge.Config.Bridge.PublicPortals { - joinRule = event.JoinRulePublic - } - _, err = intent.SendMassagedStateEvent(ctx, portal.MXID, event.StateJoinRules, "", &event.JoinRulesEventContent{JoinRule: joinRule}, int64(ts)) - if errors.Is(err, mautrix.MForbidden) { - _, err = portal.MainIntent().SendMassagedStateEvent(ctx, portal.MXID, event.StateJoinRules, "", &event.JoinRulesEventContent{JoinRule: joinRule}, int64(ts)) - } - if err != nil { - log.Err(err).Msg("Couldn't set join rule") - } - } - err = portal.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to save portal in database after processing group change") - } - portal.UpdateBridgeInfo(ctx) -} - -func (portal *Portal) sendMembershipForPuppetAndUser(ctx context.Context, sender *Puppet, target uuid.UUID, membership event.Membership, action string) (puppet *Puppet, err error) { - puppet = portal.bridge.GetPuppetBySignalID(target) - if puppet == nil { - err = fmt.Errorf("couldn't get Puppet for Signal uuid %s", target) - return - } - err = portal.sendMembershipWithPuppet(ctx, sender, puppet.IntentFor(portal).UserID, membership, action) - if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(target) - if user != nil { - err = portal.sendMembershipWithPuppet(ctx, sender, user.MXID, membership, action) - } - } - return -} - -func (portal *Portal) sendMembershipWithPuppet(ctx context.Context, sender *Puppet, target id.UserID, membership event.Membership, action string) (err error) { - _, err = sender.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, target, membership, "") - if errors.Is(err, mautrix.MForbidden) { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, target, membership, fmt.Sprintf("%s by %s", action, sender.GetDisplayname())) - } - if err != nil { - zerolog.Ctx(ctx).Warn().Stringer("Membership Action failed for user", target).Msg(action) - } - return -} - -func (portal *Portal) handleSignalReaction(sender *Puppet, react *signalpb.DataMessage_Reaction, ts uint64) { - log := portal.log.With(). - Str("action", "handle signal reaction"). - Stringer("sender_uuid", sender.SignalID). - Uint64("target_msg_ts", react.GetTargetSentTimestamp()). - Str("target_msg_sender", react.GetTargetAuthorAci()). - Bool("remove", react.GetRemove()). - Logger() - ctx := log.WithContext(context.TODO()) - targetSenderUUID, err := uuid.Parse(react.GetTargetAuthorAci()) - if err != nil { - log.Err(err).Msg("Failed to parse target message sender UUID") - return - } - targetMsg, err := portal.bridge.DB.Message.GetBySignalID(ctx, targetSenderUUID, react.GetTargetSentTimestamp(), 0, portal.Receiver) - if err != nil { - log.Err(err).Msg("Failed to get target message from database") - return - } else if targetMsg == nil { - log.Warn().Msg("Target message not found") - return - } - existingReaction, err := portal.bridge.DB.Reaction.GetBySignalID(ctx, targetMsg.Sender, targetMsg.Timestamp, sender.SignalID, portal.Receiver) - if err != nil { - log.Err(err).Msg("Failed to get existing reaction from database") - return - } else if existingReaction != nil && existingReaction.Emoji == react.GetEmoji() { - log.Debug().Msg("Ignoring duplicate reaction") - return - } - intent := sender.IntentFor(portal) - if existingReaction != nil { - _, err = intent.RedactEvent(ctx, portal.MXID, existingReaction.MXID, mautrix.ReqRedact{ - TxnID: "mxsg_unreact_" + existingReaction.MXID.String(), - }) - if errors.Is(err, mautrix.MForbidden) { - log.Debug().Err(err).Msg("Failed to redact reaction with ghost, retrying with main intent") - _, err = portal.MainIntent().RedactEvent(ctx, portal.MXID, existingReaction.MXID, mautrix.ReqRedact{ - TxnID: "mxsg_unreact_" + existingReaction.MXID.String(), - }) - } - if err != nil { - log.Err(err).Msg("Failed to redact reaction") - } - if react.GetRemove() { - err = existingReaction.Delete(ctx) - if err != nil { - log.Err(err).Msg("Failed to remove reaction from database after redacting") - } - return - } - } else if react.GetRemove() { - log.Warn().Msg("Existing reaction for removal not found") - return - } - // Create a new message event with the reaction - content := &event.ReactionEventContent{ - RelatesTo: event.RelatesTo{ - Type: event.RelAnnotation, - Key: variationselector.Add(react.GetEmoji()), - EventID: targetMsg.MXID, - }, - } - resp, err := portal.sendMatrixEvent(ctx, intent, event.EventReaction, content, nil, int64(ts)) - if err != nil { - log.Err(err).Msg("Failed to send reaction") - return - } - if existingReaction == nil { - dbReaction := portal.bridge.DB.Reaction.New() - dbReaction.MXID = resp.EventID - dbReaction.RoomID = portal.MXID - dbReaction.SignalChatID = portal.ChatID - dbReaction.SignalReceiver = portal.Receiver - dbReaction.Author = sender.SignalID - dbReaction.MsgAuthor = targetMsg.Sender - dbReaction.MsgTimestamp = targetMsg.Timestamp - dbReaction.Emoji = react.GetEmoji() - err = dbReaction.Insert(ctx) - if err != nil { - log.Err(err).Msg("Failed to insert reaction to database") - } - } else { - existingReaction.Emoji = react.GetEmoji() - existingReaction.MXID = resp.EventID - err = existingReaction.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to update reaction in database") - } - } -} - -func (portal *Portal) handleSignalDelete(sender *Puppet, delete *signalpb.DataMessage_Delete, ts uint64) { - log := portal.log.With(). - Str("action", "handle signal delete"). - Stringer("sender_uuid", sender.SignalID). - Uint64("target_msg_ts", delete.GetTargetSentTimestamp()). - Uint64("delete_ts", ts). - Logger() - ctx := log.WithContext(context.TODO()) - targetMsg, err := portal.bridge.DB.Message.GetAllPartsBySignalID(ctx, sender.SignalID, delete.GetTargetSentTimestamp(), portal.Receiver) - if err != nil { - log.Err(err).Msg("Failed to get target message from database") - return - } else if len(targetMsg) == 0 { - log.Warn().Msg("Target message not found") - return - } - intent := sender.IntentFor(portal) - for _, part := range targetMsg { - _, err = intent.RedactEvent(ctx, portal.MXID, part.MXID, mautrix.ReqRedact{ - TxnID: "mxsg_delete_" + part.MXID.String(), - }) - if err != nil { - log.Err(err). - Int("part_index", part.PartIndex). - Stringer("event_id", part.MXID). - Msg("Failed to redact message") - } - err = part.Delete(ctx) - if err != nil { - log.Err(err). - Int("part_index", part.PartIndex). - Msg("Failed to delete message from database") - } - } -} - -func (portal *Portal) handleSignalNormalDataMessage(source *User, sender *Puppet, msg *signalpb.DataMessage) { - log := portal.log.With(). - Str("action", "handle signal message"). - Stringer("sender_uuid", sender.SignalID). - Uint64("msg_ts", msg.GetTimestamp()). - Logger() - ctx := log.WithContext(context.TODO()) - if portal.MXID == "" { - log.Debug().Msg("Creating Matrix room from incoming message") - if err := portal.CreateMatrixRoom(ctx, source, msg.GetGroupV2().GetRevision()); err != nil { - log.Error().Err(err).Msg("Failed to create portal room") - return - } - } else if !portal.ensureUserInvited(ctx, source) { - log.Warn().Stringer("user_id", source.MXID).Msg("Failed to ensure source user is joined to portal") - } - - existingMessage, err := portal.bridge.DB.Message.GetBySignalID(ctx, sender.SignalID, msg.GetTimestamp(), 0, portal.Receiver) - if err != nil { - log.Err(err).Msg("Failed to check if message was already bridged") - return - } else if existingMessage != nil { - log.Debug().Msg("Ignoring duplicate message") - return - } - - intent := sender.IntentFor(portal) - ctx = context.WithValue(ctx, msgconvContextKeyIntent, intent) - converted := portal.MsgConv.ToMatrix(ctx, msg) - if portal.bridge.Config.Bridge.CaptionInMessage { - converted.MergeCaption() - } - for i, part := range converted.Parts { - resp, err := portal.sendMatrixEvent(ctx, intent, part.Type, part.Content, part.Extra, int64(converted.Timestamp)) - if err != nil { - log.Err(err).Int("part_index", i).Msg("Failed to send message to Matrix") - continue - } - portal.storeMessageInDB(ctx, resp.EventID, sender.SignalID, converted.Timestamp, i) - if converted.DisappearIn != 0 { - portal.addDisappearingMessage(ctx, resp.EventID, converted.DisappearIn, sender.SignalID == source.SignalID) - // Ensure portal expiration timer is correct in DMs - if portal.implicitlyUpdateExpirationTimer(ctx, converted.DisappearIn) { - log.Info().Uint32("new_time", converted.DisappearIn).Msg("Implicitly updated expiration timer") - err := portal.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to save portal in database after implicitly updating group info") - } - } - } - } -} - -func (portal *Portal) handleSignalEditMessage(sender *Puppet, timestamp uint64, msg *signalpb.DataMessage) { - log := portal.log.With(). - Str("action", "handle signal edit"). - Stringer("sender_uuid", sender.SignalID). - Uint64("target_msg_ts", timestamp). - Uint64("edit_msg_ts", msg.GetTimestamp()). - Logger() - if portal.MXID == "" { - log.Debug().Msg("Dropping edit message in chat with no portal") - return - } - ctx := log.WithContext(context.TODO()) - targetMessage, err := portal.bridge.DB.Message.GetAllPartsBySignalID(ctx, sender.SignalID, timestamp, portal.Receiver) - if err != nil { - log.Err(err).Msg("Failed to get target message") - return - } else if len(targetMessage) == 0 { - log.Debug().Msg("Target message not found (edit may have been already handled)") - return - } - - intent := sender.IntentFor(portal) - ctx = context.WithValue(ctx, msgconvContextKeyIntent, intent) - converted := portal.MsgConv.ToMatrix(ctx, msg) - if portal.bridge.Config.Bridge.CaptionInMessage { - converted.MergeCaption() - } - if len(converted.Parts) != len(targetMessage) { - log.Error(). - Int("target_parts", len(targetMessage)). - Int("new_parts", len(converted.Parts)). - Msg("Mismatched number of parts in edit") - return - } - for i, part := range converted.Parts { - part.Content.SetEdit(targetMessage[i].MXID) - if part.Extra != nil { - part.Extra = map[string]any{ - "m.new_content": part.Extra, - } - } - _, err = portal.sendMatrixEvent(ctx, intent, part.Type, part.Content, part.Extra, int64(converted.Timestamp)) - if err != nil { - log.Err(err).Int("part_index", i).Msg("Failed to send edit to Matrix") - } - } - err = targetMessage[0].SetTimestamp(ctx, msg.GetTimestamp()) - if err != nil { - log.Err(err).Msg("Failed to update message edit timestamp in database") - } -} - -const SignalTypingTimeout = 15 * time.Second - -func (portal *Portal) handleSignalTypingMessage(sender *Puppet, msg *signalpb.TypingMessage) { - if portal.MXID == "" { - portal.log.Debug().Msg("Dropping typing message in chat with no portal") - return - } - ctx := context.TODO() - intent := sender.IntentFor(portal) - // Don't bridge double puppeted typing notifications to avoid echoing - if intent.IsCustomPuppet { - return - } - var err error - switch msg.GetAction() { - case signalpb.TypingMessage_STARTED: - _, err = intent.UserTyping(ctx, portal.MXID, true, SignalTypingTimeout) - case signalpb.TypingMessage_STOPPED: - _, err = intent.UserTyping(ctx, portal.MXID, false, 0) - } - if err != nil { - portal.log.Err(err). - Stringer("user_id", sender.SignalID). - Msg("Failed to handle Signal typing notification") - } -} - -func (portal *Portal) storeMessageInDB(ctx context.Context, eventID id.EventID, senderSignalID uuid.UUID, timestamp uint64, partIndex int) { - dbMessage := portal.bridge.DB.Message.New() - dbMessage.MXID = eventID - dbMessage.RoomID = portal.MXID - dbMessage.Sender = senderSignalID - dbMessage.Timestamp = timestamp - dbMessage.PartIndex = partIndex - dbMessage.SignalChatID = portal.ChatID - dbMessage.SignalReceiver = portal.Receiver - err := dbMessage.Insert(ctx) - if err != nil { - portal.log.Err(err).Msg("Failed to insert message into database") - } -} - -func (portal *Portal) addDisappearingMessage(ctx context.Context, eventID id.EventID, expireInSeconds uint32, startTimerNow bool) { - portal.bridge.disappearingMessagesManager.AddDisappearingMessage(ctx, eventID, portal.MXID, time.Duration(expireInSeconds)*time.Second, startTimerNow) -} - -func (portal *Portal) MarkDelivered(ctx context.Context, msg *database.Message) { - if !portal.IsPrivateChat() { - return - } - portal.bridge.SendRawMessageCheckpoint(&status.MessageCheckpoint{ - EventID: msg.MXID, - RoomID: portal.MXID, - Step: status.MsgStepRemote, - Timestamp: jsontime.UnixMilliNow(), - Status: status.MsgStatusDelivered, - ReportedBy: status.MsgReportedByBridge, - }) - portal.sendStatusEvent(ctx, msg.MXID, "", nil, &[]id.UserID{portal.MainIntent().UserID}) -} - -type customReadReceipt struct { - Timestamp int64 `json:"ts,omitempty"` - DoublePuppetSource string `json:"fi.mau.double_puppet_source,omitempty"` -} - -type customReadMarkers struct { - mautrix.ReqSetReadMarkers - ReadExtra customReadReceipt `json:"com.beeper.read.extra"` - FullyReadExtra customReadReceipt `json:"com.beeper.fully_read.extra"` -} - -func (portal *Portal) SendReadReceipt(ctx context.Context, sender *Puppet, msg *database.Message) error { - intent := sender.IntentFor(portal) - if intent.IsCustomPuppet { - extra := customReadReceipt{DoublePuppetSource: portal.bridge.Name} - return intent.SetReadMarkers(ctx, portal.MXID, &customReadMarkers{ - ReqSetReadMarkers: mautrix.ReqSetReadMarkers{ - Read: msg.MXID, - FullyRead: msg.MXID, - }, - ReadExtra: extra, - FullyReadExtra: extra, - }) - } else { - return intent.MarkRead(ctx, portal.MXID, msg.MXID) - } -} - -func typingDiff(prev, new []id.UserID) (started, stopped []id.UserID) { -OuterNew: - for _, userID := range new { - for _, previousUserID := range prev { - if userID == previousUserID { - continue OuterNew - } - } - started = append(started, userID) - } -OuterPrev: - for _, userID := range prev { - for _, previousUserID := range new { - if userID == previousUserID { - continue OuterPrev - } - } - stopped = append(stopped, userID) - } - return -} - -func (portal *Portal) setTyping(userIDs []id.UserID, isTyping bool) { - for _, userID := range userIDs { - user := portal.bridge.GetUserByMXID(userID) - if user == nil || !user.IsLoggedIn() { - continue - } - - // Check to see if portal.ChatID is a standard UUID (with dashes) - // Note: not handling sending to a group right now, since that will - // require SenderKey sending to not be terrible - dmUserID := portal.UserID() - if !dmUserID.IsEmpty() && dmUserID.Type == libsignalgo.ServiceIDTypeACI { - // this is a 1:1 chat - portal.log.Debug().Msg("Sending Typing event to Signal") - ctx := context.TODO() - typingMessage := signalmeow.TypingMessage(isTyping) - result := user.Client.SendMessage(ctx, portal.UserID(), typingMessage) - if !result.WasSuccessful { - portal.log.Err(result.FailedSendResult.Error).Msg("Error sending event to Signal") - } - } - } -} - -func (portal *Portal) HandleMatrixTyping(newTyping []id.UserID) { - if portal.IsNoteToSelf() { - return - } - - portal.currentlyTypingLock.Lock() - defer portal.currentlyTypingLock.Unlock() - startedTyping, stoppedTyping := typingDiff(portal.currentlyTyping, newTyping) - portal.currentlyTyping = newTyping - portal.setTyping(startedTyping, true) - portal.setTyping(stoppedTyping, false) -} - -func (portal *Portal) HandleMatrixReadReceipt(brSender bridge.User, eventID id.EventID, receipt event.ReadReceipt) { - portal.handleMatrixReadReceipt(brSender.(*User), eventID, uint64(receipt.Timestamp.UnixMilli()), true) -} - -func (portal *Portal) handleMatrixReadReceipt(sender *User, eventID id.EventID, maxTimestamp uint64, isExplicit bool) { - if !sender.IsLoggedIn() { - return - } - logWith := portal.log.With(). - Stringer("event_id", eventID). - Stringer("sender", sender.MXID). - Bool("explicit", isExplicit) - if isExplicit { - logWith = logWith.Str("action", "handle matrix read receipt") - } - log := logWith.Logger() - log.Debug().Msg("Handling Matrix read receipt") - portal.ScheduleDisappearing() - ctx := log.WithContext(context.TODO()) - - if isExplicit { - dbMessage, _ := portal.bridge.DB.Message.GetByMXID(ctx, eventID) - if dbMessage != nil { - maxTimestamp = dbMessage.Timestamp - } - } - prevLastReadTS := sender.GetLastReadTS(ctx, portal.PortalKey) - if maxTimestamp <= prevLastReadTS { - log.Debug(). - Uint64("prev_last_read_ts", prevLastReadTS). - Uint64("max_timestamp", maxTimestamp). - Msg("Ignoring read receipt older than last read timestamp") - return - } - minTimestamp := prevLastReadTS - if minTimestamp == 0 { - minTimestamp = maxTimestamp - 2000 - } - dbMessages, err := portal.bridge.DB.Message.GetAllBetweenTimestamps(ctx, portal.PortalKey, minTimestamp, maxTimestamp) - if err != nil { - log.Err(err).Msg("Failed to get messages between timestamps to mark as read") - return - } - messagesToRead := map[uuid.UUID][]uint64{} - for _, msg := range dbMessages { - messagesToRead[msg.Sender] = append(messagesToRead[msg.Sender], msg.Timestamp) - } - // Always update last read ts for non-explicit read receipts, because that means there's a message about to be sent - if (len(dbMessages) > 0 || !isExplicit) && maxTimestamp != prevLastReadTS { - sender.SetLastReadTS(ctx, portal.PortalKey, maxTimestamp) - } - if isExplicit || len(messagesToRead) > 0 { - log.Debug(). - Any("targets", messagesToRead). - Uint64("prev_last_read_ts", prevLastReadTS). - Uint64("min_timestamp", minTimestamp). - Uint64("max_timestamp", maxTimestamp). - Msg("Collected read receipt target messages") - } - - // TODO send sync message manually containing all read receipts instead of a separate message for each recipient - - for destination, messages := range messagesToRead { - // Don't send read receipts for own messages - if destination == sender.SignalID { - continue - } - // Don't use portal.sendSignalMessage because we're sending this straight to - // who sent the original message, not the portal's ChatID - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - result := sender.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(destination), signalmeow.ReadReceptMessageForTimestamps(messages)) - cancel() - if !result.WasSuccessful { - log.Err(result.FailedSendResult.Error). - Stringer("destination", destination). - Uints64("message_ids", messages). - Msg("Failed to send read receipt to Signal") - } else { - log.Debug(). - Stringer("destination", destination). - Uints64("message_ids", messages). - Msg("Sent read receipt to Signal") - } - } -} - -func (portal *Portal) sendMainIntentMessage(ctx context.Context, content *event.MessageEventContent) (*mautrix.RespSendEvent, error) { - return portal.sendMatrixEvent(ctx, portal.MainIntent(), event.EventMessage, content, nil, 0) -} - -func (portal *Portal) encrypt(ctx context.Context, intent *appservice.IntentAPI, content *event.Content, eventType event.Type) (event.Type, error) { - if !portal.Encrypted || portal.bridge.Crypto == nil { - return eventType, nil - } - intent.AddDoublePuppetValue(content) - // TODO maybe the locking should be inside mautrix-go? - portal.encryptLock.Lock() - defer portal.encryptLock.Unlock() - err := portal.bridge.Crypto.Encrypt(ctx, portal.MXID, eventType, content) - if err != nil { - return eventType, fmt.Errorf("failed to encrypt event: %w", err) - } - return event.EventEncrypted, nil -} - -func (portal *Portal) sendMatrixEvent(ctx context.Context, intent *appservice.IntentAPI, eventType event.Type, content any, extraContent map[string]any, timestamp int64) (*mautrix.RespSendEvent, error) { - wrappedContent := event.Content{Parsed: content, Raw: extraContent} - if eventType != event.EventReaction { - var err error - eventType, err = portal.encrypt(ctx, intent, &wrappedContent, eventType) - if err != nil { - return nil, err - } - } - - _, _ = intent.UserTyping(ctx, portal.MXID, false, 0) - return intent.SendMassagedMessageEvent(ctx, portal.MXID, eventType, &wrappedContent, timestamp) -} - -func (portal *Portal) getEncryptionEventContent() (evt *event.EncryptionEventContent) { - evt = &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1} - if rot := portal.bridge.Config.Bridge.Encryption.Rotation; rot.EnableCustom { - evt.RotationPeriodMillis = rot.Milliseconds - evt.RotationPeriodMessages = rot.Messages - } - return -} - -func (portal *Portal) shouldSetDMRoomMetadata() bool { - return !portal.IsPrivateChat() || - portal.bridge.Config.Bridge.PrivateChatPortalMeta == "always" || - (portal.IsEncrypted() && portal.bridge.Config.Bridge.PrivateChatPortalMeta != "never") -} - -func (portal *Portal) ensureUserInvited(ctx context.Context, user *User) bool { - return user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) -} - -func (portal *Portal) CreateMatrixRoom(ctx context.Context, user *User, groupRevision uint32) error { - portal.roomCreateLock.Lock() - defer portal.roomCreateLock.Unlock() - if portal.MXID != "" { - portal.log.Debug().Msg("Not creating room: already exists") - return nil - } - portal.log.Debug().Msg("Creating matrix room") - - intent := portal.MainIntent() - - if err := intent.EnsureRegistered(ctx); err != nil { - portal.log.Error().Err(err).Msg("failed to ensure registered") - return err - } - - bridgeInfoStateKey, bridgeInfo := portal.getBridgeInfo() - initialState := []*event.Event{{ - Type: event.StateBridge, - Content: event.Content{Parsed: bridgeInfo}, - StateKey: &bridgeInfoStateKey, - }, { - // TODO remove this once https://github.com/matrix-org/matrix-doc/pull/2346 is in spec - Type: event.StateHalfShotBridge, - Content: event.Content{Parsed: bridgeInfo}, - StateKey: &bridgeInfoStateKey, - }} - - if !portal.AvatarURL.IsEmpty() { - initialState = append(initialState, &event.Event{ - Type: event.StateRoomAvatar, - Content: event.Content{Parsed: &event.RoomAvatarEventContent{ - URL: portal.AvatarURL.CUString(), - }}, - }) - } - - creationContent := make(map[string]interface{}) - if !portal.bridge.Config.Bridge.FederateRooms { - creationContent["m.federate"] = false - } - - var invite []id.UserID - autoJoinInvites := portal.bridge.SpecVersions.Supports(mautrix.BeeperFeatureAutojoinInvites) - if autoJoinInvites { - invite = append(invite, user.MXID) - } - - if portal.bridge.Config.Bridge.Encryption.Default { - initialState = append(initialState, &event.Event{ - Type: event.StateEncryption, - Content: event.Content{ - Parsed: portal.getEncryptionEventContent(), - }, - }) - portal.Encrypted = true - - if portal.IsPrivateChat() && portal.MainIntent() != portal.bridge.Bot { - invite = append(invite, portal.bridge.Bot.UserID) - } - } - - var dmPuppet *Puppet - var groupInfo *signalmeow.Group - if portal.IsPrivateChat() { - dmPuppet = portal.GetDMPuppet() - if dmPuppet != nil { - dmPuppet.UpdateInfo(ctx, user, nil) - portal.UpdateDMInfo(ctx, false) - } else { - portal.UpdatePNIDMInfo(ctx, user) - } - } else { - groupInfo = portal.UpdateGroupInfo(ctx, user, nil, groupRevision, true) - if groupInfo == nil { - portal.log.Error().Msg("Didn't get group info after updating portal") - return errors.New("failed to get group info") - } - for member := range portal.SyncParticipants(ctx, user, groupInfo) { - invite = append(invite, member) - } - } - - req := &mautrix.ReqCreateRoom{ - Visibility: "private", - Name: portal.Name, - Topic: portal.Topic, - Invite: invite, - Preset: "private_chat", - IsDirect: portal.IsPrivateChat(), - InitialState: initialState, - CreationContent: creationContent, - - BeeperAutoJoinInvites: autoJoinInvites, - } - resp, err := intent.CreateRoom(ctx, req) - if err != nil { - portal.log.Warn().Err(err).Msg("failed to create room") - return err - } - portal.log = portal.log.With().Stringer("room_id", resp.RoomID).Logger() - - portal.NameSet = len(req.Name) > 0 - portal.TopicSet = len(req.Topic) > 0 - portal.AvatarSet = !portal.AvatarURL.IsEmpty() - portal.MXID = resp.RoomID - portal.bridge.portalsLock.Lock() - portal.bridge.portalsByMXID[portal.MXID] = portal - portal.bridge.portalsLock.Unlock() - err = portal.Update(ctx) - if err != nil { - portal.log.Err(err).Msg("Failed to save portal room ID") - return err - } - portal.log.Info().Msg("Created matrix room for portal") - - if !autoJoinInvites { - if !portal.IsPrivateChat() { - portal.SyncParticipants(ctx, user, groupInfo) - } else if portal.Encrypted { - err = portal.bridge.Bot.EnsureJoined(ctx, portal.MXID, appservice.EnsureJoinedParams{BotOverride: portal.MainIntent().Client}) - if err != nil { - portal.log.Error().Err(err).Msg("Failed to ensure bridge bot is joined to private chat portal") - } - } - user.ensureInvited(ctx, portal.MainIntent(), portal.MXID, portal.IsPrivateChat()) - } - user.syncChatDoublePuppetDetails(portal, true) - go portal.addToPersonalSpace(portal.log.WithContext(context.TODO()), user) - - if dmPuppet != nil { - user.UpdateDirectChats(ctx, map[id.UserID][]id.RoomID{ - dmPuppet.MXID: {portal.MXID}, - }) - } - - return nil -} - -func (portal *Portal) GetDMPuppet() *Puppet { - userID := portal.UserID() - if userID.IsEmpty() || userID.Type != libsignalgo.ServiceIDTypeACI { - return nil - } - return portal.bridge.GetPuppetBySignalID(userID.UUID) -} - -func (portal *Portal) UpdateInfo(ctx context.Context, source *User, groupInfo *signalmeow.Group, revision uint32) { - if portal.IsPrivateChat() { - portal.UpdateDMInfo(ctx, false) - return - } - groupInfo = portal.UpdateGroupInfo(ctx, source, groupInfo, revision, false) - if groupInfo != nil { - members := portal.SyncParticipants(ctx, source, groupInfo) - portal.updatePowerLevelsAndJoinRule(ctx, groupInfo, members) - } -} - -const PrivateChatTopic = "Signal private chat" -const NoteToSelfName = "Signal Note to Self" - -func (portal *Portal) PostReIDUpdate(ctx context.Context, user *User) { - _, err := portal.bridge.Bot.SetPowerLevel(ctx, portal.MXID, portal.MainIntent().UserID, 100) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update ghost power level after portal re-ID") - } - portal.GetDMPuppet().UpdateInfo(ctx, user, nil) - portal.UpdateDMInfo(ctx, true) - if !portal.Encrypted { - _, _ = portal.bridge.Bot.LeaveRoom(ctx, portal.MXID) - } -} - -func (portal *Portal) UpdateDMInfo(ctx context.Context, forceSave bool) { - log := zerolog.Ctx(ctx).With(). - Str("function", "UpdateDMInfo"). - Logger() - log.Trace().Msg("Updating portal info") - ctx = log.WithContext(ctx) - puppet := portal.GetDMPuppet() - - update := forceSave - if portal.UserID().UUID == portal.Receiver { - noteToSelfAvatar := portal.bridge.Config.Bridge.NoteToSelfAvatar.ParseOrIgnore() - avatarHash := sha256.Sum256([]byte(noteToSelfAvatar.String())) - - update = portal.updateName(ctx, NoteToSelfName, nil) || update - update = portal.updateAvatarWithMXC(ctx, "notetoself", hex.EncodeToString(avatarHash[:]), noteToSelfAvatar) || update - } else if portal.shouldSetDMRoomMetadata() { - update = portal.updateName(ctx, puppet.Name, nil) || update - update = portal.updateAvatarWithMXC(ctx, puppet.AvatarPath, puppet.AvatarHash, puppet.AvatarURL) || update - } else { - // Clear name/avatar if they're set in a DM that shouldn't have them set - if portal.Name != "" && portal.NameSet { - update = portal.updateName(ctx, "", nil) || update - } - // Avatar is currently never set in PNI portals - //if !portal.AvatarURL.IsEmpty() && portal.AvatarSet { - // update = true - // portal.AvatarURL = id.ContentURI{} - // portal.AvatarHash = "" - // portal.AvatarPath = "" - // portal.updateAvatarInRoom(ctx, nil) - //} - } - topic := PrivateChatTopic - if portal.bridge.Config.Bridge.NumberInTopic && puppet.Number != "" { - topic = fmt.Sprintf("%s with %s", topic, puppet.Number) - } - update = portal.updateTopic(ctx, topic, nil) || update - if update { - err := portal.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to save portal in database after updating group info") - } - portal.UpdateBridgeInfo(ctx) - } -} - -func (portal *Portal) UpdatePNIDMInfo(ctx context.Context, user *User) { - portalUserID := portal.UserID() - if portalUserID.Type != libsignalgo.ServiceIDTypePNI { - return - } - log := zerolog.Ctx(ctx) - update := false - recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, uuid.Nil, portalUserID.UUID, nil) - if err != nil { - log.Err(err).Msg("Failed to get PNI DM recipient entry") - } - if recipient == nil { - recipient = &types.Recipient{PNI: portalUserID.UUID} - } - topic := PrivateChatTopic - name := portalUserID.UUID.String() - if recipient.E164 != "" { - topic = fmt.Sprintf("%s with %s", topic, recipient.E164) - name = recipient.E164 - } - if recipient.ContactName != "" { - name = recipient.ContactName - } - update = portal.updateTopic(ctx, topic, nil) || update - update = portal.updateName(ctx, name, nil) || update - if update { - err = portal.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to save portal in database after updating group info") - } - portal.UpdateBridgeInfo(ctx) - } -} - -func (portal *Portal) updatePowerLevelsAndJoinRule(ctx context.Context, info *signalmeow.Group, members map[id.UserID]int) { - log := zerolog.Ctx(ctx).With(). - Str("function", "updatePowerLevelsAndJoinRule"). - Logger() - log.Trace().Msg("Updating power levels and join rule") - joinRuleContent := event.JoinRulesEventContent{} - err := portal.MainIntent().StateEvent(ctx, portal.MXID, event.StateJoinRules, "", &joinRuleContent) - if err != nil { - log.Err(err).Msg("Failed to get join rule") - return - } - joinRule := joinRuleContent.JoinRule - newJoinRule := event.JoinRuleInvite - levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) - if err != nil { - log.Err(err).Msg("Failed to get power levels") - return - } - botLevel := levels.GetUserLevel(portal.MainIntent().UserID) - changed := false - for mxid, level := range members { - oldLevel := levels.GetUserLevel(mxid) - difference := oldLevel - level - if oldLevel < botLevel && (difference < 0 || difference > 49) { - changed = levels.EnsureUserLevel(mxid, level) || changed - } - } - newEventsDefault := 0 - if info.AnnouncementsOnly { - newEventsDefault = 50 - } - if newEventsDefault != levels.EventsDefault { - levels.EventsDefault = newEventsDefault - changed = true - } - if info.AccessControl != nil { - level := 0 - if info.AccessControl.Attributes == signalmeow.AccessControl_ADMINISTRATOR { - level = 50 - } - changed = levels.EnsureEventLevel(event.StateRoomName, level) || changed - changed = levels.EnsureEventLevel(event.StateTopic, level) || changed - changed = levels.EnsureEventLevel(event.StateRoomAvatar, level) || changed - level = 0 - if info.AccessControl.Members == signalmeow.AccessControl_ADMINISTRATOR { - level = 50 - } - if levels.InvitePtr == nil || *levels.InvitePtr != level { - levels.InvitePtr = &level - changed = true - } - if info.AccessControl.AddFromInviteLink == signalmeow.AccessControl_ADMINISTRATOR { - newJoinRule = event.JoinRuleKnock - } else if info.AccessControl.AddFromInviteLink == signalmeow.AccessControl_ANY && (portal.bridge.Config.Bridge.PublicPortals || joinRule == event.JoinRulePublic) { - newJoinRule = event.JoinRulePublic - } - } - if newJoinRule != joinRule { - _, err = portal.MainIntent().SendStateEvent(ctx, portal.MXID, event.StateJoinRules, "", &event.JoinRulesEventContent{JoinRule: joinRule}) - if err != nil { - log.Err(err).Msg("Failed to set join rule") - } - } - if changed { - _, err = portal.MainIntent().SetPowerLevels(ctx, portal.MXID, levels) - if err != nil { - log.Err(err).Msg("Failed to set power levels") - } - } -} - -func (portal *Portal) UpdateGroupInfo(ctx context.Context, source *User, info *signalmeow.Group, revision uint32, forceFetch bool) *signalmeow.Group { - logWith := zerolog.Ctx(ctx).With(). - Str("function", "UpdateGroupInfo"). - Uint32("revision", revision). - Stringer("source_user_mxid", source.MXID) - if info != nil { - logWith = logWith.Uint32("info_revision", info.Revision) - } - log := logWith.Logger() - if info == nil { - if revision <= portal.Revision && !forceFetch { - log.Debug().Msg("Not fetching group info to update portal: given revision is not newer") - return nil - } - log.Debug().Msg("Fetching group info to update portal") - var err error - info, err = source.Client.RetrieveGroupByID(ctx, portal.GroupID(), revision) - if err != nil { - log.Err(err). - Stringer("source_user_id", source.MXID). - Msg("Failed to fetch group info") - return nil - } - } - if portal.Revision > info.Revision { - log.Debug().Uint32("current_revision", portal.Revision).Msg("Not updating portal with data from older revision") - return info - } - logEvt := log.Trace() - if portal.Revision != info.Revision { - logEvt = log.Debug() - } - logEvt.Uint32("current_revision", portal.Revision).Msg("Updating portal info") - ctx = log.WithContext(ctx) - update := false - if portal.Revision < info.Revision { - portal.Revision = info.Revision - update = true - } - update = portal.updateName(ctx, info.Title, nil) || update - update = portal.updateTopic(ctx, info.Description, nil) || update - update = portal.updateAvatarWithInfo(ctx, source, info, nil) || update - update = portal.updateExpirationTimer(ctx, info.DisappearingMessagesDuration) || update - if update { - err := portal.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to save portal in database after updating group info") - } - portal.UpdateBridgeInfo(ctx) - } - return info -} - -func (portal *Portal) updateExpirationTimer(ctx context.Context, newExpirationTimer uint32) bool { - if portal.ExpirationTime == newExpirationTimer { - return false - } - portal.ExpirationTime = newExpirationTimer - if portal.MXID != "" { - msg := portal.MsgConv.ConvertDisappearingTimerChangeToMatrix(ctx, newExpirationTimer, false) - _, err := portal.sendMainIntentMessage(ctx, msg.Content) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to send notice about disappearing message timer changing") - } - } - return true -} - -func (portal *Portal) implicitlyUpdateExpirationTimer(ctx context.Context, newExpirationTimer uint32) bool { - if portal.ExpirationTime == newExpirationTimer { - return false - } - portal.ExpirationTime = newExpirationTimer - if portal.MXID != "" { - msg := portal.MsgConv.ConvertDisappearingTimerChangeToMatrix(ctx, newExpirationTimer, false) - msg.Content.Body = fmt.Sprintf("Automatically enabled disappearing message timer (%s) because incoming message is disappearing", exfmt.Duration(time.Duration(newExpirationTimer)*time.Second)) - _, err := portal.sendMainIntentMessage(ctx, msg.Content) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to send notice about disappearing message timer changing implicitly") - } - } - return true -} - -func (portal *Portal) updateName(ctx context.Context, newName string, sender *Puppet) bool { - if portal.Name == newName && (portal.NameSet || portal.MXID == "") { - return false - } - portal.Name = newName - portal.NameSet = false - if portal.MXID != "" { - intent := portal.MainIntent() - if sender != nil { - intent = sender.IntentFor(portal) - } - _, err := intent.SetRoomName(ctx, portal.MXID, portal.Name) - if errors.Is(err, mautrix.MForbidden) && intent != portal.MainIntent() { - _, err = portal.MainIntent().SetRoomName(ctx, portal.MXID, portal.Name) - } - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update room name") - } else { - portal.NameSet = true - } - } - return true -} - -func (portal *Portal) updateTopic(ctx context.Context, newTopic string, sender *Puppet) bool { - if portal.Topic == newTopic && (portal.TopicSet || portal.MXID == "") { - return false - } - portal.Topic = newTopic - portal.TopicSet = false - if portal.MXID != "" { - intent := portal.MainIntent() - if sender != nil { - intent = sender.IntentFor(portal) - } - _, err := intent.SetRoomTopic(ctx, portal.MXID, portal.Topic) - if errors.Is(err, mautrix.MForbidden) && intent != portal.MainIntent() { - _, err = portal.MainIntent().SetRoomTopic(ctx, portal.MXID, portal.Topic) - } - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update room topic") - } else { - portal.TopicSet = true - } - } - return true -} - -func (portal *Portal) updateAvatarWithInfo(ctx context.Context, source *User, group signalmeow.GroupAvatarMeta, sender *Puppet) bool { - // If the avatar path is different, the avatar probably changed - avatarPath := group.GetAvatarPath() - if avatarPath == nil { - return false - } - if portal.AvatarPath == *avatarPath && - // If the avatar mxc isn't set, we need to reupload it (except if the avatar is unset in Signal) - (!portal.AvatarURL.IsEmpty() || *avatarPath == "") && - // If the avatar isn't set in the room, we need to update the room state (except if there's no Matrix room yet) - (portal.AvatarSet || portal.MXID == "") { - return false - } - if *avatarPath == "" { - portal.AvatarPath = "" - portal.AvatarSet = false - portal.AvatarURL = id.ContentURI{} - portal.AvatarHash = "" - // Just clear the Matrix room avatar and return - portal.updateAvatarInRoom(ctx, sender) - return true - } - log := zerolog.Ctx(ctx) - log.Debug().Str("avatar_path", portal.AvatarPath).Msg("Downloading new group avatar from Signal") - avatarBytes, err := source.Client.DownloadGroupAvatar(ctx, group) - if err != nil { - log.Err(err).Msg("Failed to download new avatar for portal") - return true - } - hash := sha256.Sum256(avatarBytes) - newAvatarHash := hex.EncodeToString(hash[:]) - if portal.AvatarHash == newAvatarHash && (portal.AvatarSet || portal.MXID == "") { - // No need to change anything else, but save the new path to the database - return true - } - portal.AvatarPath = *avatarPath - portal.AvatarSet = false - portal.AvatarURL = id.ContentURI{} - portal.AvatarHash = newAvatarHash - log.Debug().Str("avatar_hash", portal.AvatarHash).Msg("Uploading new group avatar to Matrix") - resp, err := portal.MainIntent().UploadBytes(ctx, avatarBytes, http.DetectContentType(avatarBytes)) - if err != nil { - log.Err(err).Msg("Failed to upload new avatar for portal") - } else { - portal.AvatarURL = resp.ContentURI - portal.updateAvatarInRoom(ctx, sender) - } - return true -} - -func (portal *Portal) updateAvatarWithMXC(ctx context.Context, newAvatarPath, newAvatarHash string, newAvatarURI id.ContentURI) bool { - if portal.AvatarHash == newAvatarHash && (portal.AvatarSet || portal.MXID == "") { - return false - } - portal.AvatarPath = newAvatarPath - portal.AvatarHash = newAvatarHash - portal.AvatarURL = newAvatarURI - portal.AvatarSet = false - portal.updateAvatarInRoom(ctx, nil) - return true -} - -func (portal *Portal) updateAvatarInRoom(ctx context.Context, sender *Puppet) { - if portal.MXID == "" || portal.AvatarSet { - return - } - zerolog.Ctx(ctx).Debug(). - Str("avatar_path", portal.AvatarPath). - Str("avatar_hash", portal.AvatarHash). - Stringer("avatar_mxc", portal.AvatarURL). - Msg("Updating avatar in Matrix room") - intent := portal.MainIntent() - if sender != nil { - intent = sender.IntentFor(portal) - } - _, err := intent.SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) - if errors.Is(err, mautrix.MForbidden) && intent != portal.MainIntent() { - _, err = portal.MainIntent().SetRoomAvatar(ctx, portal.MXID, portal.AvatarURL) - } - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update room avatar") - } else { - portal.AvatarSet = true - } -} - -func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info *signalmeow.Group) map[id.UserID]int { - log := zerolog.Ctx(ctx) - userIDs := make(map[id.UserID]int) - currentMembers := make(map[id.UserID]event.Membership) - var err error - if portal.MXID != "" { - memberEventData, err := portal.MainIntent().Members(ctx, portal.MXID, mautrix.ReqMembers{}) - if err != nil { - log.Err(err).Msg("couldn't get portal members") - return nil - } - for _, evt := range memberEventData.Chunk { - evt.Content.ParseRaw(event.StateMember) - currentMembers[id.UserID(*evt.StateKey)] = evt.Content.AsMember().Membership - } - } - for _, member := range info.Members { - puppet := portal.bridge.GetPuppetBySignalID(member.ACI) - if puppet == nil { - log.Warn().Stringer("signal_user_id", member.ACI).Msg("Couldn't get puppet for group member") - continue - } - puppet.UpdateInfo(ctx, source, nil) - intent := puppet.IntentFor(portal) - if member.ACI != source.SignalID && portal.MXID != "" { - userIDs[intent.UserID] = ((int)(member.Role) >> 1) * 50 - } - delete(currentMembers, intent.UserID) - if portal.MXID != "" { - if currentMembers[intent.UserID] != event.MembershipJoin { - err := intent.EnsureJoined(ctx, portal.MXID) - if err != nil { - log.Err(err).Stringer("signal_user_id", member.ACI).Msg("Failed to ensure user is joined to portal") - } - } - if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(member.ACI) - if user != nil { - delete(currentMembers, user.MXID) - userIDs[user.MXID] = ((int)(member.Role) >> 1) * 50 - currentMembership := currentMembers[user.MXID] - if currentMembership == event.MembershipJoin || currentMembership == event.MembershipInvite { - continue - } - user.ensureInvited(ctx, intent, portal.MXID, false) - } - } - } - } - if portal.MXID == "" { - return userIDs - } - for _, pendingMember := range info.PendingMembers { - if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { - continue - } - puppet := portal.bridge.GetPuppetBySignalID(pendingMember.ServiceID.UUID) - if puppet == nil { - log.Warn().Stringer("signal_user_id", pendingMember.ServiceID.UUID).Msg("Couldn't get puppet for group member") - continue - } - mxid := puppet.IntentFor(portal).UserID - membership := currentMembers[mxid] - if membership == event.MembershipJoin || membership == event.MembershipBan { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") - } - } - if membership != event.MembershipInvite { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipInvite, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to invite") - } - } - userIDs[mxid] = ((int)(pendingMember.Role) >> 1) * 50 - delete(currentMembers, mxid) - if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(pendingMember.ServiceID.UUID) - if user == nil { - continue - } - mxid = user.MXID - membership := currentMembers[mxid] - err = nil - if membership == event.MembershipJoin || membership == event.MembershipBan { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") - } - } - if membership != event.MembershipInvite { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipInvite, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to invite") - } - } - userIDs[mxid] = ((int)(pendingMember.Role) >> 1) * 50 - delete(currentMembers, mxid) - } - } - for _, requestingMember := range info.RequestingMembers { - puppet := portal.bridge.GetPuppetBySignalID(requestingMember.ACI) - if puppet == nil { - log.Warn().Stringer("signal_user_id", requestingMember.ACI).Msg("Couldn't get puppet for group member") - continue - } - mxid := puppet.IntentFor(portal).UserID - membership := currentMembers[mxid] - if membership == event.MembershipJoin || membership == event.MembershipBan { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") - } - } - if membership != event.MembershipKnock { - _, err = puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipKnock, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to knock") - } - } - delete(currentMembers, mxid) - } - for _, bannedMember := range info.BannedMembers { - if bannedMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { - continue - } - puppet := portal.bridge.GetPuppetBySignalID(bannedMember.ServiceID.UUID) - if puppet == nil { - log.Warn().Stringer("signal_user_id", bannedMember.ServiceID.UUID).Msg("Couldn't get puppet for group member") - continue - } - mxid := puppet.IntentFor(portal).UserID - if currentMembers[mxid] != event.MembershipBan { - _, err := portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipBan, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to ban") - } - } - delete(currentMembers, mxid) - if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(bannedMember.ServiceID.UUID) - if user == nil { - continue - } - mxid = user.MXID - if currentMembers[mxid] != event.MembershipBan { - _, err = portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipBan, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to ban") - } - } - delete(currentMembers, mxid) - } - } - for mxid, membership := range currentMembers { - if membership == event.MembershipLeave { - continue - } - puppet := portal.bridge.GetPuppetByMXID(mxid) - if puppet != nil { - _, err := portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") - } - } else { - user := portal.bridge.GetUserByMXIDIfExists(mxid) - if user != nil { - if user.IsLoggedIn() { - _, err := portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, mxid, event.MembershipLeave, "") - if err != nil { - log.Err(err).Stringer("mxid", mxid).Msg("Couldn't change membership to leave") - } - } - } - } - } - return userIDs -} - -func (portal *Portal) getBridgeInfoStateKey() string { - return fmt.Sprintf("net.maunium.signal://signal/%s", portal.ChatID) -} - -func (portal *Portal) ScheduleDisappearing() { - portal.bridge.disappearingMessagesManager.ScheduleDisappearingForRoom(context.TODO(), portal.MXID) -} - -func (portal *Portal) addToPersonalSpace(ctx context.Context, user *User) bool { - spaceID := user.GetSpaceRoom(ctx) - if len(spaceID) == 0 || user.IsInSpace(ctx, portal.PortalKey) { - return false - } - _, err := portal.bridge.Bot.SendStateEvent(ctx, spaceID, event.StateSpaceChild, portal.MXID.String(), &event.SpaceChildEventContent{ - Via: []string{portal.bridge.Config.Homeserver.Domain}, - }) - if err != nil { - zerolog.Ctx(ctx).Err(err). - Stringer("user_id", user.MXID). - Stringer("space_id", spaceID). - Msg("Failed to add room to user's personal filtering space") - return false - } else { - zerolog.Ctx(ctx).Debug(). - Stringer("user_id", user.MXID). - Stringer("space_id", spaceID). - Msg("Added room to user's personal filtering space") - user.MarkInSpace(ctx, portal.PortalKey) - return true - } -} - -func (portal *Portal) HasRelaybot() bool { - return portal.bridge.Config.Bridge.Relay.Enabled && len(portal.RelayUserID) > 0 -} - -func (portal *Portal) addRelaybotFormat(ctx context.Context, userID id.UserID, evt *event.Event, content *event.MessageEventContent) bool { - member := portal.MainIntent().Member(ctx, portal.MXID, userID) - if member == nil { - member = &event.MemberEventContent{} - } - // Stickers can't have captions, so force them into images when relaying - if evt.Type == event.EventSticker { - content.MsgType = event.MsgImage - evt.Type = event.EventMessage - } - content.EnsureHasHTML() - data, err := portal.bridge.Config.Bridge.Relay.FormatMessage(content, userID, *member) - if err != nil { - portal.log.Err(err).Msg("Failed to apply relaybot format") - } - content.FormattedBody = data - // Force FileName field so the formatted body is used as a caption - if content.FileName == "" { - content.FileName = content.Body - } - return true -} - -func (portal *Portal) Delete() { - err := portal.Portal.Delete(context.TODO()) - if err != nil { - portal.log.Err(err).Msg("Failed to delete portal from db") - } - portal.bridge.portalsLock.Lock() - portal.unlockedDeleteCache() - portal.bridge.portalsLock.Unlock() -} - -func (portal *Portal) unlockedDelete() { - err := portal.Portal.Delete(context.TODO()) - if err != nil { - portal.log.Err(err).Msg("Failed to delete portal from db") - } - portal.unlockedDeleteCache() -} - -func (portal *Portal) unlockedDeleteCache() { - delete(portal.bridge.portalsByID, portal.PortalKey) - if len(portal.MXID) > 0 { - delete(portal.bridge.portalsByMXID, portal.MXID) - } - if portal.Receiver == uuid.Nil { - portal.bridge.usersLock.Lock() - for _, user := range portal.bridge.usersBySignalID { - user.RemoveInSpaceCache(portal.PortalKey) - } - portal.bridge.usersLock.Unlock() - } else { - user := portal.bridge.GetUserBySignalID(portal.Receiver) - if user != nil { - user.RemoveInSpaceCache(portal.PortalKey) - } - } -} - -func (portal *Portal) Cleanup(ctx context.Context, puppetsOnly bool) { - portal.bridge.CleanupRoom(ctx, &portal.log, portal.MainIntent(), portal.MXID, puppetsOnly) -} - -func (br *SignalBridge) CleanupRoom(ctx context.Context, log *zerolog.Logger, intent *appservice.IntentAPI, mxid id.RoomID, puppetsOnly bool) { - if len(mxid) == 0 { - return - } - if br.SpecVersions.Supports(mautrix.BeeperFeatureRoomYeeting) { - err := intent.BeeperDeleteRoom(ctx, mxid) - if err == nil || errors.Is(err, mautrix.MNotFound) { - return - } - log.Warn().Err(err).Msg("Failed to delete room using beeper yeet endpoint, falling back to normal behavior") - } - members, err := intent.JoinedMembers(ctx, mxid) - if err != nil { - log.Err(err).Msg("Failed to get portal members for cleanup") - return - } - for member := range members.Joined { - if member == intent.UserID { - continue - } - puppet := br.GetPuppetByMXID(member) - if puppet != nil { - _, err = puppet.DefaultIntent().LeaveRoom(ctx, mxid) - if err != nil { - log.Err(err).Msg("Failed to leave as puppet while cleaning up portal") - } - } else if !puppetsOnly { - _, err = intent.KickUser(ctx, mxid, &mautrix.ReqKickUser{UserID: member, Reason: "Deleting portal"}) - if err != nil { - log.Err(err).Msg("Failed to kick user while cleaning up portal") - } - } - } - _, err = intent.LeaveRoom(ctx, mxid) - if err != nil { - log.Err(err).Msg("Failed to leave room while cleaning up portal") - } -} - -func (portal *Portal) HandleMatrixLeave(brSender bridge.User, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix leave"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - if portal.IsPrivateChat() { - log.Info().Msg("User left private chat portal, cleaning up and deleting...") - portal.Delete() - portal.Cleanup(ctx, false) - return - } else if portal.bridge.Config.Bridge.BridgeMatrixLeave { - portal.deleteMember(sender, sender.SignalID, evt) - } - portal.CleanupIfEmpty(ctx) -} -func (portal *Portal) HandleMatrixKick(brSender bridge.User, ghost bridge.Ghost, evt *event.Event) { - portal.deleteMember(brSender.(*User), ghost.(*Puppet).SignalID, evt) -} -func (portal *Portal) deleteMember(sender *User, target uuid.UUID, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix kick/leave"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - groupChange := &signalmeow.GroupChange{DeleteMembers: []*uuid.UUID{&target}} - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error deleting Member from Signal") - return - } - portal.Revision = revision - portal.Update(ctx) -} -func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix invite"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - puppet := brGhost.(*Puppet) - role := signalmeow.GroupMember_DEFAULT - levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) - if err != nil { - log.Err(err).Msg("Couldn't get power levels") - if levels.GetUserLevel(puppet.IntentFor(portal).UserID) >= 50 { - role = signalmeow.GroupMember_ADMINISTRATOR - } - } - groupChange := &signalmeow.GroupChange{AddMembers: []*signalmeow.AddMember{{ - GroupMember: signalmeow.GroupMember{ - ACI: puppet.SignalID, - Role: role, - }, - }}} - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error inviting user on Signal") - } - puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixAcceptKnock(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix accept knock"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - puppet := brGhost.(*Puppet) - role := signalmeow.GroupMember_DEFAULT - levels, err := portal.MainIntent().PowerLevels(ctx, portal.MXID) - if err != nil { - log.Err(err).Msg("Couldn't get power levels") - if levels.GetUserLevel(puppet.IntentFor(portal).UserID) >= 50 { - role = signalmeow.GroupMember_ADMINISTRATOR - } - } - groupChange := &signalmeow.GroupChange{PromoteRequestingMembers: []*signalmeow.RoleMember{{ - ACI: puppet.SignalID, - Role: role, - }}} - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error accepting join request on Signal") - } - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixRejectKnock(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { - portal.removeRequestingMember(brSender.(*User), brGhost.(*Puppet).SignalID, evt) -} - -func (portal *Portal) HandleMatrixRetractKnock(brSender bridge.User, evt *event.Event) { - portal.removeRequestingMember(brSender.(*User), brSender.(*User).SignalID, evt) -} - -func (portal *Portal) removeRequestingMember(sender *User, target uuid.UUID, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix knock -> leave"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - groupChange := &signalmeow.GroupChange{DeleteRequestingMembers: []*uuid.UUID{&target}} - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error removing requesting member") - } - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixKnock(brSender bridge.User, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix knock"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - log.Debug().Msg("Knocks aren't implemented yet :(") -} - -func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix ban"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - puppet := brGhost.(*Puppet) - groupChange := &signalmeow.GroupChange{AddBannedMembers: []*signalmeow.BannedMember{{ - ServiceID: libsignalgo.NewACIServiceID(puppet.SignalID), - Timestamp: uint64(time.Now().UnixMilli()), - }}} - switch prevMembership := evt.Unsigned.PrevContent.AsMember().Membership; prevMembership { - case event.MembershipJoin: - groupChange.DeleteMembers = []*uuid.UUID{&puppet.SignalID} - case event.MembershipKnock: - groupChange.DeleteRequestingMembers = []*uuid.UUID{&puppet.SignalID} - case event.MembershipInvite: - serviceID := libsignalgo.NewACIServiceID(puppet.SignalID) - groupChange.DeletePendingMembers = []*libsignalgo.ServiceID{&serviceID} - } - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error banning on Signal") - } - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixUnban(brSender bridge.User, brGhost bridge.Ghost, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix unban"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - puppet := brGhost.(*Puppet) - serviceID := libsignalgo.NewACIServiceID(puppet.SignalID) - groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*libsignalgo.ServiceID{&serviceID}} - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error unbanning on Signal") - } - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix power levels"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - if !sender.IsLoggedIn() { - log.Warn().Msg("Can't change power levels: user is not logged in") - return - } - evt.Content.ParseRaw(event.StatePowerLevels) - levels := evt.Content.AsPowerLevels() - var prevLevels *event.PowerLevelsEventContent - if evt.Unsigned.PrevContent != nil { - evt.Unsigned.PrevContent.ParseRaw(event.StatePowerLevels) - prevLevels = evt.Unsigned.PrevContent.AsPowerLevels() - } else { - prevLevels = &event.PowerLevelsEventContent{} - } - groupChange := &signalmeow.GroupChange{} - var role signalmeow.GroupMemberRole - for user, level := range levels.Users { - prevLevel := prevLevels.GetUserLevel(user) - if (level >= 50 && prevLevel < 50) || (level < 50 && prevLevel >= 50) { - puppet := portal.bridge.GetPuppetByMXID(user) - if puppet == nil { - log.Warn().Stringer("mxid", user).Msg("Couldn't get puppet for power level change") - continue - } - role = signalmeow.GroupMember_DEFAULT - if level >= 50 { - role = signalmeow.GroupMember_ADMINISTRATOR - } - groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles, &signalmeow.RoleMember{ - ACI: puppet.SignalID, - Role: role, - }) - } - } - if levels.EventsDefault >= 50 && prevLevels.EventsDefault < 50 { - announcementsOnly := true - groupChange.ModifyAnnouncementsOnly = &announcementsOnly - } else if levels.EventsDefault < 50 && prevLevels.EventsDefault >= 50 { - announcementsOnly := false - groupChange.ModifyAnnouncementsOnly = &announcementsOnly - } - if levels.StateDefault() >= 50 && prevLevels.StateDefault() < 50 { - attributesAccess := signalmeow.AccessControl_ADMINISTRATOR - groupChange.ModifyAttributesAccess = &attributesAccess - } else if levels.StateDefault() < 50 && prevLevels.StateDefault() >= 50 { - attributesAccess := signalmeow.AccessControl_MEMBER - groupChange.ModifyAttributesAccess = &attributesAccess - } - if levels.Invite() >= 50 && prevLevels.Invite() < 50 { - memberAccess := signalmeow.AccessControl_ADMINISTRATOR - groupChange.ModifyMemberAccess = &memberAccess - } else if levels.Invite() < 50 && prevLevels.Invite() >= 50 { - memberAccess := signalmeow.AccessControl_MEMBER - groupChange.ModifyMemberAccess = &memberAccess - } - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error changing group access control") - return - } - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixJoinRule(brSender bridge.User, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix join rule"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - if !sender.IsLoggedIn() { - log.Warn().Msg("Can't change join rule: user is not logged in") - return - } - evt.Content.ParseRaw(event.StateJoinRules) - joinRule := evt.Content.AsJoinRules().JoinRule - groupChange := &signalmeow.GroupChange{} - addFromInviteLinkAccess := signalmeow.AccessControl_UNSATISFIABLE - if joinRule == event.JoinRuleKnock { - addFromInviteLinkAccess = signalmeow.AccessControl_ADMINISTRATOR - } else if joinRule == event.JoinRulePublic { - addFromInviteLinkAccess = signalmeow.AccessControl_ANY - } - groupChange.ModifyAddFromInviteLinkAccess = &addFromInviteLinkAccess - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error updating group access control") - return - } - portal.Revision = revision - portal.Update(ctx) -} - -func (portal *Portal) HandleMatrixMeta(brSender bridge.User, evt *event.Event) { - log := portal.log.With(). - Str("action", "handle matrix meta"). - Stringer("event_id", evt.ID). - Str("event_type", evt.Type.String()). - Logger() - ctx := log.WithContext(context.TODO()) - sender := brSender.(*User) - if !sender.IsLoggedIn() { - log.Warn().Msg("Can't change room info: user is not logged in") - return - } - - var err error - groupChange := &signalmeow.GroupChange{Revision: portal.Revision + 1} - var avatarPath *string - var avatarHash string - var avatarURL id.ContentURI - var avatarChanged bool - switch content := evt.Content.Parsed.(type) { - case *event.RoomNameEventContent: - if content.Name == portal.Name { - return - } - portal.Name = content.Name - groupChange.ModifyTitle = &content.Name - case *event.TopicEventContent: - if content.Topic == portal.Topic { - return - } - portal.Topic = content.Topic - groupChange.ModifyDescription = &content.Topic - case *event.RoomAvatarEventContent: - url := content.URL.ParseOrIgnore() - if url == portal.AvatarURL { - return - } - var data []byte - if !url.IsEmpty() { - data, err = portal.MainIntent().DownloadBytes(ctx, url) - if err != nil { - log.Err(err).Stringer("Failed to download updated avatar %s", url) - return - } - log.Debug().Stringers("%s set the group avatar to %s", []fmt.Stringer{sender.MXID, url}) - } else { - log.Debug().Stringer("%s removed the group avatar", sender.MXID) - } - avatarPath, err = sender.Client.UploadGroupAvatar(ctx, data, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Failed to upload group avatar") - return - } - groupChange.ModifyAvatar = avatarPath - hash := sha256.Sum256(data) - avatarHash = hex.EncodeToString(hash[:]) - avatarChanged = true - avatarURL = url - } - revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - log.Err(err).Msg("Error updating group attributes") - return - } - if avatarChanged { - log.Debug().Msg("Successfully updated group avatar") - portal.AvatarSet = true - portal.AvatarPath = *avatarPath - portal.AvatarHash = avatarHash - portal.AvatarURL = avatarURL - portal.UpdateBridgeInfo(ctx) - } - portal.Revision = revision - portal.Update(ctx) - log.Info().Msg("finished updating group") -} - -func (portal *Portal) CleanupIfEmpty(ctx context.Context) { - log := portal.log.With(). - Str("action", "Clean up if empty"). - Logger() - users, err := portal.GetMatrixUsers(ctx) - if err != nil { - log.Err(err).Msg("Failed to get Matrix user list to determine if portal needs to be cleaned up") - return - } - - if len(users) == 0 { - log.Info().Msg("Room seems to be empty, cleaning up...") - portal.Delete() - portal.Cleanup(ctx, false) - } -} - -func (portal *Portal) GetMatrixUsers(ctx context.Context) ([]id.UserID, error) { - members, err := portal.MainIntent().JoinedMembers(ctx, portal.MXID) - if err != nil { - return nil, fmt.Errorf("failed to get member list: %w", err) - } - var users []id.UserID - for userID := range members.Joined { - _, isPuppet := portal.bridge.ParsePuppetMXID(userID) - if !isPuppet && userID != portal.bridge.Bot.UserID { - users = append(users, userID) - } - } - return users, nil -} - -func (portal *Portal) GetInviteLink(ctx context.Context, source *User) (string, error) { - info, err := source.Client.RetrieveGroupByID(ctx, portal.GroupID(), portal.Revision) - if err != nil { - zerolog.Ctx(ctx).Err(err). - Stringer("source_user_id", source.MXID). - Msg("Failed to fetch group info") - return "", err - } - inviteLinkPassword, err := info.GetInviteLink() - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to get invite link") - } - return inviteLinkPassword, nil -} - -func (portal *Portal) ResetInviteLink(ctx context.Context, source *User) error { - inviteLinkPassword := signalmeow.GenerateInviteLinkPassword() - groupChange := &signalmeow.GroupChange{ModifyInviteLinkPassword: &inviteLinkPassword} - revision, err := source.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Error setting invite link password") - return err - } - portal.Revision = revision - return portal.Update(ctx) -} - -func (portal *Portal) GetEncryptionEventContent() (evt *event.EncryptionEventContent) { - evt = &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1} - if rot := portal.bridge.Config.Bridge.Encryption.Rotation; rot.EnableCustom { - evt.RotationPeriodMillis = rot.Milliseconds - evt.RotationPeriodMessages = rot.Messages - } - return -} diff --git a/provisioning.go b/provisioning.go deleted file mode 100644 index 46b52d1..0000000 --- a/provisioning.go +++ /dev/null @@ -1,640 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - _ "net/http/pprof" - "strconv" - "strings" - "sync" - "time" - - "github.com/google/uuid" - "github.com/gorilla/mux" - "github.com/rs/zerolog" - "github.com/rs/zerolog/hlog" - "go.mau.fi/util/requestlog" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/legacyprovision" - "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" -) - -type provisioningContextKey int - -const ( - provisioningUserKey provisioningContextKey = iota -) - -type provisioningHandle struct { - id int - context context.Context - cancel context.CancelFunc - channel <-chan signalmeow.ProvisioningResponse -} - -type ProvisioningAPI struct { - bridge *SignalBridge - log zerolog.Logger - provisioningHandles []*provisioningHandle - provisioningUsers map[string]int - provisioningMutexes map[string]*sync.Mutex -} - -func (prov *ProvisioningAPI) Init() { - prov.log.Debug().Str("prefix", prov.bridge.Config.Bridge.Provisioning.Prefix).Msg("Enabling provisioning API") - prov.provisioningUsers = make(map[string]int) - prov.provisioningMutexes = make(map[string]*sync.Mutex) - r := prov.bridge.AS.Router.PathPrefix(prov.bridge.Config.Bridge.Provisioning.Prefix).Subrouter() - r.Use(hlog.NewHandler(prov.log)) - r.Use(requestlog.AccessLogger(true)) - r.Use(prov.AuthMiddleware) - r.HandleFunc("/v2/whoami", prov.WhoAmI).Methods(http.MethodGet) - r.HandleFunc("/v2/link/new", prov.LinkNew).Methods(http.MethodPost) - r.HandleFunc("/v2/link/wait/scan", prov.LinkWaitForScan).Methods(http.MethodPost) - r.HandleFunc("/v2/link/wait/account", prov.LinkWaitForAccount).Methods(http.MethodPost) - r.HandleFunc("/v2/logout", prov.Logout).Methods(http.MethodPost) - r.HandleFunc("/v2/resolve_identifier/{phonenum}", prov.ResolveIdentifier).Methods(http.MethodGet) - r.HandleFunc("/v2/pm/{phonenum}", prov.StartPM).Methods(http.MethodPost) - - if prov.bridge.Config.Bridge.Provisioning.DebugEndpoints { - prov.log.Debug().Msg("Enabling debug API at /debug") - r := prov.bridge.AS.Router.PathPrefix("/debug").Subrouter() - r.Use(prov.AuthMiddleware) - r.PathPrefix("/pprof").Handler(http.DefaultServeMux) - } -} - -func (prov *ProvisioningAPI) AuthMiddleware(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - auth := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") - if auth != prov.bridge.Config.Bridge.Provisioning.SharedSecret { - zerolog.Ctx(r.Context()).Warn().Msg("Authentication token does not match shared secret") - legacyprovision.JSONResponse(w, http.StatusForbidden, &mautrix.RespError{ - Err: "Authentication token does not match shared secret", - ErrCode: mautrix.MForbidden.ErrCode, - }) - return - } - userID := r.URL.Query().Get("user_id") - user := prov.bridge.GetUserByMXID(id.UserID(userID)) - h.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), provisioningUserKey, user))) - }) -} - -func (prov *ProvisioningAPI) resolveIdentifier(ctx context.Context, user *User, inputPhone string) (int, *legacyprovision.ResolveIdentifierResponse, error) { - if user.Client == nil { - return http.StatusUnauthorized, nil, errors.New("not currently connected to Signal") - } - e164Number, err := strconv.ParseUint(numberCleaner.Replace(inputPhone), 10, 64) - if err != nil { - return http.StatusBadRequest, nil, fmt.Errorf("error parsing phone number: %w", err) - } - e164String := fmt.Sprintf("+%d", e164Number) - var aci, pni uuid.UUID - var recipient *types.Recipient - if recipient, err = user.Client.ContactByE164(ctx, e164String); err != nil { - return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number in local contact list: %w", err) - } else if recipient != nil { - aci = recipient.ACI - pni = recipient.PNI - } else if resp, err := user.Client.LookupPhone(ctx, e164Number); err != nil { - return http.StatusInternalServerError, nil, fmt.Errorf("error looking up number on server: %w", err) - } else { - aci = resp[e164Number].ACI - pni = resp[e164Number].PNI - if aci == uuid.Nil && pni == uuid.Nil { - return http.StatusNotFound, nil, errors.New("user not found on Signal") - } - recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") - } - aci, pni = recipient.ACI, recipient.PNI - } - zerolog.Ctx(ctx).Debug(). - Uint64("e164", e164Number). - Stringer("aci", aci). - Stringer("pni", pni). - Msg("Found DM target user") - - var targetServiceID libsignalgo.ServiceID - var otherUserInfo *legacyprovision.ResolveIdentifierResponseOtherUser - if aci != uuid.Nil { - targetServiceID = libsignalgo.NewACIServiceID(aci) - puppet := prov.bridge.GetPuppetBySignalID(aci) - otherUserInfo = &legacyprovision.ResolveIdentifierResponseOtherUser{ - MXID: puppet.MXID, - DisplayName: puppet.Name, - AvatarURL: puppet.AvatarURL, - } - } else { - targetServiceID = libsignalgo.NewPNIServiceID(pni) - // TODO fill other user displayname/avatar if there's a contact entry? - } - portal := user.GetPortalByChatID(targetServiceID.String()) - - return http.StatusOK, &legacyprovision.ResolveIdentifierResponse{ - RoomID: portal.MXID, - ChatID: legacyprovision.ResolveIdentifierResponseChatID{ - UUID: targetServiceID.String(), - Number: e164String, - }, - OtherUser: otherUserInfo, - }, nil -} - -func (prov *ProvisioningAPI) ResolveIdentifier(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - phoneNum := mux.Vars(r)["phonenum"] - - log := prov.log.With(). - Str("action", "resolve_identifier"). - Stringer("user_id", user.MXID). - Str("phone_num", phoneNum). - Logger() - ctx := log.WithContext(r.Context()) - log.Debug().Msg("resolving identifier") - - status, resp, err := prov.resolveIdentifier(ctx, user, phoneNum) - if err != nil { - errCode := "M_INTERNAL" - if status == http.StatusNotFound { - log.Debug().Msg("contact not found") - errCode = "M_NOT_FOUND" - } else { - log.Err(err).Msg("error looking up contact") - } - legacyprovision.JSONResponse(w, status, legacyprovision.Error{ - Success: false, - Error: err.Error(), - ErrCode: errCode, - }) - return - } - legacyprovision.JSONResponse(w, status, legacyprovision.Response{ - Success: true, - Status: "ok", - ResolveIdentifierResponse: resp, - }) -} - -func (prov *ProvisioningAPI) StartPM(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - phoneNum := mux.Vars(r)["phonenum"] - - log := prov.log.With(). - Str("action", "start_pm"). - Stringer("user_id", user.MXID). - Str("phone_num", phoneNum). - Logger() - ctx := log.WithContext(r.Context()) - log.Debug().Msg("starting private message") - - status, resp, err := prov.resolveIdentifier(ctx, user, phoneNum) - if err != nil { - errCode := "M_INTERNAL" - if status == http.StatusNotFound { - log.Debug().Msg("contact not found") - errCode = "M_NOT_FOUND" - } else { - log.Err(err).Msg("error looking up contact") - } - legacyprovision.JSONResponse(w, status, legacyprovision.Error{ - Success: false, - Error: err.Error(), - ErrCode: errCode, - }) - return - } - - portal := user.GetPortalByChatID(resp.ChatID.UUID) - if portal.MXID == "" { - if err := portal.CreateMatrixRoom(r.Context(), user, 0); err != nil { - log.Err(err).Msg("error looking up contact") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: "Error creating Matrix room", - ErrCode: "M_INTERNAL", - }) - return - } - resp.JustCreated = true - resp.RoomID = portal.MXID - } - if resp.JustCreated { - status = http.StatusCreated - } - - legacyprovision.JSONResponse(w, status, legacyprovision.Response{ - Success: true, - Status: "ok", - ResolveIdentifierResponse: resp, - }) -} - -func (prov *ProvisioningAPI) mutexForUser(user *User) *sync.Mutex { - if _, ok := prov.provisioningMutexes[user.MXID.String()]; !ok { - prov.provisioningMutexes[user.MXID.String()] = &sync.Mutex{} - } - return prov.provisioningMutexes[user.MXID.String()] -} - -func (prov *ProvisioningAPI) newOrExistingSession(user *User) (newSessionLoggedIn bool, handle *provisioningHandle, err error) { - prov.mutexForUser(user).Lock() - defer prov.mutexForUser(user).Unlock() - - if existingSessionID, ok := prov.provisioningUsers[user.MXID.String()]; ok { - provisioningHandle := prov.provisioningHandles[existingSessionID] - return false, provisioningHandle, nil - } - - provChan, err := user.Login() - if err != nil { - return false, nil, fmt.Errorf("Error logging in: %w", err) - } - provisioningCtx, cancel := context.WithCancel(context.TODO()) - handle = &provisioningHandle{ - context: provisioningCtx, - cancel: cancel, - channel: provChan, - } - prov.provisioningHandles = append(prov.provisioningHandles, handle) - handle.id = len(prov.provisioningHandles) - 1 - prov.provisioningUsers[user.MXID.String()] = handle.id - return true, handle, nil -} - -func (prov *ProvisioningAPI) existingSession(user *User) (handle *provisioningHandle) { - prov.mutexForUser(user).Lock() - defer prov.mutexForUser(user).Unlock() - - if existingSessionID, ok := prov.provisioningUsers[user.MXID.String()]; ok { - provisioningHandle := prov.provisioningHandles[existingSessionID] - return provisioningHandle - } - return nil -} - -func (prov *ProvisioningAPI) clearSession(ctx context.Context, user *User) { - log := zerolog.Ctx(ctx).With().Str("function", "clearSession").Logger() - prov.mutexForUser(user).Lock() - defer prov.mutexForUser(user).Unlock() - - if existingSessionID, ok := prov.provisioningUsers[user.MXID.String()]; ok { - log.Debug().Int("existing_session_id", existingSessionID).Msg("clearing existing session") - if existingSessionID >= len(prov.provisioningHandles) { - log.Warn().Msg("session does not exist") - return - } - if prov.provisioningHandles[existingSessionID].cancel != nil { - prov.provisioningHandles[existingSessionID].cancel() - } - prov.provisioningHandles[existingSessionID] = nil - delete(prov.provisioningUsers, user.MXID.String()) - } else { - prov.log.Debug().Msg("no session found") - } -} - -func (prov *ProvisioningAPI) loginOrSendError(ctx context.Context, w http.ResponseWriter, user *User) (*provisioningHandle, error) { - newSessionLoggedIn, handle, err := prov.newOrExistingSession(user) - if err != nil { - return nil, err - } - if !newSessionLoggedIn { - zerolog.Ctx(ctx).Debug(). - Int("existing_provisioning_handle", handle.id). - Msg("user already has pending provisioning request, cancelling") - prov.clearSession(ctx, user) - _, handle, err = prov.newOrExistingSession(user) - if err != nil { - return nil, fmt.Errorf("error logging in after cancelling existing session: %w", err) - } - } - return handle, nil -} - -func (prov *ProvisioningAPI) checkSessionAndReturnHandle(ctx context.Context, w http.ResponseWriter, currentSession int) *provisioningHandle { - log := zerolog.Ctx(ctx).With().Str("function", "checkSessionAndReturnHandle").Logger() - user := ctx.Value(provisioningUserKey).(*User) - handle := prov.existingSession(user) - if handle == nil { - log.Warn().Msg("no session found") - legacyprovision.JSONResponse(w, http.StatusNotFound, legacyprovision.Error{ - Success: false, - Error: "No session found", - ErrCode: "M_NOT_FOUND", - }) - return nil - } - if handle.id != currentSession { - log.Warn(). - Int("handle_id", handle.id). - Int("current_session", currentSession). - Msg("session_id does not match user's session_id") - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: "session_id does not match user's session_id", - ErrCode: "M_BAD_JSON", - }) - return nil - } - return handle -} - -func (prov *ProvisioningAPI) WhoAmI(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - log := prov.log.With(). - Str("action", "whoami"). - Stringer("user_id", user.MXID). - Logger() - log.Debug().Msg("getting whoami") - - data := legacyprovision.WhoAmIResponse{ - Permissions: int(user.PermissionLevel), - MXID: user.MXID.String(), - } - if user.IsLoggedIn() { - data.Signal = &legacyprovision.WhoAmIResponseSignal{ - Number: user.SignalUsername, - UUID: user.SignalID.String(), - Ok: user.Client.IsConnected(), - } - puppet := user.bridge.GetPuppetBySignalID(user.SignalID) - if puppet != nil { - data.Signal.Name = puppet.Name - } - } - legacyprovision.JSONResponse(w, http.StatusOK, data) -} - -func (prov *ProvisioningAPI) LinkNew(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - log := prov.log.With(). - Str("action", "link_new"). - Stringer("user_id", user.MXID). - Logger() - ctx := log.WithContext(r.Context()) - log.Debug().Msg("starting login") - - handle, err := prov.loginOrSendError(ctx, w, user) - if err != nil { - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: err.Error(), - ErrCode: "M_INTERNAL", - }) - return - } - - log = log.With().Int("session_id", handle.id).Logger() - log.Debug().Msg("waiting for provisioning response") - - select { - case resp := <-handle.channel: - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - log.Err(resp.Err).Msg("Error getting provisioning URL") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: resp.Err.Error(), - ErrCode: "M_INTERNAL", - }) - return - } - if resp.State != signalmeow.StateProvisioningURLReceived { - log.Err(resp.Err).Stringer("state", resp.State).Msg("unexpected state") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: fmt.Sprintf("Unexpected state %s", resp.State.String()), - ErrCode: "M_INTERNAL", - }) - return - } - - log.Debug().Str("provisioning_url", resp.ProvisioningURL).Msg("provisioning URL received") - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ - Success: true, - Status: "provisioning_url_received", - SessionID: fmt.Sprintf("%d", handle.id), - URI: resp.ProvisioningURL, - }) - case <-time.After(30 * time.Second): - log.Warn().Msg("Timeout waiting for provisioning response (new)") - legacyprovision.JSONResponse(w, http.StatusGatewayTimeout, legacyprovision.Error{ - Success: false, - Error: "Timeout waiting for provisioning response (new)", - ErrCode: "M_TIMEOUT", - }) - } -} - -func (prov *ProvisioningAPI) LinkWaitForScan(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - - var body legacyprovision.LinkWaitForScanRequest - err := json.NewDecoder(r.Body).Decode(&body) - if err != nil { - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: "Error decoding JSON body", - ErrCode: "M_BAD_JSON", - }) - return - } - sessionID, err := strconv.Atoi(body.SessionID) - if err != nil { - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: "Error decoding session ID in JSON body", - ErrCode: "M_BAD_JSON", - }) - return - } - - log := prov.log.With(). - Str("action", "link_wait_for_scan"). - Stringer("user_id", user.MXID). - Str("session_id", body.SessionID). - Logger() - ctx := log.WithContext(r.Context()) - log.Debug().Msg("waiting for scan") - - handle := prov.checkSessionAndReturnHandle(ctx, w, sessionID) - if handle == nil { - return - } - - select { - case resp := <-handle.channel: - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - log.Err(resp.Err).Msg("Error waiting for scan") - // If context was cancelled be chill - if errors.Is(resp.Err, context.Canceled) { - log.Debug().Msg("Context cancelled waiting for scan") - return - } - // If we error waiting for the scan, treat it as a normal error not 5xx - // so that the client will retry quietly. Also, it's really not an internal - // error, sitting with a WS open waiting for a scan is inherently flaky. - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: resp.Err.Error(), - ErrCode: "M_INTERNAL", - }) - return - } - if resp.State != signalmeow.StateProvisioningDataReceived { - log.Err(resp.Err).Stringer("state", resp.State).Msg("unexpected state") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: fmt.Sprintf("Unexpected state %s", resp.State.String()), - ErrCode: "M_INTERNAL", - }) - return - } - log.Debug().Msg("provisioning data received") - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ - Success: true, - Status: "provisioning_data_received", - }) - - // Update user with SignalID - if resp.ProvisioningData.ACI != uuid.Nil { - user.saveSignalID(ctx, resp.ProvisioningData.ACI, resp.ProvisioningData.Number) - } - return - case <-time.After(45 * time.Second): - log.Warn().Msg("Timeout waiting for provisioning response (scan)") - // Using 400 here to match the old bridge - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: "Timeout waiting for QR code scan", - ErrCode: "M_BAD_REQUEST", - }) - return - } -} - -func (prov *ProvisioningAPI) LinkWaitForAccount(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - - var body legacyprovision.LinkWaitForAccountRequest - err := json.NewDecoder(r.Body).Decode(&body) - if err != nil { - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: "Error decoding JSON body", - ErrCode: "M_BAD_JSON", - }) - return - } - sessionID, err := strconv.Atoi(body.SessionID) - if err != nil { - legacyprovision.JSONResponse(w, http.StatusBadRequest, legacyprovision.Error{ - Success: false, - Error: "Error decoding session ID in JSON body", - ErrCode: "M_BAD_JSON", - }) - return - } - deviceName := body.DeviceName - - log := prov.log.With(). - Str("action", "link_wait_for_account"). - Stringer("user_id", user.MXID). - Int("session_id", sessionID). - Str("device_name", deviceName). - Logger() - ctx := log.WithContext(r.Context()) - log.Debug().Msg("waiting for account") - - handle := prov.checkSessionAndReturnHandle(ctx, w, sessionID) - if handle == nil { - return - } - - select { - case resp := <-handle.channel: - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { - log.Err(resp.Err).Msg("Error waiting for account") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: resp.Err.Error(), - ErrCode: "M_INTERNAL", - }) - return - } - if resp.State != signalmeow.StateProvisioningPreKeysRegistered { - log.Err(resp.Err).Stringer("state", resp.State).Msg("unexpected state") - legacyprovision.JSONResponse(w, http.StatusInternalServerError, legacyprovision.Error{ - Success: false, - Error: fmt.Sprintf("Unexpected state %s", resp.State.String()), - ErrCode: "M_INTERNAL", - }) - return - } - - log.Debug().Msg("prekeys registered") - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ - Success: true, - Status: "prekeys_registered", - UUID: user.SignalID.String(), - Number: user.SignalUsername, - }) - - // Connect to Signal!! - user.Connect() - return - case <-time.After(30 * time.Second): - log.Warn().Msg("Timeout waiting for provisioning response (account)") - legacyprovision.JSONResponse(w, http.StatusGatewayTimeout, legacyprovision.Error{ - Success: false, - Error: "Timeout waiting for provisioning response (account)", - ErrCode: "M_TIMEOUT", - }) - return - } -} - -func (prov *ProvisioningAPI) Logout(w http.ResponseWriter, r *http.Request) { - user := r.Context().Value(provisioningUserKey).(*User) - log := prov.log.With(). - Str("action", "logout"). - Stringer("user_id", user.MXID). - Logger() - ctx := log.WithContext(r.Context()) - log.Debug().Msg("Logout called (but not logging out)") - - prov.clearSession(ctx, user) - - // For now do nothing - we need this API to return 200 to be compatible with - // the old Signal bridge, which needed a call to Logout before allowing LinkNew - // to be called, but we don't actually want to logout, we want to allow a reconnect. - legacyprovision.JSONResponse(w, http.StatusOK, legacyprovision.Response{ - Success: true, - Status: "logged_out", - }) -} diff --git a/puppet.go b/puppet.go deleted file mode 100644 index 857312e..0000000 --- a/puppet.go +++ /dev/null @@ -1,411 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "net/http" - "regexp" - - "github.com/google/uuid" - "github.com/rs/zerolog" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/appservice" - "maunium.net/go/mautrix/bridge" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/database" - "go.mau.fi/mautrix-signal/pkg/signalmeow/types" -) - -func (br *SignalBridge) GetPuppetByMXID(mxid id.UserID) *Puppet { - signalID, ok := br.ParsePuppetMXID(mxid) - if !ok { - return nil - } - - return br.GetPuppetBySignalID(signalID) -} - -func (br *SignalBridge) GetPuppetBySignalIDString(id string) *Puppet { - parsed, err := uuid.Parse(id) - if err != nil { - return nil - } - return br.GetPuppetBySignalID(parsed) -} - -func (br *SignalBridge) GetPuppetBySignalID(id uuid.UUID) *Puppet { - if id == uuid.Nil { - br.ZLog.Warn().Msg("Trying to get puppet with empty signal_user_id") - return nil - } - - br.puppetsLock.Lock() - defer br.puppetsLock.Unlock() - - puppet, ok := br.puppets[id] - if !ok { - dbPuppet, err := br.DB.Puppet.GetBySignalID(context.TODO(), id) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get puppet from database") - return nil - } - return br.loadPuppet(context.TODO(), dbPuppet, &id) - } - return puppet -} - -func (br *SignalBridge) GetPuppetByCustomMXID(mxid id.UserID) *Puppet { - br.puppetsLock.Lock() - defer br.puppetsLock.Unlock() - - puppet, ok := br.puppetsByCustomMXID[mxid] - if !ok { - dbPuppet, err := br.DB.Puppet.GetByCustomMXID(context.TODO(), mxid) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get puppet from database") - return nil - } - return br.loadPuppet(context.TODO(), dbPuppet, nil) - } - return puppet -} - -func (br *SignalBridge) GetAllPuppetsWithCustomMXID() []*Puppet { - puppets, err := br.DB.Puppet.GetAllWithCustomMXID(context.TODO()) - if err != nil { - br.ZLog.Error().Err(err).Msg("Failed to get all puppets with custom MXID") - return nil - } - return br.dbPuppetsToPuppets(puppets) -} - -func (br *SignalBridge) FormatPuppetMXID(u uuid.UUID) id.UserID { - return id.NewUserID( - br.Config.Bridge.FormatUsername(u.String()), - br.Config.Homeserver.Domain, - ) -} - -func (br *SignalBridge) loadPuppet(ctx context.Context, dbPuppet *database.Puppet, u *uuid.UUID) *Puppet { - if dbPuppet == nil { - if u == nil { - return nil - } - dbPuppet = br.DB.Puppet.New() - dbPuppet.SignalID = *u - err := dbPuppet.Insert(ctx) - if err != nil { - br.ZLog.Error().Err(err).Stringer("signal_user_id", *u).Msg("Failed to insert new puppet") - return nil - } - } - - puppet := br.NewPuppet(dbPuppet) - br.puppets[puppet.SignalID] = puppet - if puppet.CustomMXID != "" { - br.puppetsByCustomMXID[puppet.CustomMXID] = puppet - } - return puppet -} - -func (br *SignalBridge) dbPuppetsToPuppets(dbPuppets []*database.Puppet) []*Puppet { - br.puppetsLock.Lock() - defer br.puppetsLock.Unlock() - - output := make([]*Puppet, len(dbPuppets)) - for index, dbPuppet := range dbPuppets { - if dbPuppet == nil { - continue - } - puppet, ok := br.puppets[dbPuppet.SignalID] - if !ok { - puppet = br.loadPuppet(context.TODO(), dbPuppet, nil) - } - output[index] = puppet - } - return output -} - -func (br *SignalBridge) NewPuppet(dbPuppet *database.Puppet) *Puppet { - return &Puppet{ - Puppet: dbPuppet, - bridge: br, - log: br.ZLog.With().Stringer("signal_user_id", dbPuppet.SignalID).Logger(), - - MXID: br.FormatPuppetMXID(dbPuppet.SignalID), - } -} - -func (br *SignalBridge) ParsePuppetMXID(mxid id.UserID) (uuid.UUID, bool) { - if userIDRegex == nil { - pattern := fmt.Sprintf( - "^@%s:%s$", - // The "SignalID" portion of the MXID is a (lowercase) UUID - br.Config.Bridge.FormatUsername("([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"), - br.Config.Homeserver.Domain, - ) - br.ZLog.Debug().Str("pattern", pattern).Msg("Compiling userIDRegex") - - userIDRegex = regexp.MustCompile(pattern) - } - - match := userIDRegex.FindStringSubmatch(string(mxid)) - if len(match) == 2 { - parsed, err := uuid.Parse(match[1]) - if err != nil { - return uuid.Nil, false - } - return parsed, true - } - - return uuid.Nil, false -} - -type Puppet struct { - *database.Puppet - - bridge *SignalBridge - log zerolog.Logger - - MXID id.UserID - - customIntent *appservice.IntentAPI - customUser *User -} - -var userIDRegex *regexp.Regexp - -var ( - _ bridge.Ghost = (*Puppet)(nil) - _ bridge.GhostWithProfile = (*Puppet)(nil) -) - -func (puppet *Puppet) GetMXID() id.UserID { - return puppet.MXID -} - -func (puppet *Puppet) DefaultIntent() *appservice.IntentAPI { - return puppet.bridge.AS.Intent(puppet.MXID) -} - -func (puppet *Puppet) CustomIntent() *appservice.IntentAPI { - if puppet == nil { - return nil - } - return puppet.customIntent -} - -func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI { - if puppet != nil { - if puppet.customIntent == nil || portal.UserID().UUID == puppet.SignalID { - return puppet.DefaultIntent() - } - return puppet.customIntent - } - return nil -} - -func (puppet *Puppet) GetDisplayname() string { - return puppet.Name -} - -func (puppet *Puppet) GetAvatarURL() id.ContentURI { - return puppet.AvatarURL -} - -func (puppet *Puppet) UpdateInfo(ctx context.Context, source *User, contactAvatar *types.ContactAvatar) { - log := zerolog.Ctx(ctx).With(). - Str("function", "Puppet.UpdateInfo"). - Stringer("signal_user_id", puppet.SignalID). - Logger() - ctx = log.WithContext(ctx) - var err error - log.Debug().Msg("Fetching contact info to update puppet") - info, err := source.Client.ContactByACI(ctx, puppet.SignalID) - if err != nil { - log.Err(err).Msg("Failed to fetch contact info") - return - } - if !puppet.bridge.Config.Bridge.UseOutdatedProfiles && puppet.ProfileFetchedAt.After(info.Profile.FetchedAt) { - log.Debug(). - Time("contact_profile_fetched_at", info.Profile.FetchedAt). - Time("puppet_profile_fetched_at", puppet.ProfileFetchedAt). - Msg("Ignoring outdated contact info") - return - } - if contactAvatar != nil { - info.ContactAvatar = *contactAvatar - } - - log.Trace().Msg("Updating puppet info") - - update := false - if puppet.ProfileFetchedAt.IsZero() && !info.Profile.FetchedAt.IsZero() { - update = true - } - puppet.ProfileFetchedAt = info.Profile.FetchedAt - if info.E164 != "" && puppet.Number != info.E164 { - puppet.Number = info.E164 - update = true - } - update = puppet.updateName(ctx, info) || update - update = puppet.updateAvatar(ctx, source, info) || update - if update { - puppet.ContactInfoSet = false - puppet.UpdateContactInfo(ctx) - err = puppet.Update(ctx) - if err != nil { - log.Err(err).Msg("Failed to save puppet to database after updating") - } - go puppet.updatePortalMeta(ctx) - log.Debug().Msg("Puppet info updated") - } -} -func (puppet *Puppet) UpdateContactInfo(ctx context.Context) { - if !puppet.bridge.SpecVersions.Supports(mautrix.BeeperFeatureArbitraryProfileMeta) || puppet.ContactInfoSet { - return - } - - identifiers := []string{ - fmt.Sprintf("signal:%s", puppet.SignalID), - } - if puppet.Number != "" { - identifiers = append(identifiers, fmt.Sprintf("tel:%s", puppet.Number)) - } - contactInfo := map[string]any{ - "com.beeper.bridge.identifiers": identifiers, - "com.beeper.bridge.remote_id": puppet.SignalID.String(), - "com.beeper.bridge.service": "signal", - "com.beeper.bridge.network": "signal", - } - err := puppet.DefaultIntent().BeeperUpdateProfile(ctx, contactInfo) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to store custom contact info in profile") - } else { - puppet.ContactInfoSet = true - } -} - -func (puppet *Puppet) updatePortalMeta(ctx context.Context) { - for _, portal := range puppet.bridge.FindPrivateChatPortalsWith(puppet.SignalID) { - // Get room create lock to prevent races between receiving contact info and room creation. - portal.roomCreateLock.Lock() - portal.UpdateDMInfo(ctx, false) - portal.roomCreateLock.Unlock() - } -} - -func (puppet *Puppet) updateAvatar(ctx context.Context, source *User, info *types.Recipient) bool { - var avatarData []byte - var avatarContentType string - log := zerolog.Ctx(ctx) - if puppet.bridge.Config.Bridge.UseContactAvatars && info.ContactAvatar.Hash != "" { - if puppet.AvatarHash == info.ContactAvatar.Hash && puppet.AvatarSet { - return false - } - avatarData = info.ContactAvatar.Image - avatarContentType = info.ContactAvatar.ContentType - if avatarData == nil { - // TODO what to do? 🤔 - return false - } - puppet.AvatarSet = false - puppet.AvatarPath = "" - } else { - if puppet.AvatarPath == info.Profile.AvatarPath && puppet.AvatarSet { - return false - } - if info.Profile.AvatarPath == "" { - puppet.AvatarURL = id.ContentURI{} - puppet.AvatarPath = "" - puppet.AvatarHash = "" - puppet.AvatarSet = false - err := puppet.DefaultIntent().SetAvatarURL(ctx, puppet.AvatarURL) - if err != nil { - log.Err(err).Msg("Failed to remove user avatar") - return true - } - log.Debug().Msg("Avatar removed") - puppet.AvatarSet = true - return true - } - var err error - avatarData, err = source.Client.DownloadUserAvatar(ctx, info.Profile.AvatarPath, info.Profile.Key) - if err != nil { - log.Err(err). - Str("profile_avatar_path", info.Profile.AvatarPath). - Msg("Failed to download new user avatar") - return true - } - avatarContentType = http.DetectContentType(avatarData) - } - hash := sha256.Sum256(avatarData) - newHash := hex.EncodeToString(hash[:]) - if puppet.AvatarHash == newHash && puppet.AvatarSet { - log.Debug(). - Str("avatar_hash", newHash). - Str("new_avatar_path", puppet.AvatarPath). - Msg("Avatar path changed, but hash didn't") - // Path changed, but actual avatar didn't - return true - } - puppet.AvatarPath = info.Profile.AvatarPath - puppet.AvatarHash = newHash - puppet.AvatarSet = false - puppet.AvatarURL = id.ContentURI{} - resp, err := puppet.DefaultIntent().UploadBytes(ctx, avatarData, avatarContentType) - if err != nil { - log.Err(err). - Str("avatar_hash", puppet.AvatarHash). - Msg("Failed to upload new user avatar") - return true - } - puppet.AvatarURL = resp.ContentURI - err = puppet.DefaultIntent().SetAvatarURL(ctx, puppet.AvatarURL) - if err != nil { - log.Err(err).Msg("Failed to update user avatar") - return true - } - log.Debug(). - Str("avatar_hash", newHash). - Stringer("avatar_mxc", resp.ContentURI). - Msg("Avatar updated successfully") - puppet.AvatarSet = true - return true -} - -func (puppet *Puppet) updateName(ctx context.Context, contact *types.Recipient) bool { - // TODO set name quality - newName := puppet.bridge.Config.Bridge.FormatDisplayname(contact) - if puppet.NameSet && puppet.Name == newName { - return false - } - puppet.Name = newName - puppet.NameSet = false - err := puppet.DefaultIntent().SetDisplayName(ctx, newName) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update user displayname") - } else { - puppet.NameSet = true - } - return true -} diff --git a/user.go b/user.go deleted file mode 100644 index dc16f98..0000000 --- a/user.go +++ /dev/null @@ -1,1020 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Scott Weber -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - "context" - "errors" - "fmt" - "net/http" - "strings" - "sync" - "time" - - "github.com/google/uuid" - "github.com/rs/zerolog" - "golang.org/x/exp/maps" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/appservice" - "maunium.net/go/mautrix/bridge" - "maunium.net/go/mautrix/bridge/bridgeconfig" - "maunium.net/go/mautrix/bridge/status" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/database" - "go.mau.fi/mautrix-signal/pkg/libsignalgo" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - "go.mau.fi/mautrix-signal/pkg/signalmeow/events" - signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" -) - -var ( - ErrNotConnected = errors.New("not connected") - ErrNotLoggedIn = errors.New("not logged in") -) - -func (br *SignalBridge) GetUserByMXID(userID id.UserID) *User { - return br.maybeGetUserByMXID(userID, &userID) -} - -func (br *SignalBridge) GetUserByMXIDIfExists(userID id.UserID) *User { - return br.maybeGetUserByMXID(userID, nil) -} - -func (br *SignalBridge) maybeGetUserByMXID(userID id.UserID, userIDPtr *id.UserID) *User { - if userID == br.Bot.UserID || br.IsGhost(userID) { - return nil - } - br.usersLock.Lock() - defer br.usersLock.Unlock() - - user, ok := br.usersByMXID[userID] - if !ok { - dbUser, err := br.DB.User.GetByMXID(context.TODO(), userID) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get user from database") - return nil - } - return br.loadUser(context.TODO(), dbUser, userIDPtr) - } - return user -} - -func (br *SignalBridge) GetUserBySignalID(id uuid.UUID) *User { - br.usersLock.Lock() - defer br.usersLock.Unlock() - return br.unlockedGetUserBySignalID(id) -} - -func (br *SignalBridge) unlockedGetUserBySignalID(id uuid.UUID) *User { - user, ok := br.usersBySignalID[id] - if !ok { - dbUser, err := br.DB.User.GetBySignalID(context.TODO(), id) - if err != nil { - br.ZLog.Err(err).Msg("Failed to get user from database") - return nil - } - return br.loadUser(context.TODO(), dbUser, nil) - } - return user -} - -func (br *SignalBridge) GetAllLoggedInUsers() []*User { - br.usersLock.Lock() - defer br.usersLock.Unlock() - - dbUsers, err := br.DB.User.GetAllLoggedIn(context.TODO()) - if err != nil { - br.ZLog.Err(err).Msg("Error getting all logged in users") - return nil - } - users := make([]*User, len(dbUsers)) - - for idx, dbUser := range dbUsers { - user, ok := br.usersByMXID[dbUser.MXID] - if !ok { - user = br.loadUser(context.TODO(), dbUser, nil) - } - users[idx] = user - } - return users -} - -func (br *SignalBridge) loadUser(ctx context.Context, dbUser *database.User, mxid *id.UserID) *User { - if dbUser == nil { - if mxid == nil { - return nil - } - dbUser = br.DB.User.New() - dbUser.MXID = *mxid - err := dbUser.Insert(ctx) - if err != nil { - br.ZLog.Err(err).Msg("Error creating user %s") - return nil - } - } - - user := br.NewUser(dbUser) - br.usersByMXID[user.MXID] = user - if user.SignalID != uuid.Nil { - br.usersBySignalID[user.SignalID] = user - } - if user.ManagementRoom != "" { - br.managementRoomsLock.Lock() - br.managementRooms[user.ManagementRoom] = user - br.managementRoomsLock.Unlock() - } - return user -} - -func (br *SignalBridge) NewUser(dbUser *database.User) *User { - user := &User{ - User: dbUser, - bridge: br, - log: br.ZLog.With().Stringer("user_id", dbUser.MXID).Logger(), - - PermissionLevel: br.Config.Bridge.Permissions.Get(dbUser.MXID), - } - user.Admin = user.PermissionLevel >= bridgeconfig.PermissionLevelAdmin - user.BridgeState = br.NewBridgeStateQueue(user) - return user -} - -type User struct { - *database.User - - sync.Mutex - - bridge *SignalBridge - log zerolog.Logger - - Admin bool - PermissionLevel bridgeconfig.PermissionLevel - - Client *signalmeow.Client - - BridgeState *bridge.BridgeStateQueue - - spaceMembershipChecked bool - spaceCreateLock sync.Mutex -} - -var ( - _ bridge.User = (*User)(nil) - _ status.BridgeStateFiller = (*User)(nil) -) - -func (user *User) GetPermissionLevel() bridgeconfig.PermissionLevel { - return user.PermissionLevel -} - -func (user *User) IsLoggedIn() bool { - user.Lock() - defer user.Unlock() - - return user.Client != nil && user.Client.IsLoggedIn() -} - -func (user *User) GetManagementRoomID() id.RoomID { - return user.ManagementRoom -} - -func (user *User) SetManagementRoom(roomID id.RoomID) { - user.bridge.managementRoomsLock.Lock() - defer user.bridge.managementRoomsLock.Unlock() - - existing, ok := user.bridge.managementRooms[roomID] - if ok { - existing.ManagementRoom = "" - err := existing.Update(context.TODO()) - if err != nil { - existing.log.Err(err).Msg("Failed to update user when removing management room") - } - } - - user.ManagementRoom = roomID - user.bridge.managementRooms[user.ManagementRoom] = user - err := user.Update(context.TODO()) - if err != nil { - user.log.Error().Err(err).Msg("Error setting management room") - } -} - -func (user *User) GetIDoublePuppet() bridge.DoublePuppet { - p := user.bridge.GetPuppetByCustomMXID(user.MXID) - if p == nil || p.CustomIntent() == nil { - return nil - } - return p -} - -func (user *User) GetIGhost() bridge.Ghost { - p := user.bridge.GetPuppetBySignalID(user.SignalID) - if p == nil { - return nil - } - return p -} - -func (user *User) ensureInvited(ctx context.Context, intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) (ok bool) { - log := user.log.With().Str("action", "ensure_invited").Stringer("room_id", roomID).Logger() - if user.bridge.StateStore.IsMembership(ctx, roomID, user.MXID, event.MembershipJoin) { - ok = true - return - } - extraContent := make(map[string]interface{}) - if isDirect { - extraContent["is_direct"] = true - } - customPuppet := user.bridge.GetPuppetByCustomMXID(user.MXID) - if customPuppet != nil && customPuppet.CustomIntent() != nil { - extraContent["fi.mau.will_auto_accept"] = true - } - _, err := intent.InviteUser(ctx, roomID, &mautrix.ReqInviteUser{UserID: user.MXID}, extraContent) - var httpErr mautrix.HTTPError - if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") { - err = user.bridge.StateStore.SetMembership(ctx, roomID, user.MXID, event.MembershipJoin) - if err != nil { - log.Warn().Err(err).Msg("Failed to update membership in state store") - } - ok = true - return - } else if err != nil { - log.Warn().Err(err).Msg("Failed to invite user to room") - } else { - ok = true - } - - if customPuppet != nil && customPuppet.CustomIntent() != nil { - err = customPuppet.CustomIntent().EnsureJoined(ctx, roomID, appservice.EnsureJoinedParams{IgnoreCache: true}) - if err != nil { - log.Warn().Err(err).Msg("Failed to auto-join custom puppet") - ok = false - } else { - ok = true - } - } - return -} - -func (user *User) GetSpaceRoom(ctx context.Context) id.RoomID { - if !user.bridge.Config.Bridge.PersonalFilteringSpaces { - return "" - } - - if len(user.SpaceRoom) == 0 { - user.spaceCreateLock.Lock() - defer user.spaceCreateLock.Unlock() - if len(user.SpaceRoom) > 0 { - return user.SpaceRoom - } - - resp, err := user.bridge.Bot.CreateRoom(ctx, &mautrix.ReqCreateRoom{ - Visibility: "private", - Name: "Signal", - Topic: "Your Signal bridged chats", - InitialState: []*event.Event{{ - Type: event.StateRoomAvatar, - Content: event.Content{ - Parsed: &event.RoomAvatarEventContent{ - URL: user.bridge.Config.AppService.Bot.ParsedAvatar.CUString(), - }, - }, - }}, - CreationContent: map[string]interface{}{ - "type": event.RoomTypeSpace, - }, - PowerLevelOverride: &event.PowerLevelsEventContent{ - Users: map[id.UserID]int{ - user.bridge.Bot.UserID: 9001, - user.MXID: 50, - }, - }, - }) - - if err != nil { - user.log.Err(err).Msg("Failed to auto-create space room") - } else { - user.SpaceRoom = resp.RoomID - err = user.Update(context.TODO()) - if err != nil { - user.log.Err(err).Msg("Failed to save user in database after creating space room") - } - user.ensureInvited(ctx, user.bridge.Bot, user.SpaceRoom, false) - } - } else if !user.spaceMembershipChecked { - user.ensureInvited(ctx, user.bridge.Bot, user.SpaceRoom, false) - } - user.spaceMembershipChecked = true - - return user.SpaceRoom -} - -func (user *User) syncChatDoublePuppetDetails(portal *Portal, justCreated bool) { - doublePuppet := portal.bridge.GetPuppetByCustomMXID(user.MXID) - if doublePuppet == nil { - return - } - if doublePuppet == nil || doublePuppet.CustomIntent() == nil || len(portal.MXID) == 0 { - return - } - - // TODO: Get chat setting from Signal and sync them here - //if justCreated || !user.bridge.Config.Bridge.TagOnlyOnCreate { - // chat, err := user.Client.Store.ChatSettings.GetChatSettings(portal.Key().ChatID) - // if err != nil { - // user.log.Warn().Err(err).Msgf("Failed to get settings of %s", portal.Key().ChatID) - // return - // } - // intent := doublePuppet.CustomIntent() - // if portal.Key.JID == types.StatusBroadcastJID && justCreated { - // if user.bridge.Config.Bridge.MuteStatusBroadcast { - // user.updateChatMute(intent, portal, time.Now().Add(365*24*time.Hour)) - // } - // if len(user.bridge.Config.Bridge.StatusBroadcastTag) > 0 { - // user.updateChatTag(intent, portal, user.bridge.Config.Bridge.StatusBroadcastTag, true) - // } - // return - // } else if !chat.Found { - // return - // } - // user.updateChatMute(intent, portal, chat.MutedUntil) - // user.updateChatTag(intent, portal, user.bridge.Config.Bridge.ArchiveTag, chat.Archived) - // user.updateChatTag(intent, portal, user.bridge.Config.Bridge.PinnedTag, chat.Pinned) - //} -} - -func (user *User) GetMXID() id.UserID { - return user.MXID -} -func (user *User) GetRemoteID() string { - return user.SignalID.String() -} -func (user *User) GetRemoteName() string { - return user.SignalUsername -} - -func (user *User) startupTryConnect(retryCount int) { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) - - // Make sure user has the Signal device populated - user.populateSignalDevice() - - user.log.Debug().Msg("Connecting to Signal") - ctx := user.log.WithContext(context.Background()) - statusChan, err := user.Client.StartReceiveLoops(ctx) - - if err != nil { - user.log.Error().Err(err).Msg("Error connecting on startup") - if errors.Is(err, ErrNotLoggedIn) { - user.log.Warn().Msg("Not logged in, clearing Signal device keys") - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - user.clearKeysAndDisconnect() - } else if retryCount < 6 { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) - retryInSeconds := 2 << retryCount - user.log.Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") - time.Sleep(time.Duration(retryInSeconds) * time.Second) - user.startupTryConnect(retryCount + 1) - } else { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) - } - } - - if statusChan == nil { - user.log.Error().Msg("statusChan is nil after Connect") - return - } - // After Connect returns, all bridge states are triggered by events on the statusChan - go func() { - var peekedConnectionStatus signalmeow.SignalConnectionStatus - for { - var connectionStatus signalmeow.SignalConnectionStatus - if peekedConnectionStatus.Event != signalmeow.SignalConnectionEventNone { - user.log.Debug(). - Stringer("peeked_connection_status_event", peekedConnectionStatus.Event). - Msg("Using peeked connectionStatus event") - connectionStatus = peekedConnectionStatus - peekedConnectionStatus = signalmeow.SignalConnectionStatus{} - } else { - var ok bool - connectionStatus, ok = <-statusChan - if !ok { - user.log.Debug().Msg("statusChan channel closed") - return - } - } - - err := connectionStatus.Err - switch connectionStatus.Event { - case signalmeow.SignalConnectionEventConnected: - user.log.Debug().Msg("Sending Connected BridgeState") - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) - user.bridge.Metrics.TrackConnectionState(user.SignalID, true) - user.bridge.Metrics.TrackLoginState(user.SignalID, true) - - case signalmeow.SignalConnectionEventDisconnected: - user.log.Debug().Msg("Received SignalConnectionEventDisconnected") - - // Debounce: wait 7s before sending TransientDisconnect, in case we get a reconnect - // We should wait until the next message comes in, or 7 seconds has passed. - // - If a disconnected event comes in, just loop again, unless it's been more than 7 seconds. - // - If a non-disconnected event comes in, store it in peekedConnectionStatus, - // break out of this loop and go back to the top of the goroutine to handle it in the switch. - // - If 7 seconds passes without any non-disconnect messages, send the TransientDisconnect. - // (Why 7 seconds? It was 5 at first, but websockets min retry is 5 seconds, - // so it would send TransientDisconnect right before reconnecting. 7 seems to work well.) - debounceTimer := time.NewTimer(7 * time.Second) - PeekLoop: - for { - var ok bool - select { - case peekedConnectionStatus, ok = <-statusChan: - // Handle channel closing - if !ok { - user.log.Debug().Msg("connectionStatus channel closed") - return - } - // If it's another Disconnected event, just keep looping - if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected { - peekedConnectionStatus = signalmeow.SignalConnectionStatus{} - continue - } - // If it's a non-disconnect event, break out of the PeekLoop and handle it in the switch - break PeekLoop - case <-debounceTimer.C: - // Time is up, so break out of the loop and send the TransientDisconnect - break PeekLoop - } - } - // We're out of the PeekLoop, so either we got a non-disconnect event, or it's been 7 seconds (or both). - // We want to send TransientDisconnect if it's been 7 seconds, but not if the latest event was something - // other than Disconnected - if !debounceTimer.Stop() { // If the timer has already expired - // Send TransientDisconnect only if the latest event is a disconnect or no event - // (peekedConnectionStatus could be something else if the timer and the event race) - if peekedConnectionStatus.Event == signalmeow.SignalConnectionEventDisconnected || - peekedConnectionStatus.Event == signalmeow.SignalConnectionEventNone { - user.log.Debug().Msg("Sending TransientDisconnect BridgeState") - if err == nil { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect}) - } else { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) - } - user.bridge.Metrics.TrackConnectionState(user.SignalID, false) - } - } - - case signalmeow.SignalConnectionEventLoggedOut: - user.log.Debug().Msg("Sending BadCredentials BridgeState") - if err == nil { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - } else { - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: err.Error()}) - } - user.bridge.Metrics.TrackConnectionState(user.SignalID, false) - user.bridge.Metrics.TrackLoginState(user.SignalID, false) - user.clearKeysAndDisconnect() - if managementRoom := user.GetManagementRoomID(); managementRoom != "" { - _, _ = user.bridge.Bot.SendText(ctx, managementRoom, "You've been logged out of Signal") - } - - case signalmeow.SignalConnectionEventError: - user.log.Debug().Msg("Sending UnknownError BridgeState") - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) - user.bridge.Metrics.TrackConnectionState(user.SignalID, false) - - case signalmeow.SignalConnectionCleanShutdown: - if user.Client.IsLoggedIn() { - user.log.Debug().Msg("Clean Shutdown - sending no BridgeState") - } else { - user.log.Debug().Msg("Clean Shutdown, but logged out - Sending BadCredentials BridgeState") - user.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - } - user.bridge.Metrics.TrackConnectionState(user.SignalID, false) - } - } - }() -} - -func (user *User) clearKeysAndDisconnect() { - // We need to clear out keys associated with the Signal device that no longer has valid credentials - user.log.Debug().Msg("Clearing out Signal device keys") - err := user.Client.ClearKeysAndDisconnect(context.TODO()) - if err != nil { - user.log.Err(err).Msg("Error clearing device keys") - } -} - -func (br *SignalBridge) StartUsers() { - br.ZLog.Debug().Msg("Starting users") - - usersWithToken := br.GetAllLoggedInUsers() - for _, u := range usersWithToken { - device := u.populateSignalDevice() - if device == nil || !device.IsLoggedIn() { - br.ZLog.Warn().Stringer("user_id", u.MXID).Msg("No device found for user, skipping Connect and sending BadCredentials BridgeState") - u.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) - continue - } - go u.Connect() - } - if len(usersWithToken) == 0 { - br.SendGlobalBridgeState(status.BridgeState{StateEvent: status.StateUnconfigured}.Fill(nil)) - } - - br.ZLog.Debug().Msg("Starting custom puppets") - for _, customPuppet := range br.GetAllPuppetsWithCustomMXID() { - go func(puppet *Puppet) { - br.ZLog.Debug().Stringer("user_id", puppet.CustomMXID).Msg("Starting custom puppet") - - if err := puppet.StartCustomMXID(true); err != nil { - puppet.log.Error().Err(err).Msg("Failed to start custom puppet") - } - }(customPuppet) - } -} - -func (user *User) Login() (<-chan signalmeow.ProvisioningResponse, error) { - user.Lock() - defer user.Unlock() - - provChan := signalmeow.PerformProvisioning(context.TODO(), user.bridge.MeowStore, user.bridge.Config.Signal.DeviceName) - - return provChan, nil -} - -func (user *User) Connect() { - user.startupTryConnect(0) -} - -func (user *User) saveSignalID(ctx context.Context, id uuid.UUID, number string) { - user.bridge.usersLock.Lock() - defer user.bridge.usersLock.Unlock() - if user.SignalID == id && user.SignalUsername == number { - return - } - if user.SignalID != id { - existingUser := user.bridge.unlockedGetUserBySignalID(id) - if existingUser != nil { - // TODO this doesn't clear the signal store properly - // the store also only has the uuid as primary key, even though it should have uuid + device id - zerolog.Ctx(ctx).Warn(). - Stringer("previous_user", existingUser.MXID). - Stringer("signal_uuid", id). - Msg("Another user is already logged in with same UUID, logging out previous user") - existingUser.bridge.Metrics.TrackLoginState(user.SignalID, false) - _ = existingUser.Disconnect() - existingUser.SignalID = uuid.Nil - existingUser.SignalUsername = "" - err := existingUser.Update(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to clear previous user's signal UUID") - } - } - } - user.SignalID = id - user.SignalUsername = number - user.bridge.usersBySignalID[id] = user - err := user.Update(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save user's signal UUID") - } -} - -func (user *User) populateSignalDevice() *signalmeow.Client { - user.Lock() - defer user.Unlock() - log := user.log.With(). - Str("action", "populate signal device"). - Stringer("signal_id", user.SignalID). - Logger() - - if user.SignalID == uuid.Nil { - return nil - } - // TODO clear client on logout properly so that populating can skip creating if it already exists - /*else if user.Client != nil { - return user.Client - }*/ - - device, err := user.bridge.MeowStore.DeviceByACI(context.TODO(), user.SignalID) - if err != nil { - log.Err(err).Msg("Failed to get device from database") - return nil - } else if device == nil { - log.Err(ErrNotLoggedIn).Msg("No device found for user") - return nil - } - - user.Client = &signalmeow.Client{ - Store: device, - EventHandler: user.eventHandler, - } - go user.tryAutomaticDoublePuppeting() - return user.Client -} - -func (user *User) handleReceipt(evt *events.Receipt) { - log := user.log.With(). - Str("action", "handle receipt"). - Stringer("receipt_type", evt.Content.GetType()). - Stringer("sender_uuid", evt.Sender). - Logger() - ctx := log.WithContext(context.TODO()) - messages, err := user.bridge.DB.Message.GetManyBySignalID(ctx, user.SignalID, evt.Content.GetTimestamp(), user.SignalID, false) - if err != nil { - log.Err(err).Msg("Failed to get receipt target messages from database") - return - } - sender := user.bridge.GetPuppetBySignalID(evt.Sender) - missingMessageIDMap := make(map[uint64]struct{}, len(evt.Content.GetTimestamp())) - for _, msg := range evt.Content.GetTimestamp() { - missingMessageIDMap[msg] = struct{}{} - } - foundMessageIDs := make([]uint64, len(messages)) - switch evt.Content.GetType() { - case signalpb.ReceiptMessage_READ: - messageMap := make(map[string]*database.Message) - for i, msg := range messages { - foundMessageIDs[i] = msg.Timestamp - delete(missingMessageIDMap, msg.Timestamp) - // The database returns messages from newest to oldest, so only include the first message per chat - _, ok := messageMap[msg.SignalChatID] - if !ok { - messageMap[msg.SignalChatID] = msg - } - } - log.Debug(). - Uints64("found_message_ids", foundMessageIDs). - Uints64("not_found_message_ids", maps.Keys(missingMessageIDMap)). - Int("chat_count", len(messageMap)). - Msg("Received read receipt") - for _, msg := range messageMap { - portal := user.GetPortalByChatID(msg.SignalChatID) - if portal == nil { - continue - } - err = portal.SendReadReceipt(ctx, sender, msg) - if err != nil { - log.Err(err).Msg("Failed to send read receipt") - } - } - case signalpb.ReceiptMessage_DELIVERY: - messageMap := make(map[string][]*database.Message) - for i, msg := range messages { - foundMessageIDs[i] = msg.Timestamp - delete(missingMessageIDMap, msg.Timestamp) - messageMap[msg.SignalChatID] = append(messageMap[msg.SignalChatID], msg) - } - log.Debug(). - Uints64("found_message_ids", foundMessageIDs). - Uints64("not_found_message_ids", maps.Keys(missingMessageIDMap)). - Int("chat_count", len(messageMap)). - Msg("Received delivery receipt") - for _, msgs := range messageMap { - portal := user.GetPortalByChatID(msgs[0].SignalChatID) - if portal == nil { - continue - } - // There should always only be 1 part, but use the last part to be safe - portal.MarkDelivered(ctx, msgs[len(msgs)-1]) - } - } -} - -func (user *User) handleReadSelf(evt *events.ReadSelf) { - ctx := context.TODO() - messagesByChat := map[string]*database.Message{} - for _, part := range evt.Messages { - log := user.log.With(). - Str("action", "handle read self"). - Str("sender_uuid", part.GetSenderAci()). - Uint64("msg_timestamp", part.GetTimestamp()). - Logger() - ctx := log.WithContext(context.TODO()) - if senderUUID, err := uuid.Parse(part.GetSenderAci()); err != nil { - log.Err(err).Msg("Failed to parse sender UUID") - } else if msg, err := user.bridge.DB.Message.GetLastPartBySignalIDWithUnknownReceiver(ctx, senderUUID, part.GetTimestamp(), user.SignalID); err != nil { - log.Err(err).Msg("Failed to get message from database") - } else if msg == nil { - log.Warn().Msg("Message not found in database") - } else if existingMsg, ok := messagesByChat[msg.SignalChatID]; ok && existingMsg.Timestamp > msg.Timestamp { - log.Trace(). - Str("chat_id", msg.SignalChatID). - Uint64("newer_msg", existingMsg.Timestamp). - Msg("Receipt event contains a newer message, skipping this one") - } else { - log.Trace().Str("chat_id", msg.SignalChatID).Msg("Received own read receipt") - messagesByChat[msg.SignalChatID] = msg - } - } - puppet := user.bridge.GetPuppetBySignalID(user.SignalID) - for _, msg := range messagesByChat { - portal := user.GetPortalByChatID(msg.SignalChatID) - if portal == nil { - continue - } - user.log.Debug(). - Str("action", "handle read self"). - Str("chat_id", msg.SignalChatID). - Uint64("msg_timestamp", msg.Timestamp). - Stringer("msg_mxid", msg.MXID). - Msg("Bridging own read receipt") - portal.ScheduleDisappearing() - user.SetLastReadTS(ctx, portal.PortalKey, msg.Timestamp) - err := portal.SendReadReceipt(ctx, puppet, msg) - if err != nil { - user.log.Err(err).Stringer("mxid", msg.MXID).Msg("Failed to send read receipt") - } - } -} - -func (user *User) handleContactList(evt *events.ContactList) { - ctx := user.log.With().Str("action", "handle contact list").Logger().WithContext(context.TODO()) - for _, contact := range evt.Contacts { - if contact.ACI == uuid.Nil { - continue - } - puppet := user.bridge.GetPuppetBySignalID(contact.ACI) - if puppet == nil { - continue - } - puppet.UpdateInfo(ctx, user, &contact.ContactAvatar) - } -} - -func (user *User) handleACIFound(evt *events.ACIFound) { - log := user.log.With(). - Str("action", "handle aci found"). - Stringer("aci", evt.ACI.UUID). - Stringer("pni", evt.PNI.UUID). - Logger() - log.Debug().Msg("Handling ACI found event") - defer func() { - log.Debug().Msg("Finished handling ACI found event") - }() - ctx := log.WithContext(context.TODO()) - user.bridge.portalsLock.Lock() - defer user.bridge.portalsLock.Unlock() - pniPortal := user.bridge.unlockedGetPortalByChatID(database.PortalKey{ - ChatID: evt.PNI.String(), - Receiver: user.SignalID, - }, false) - if pniPortal == nil { - log.Debug().Msg("PNI portal doesn't exist, ignoring event") - return - } - pniPortal.roomCreateLock.Lock() - defer pniPortal.roomCreateLock.Unlock() - if pniPortal.MXID == "" { - log.Info().Msg("PNI portal doesn't have Matrix room, deleting row") - pniPortal.unlockedDelete() - return - } - log.UpdateContext(func(c zerolog.Context) zerolog.Context { - return c.Stringer("pni_portal_mxid", pniPortal.MXID) - }) - aciPortal := user.bridge.unlockedGetPortalByChatID(database.PortalKey{ - ChatID: evt.ACI.String(), - Receiver: user.SignalID, - }, false) - if aciPortal == nil { - log.Info().Msg("ACI portal doesn't exist, re-ID'ing PNI portal") - err := pniPortal.unlockedReID(ctx, evt.ACI.String()) - if err != nil { - log.Err(err).Msg("Failed to re-ID PNI portal") - } else { - go pniPortal.PostReIDUpdate(ctx, user) - } - return - } - aciPortal.roomCreateLock.Lock() - defer aciPortal.roomCreateLock.Unlock() - if aciPortal.MXID == "" { - log.Info().Msg("ACI portal row exists, but doesn't have a Matrix room. Deleting ACI portal row and re-ID'ing PNI portal") - aciPortal.unlockedDelete() - err := pniPortal.unlockedReID(ctx, evt.ACI.String()) - if err != nil { - log.Err(err).Msg("Failed to re-ID PNI portal") - } else { - go pniPortal.PostReIDUpdate(ctx, user) - } - } else { - log.UpdateContext(func(c zerolog.Context) zerolog.Context { - return c.Stringer("aci_portal_mxid", aciPortal.MXID) - }) - log.Info().Msg("Both ACI and PNI portal have Matrix room, tombstoning PNI portal") - pniPortal.unlockedDelete() - go func() { - _, err := pniPortal.MainIntent().SendStateEvent(ctx, pniPortal.MXID, event.StateTombstone, "", &event.TombstoneEventContent{ - Body: fmt.Sprintf("This room has been merged"), - ReplacementRoom: aciPortal.MXID, - }) - if err != nil { - log.Err(err).Msg("Failed to send tombstone to PNI portal") - } - pniPortal.Cleanup(ctx, err == nil) - }() - } -} - -func (portal *Portal) unlockedReID(ctx context.Context, newID string) error { - err := portal.Portal.ReID(ctx, newID) - if err != nil { - return err - } - delete(portal.bridge.portalsByID, portal.PortalKey) - portal.PortalKey.ChatID = newID - portal.bridge.portalsByID[portal.PortalKey] = portal - err = portal.MainIntent().EnsureJoined(ctx, portal.MXID, appservice.EnsureJoinedParams{IgnoreCache: true}) - if err != nil { - return fmt.Errorf("failed to ensure ghost is joined to portal: %w", err) - } - return nil -} - -func (user *User) eventHandler(rawEvt events.SignalEvent) { - switch evt := rawEvt.(type) { - case *events.ChatEvent: - portal := user.GetPortalByChatID(evt.Info.ChatID) - if portal != nil { - portal.signalMessages <- portalSignalMessage{user: user, evt: evt} - } else { - user.log.Warn().Str("chat_id", evt.Info.ChatID).Msg("Couldn't get portal, dropping message") - } - case *events.DecryptionError: - portal := user.GetPortalByChatID(evt.Sender.String()) - if portal == nil { - user.log.Warn().Stringer("chat_id", evt.Sender).Msg("Couldn't get portal for decryption error") - return - } - content := &event.MessageEventContent{MsgType: event.MsgNotice} - name := user.bridge.GetPuppetBySignalID(evt.Sender).Name - if name == "" { - name = "This user" - } - content.Body = fmt.Sprintf("%s sent a message that couldn't be decrypted. It may have been in this chat or a group chat. Please check your Signal app", name) - portal.sendMainIntentMessage(context.TODO(), content) - case *events.Receipt: - user.handleReceipt(evt) - case *events.ReadSelf: - user.handleReadSelf(evt) - case *events.Call: - portal := user.GetPortalByChatID(evt.Info.ChatID) - content := &event.MessageEventContent{MsgType: event.MsgNotice} - if evt.IsRinging { - content.Body = "Incoming call" - if portal.IsPrivateChat() { - content.MsgType = event.MsgText - } - } else { - content.Body = "Call ended" - } - portal.sendMainIntentMessage(context.TODO(), content) - case *events.ContactList: - user.handleContactList(evt) - case *events.ACIFound: - user.handleACIFound(evt) - default: - user.log.Warn().Type("event_type", evt).Msg("Unrecognized event type from signalmeow") - } -} - -func (user *User) GetPortalByChatID(signalID string) *Portal { - return user.bridge.GetPortalByChatID(database.PortalKey{ - ChatID: signalID, - Receiver: user.SignalID, - }) -} - -func (user *User) GetPortalByChatIDIfExists(signalID string) *Portal { - return user.bridge.GetPortalByChatIDIfExists(database.PortalKey{ - ChatID: signalID, - Receiver: user.SignalID, - }) -} - -func (user *User) disconnectNoLock() (*signalmeow.Client, error) { - if user.Client == nil { - return nil, ErrNotConnected - } - - disconnectedDevice := user.Client - err := user.Client.StopReceiveLoops() - user.Client = nil - return disconnectedDevice, err -} - -func (user *User) Disconnect() error { - user.Lock() - defer user.Unlock() - user.log.Info().Msg("Disconnecting session manually") - _, err := user.disconnectNoLock() - return err -} - -func (user *User) Logout() error { - user.Lock() - defer user.Unlock() - user.log.Info().Msg("Logging out of session") - loggedOutDevice, err := user.disconnectNoLock() - user.bridge.MeowStore.DeleteDevice(context.TODO(), &loggedOutDevice.Store.DeviceData) - user.bridge.GetPuppetByCustomMXID(user.MXID).ClearCustomMXID() - user.bridge.Metrics.TrackLoginState(user.SignalID, false) - return err -} - -func (user *User) UpdateDirectChats(ctx context.Context, chats map[id.UserID][]id.RoomID) { - if !user.bridge.Config.Bridge.SyncDirectChatList { - return - } - - puppet := user.bridge.GetPuppetByMXID(user.MXID) - if puppet == nil { - return - } - - intent := puppet.CustomIntent() - if intent == nil { - return - } - - method := http.MethodPatch - if chats == nil { - chats = user.getDirectChats() - method = http.MethodPut - } - - user.log.Debug().Msg("Updating m.direct list on homeserver") - - var err error - if user.bridge.Config.Homeserver.Software == bridgeconfig.SoftwareAsmux { - urlPath := intent.BuildURL(mautrix.ClientURLPath{"unstable", "com.beeper.asmux", "dms"}) - _, err = intent.MakeFullRequest(ctx, mautrix.FullRequest{ - Method: method, - URL: urlPath, - Headers: http.Header{"X-Asmux-Auth": {user.bridge.AS.Registration.AppToken}}, - RequestJSON: chats, - }) - } else { - existingChats := map[id.UserID][]id.RoomID{} - - err = intent.GetAccountData(ctx, event.AccountDataDirectChats.Type, &existingChats) - if err != nil { - user.log.Warn().Err(err).Msg("Failed to get m.direct event to update it") - return - } - - for userID, rooms := range existingChats { - if _, ok := user.bridge.ParsePuppetMXID(userID); !ok { - // This is not a ghost user, include it in the new list - chats[userID] = rooms - } else if _, ok := chats[userID]; !ok && method == http.MethodPatch { - // This is a ghost user, but we're not replacing the whole list, so include it too - chats[userID] = rooms - } - } - - err = intent.SetAccountData(ctx, event.AccountDataDirectChats.Type, &chats) - } - - if err != nil { - user.log.Warn().Err(err).Msg("Failed to update m.direct event") - } -} - -func (user *User) getDirectChats() map[id.UserID][]id.RoomID { - chats := map[id.UserID][]id.RoomID{} - - privateChats, err := user.bridge.DB.Portal.FindPrivateChatsOf(context.TODO(), user.SignalID) - if err != nil { - user.log.Err(err).Msg("Failed to get private chats") - return chats - } - for _, portal := range privateChats { - portalUserID := portal.UserID() - if portal.MXID != "" && portalUserID.Type == libsignalgo.ServiceIDTypeACI { - puppetMXID := user.bridge.FormatPuppetMXID(portalUserID.UUID) - - chats[puppetMXID] = []id.RoomID{portal.MXID} - } - } - - return chats -} From ca53ff0e6310a5f48785e7b55722e1f6c291050b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Aug 2024 02:22:41 +0300 Subject: [PATCH 266/718] ci: remove v2 prefix --- .gitlab-ci.yml | 5 ++--- Dockerfile | 14 +++++++------- Dockerfile.v2.ci => Dockerfile.ci | 0 build-v2.sh => build.sh | 0 4 files changed, 9 insertions(+), 10 deletions(-) rename Dockerfile.v2.ci => Dockerfile.ci (100%) rename build-v2.sh => build.sh (100%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 952dabc..6420bf8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,12 +1,11 @@ include: - project: 'mautrix/ci' - file: '/gov2.yml' + file: '/gov2-as-default.yml' variables: BUILDER_IMAGE: dock.mau.dev/tulir/gomuks-build-docker/signal - BINARY_NAME_V2: mautrix-signal # 32-bit arm builds aren't supported -build arm v2: +build arm: rules: - when: never diff --git a/Dockerfile b/Dockerfile index de716c5..16c7d5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ ARG DBG=0 RUN ./build-rust.sh # -- Build mautrix-signal (with Go) -- -FROM golang:1-alpine3.19 AS go-builder +FROM golang:1-alpine3.20 AS go-builder RUN apk add --no-cache git ca-certificates build-base olm-dev WORKDIR /build @@ -20,9 +20,10 @@ COPY *.go go.* *.yaml *.sh ./ COPY pkg/signalmeow/. pkg/signalmeow/. COPY pkg/libsignalgo/* pkg/libsignalgo/ COPY pkg/libsignalgo/resources/. pkg/libsignalgo/resources/. -COPY config/. config/. -COPY database/. database/. -COPY msgconv/. msgconv/. +COPY pkg/msgconv/. pkg/msgconv/. +COPY pkg/signalid/. pkg/signalid/. +COPY pkg/connector/. pkg/connector/. +COPY cmd/. cmd/. COPY .git .git ARG DBG=0 @@ -38,15 +39,14 @@ EOF RUN ./build-go.sh # -- Run mautrix-signal -- -FROM alpine:3.19 +FROM alpine:3.20 ENV UID=1337 \ GID=1337 -RUN apk add --no-cache ffmpeg su-exec ca-certificates bash jq curl yq olm +RUN apk add --no-cache ffmpeg su-exec ca-certificates bash jq curl yq-go olm COPY --from=go-builder /build/mautrix-signal /usr/bin/mautrix-signal -COPY --from=go-builder /build/example-config.yaml /opt/mautrix-signal/example-config.yaml COPY --from=go-builder /build/docker-run.sh /docker-run.sh COPY --from=go-builder /go/bin/dlv /usr/bin/dlv VOLUME /data diff --git a/Dockerfile.v2.ci b/Dockerfile.ci similarity index 100% rename from Dockerfile.v2.ci rename to Dockerfile.ci diff --git a/build-v2.sh b/build.sh similarity index 100% rename from build-v2.sh rename to build.sh From b21e6575778201725888e175781964ea215d19ad Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Aug 2024 16:29:39 +0300 Subject: [PATCH 267/718] ci: fix executable name in Dockerfile.ci --- Dockerfile.ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.ci b/Dockerfile.ci index 0ff0c8c..e98ad03 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -5,7 +5,7 @@ ENV UID=1337 \ RUN apk add --no-cache ffmpeg su-exec ca-certificates bash jq curl yq-go -ARG EXECUTABLE=./mautrix-signal-v2 +ARG EXECUTABLE=./mautrix-signal COPY $EXECUTABLE /usr/bin/mautrix-signal COPY ./docker-run.sh /docker-run.sh ENV BRIDGEV2=1 From 9a1d3853c8d11bf58972feb737ce5852e7af4c31 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Aug 2024 20:50:25 +0300 Subject: [PATCH 268/718] legacymigrate: ignore invalid disappearing_message rows [skip cd] --- cmd/mautrix-signal/legacymigrate.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/mautrix-signal/legacymigrate.sql b/cmd/mautrix-signal/legacymigrate.sql index 9266e9d..258194f 100644 --- a/cmd/mautrix-signal/legacymigrate.sql +++ b/cmd/mautrix-signal/legacymigrate.sql @@ -128,7 +128,8 @@ SELECT 'after_read', -- type expiration_seconds * 1000000000, -- timer CASE WHEN expiration_ts IS NOT NULL THEN expiration_ts * 1000000000 END -- disappear_at -FROM disappearing_message_old; +FROM disappearing_message_old +WHERE expiration_ts < 9000000000; INSERT INTO reaction ( bridge_id, message_id, message_part_id, sender_id, emoji_id, emoji, From 24ca68af284968dd3edf1a4e6fabb149aa0e5d34 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Aug 2024 23:14:15 +0300 Subject: [PATCH 269/718] legacymigrate: maybe fix migrating relay users [skip cd] --- cmd/mautrix-signal/legacymigrate.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/mautrix-signal/legacymigrate.sql b/cmd/mautrix-signal/legacymigrate.sql index 258194f..806fcc2 100644 --- a/cmd/mautrix-signal/legacymigrate.sql +++ b/cmd/mautrix-signal/legacymigrate.sql @@ -35,7 +35,7 @@ SELECT NULL, -- parent_id '', -- parent_receiver CASE WHEN portal_old.relay_user_id<>'' THEN '' END, -- relay_bridge_id - CASE WHEN portal_old.relay_user_id<>'' THEN portal_old.relay_user_id END, -- relay_login_id + CASE WHEN portal_old.relay_user_id<>'' THEN (SELECT id FROM user_login WHERE user_mxid=portal_old.relay_user_id) END, -- relay_login_id CASE WHEN LENGTH(chat_id)=44 THEN NULL ELSE chat_id END, -- other_user_id name, topic, From eeffb0d7e5dcef3b5a434c056d35b07db2286273 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 8 Aug 2024 01:31:16 +0300 Subject: [PATCH 270/718] chatinfo: allow passing service IDs to ResolveIdentifier --- pkg/connector/chatinfo.go | 60 +++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index a5d99c9..8051344 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -106,35 +106,45 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use } func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { - number, err := bridgev2.CleanPhoneNumber(number) - if err != nil { - return nil, err - } - e164Number, err := strconv.ParseUint(strings.TrimPrefix(number, "+"), 10, 64) - if err != nil { - return nil, fmt.Errorf("error parsing phone number: %w", err) - } - e164String := fmt.Sprintf("+%d", e164Number) var aci, pni uuid.UUID + var e164Number uint64 var recipient *types.Recipient - if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { - return nil, fmt.Errorf("error looking up number in local contact list: %w", err) - } else if recipient != nil { - aci = recipient.ACI - pni = recipient.PNI - } else if resp, err := s.Client.LookupPhone(ctx, e164Number); err != nil { - return nil, fmt.Errorf("error looking up number on server: %w", err) - } else { - aci = resp[e164Number].ACI - pni = resp[e164Number].PNI - if aci == uuid.Nil && pni == uuid.Nil { - return nil, nil - } - recipient, err = s.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) + serviceID, err := libsignalgo.ServiceIDFromString(number) + if err != nil { + number, err = bridgev2.CleanPhoneNumber(number) if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") + return nil, err + } + e164Number, err = strconv.ParseUint(strings.TrimPrefix(number, "+"), 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing phone number: %w", err) + } + e164String := fmt.Sprintf("+%d", e164Number) + if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { + return nil, fmt.Errorf("error looking up number in local contact list: %w", err) + } else if recipient != nil { + aci = recipient.ACI + pni = recipient.PNI + } else if resp, err := s.Client.LookupPhone(ctx, e164Number); err != nil { + return nil, fmt.Errorf("error looking up number on server: %w", err) + } else { + aci = resp[e164Number].ACI + pni = resp[e164Number].PNI + if aci == uuid.Nil && pni == uuid.Nil { + return nil, nil + } + recipient, err = s.Client.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, e164String) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI + } + } else { + aci, pni = serviceID.ToACIAndPNI() + recipient, err = s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) + if err != nil { + return nil, fmt.Errorf("error loading recipient: %w", err) } - aci, pni = recipient.ACI, recipient.PNI } zerolog.Ctx(ctx).Debug(). Uint64("e164", e164Number). From fd4b7366e15cd6fd03e294023b7bd5b654412e5e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 8 Aug 2024 23:31:40 +0300 Subject: [PATCH 271/718] legacymigrate: ignore user_portal rows whose user isn't logged in --- cmd/mautrix-signal/legacymigrate.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/mautrix-signal/legacymigrate.sql b/cmd/mautrix-signal/legacymigrate.sql index 806fcc2..1895bfd 100644 --- a/cmd/mautrix-signal/legacymigrate.sql +++ b/cmd/mautrix-signal/legacymigrate.sql @@ -168,7 +168,8 @@ SELECT false, -- preferred CASE WHEN last_read_ts = 0 THEN NULL ELSE last_read_ts * 1000000 END -- last_read FROM user_portal_old -LEFT JOIN user_old ON user_old.mxid = user_portal_old.user_mxid; +LEFT JOIN user_old ON user_old.mxid = user_portal_old.user_mxid +WHERE user_old.uuid IS NOT NULL; DROP TABLE disappearing_message_old; DROP TABLE reaction_old; From b7a5bb74b35e876a0a9d309364ff25ca9c45ef3f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 8 Aug 2024 23:32:48 +0300 Subject: [PATCH 272/718] chatinfo: implement ValidateUserID --- go.mod | 21 +++++++-------------- go.sum | 21 +++++++-------------- pkg/connector/chatinfo.go | 7 +++++++ 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 45187a6..ac5eeba 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,8 @@ require ( github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 - github.com/lib/pq v1.10.9 github.com/mattn/go-pointer v0.0.1 - github.com/mattn/go-sqlite3 v1.14.22 - github.com/prometheus/client_golang v1.19.1 github.com/rs/zerolog v1.33.0 - github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 @@ -19,24 +15,23 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240806214251-e0f58dccf432 + maunium.net/go/mautrix v0.19.1-0.20240808174455-5edfcff2b7b6 nhooyr.io/websocket v1.8.11 ) require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.5.0 // indirect + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect @@ -44,10 +39,8 @@ require ( go.mau.fi/zeroconfig v0.1.3 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect ) - -//replace maunium.net/go/mautrix => ../mautrix-go -//replace go.mau.fi/util => ../../Go/go-util diff --git a/go.sum b/go.sum index 50a5dcc..11d927a 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -20,8 +16,11 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -35,17 +34,11 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +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= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= @@ -95,7 +88,7 @@ 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.19.1-0.20240806214251-e0f58dccf432 h1:Gz1nMg/s4B0VZD4e31wfaghR5cSk2NQVuQkxdCBuI7o= -maunium.net/go/mautrix v0.19.1-0.20240806214251-e0f58dccf432/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= +maunium.net/go/mautrix v0.19.1-0.20240808174455-5edfcff2b7b6 h1:OGskR/suV/6OGgURhucS8eH5QRyRzw7Wkpf8exrOakk= +maunium.net/go/mautrix v0.19.1-0.20240808174455-5edfcff2b7b6/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 8051344..7083701 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -105,6 +105,13 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use return ui } +var _ bridgev2.IdentifierValidatingNetwork = (*SignalConnector)(nil) + +func (s *SignalConnector) ValidateUserID(id networkid.UserID) bool { + _, err := signalid.ParseUserIDAsServiceID(id) + return err == nil +} + func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { var aci, pni uuid.UUID var e164Number uint64 From f3a286f68a91ef593bccb71db433472c7d8072f4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 9 Aug 2024 01:59:13 +0300 Subject: [PATCH 273/718] build: always update submodules [skip ci] --- build-rust.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build-rust.sh b/build-rust.sh index 4201bb4..c7954a2 100755 --- a/build-rust.sh +++ b/build-rust.sh @@ -6,4 +6,5 @@ # RUST_PROFILE=dev #fi RUST_PROFILE=release +git submodule update --init cd pkg/libsignalgo/libsignal && RUSTFLAGS="-Ctarget-feature=-crt-static" RUSTC_WRAPPER="" cargo build -p libsignal-ffi --profile=$RUST_PROFILE From 77cf7e79854ae7bffecbc0f9f48fee06bacf6572 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:03:50 +0200 Subject: [PATCH 274/718] groupinfo: look up ACI from local devices when receiving PNI group member (#528) --- pkg/connector/groupinfo.go | 42 ++++++++++++++++++++++--------- pkg/signalmeow/store/container.go | 10 ++++++++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 3bf809d..db06b95 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -20,6 +20,7 @@ import ( "context" "time" + "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" @@ -120,11 +121,12 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden } } for _, member := range groupInfo.PendingMembers { - if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) + if aci == nil { continue } members.Members = append(members.Members, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ServiceID.UUID), + EventSender: s.makeEventSender(*aci), PowerLevel: roleToPL(member.Role), Membership: event.MembershipInvite, }) @@ -136,11 +138,12 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden }) } for _, member := range groupInfo.BannedMembers { - if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) + if aci == nil { continue } members.Members = append(members.Members, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ServiceID.UUID), + EventSender: s.makeEventSender(*aci), Membership: event.MembershipBan, }) } @@ -243,21 +246,23 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint }) } for _, member := range groupChange.AddPendingMembers { - if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) + if aci == nil { continue } mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ServiceID.UUID), + EventSender: s.makeEventSender(*aci), PowerLevel: roleToPL(member.Role), Membership: event.MembershipInvite, }) } for _, memberServiceID := range groupChange.DeletePendingMembers { - if memberServiceID.Type != libsignalgo.ServiceIDTypeACI { + aci := s.maybeResolvePNItoACI(ctx, memberServiceID) + if aci == nil { continue } mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(memberServiceID.UUID), + EventSender: s.makeEventSender(*aci), Membership: event.MembershipLeave, PrevMembership: event.MembershipInvite, }) @@ -276,20 +281,22 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint }) } for _, member := range groupChange.AddBannedMembers { - if member.ServiceID.Type != libsignalgo.ServiceIDTypeACI { + aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) + if aci == nil { continue } mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ServiceID.UUID), + EventSender: s.makeEventSender(*aci), Membership: event.MembershipBan, }) } for _, memberServiceID := range groupChange.DeleteBannedMembers { - if memberServiceID.Type != libsignalgo.ServiceIDTypeACI { + aci := s.maybeResolvePNItoACI(ctx, memberServiceID) + if aci == nil { continue } mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(memberServiceID.UUID), + EventSender: s.makeEventSender(*aci), Membership: event.MembershipLeave, PrevMembership: event.MembershipBan, }) @@ -300,6 +307,17 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint return ic } +func (s *SignalClient) maybeResolvePNItoACI(ctx context.Context, serviceID *libsignalgo.ServiceID) *uuid.UUID { + if serviceID.Type == libsignalgo.ServiceIDTypeACI { + return &serviceID.UUID + } + device, err := s.Client.Store.DeviceStore.DeviceByPNI(ctx, serviceID.UUID) + if err != nil || device == nil { + return nil + } + return &device.ACI +} + func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal, fromRevision, toRevision uint32, ts uint64) { if fromRevision >= toRevision { return diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 9edafef..a08b42d 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -19,6 +19,7 @@ var _ DeviceStore = (*Container)(nil) type DeviceStore interface { PutDevice(ctx context.Context, dd *DeviceData) error DeviceByACI(ctx context.Context, aci uuid.UUID) (*Device, error) + DeviceByPNI(ctx context.Context, pni uuid.UUID) (*Device, error) } // Container is a wrapper for a SQL database that can contain multiple signalmeow sessions. @@ -39,6 +40,7 @@ FROM signalmeow_device ` const getDeviceQuery = getAllDevicesQuery + " WHERE aci_uuid=$1" +const deviceByPNIQuery = getAllDevicesQuery + "WHERE pni_uuid=$1" func (c *Container) Upgrade(ctx context.Context) error { return c.db.Upgrade(ctx) @@ -122,6 +124,14 @@ func (c *Container) DeviceByACI(ctx context.Context, aci uuid.UUID) (*Device, er return sess, err } +func (c *Container) DeviceByPNI(ctx context.Context, pni uuid.UUID) (*Device, error) { + sess, err := c.scanDevice(c.db.QueryRow(ctx, deviceByPNIQuery, pni)) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return sess, err +} + const ( insertDeviceQuery = ` INSERT INTO signalmeow_device ( From c3fd55cf3872b75118f0a8aca0609b9c70aa5061 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:42:34 +0200 Subject: [PATCH 275/718] handlematrix: add support for most membership changes (#527) Missing knocks and joins [skip cd] --- go.mod | 2 +- go.sum | 4 +- pkg/connector/groupinfo.go | 4 +- pkg/connector/handlematrix.go | 128 ++++++++++++++++++++++++++++++++++ pkg/signalid/ids.go | 8 +++ pkg/signalmeow/groups.go | 14 ++-- 6 files changed, 149 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index ac5eeba..c49fa0f 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240808174455-5edfcff2b7b6 + maunium.net/go/mautrix v0.19.1-0.20240809135320-eb84187368b7 nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 11d927a..4972d7b 100644 --- a/go.sum +++ b/go.sum @@ -88,7 +88,7 @@ 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.19.1-0.20240808174455-5edfcff2b7b6 h1:OGskR/suV/6OGgURhucS8eH5QRyRzw7Wkpf8exrOakk= -maunium.net/go/mautrix v0.19.1-0.20240808174455-5edfcff2b7b6/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= +maunium.net/go/mautrix v0.19.1-0.20240809135320-eb84187368b7 h1:xAq4d1rW/5WN7szBtxHNY/63EPNdji+h7FXlLGBUfJU= +maunium.net/go/mautrix v0.19.1-0.20240809135320-eb84187368b7/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index db06b95..5c25942 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -345,7 +345,9 @@ func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal for _, gc := range groupChanges { log.Debug().Uint32("current_rev", gc.GroupChange.Revision).Msg("Processing group change") chatInfoChange := s.groupChangeToChatInfoChange(ctx, gc.GroupChange.Revision, gc.GroupChange) - portal.ProcessChatInfoChange(ctx, s.makeEventSender(gc.GroupChange.SourceACI), s.UserLogin, chatInfoChange, time.UnixMilli(int64(ts))) + if gc.GroupChange.SourceServiceID.Type == libsignalgo.ServiceIDTypeACI { + portal.ProcessChatInfoChange(ctx, s.makeEventSender(gc.GroupChange.SourceServiceID.UUID), s.UserLogin, chatInfoChange, time.UnixMilli(int64(ts))) + } if gc.GroupChange.Revision == toRevision { break } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 9e8c353..2b8ca26 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -30,6 +30,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalid" @@ -344,3 +345,130 @@ func (s *SignalClient) HandleMatrixRoomTopic(ctx context.Context, msg *bridgev2. ModifyDescription: &msg.Content.Topic, }, nil) } + +func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2.MatrixMembershipChange) (bool, error) { + var targetIntent bridgev2.MatrixAPI + var targetSignalID uuid.UUID + var err error + if msg.Portal.RoomType == database.RoomTypeDM { + //TODO: this probably needs to revert some changes and clean up the portal on leaves + switch msg.Type { + case bridgev2.Invite: + return false, fmt.Errorf("cannot invite additional user to dm") + default: + return false, nil + } + } + if msg.TargetGhost != nil { + targetIntent = msg.TargetGhost.Intent + targetSignalID, err = signalid.ParseUserID(msg.TargetGhost.ID) + if err != nil { + return false, fmt.Errorf("failed to parse target ghost signal id: %w", err) + } + } else if msg.TargetUserLogin != nil { + targetSignalID, err = signalid.ParseUserLoginID(msg.TargetUserLogin.ID) + if err != nil { + return false, fmt.Errorf("failed to parse target user signal id: %w", err) + } + targetIntent = msg.TargetUserLogin.User.DoublePuppet(ctx) + if targetIntent == nil { + ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(msg.TargetUserLogin.ID)) + if err != nil { + return false, fmt.Errorf("failed to get ghost for user: %w", err) + } + targetIntent = ghost.Intent + } + } + log := zerolog.Ctx(ctx).With(). + Str("From Membership", string(msg.Type.From)). + Str("To Membership", string(msg.Type.To)). + Logger() + gc := &signalmeow.GroupChange{} + role := signalmeow.GroupMember_DEFAULT + if msg.Type.To == event.MembershipInvite || msg.Type == bridgev2.AcceptKnock { + levels, err := msg.Portal.Bridge.Matrix.GetPowerLevels(ctx, msg.Portal.MXID) + if err != nil { + log.Err(err).Msg("Couldn't get power levels") + if levels.GetUserLevel(targetIntent.GetMXID()) >= 50 { + role = signalmeow.GroupMember_ADMINISTRATOR + } + } + } + switch msg.Type { + case bridgev2.AcceptInvite: + gc.PromotePendingMembers = []*signalmeow.PromotePendingMember{{ + ACI: targetSignalID, + }} + case bridgev2.RevokeInvite, bridgev2.RejectInvite: + deletePendingMember := libsignalgo.NewACIServiceID(targetSignalID) + gc.DeletePendingMembers = []*libsignalgo.ServiceID{&deletePendingMember} + case bridgev2.Leave, bridgev2.Kick: + gc.DeleteMembers = []*uuid.UUID{&targetSignalID} + case bridgev2.Invite: + gc.AddMembers = []*signalmeow.AddMember{{ + GroupMember: signalmeow.GroupMember{ + ACI: targetSignalID, + Role: role, + }, + }} + // TODO: joining and knocking requires a way to obtain the invite link + // because the joining/knocking member doesn't have the GroupMasterKey yet + // case bridgev2.Join: + // gc.AddMembers = []*signalmeow.AddMember{{ + // GroupMember: signalmeow.GroupMember{ + // ACI: targetSignalID, + // Role: role, + // }, + // JoinFromInviteLink: true, + // }} + // case bridgev2.Knock: + // gc.AddRequestingMembers = []*signalmeow.RequestingMember{{ + // ACI: targetSignalID, + // Timestamp: uint64(time.Now().UnixMilli()), + // }} + case bridgev2.AcceptKnock: + gc.PromoteRequestingMembers = []*signalmeow.RoleMember{{ + ACI: targetSignalID, + Role: role, + }} + case bridgev2.RetractKnock, bridgev2.RejectKnock: + gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID} + case bridgev2.BanKnocked, bridgev2.BanInvited, bridgev2.BanJoined, bridgev2.BanLeft: + gc.AddBannedMembers = []*signalmeow.BannedMember{{ + ServiceID: libsignalgo.NewACIServiceID(targetSignalID), + Timestamp: uint64(time.Now().UnixMilli()), + }} + switch msg.Type { + case bridgev2.BanJoined: + gc.DeleteMembers = []*uuid.UUID{&targetSignalID} + case bridgev2.BanInvited: + deletePendingMember := libsignalgo.NewACIServiceID(targetSignalID) + gc.DeletePendingMembers = []*libsignalgo.ServiceID{&deletePendingMember} + case bridgev2.BanKnocked: + gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID} + } + case bridgev2.Unban: + unbanUser := libsignalgo.NewACIServiceID(targetSignalID) + gc.DeleteBannedMembers = []*libsignalgo.ServiceID{&unbanUser} + default: + log.Debug().Msg("unsupported membership change") + return false, nil + } + _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) + if err != nil || groupID == "" { + return false, err + } + gc.Revision = msg.Portal.Metadata.(*signalid.PortalMetadata).Revision + 1 + revision, err := s.Client.UpdateGroup(ctx, gc, groupID) + if err != nil { + return false, err + } + if msg.Type == bridgev2.Invite { + err = targetIntent.EnsureJoined(ctx, msg.Portal.MXID) + if err != nil { + return false, err + } + } + msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision + return true, nil +} diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go index f99bf9d..99ef7b3 100644 --- a/pkg/signalid/ids.go +++ b/pkg/signalid/ids.go @@ -39,6 +39,14 @@ func ParseUserID(userID networkid.UserID) (uuid.UUID, error) { } } +func ParseUserLoginID(userLoginID networkid.UserLoginID) (uuid.UUID, error) { + userID, err := uuid.Parse(string(userLoginID)) + if err != nil { + return uuid.Nil, err + } + return userID, nil +} + func ParseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { return libsignalgo.ServiceIDFromString(string(userID)) } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 0a67ef6..9031194 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -154,7 +154,7 @@ type RequestingMember struct { Timestamp uint64 } -type PromotePendingMembers struct { +type PromotePendingMember struct { ACI uuid.UUID ProfileKey libsignalgo.ProfileKey } @@ -178,7 +178,7 @@ type BannedMember struct { type GroupChange struct { groupMasterKey types.SerializedGroupMasterKey - SourceACI uuid.UUID + SourceServiceID libsignalgo.ServiceID Revision uint32 AddMembers []*AddMember DeleteMembers []*uuid.UUID @@ -186,7 +186,7 @@ type GroupChange struct { ModifyMemberProfileKeys []*ProfileKeyMember AddPendingMembers []*PendingMember DeletePendingMembers []*libsignalgo.ServiceID - PromotePendingMembers []*GroupMember + PromotePendingMembers []*PromotePendingMember ModifyTitle *string ModifyAvatar *string ModifyDisappearingMessagesDuration *uint32 @@ -862,9 +862,9 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return nil, fmt.Errorf("wrong serviceid kind: expected aci, got pni") } decryptedGroupChange := &GroupChange{ - groupMasterKey: groupMasterKey, - Revision: encryptedActions.Revision, - SourceACI: sourceServiceID.UUID, + groupMasterKey: groupMasterKey, + Revision: encryptedActions.Revision, + SourceServiceID: sourceServiceID, } if encryptedActions.ModifyTitle != nil { @@ -992,7 +992,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange if err != nil { return nil, err } - decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &GroupMember{ + decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &PromotePendingMember{ ACI: *aci, ProfileKey: *profileKey, }) From 4ba7ef744254083389b9be70b51d488c21eb22ed Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 9 Aug 2024 22:18:26 +0300 Subject: [PATCH 276/718] signalmeow: make sync contacts call on connect optional --- pkg/connector/config.go | 16 +++++++++------- pkg/connector/connector.go | 2 ++ pkg/connector/example-config.yaml | 2 ++ pkg/signalmeow/client.go | 1 + pkg/signalmeow/receiving.go | 4 +++- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pkg/connector/config.go b/pkg/connector/config.go index 20fb6e8..0d98583 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -31,13 +31,14 @@ import ( var ExampleConfig string type SignalConfig struct { - DisplaynameTemplate string `yaml:"displayname_template"` - UseContactAvatars bool `yaml:"use_contact_avatars"` - UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` - NumberInTopic bool `yaml:"number_in_topic"` - DeviceName string `yaml:"device_name"` - NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` - LocationFormat string `yaml:"location_format"` + DisplaynameTemplate string `yaml:"displayname_template"` + UseContactAvatars bool `yaml:"use_contact_avatars"` + SyncContactsOnStartup bool `yaml:"sync_contacts_on_startup"` + UseOutdatedProfiles bool `yaml:"use_outdated_profiles"` + NumberInTopic bool `yaml:"number_in_topic"` + DeviceName string `yaml:"device_name"` + NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` + LocationFormat string `yaml:"location_format"` displaynameTemplate *template.Template `yaml:"-"` } @@ -74,6 +75,7 @@ func (c *SignalConfig) FormatDisplayname(contact *types.Recipient) string { func upgradeConfig(helper up.Helper) { helper.Copy(up.Str, "displayname_template") helper.Copy(up.Bool, "use_contact_avatars") + helper.Copy(up.Bool, "sync_contacts_on_startup") helper.Copy(up.Bool, "use_outdated_profiles") helper.Copy(up.Bool, "number_in_topic") helper.Copy(up.Str, "device_name") diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 6a4e4dc..bb98238 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -107,6 +107,8 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use sc.Client = &signalmeow.Client{ Store: device, EventHandler: sc.handleSignalEvent, + + SyncContactsOnConnect: s.Config.SyncContactsOnStartup, } } login.Client = sc diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml index 4c399b3..eea81f2 100644 --- a/pkg/connector/example-config.yaml +++ b/pkg/connector/example-config.yaml @@ -7,6 +7,8 @@ displayname_template: '{{or .ProfileName .PhoneNumber "Unknown user"}}' # Should avatars from the user's contact list be used? This is not safe on multi-user instances. use_contact_avatars: false +# Should the bridge request the user's contact list from the phone on startup? +sync_contacts_on_startup: true # Should the bridge sync ghost user info even if profile fetching fails? This is not safe on multi-user instances. use_outdated_profiles: false # Should the Signal user's phone number be included in the room topic in private chat portal rooms? diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index f311e9a..128e6db 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -40,6 +40,7 @@ type Client struct { ProfileCache *ProfileCache GroupCallCache *map[string]bool LastContactRequestTime time.Time + SyncContactsOnConnect bool encryptionLock sync.Mutex diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index b28a992..bfceca6 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -188,7 +188,9 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection case <-initialConnectChan: log.Info().Msg("Both websockets connected, sending contacts sync request") // TODO hacky - cli.SendContactSyncRequest(ctx) + if cli.SyncContactsOnConnect { + cli.SendContactSyncRequest(ctx) + } if cli.Store.MasterKey == nil { cli.SendStorageMasterKeyRequest(ctx) } From 610626578785f371a90c061a8aa38f9fb7195af0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 9 Aug 2024 23:41:02 +0300 Subject: [PATCH 277/718] dbmeta: don't save revision for DMs --- pkg/signalid/dbmeta.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index 2d85a0c..2b5a164 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -17,7 +17,7 @@ package signalid type PortalMetadata struct { - Revision uint32 `json:"revision"` + Revision uint32 `json:"revision,omitempty"` } type MessageMetadata struct { From 5d19a74fb0714891a3e1caa320673c03d3b2df17 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 9 Aug 2024 23:43:15 +0300 Subject: [PATCH 278/718] dependencies: update mautrix-go --- ROADMAP.md | 8 ++++---- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 9c0cedb..1695ea0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -22,9 +22,9 @@ * [x] Topic * [ ] Membership actions * [ ] Join (accepting invites) - * [ ] Invite - * [ ] Leave - * [ ] Kick/Ban/Unban + * [x] Invite + * [x] Leave + * [x] Kick/Ban/Unban * [x] Group permissions * [x] Typing notifications * [x] Read receipts @@ -70,5 +70,5 @@ * [x] When receiving message * [x] Linking as secondary device * [ ] Registering as primary device - * [ ] Private chat/group creation by inviting Matrix puppet of Signal user to new room + * [x] Private chat/group creation by inviting Matrix puppet of Signal user to new room * [x] Option to use own Matrix account for messages sent from other Signal clients diff --git a/go.mod b/go.mod index c49fa0f..5aed753 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240809135320-eb84187368b7 + maunium.net/go/mautrix v0.19.1-0.20240809204656-49b1f240edfe nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 4972d7b..9a4fbef 100644 --- a/go.sum +++ b/go.sum @@ -88,7 +88,7 @@ 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.19.1-0.20240809135320-eb84187368b7 h1:xAq4d1rW/5WN7szBtxHNY/63EPNdji+h7FXlLGBUfJU= -maunium.net/go/mautrix v0.19.1-0.20240809135320-eb84187368b7/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= +maunium.net/go/mautrix v0.19.1-0.20240809204656-49b1f240edfe h1:tM92VT4DcjnzqHCPFnEj6xwYJ2r2cj9zc6c1mXcSXPk= +maunium.net/go/mautrix v0.19.1-0.20240809204656-49b1f240edfe/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From bf4cedb7fafddbab6e6463ecca4a91fa08f4cbb6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Aug 2024 01:40:15 +0300 Subject: [PATCH 279/718] libsignal: update to v0.55.0 --- CHANGELOG.md | 6 ++++-- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 7 +++++-- pkg/libsignalgo/version.go | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c11f6..2804eb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,10 @@ # v0.7.0 (unreleased) -* Updated to libsignal v0.54.0. +* Updated to libsignal v0.55.0. * Rewrote bridge using bridgev2 architecture. - * It is recommended to check the config file after upgrading. + * It is recommended to check the config file after upgrading. If you have + prevented the bridge from writing to the config, you should update it + manually. # v0.6.3 (2024-07-16) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index b86d58e..a8bc95b 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit b86d58e8d61e2d6f1687bfd30bd143e3eeeaaf6f +Subproject commit a8bc95bc7ebad76ee0bd467ece3321b886cbaef7 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 0292867..8c443ac 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -575,7 +575,6 @@ typedef struct { } SignalCPromiseFfiCdsiLookupResponse; typedef struct { - uint32_t reconnect_count; uint8_t raw_ip_type; double duration_secs; const char *connection_info; @@ -1521,6 +1520,8 @@ SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManage SignalFfiError *signal_connection_manager_clear_proxy(const SignalConnectionManager *connection_manager); +SignalFfiError *signal_connection_manager_on_network_change(const SignalConnectionManager *connection_manager); + SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); @@ -1581,7 +1582,9 @@ SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *pro SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_server_set_listener(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); +SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); + +SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); SignalFfiError *signal_testing_chat_service_inject_raw_server_request(const SignalChat *chat, SignalBorrowedBuffer bytes); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 59cbbd7..cb4bd77 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.54.0" +const Version = "v0.55.0" From efe80989af613a51d3f423e86815bea54b04b974 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Aug 2024 23:31:12 +0300 Subject: [PATCH 280/718] handlematrix: return wrapped errors in some handlers This enables error notices for signalmeow send errors and better HTTP responses for start chat API requests. --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/chatinfo.go | 5 +++-- pkg/connector/handlematrix.go | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 5aed753..9bd76e8 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240809204656-49b1f240edfe + maunium.net/go/mautrix v0.19.1-0.20240810203007-48b08ad8e91d nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 9a4fbef..06bbcc3 100644 --- a/go.sum +++ b/go.sum @@ -88,7 +88,7 @@ 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.19.1-0.20240809204656-49b1f240edfe h1:tM92VT4DcjnzqHCPFnEj6xwYJ2r2cj9zc6c1mXcSXPk= -maunium.net/go/mautrix v0.19.1-0.20240809204656-49b1f240edfe/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= +maunium.net/go/mautrix v0.19.1-0.20240810203007-48b08ad8e91d h1:YDx2k0hFQFoSy7u+dEZv3HsKYvDwVTaPHJHjwXBIwzk= +maunium.net/go/mautrix v0.19.1-0.20240810203007-48b08ad8e91d/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 7083701..69af735 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -26,6 +26,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/ptr" + "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" @@ -120,11 +121,11 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre if err != nil { number, err = bridgev2.CleanPhoneNumber(number) if err != nil { - return nil, err + return nil, bridgev2.WrapRespErr(err, mautrix.MInvalidParam) } e164Number, err = strconv.ParseUint(strings.TrimPrefix(number, "+"), 10, 64) if err != nil { - return nil, fmt.Errorf("error parsing phone number: %w", err) + return nil, bridgev2.WrapRespErr(fmt.Errorf("error parsing phone number: %w", err), mautrix.MInvalidParam) } e164String := fmt.Sprintf("+%d", e164Number) if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 2b8ca26..888d702 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -85,7 +85,7 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma } err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) if err != nil { - return nil, err + return nil, bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } dbMsg := &database.Message{ ID: signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), @@ -123,7 +123,7 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri DataMessage: converted, }}) if err != nil { - return err + return bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } msg.EditTarget.ID = signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) msg.EditTarget.Metadata = &signalid.MessageMetadata{ContainsAttachments: len(converted.Attachments) > 0} From 6f4781fcaa9f006f03d1bd1b67a167567b4634e3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 10 Aug 2024 23:36:19 +0300 Subject: [PATCH 281/718] signalmeow: only apply provisioning timeout to websocket step --- pkg/signalmeow/provisioning.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 1aff0cd..f3abb2c 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -85,9 +85,9 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev go func() { defer close(c) - ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) + timeoutCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() - ws, resp, err := web.OpenWebsocket(ctx, web.WebsocketProvisioningPath) + ws, resp, err := web.OpenWebsocket(timeoutCtx, web.WebsocketProvisioningPath) if err != nil { log.Err(err).Any("resp", resp).Msg("error opening provisioning websocket") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} @@ -96,7 +96,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev defer ws.Close(websocket.StatusInternalError, "Websocket StatusInternalError") provisioningCipher := NewProvisioningCipher() - provisioningURL, err := startProvisioning(ctx, ws, provisioningCipher) + provisioningURL, err := startProvisioning(timeoutCtx, ws, provisioningCipher) if err != nil { log.Err(err).Msg("startProvisioning error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} @@ -104,7 +104,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev } c <- ProvisioningResponse{State: StateProvisioningURLReceived, ProvisioningURL: provisioningURL, Err: err} - provisioningMessage, err := continueProvisioning(ctx, ws, provisioningCipher) + provisioningMessage, err := continueProvisioning(timeoutCtx, ws, provisioningCipher) if err != nil { log.Err(err).Msg("continueProvisioning error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} From 94ae69047b9de6b48173eda30179915e37793658 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 11 Aug 2024 17:01:05 +0300 Subject: [PATCH 282/718] msgconv/from-signal: fix panic bridging stickers --- pkg/msgconv/from-signal.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index e4ab6dc..4b09e80 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -388,6 +388,9 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker converted.Content.Body = sticker.GetEmoji() converted.Type = event.EventSticker converted.Content.MsgType = "" + if converted.Extra == nil { + converted.Extra = map[string]any{} + } // TODO fetch full pack metadata like the old bridge did? converted.Extra["fi.mau.signal.sticker"] = map[string]any{ "id": sticker.GetStickerId(), From 77c150f784ddf715f9515c444d13696ed7759bd0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 11 Aug 2024 21:55:21 +0300 Subject: [PATCH 283/718] dependencies: update --- go.mod | 15 ++++++++------- go.sum | 30 ++++++++++++++++-------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 9bd76e8..96d2b8f 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 - golang.org/x/crypto v0.25.0 - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - golang.org/x/net v0.27.0 + go.mau.fi/util v0.6.1-0.20240811184504-b00aa5c5af3a + golang.org/x/crypto v0.26.0 + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa + golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240810203007-48b08ad8e91d + maunium.net/go/mautrix v0.19.1-0.20240811184947-e13771ff615e nhooyr.io/websocket v1.8.11 ) @@ -28,6 +28,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/petermattis/goid v0.0.0-20240716203034-badd1c0974d6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.5.0 // indirect @@ -37,8 +38,8 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.4 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 06bbcc3..cc932c2 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/petermattis/goid v0.0.0-20240716203034-badd1c0974d6 h1:DUDJI8T/9NcGbbL+AWk6vIYlmQ8ZBS8LZqVre6zbkPQ= +github.com/petermattis/goid v0.0.0-20240716203034-badd1c0974d6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -60,23 +62,23 @@ 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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98 h1:gJ0peWecBm6TtlxKFVIc1KbooXSCHtPfsfb2Eha5A0A= -go.mau.fi/util v0.6.1-0.20240802175451-b430ebbffc98/go.mod h1:S1juuPWGau2GctPY3FR/4ec/MDLhAG2QPhdnUwpzWIo= +go.mau.fi/util v0.6.1-0.20240811184504-b00aa5c5af3a h1:A6AeueGxoDjSSf2X8Tz8X9nQ2S65uYWGVwlvTZa7Bjs= +go.mau.fi/util v0.6.1-0.20240811184504-b00aa5c5af3a/go.mod h1:ZRiX8FK4CsqVINI+3YK50nHnc+dKhfTZNf38zI31S/0= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -88,7 +90,7 @@ 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.19.1-0.20240810203007-48b08ad8e91d h1:YDx2k0hFQFoSy7u+dEZv3HsKYvDwVTaPHJHjwXBIwzk= -maunium.net/go/mautrix v0.19.1-0.20240810203007-48b08ad8e91d/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q= +maunium.net/go/mautrix v0.19.1-0.20240811184947-e13771ff615e h1:Hd3zTiI/xdCsKcpn4SbEqxNYtpFM2YNEj19zQiMcb1U= +maunium.net/go/mautrix v0.19.1-0.20240811184947-e13771ff615e/go.mod h1:GtFIC8z1F1EmpwYIG2QOhhg7/TwxeTX82OBhegABr9s= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 3c483d16f372abd8bfd082ea66c430e12ad45f94 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 13 Aug 2024 01:23:18 +0300 Subject: [PATCH 284/718] signalmeow: use go:embed for protobuf compiling --- .gitattributes | 2 + .../protobuf/ContactDiscovery.pb.go | 41 +- .../protobuf/ContactDiscovery.pb.raw | 15 + pkg/signalmeow/protobuf/DeviceName.pb.go | 22 +- pkg/signalmeow/protobuf/DeviceName.pb.raw | 9 + pkg/signalmeow/protobuf/Groups.pb.go | 552 +------ pkg/signalmeow/protobuf/Groups.pb.raw | Bin 0 -> 7313 bytes pkg/signalmeow/protobuf/Provisioning.pb.go | 67 +- pkg/signalmeow/protobuf/Provisioning.pb.raw | Bin 0 -> 804 bytes pkg/signalmeow/protobuf/SignalService.pb.go | 1386 ++--------------- pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 0 -> 19040 bytes pkg/signalmeow/protobuf/SignalService.proto | 3 +- .../protobuf/StickerResources.pb.go | 37 +- .../protobuf/StickerResources.pb.raw | 12 + pkg/signalmeow/protobuf/StorageService.pb.go | 401 +---- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 0 -> 5605 bytes .../protobuf/UnidentifiedDelivery.pb.go | 96 +- .../protobuf/UnidentifiedDelivery.pb.raw | Bin 0 -> 1172 bytes .../protobuf/WebSocketResources.pb.go | 57 +- .../protobuf/WebSocketResources.pb.raw | Bin 0 -> 645 bytes pkg/signalmeow/protobuf/build-protos.sh | 20 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 22 files changed, 275 insertions(+), 2449 deletions(-) create mode 100644 .gitattributes create mode 100644 pkg/signalmeow/protobuf/ContactDiscovery.pb.raw create mode 100644 pkg/signalmeow/protobuf/DeviceName.pb.raw create mode 100644 pkg/signalmeow/protobuf/Groups.pb.raw create mode 100644 pkg/signalmeow/protobuf/Provisioning.pb.raw create mode 100644 pkg/signalmeow/protobuf/SignalService.pb.raw create mode 100644 pkg/signalmeow/protobuf/StickerResources.pb.raw create mode 100644 pkg/signalmeow/protobuf/StorageService.pb.raw create mode 100644 pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.raw create mode 100644 pkg/signalmeow/protobuf/WebSocketResources.pb.raw diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfb4b8b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.pb.go linguist-generated=true +*.pb.raw binary linguist-generated=true diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index b252d37..f15eba4 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: ContactDiscovery.proto @@ -16,6 +16,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -210,35 +212,8 @@ func (x *CDSClientResponse) GetToken() []byte { var File_ContactDiscovery_proto protoreflect.FileDescriptor -var file_ContactDiscovery_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x9e, 0x02, 0x0a, 0x10, 0x43, 0x44, 0x53, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0d, - 0x61, 0x63, 0x69, 0x5f, 0x75, 0x61, 0x6b, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x61, 0x63, 0x69, 0x55, 0x61, 0x6b, 0x50, 0x61, 0x69, 0x72, 0x73, - 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x72, 0x65, 0x76, 0x45, 0x31, 0x36, 0x34, 0x73, 0x12, - 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x45, 0x31, 0x36, 0x34, 0x73, 0x12, 0x23, 0x0a, 0x0d, - 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x45, 0x31, 0x36, 0x34, - 0x73, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x5f, 0x6d, 0x6f, 0x72, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x61, 0x73, 0x4d, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x63, 0x6b, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x63, 0x6b, 0x12, - 0x37, 0x0a, 0x18, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x61, 0x63, 0x69, 0x73, 0x5f, 0x77, - 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x5f, 0x75, 0x61, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x15, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x41, 0x63, 0x69, 0x73, 0x57, 0x69, 0x74, - 0x68, 0x6f, 0x75, 0x74, 0x55, 0x61, 0x6b, 0x73, 0x22, 0x5a, 0x0a, 0x11, 0x43, 0x44, 0x53, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, - 0x14, 0x65, 0x31, 0x36, 0x34, 0x5f, 0x70, 0x6e, 0x69, 0x5f, 0x61, 0x63, 0x69, 0x5f, 0x74, 0x72, - 0x69, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x65, 0x31, 0x36, - 0x34, 0x50, 0x6e, 0x69, 0x41, 0x63, 0x69, 0x54, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, -} +//go:embed ContactDiscovery.pb.raw +var file_ContactDiscovery_proto_rawDesc []byte var ( file_ContactDiscovery_proto_rawDescOnce sync.Once @@ -253,7 +228,7 @@ func file_ContactDiscovery_proto_rawDescGZIP() []byte { } var file_ContactDiscovery_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_ContactDiscovery_proto_goTypes = []interface{}{ +var file_ContactDiscovery_proto_goTypes = []any{ (*CDSClientRequest)(nil), // 0: signalservice.CDSClientRequest (*CDSClientResponse)(nil), // 1: signalservice.CDSClientResponse } @@ -271,7 +246,7 @@ func file_ContactDiscovery_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_ContactDiscovery_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_ContactDiscovery_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*CDSClientRequest); i { case 0: return &v.state @@ -283,7 +258,7 @@ func file_ContactDiscovery_proto_init() { return nil } } - file_ContactDiscovery_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_ContactDiscovery_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*CDSClientResponse); i { case 0: return &v.state diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.raw b/pkg/signalmeow/protobuf/ContactDiscovery.pb.raw new file mode 100644 index 0000000..c98f8c4 --- /dev/null +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.raw @@ -0,0 +1,15 @@ + +ContactDiscovery.proto signalservice"ž +CDSClientRequest" + aci_uak_pairs ( R aciUakPairs + +prev_e164s ( R prevE164s + new_e164s ( RnewE164s# + discard_e164s ( R discardE164s +has_more (RhasMore +token ( Rtoken + token_ack (RtokenAck7 +return_acis_without_uaks (RreturnAcisWithoutUaks"Z +CDSClientResponse/ +e164_pni_aci_triples ( Re164PniAciTriples +token ( Rtoken \ No newline at end of file diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 2cdca84..27dada3 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: DeviceName.proto @@ -16,6 +16,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -88,18 +90,8 @@ func (x *DeviceName) GetCiphertext() []byte { var File_DeviceName_proto protoreflect.FileDescriptor -var file_DeviceName_proto_rawDesc = []byte{ - 0x0a, 0x10, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x22, 0x78, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x28, 0x0a, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, - 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x79, 0x6e, - 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x49, 0x76, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x49, 0x76, 0x12, 0x1e, 0x0a, 0x0a, 0x63, - 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, -} +//go:embed DeviceName.pb.raw +var file_DeviceName_proto_rawDesc []byte var ( file_DeviceName_proto_rawDescOnce sync.Once @@ -114,7 +106,7 @@ func file_DeviceName_proto_rawDescGZIP() []byte { } var file_DeviceName_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_DeviceName_proto_goTypes = []interface{}{ +var file_DeviceName_proto_goTypes = []any{ (*DeviceName)(nil), // 0: signalservice.DeviceName } var file_DeviceName_proto_depIdxs = []int32{ @@ -131,7 +123,7 @@ func file_DeviceName_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_DeviceName_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_DeviceName_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*DeviceName); i { case 0: return &v.state diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.raw b/pkg/signalmeow/protobuf/DeviceName.pb.raw new file mode 100644 index 0000000..b8aca07 --- /dev/null +++ b/pkg/signalmeow/protobuf/DeviceName.pb.raw @@ -0,0 +1,9 @@ + +DeviceName.proto signalservice"x + +DeviceName( +ephemeralPublic ( RephemeralPublic + syntheticIv ( R syntheticIv + +ciphertext ( R +ciphertext \ No newline at end of file diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index ae4b64b..e76b7c1 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: Groups.proto @@ -18,6 +18,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -2709,466 +2711,8 @@ func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetInviteLinkPassword() []by var File_Groups_proto protoreflect.FileDescriptor -var file_Groups_proto_rawDesc = []byte{ - 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc4, - 0x01, 0x0a, 0x16, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x61, - 0x63, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x63, 0x6c, 0x12, 0x1c, 0x0a, - 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x64, - 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xe7, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x2e, - 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, - 0x0a, 0x10, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x41, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, - 0x41, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x33, 0x0a, 0x04, 0x52, 0x6f, - 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, - 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x02, 0x22, - 0x74, 0x0a, 0x0d, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x1f, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x07, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x64, 0x64, 0x65, 0x64, 0x42, 0x79, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x64, 0x64, 0x65, 0x64, 0x42, - 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x8c, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, - 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x22, 0x44, 0x0a, 0x0c, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xae, 0x02, 0x0a, 0x0d, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x3d, 0x0a, 0x0a, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, - 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x07, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x12, 0x4b, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x11, - 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, - 0x6b, 0x22, 0x58, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x64, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x4d, - 0x42, 0x45, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x49, 0x53, - 0x54, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, 0x53, 0x41, - 0x54, 0x49, 0x53, 0x46, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x04, 0x22, 0xb4, 0x04, 0x0a, 0x05, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, - 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x12, 0x3c, 0x0a, 0x19, 0x64, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, - 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x19, 0x64, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, - 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, - 0x34, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x21, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x0e, 0x70, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x11, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x2e, 0x0a, - 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, - 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x0a, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x2c, 0x0a, 0x11, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x61, 0x6e, 0x6e, 0x6f, - 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x33, 0x0a, - 0x0d, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x0d, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x0d, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x22, 0xcc, 0x21, 0x0a, 0x0b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x0f, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x45, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x1a, 0xd6, 0x20, 0x0a, 0x07, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1a, - 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x61, 0x64, - 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x12, 0x4d, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, - 0x59, 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, - 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x6f, 0x6c, - 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x6b, 0x0a, 0x17, 0x6d, 0x6f, - 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x17, - 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x59, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x11, 0x61, 0x64, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x12, 0x62, 0x0a, 0x14, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x14, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x65, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, - 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, - 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6d, - 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x48, 0x0a, - 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, - 0x69, 0x74, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x69, - 0x66, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x69, 0x66, - 0x79, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x12, 0x84, 0x01, 0x0a, 0x1f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, - 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, - 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, 0x69, 0x73, 0x61, 0x70, - 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x54, - 0x69, 0x6d, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1f, 0x6d, 0x6f, 0x64, 0x69, - 0x66, 0x79, 0x44, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x70, 0x0a, 0x16, 0x6d, - 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x16, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x65, 0x0a, - 0x12, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x12, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x1d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, - 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1d, 0x6d, - 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x62, 0x0a, 0x14, - 0x61, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x61, 0x64, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x12, 0x6b, 0x0a, 0x17, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x17, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x6e, 0x0a, - 0x18, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x32, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x18, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x6f, 0x0a, - 0x18, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, - 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x33, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x18, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x5a, - 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6c, 0x0a, 0x17, 0x6d, 0x6f, - 0x64, 0x69, 0x66, 0x79, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x17, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x56, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x42, - 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x16, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x42, 0x61, 0x6e, 0x6e, - 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, - 0x61, 0x64, 0x64, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x12, 0x5f, 0x0a, 0x13, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x12, 0x81, 0x01, 0x0a, 0x1b, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6e, 0x69, 0x41, 0x63, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x18, 0x18, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x50, 0x72, - 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6e, 0x69, 0x41, - 0x63, 0x69, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, - 0x65, 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1b, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, - 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6e, 0x69, 0x41, 0x63, 0x69, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, 0x60, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x6a, 0x6f, 0x69, 0x6e, 0x46, - 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x12, 0x6a, 0x6f, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, - 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x1a, 0x3a, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, - 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x1a, 0x52, 0x0a, 0x16, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, - 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, - 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x1a, 0x7c, 0x0a, 0x1c, 0x4d, 0x6f, 0x64, 0x69, 0x66, - 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, - 0x79, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x1a, 0x3e, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x24, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, - 0x61, 0x64, 0x64, 0x65, 0x64, 0x1a, 0x41, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x7a, 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x6d, - 0x6f, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x4b, 0x65, 0x79, 0x1a, 0x9a, 0x01, 0x0a, 0x2a, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, - 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6e, 0x69, 0x41, 0x63, 0x69, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, - 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x70, 0x6e, - 0x69, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, - 0x79, 0x1a, 0x44, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, - 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x1a, 0x44, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, - 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x59, 0x0a, - 0x1d, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, - 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x52, 0x6f, - 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x1a, 0x3c, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x42, - 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x23, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, - 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x1a, 0x40, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x29, 0x0a, 0x11, 0x4d, 0x6f, 0x64, 0x69, - 0x66, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x1a, 0x3b, 0x0a, 0x17, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, - 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x2c, 0x0a, 0x12, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x1a, 0x3d, - 0x0a, 0x25, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, - 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, - 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x6d, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x1a, 0x70, 0x0a, - 0x23, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x10, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, - 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x10, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x1a, - 0x67, 0x0a, 0x20, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x1a, 0x85, 0x01, 0x0a, 0x2a, 0x4d, 0x6f, 0x64, - 0x69, 0x66, 0x79, 0x41, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x57, 0x0a, 0x17, 0x61, 0x64, 0x64, 0x46, 0x72, - 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x17, 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x1a, 0x50, 0x0a, 0x1e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, - 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x1a, 0x4d, 0x0a, 0x1d, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x41, 0x6e, 0x6e, 0x6f, - 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, - 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4f, 0x6e, 0x6c, - 0x79, 0x22, 0x73, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x06, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x12, 0x44, 0x0a, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, - 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, - 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x1d, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, - 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x1a, 0x6a, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x52, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x8b, 0x01, - 0x0a, 0x13, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, - 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xbb, 0x01, 0x0a, 0x12, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x42, 0x6c, - 0x6f, 0x62, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x61, 0x76, - 0x61, 0x74, 0x61, 0x72, 0x12, 0x44, 0x0a, 0x1c, 0x64, 0x69, 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, - 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x1c, 0x64, 0x69, - 0x73, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, - 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xe0, 0x01, 0x0a, 0x0f, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x4c, 0x0a, - 0x0a, 0x76, 0x31, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, - 0x69, 0x6e, 0x6b, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, - 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x56, 0x31, 0x48, 0x00, 0x52, - 0x0a, 0x76, 0x31, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x73, 0x0a, 0x19, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x56, 0x31, 0x12, 0x26, 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, - 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x69, 0x6e, - 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x42, 0x0a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xbc, 0x02, 0x0a, - 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, - 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x69, 0x74, - 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0b, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, - 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, - 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x11, 0x61, 0x64, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x72, 0x65, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2f, 0x0a, 0x17, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x2b, 0x0a, 0x27, - 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x50, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} +//go:embed Groups.pb.raw +var file_Groups_proto_rawDesc []byte var ( file_Groups_proto_rawDescOnce sync.Once @@ -3184,7 +2728,7 @@ func file_Groups_proto_rawDescGZIP() []byte { var file_Groups_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 40) -var file_Groups_proto_goTypes = []interface{}{ +var file_Groups_proto_goTypes = []any{ (Member_Role)(0), // 0: Member.Role (AccessControl_AccessRequired)(0), // 1: AccessControl.AccessRequired (*AvatarUploadAttributes)(nil), // 2: AvatarUploadAttributes @@ -3290,7 +2834,7 @@ func file_Groups_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_Groups_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*AvatarUploadAttributes); i { case 0: return &v.state @@ -3302,7 +2846,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Member); i { case 0: return &v.state @@ -3314,7 +2858,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*PendingMember); i { case 0: return &v.state @@ -3326,7 +2870,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*RequestingMember); i { case 0: return &v.state @@ -3338,7 +2882,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*BannedMember); i { case 0: return &v.state @@ -3350,7 +2894,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*AccessControl); i { case 0: return &v.state @@ -3362,7 +2906,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*Group); i { case 0: return &v.state @@ -3374,7 +2918,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*GroupChange); i { case 0: return &v.state @@ -3386,7 +2930,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*GroupResponse); i { case 0: return &v.state @@ -3398,7 +2942,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*GroupChanges); i { case 0: return &v.state @@ -3410,7 +2954,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*GroupChangeResponse); i { case 0: return &v.state @@ -3422,7 +2966,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*GroupAttributeBlob); i { case 0: return &v.state @@ -3434,7 +2978,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*GroupInviteLink); i { case 0: return &v.state @@ -3446,7 +2990,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*GroupJoinInfo); i { case 0: return &v.state @@ -3458,7 +3002,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*GroupExternalCredential); i { case 0: return &v.state @@ -3470,7 +3014,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions); i { case 0: return &v.state @@ -3482,7 +3026,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_AddMemberAction); i { case 0: return &v.state @@ -3494,7 +3038,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_DeleteMemberAction); i { case 0: return &v.state @@ -3506,7 +3050,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[18].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyMemberRoleAction); i { case 0: return &v.state @@ -3518,7 +3062,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[19].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyMemberProfileKeyAction); i { case 0: return &v.state @@ -3530,7 +3074,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[20].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_AddPendingMemberAction); i { case 0: return &v.state @@ -3542,7 +3086,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[21].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_DeletePendingMemberAction); i { case 0: return &v.state @@ -3554,7 +3098,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[22].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_PromotePendingMemberAction); i { case 0: return &v.state @@ -3566,7 +3110,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[23].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction); i { case 0: return &v.state @@ -3578,7 +3122,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[24].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_AddRequestingMemberAction); i { case 0: return &v.state @@ -3590,7 +3134,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[25].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_DeleteRequestingMemberAction); i { case 0: return &v.state @@ -3602,7 +3146,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[26].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_PromoteRequestingMemberAction); i { case 0: return &v.state @@ -3614,7 +3158,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[27].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_AddBannedMemberAction); i { case 0: return &v.state @@ -3626,7 +3170,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[28].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_DeleteBannedMemberAction); i { case 0: return &v.state @@ -3638,7 +3182,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[29].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyTitleAction); i { case 0: return &v.state @@ -3650,7 +3194,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[30].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyDescriptionAction); i { case 0: return &v.state @@ -3662,7 +3206,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[31].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyAvatarAction); i { case 0: return &v.state @@ -3674,7 +3218,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[32].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyDisappearingMessagesTimerAction); i { case 0: return &v.state @@ -3686,7 +3230,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[33].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyAttributesAccessControlAction); i { case 0: return &v.state @@ -3698,7 +3242,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[34].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyMembersAccessControlAction); i { case 0: return &v.state @@ -3710,7 +3254,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[35].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction); i { case 0: return &v.state @@ -3722,7 +3266,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[36].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyInviteLinkPasswordAction); i { case 0: return &v.state @@ -3734,7 +3278,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[37].Exporter = func(v any, i int) any { switch v := v.(*GroupChange_Actions_ModifyAnnouncementsOnlyAction); i { case 0: return &v.state @@ -3746,7 +3290,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[38].Exporter = func(v any, i int) any { switch v := v.(*GroupChanges_GroupChangeState); i { case 0: return &v.state @@ -3758,7 +3302,7 @@ func file_Groups_proto_init() { return nil } } - file_Groups_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_Groups_proto_msgTypes[39].Exporter = func(v any, i int) any { switch v := v.(*GroupInviteLink_GroupInviteLinkContentsV1); i { case 0: return &v.state @@ -3771,13 +3315,13 @@ func file_Groups_proto_init() { } } } - file_Groups_proto_msgTypes[11].OneofWrappers = []interface{}{ + file_Groups_proto_msgTypes[11].OneofWrappers = []any{ (*GroupAttributeBlob_Title)(nil), (*GroupAttributeBlob_Avatar)(nil), (*GroupAttributeBlob_DisappearingMessagesDuration)(nil), (*GroupAttributeBlob_Description)(nil), } - file_Groups_proto_msgTypes[12].OneofWrappers = []interface{}{ + file_Groups_proto_msgTypes[12].OneofWrappers = []any{ (*GroupInviteLink_V1Contents)(nil), } type x struct{} diff --git a/pkg/signalmeow/protobuf/Groups.pb.raw b/pkg/signalmeow/protobuf/Groups.pb.raw new file mode 100644 index 0000000000000000000000000000000000000000..7549d560184e776c7a26830944fac136320946a9 GIT binary patch literal 7313 zcmb_hOLrSd6&}S8*;kS+R}#C^#EC~UOhP7TP842em|>7ChcSsApSC?i*o3xJQF{Wz95$RYtl$^$BUrJ617}gKPZk)1#jc-lXGv|S-)s|>hfzQ1TsX^WRewoI zBIt#FGK#rVBuV3i+J6eLe82~1JeC4Rg2($^b@H;Ozt|2e#!;WEW3M&Jbt12OxaO%H zX&yS|RnX^8(Qau)*)vvH4a&oq3pC$Pf+$q>ls#*WJ%H+0Q4n%;q{q(#A?c)f6>n<2 z_81nWc2EYAE=U*OH-;p2fy(i7nXD8JH+ki^5eXxJHe|+LKPo8_#YqbO_M?CBX zVNct87nTRga%FF+QPh@sdYQcs6~Ei%-PXk^`9%h$inK;&Q+E8x!A$s|em|IfhK`beMy@u}Xbhr?^ zQJ7$IuulQ}aRDfQt~Ivn7LERr&Iqs;JcEJ#5Q-EEp|k7~-jtd>g$)eRlQsP(}}hqmrf6lnPokX#? zvvA+2sByf00Bb|D2!*qvDA(#%ZF(6h_8Dx%nJN;_s$$)!XY0$Gre$?t!8k*Xd?9`l z#a#zf0CIM)>6N-%bmCyBI#x*$noH~g+AlLy^y1dU5PQ6QDic3NFas{;wN-fLgW-nl45OsrB7bH$z zC<1Fhiu^EF^u$rawovhFMuiqKHt-vY6S|1-MJn+A}-3>?x(j z$8*j)lUM7!Oa&XlrnYH(iPKGpZAvQt(H!NI!IxO{NT5~Ekc(kwq>-vmYg<#=zCTBs zuKhe!IRe=q3$U#%%Z>?J<+@V&*&LNvFZO_ur+mH^SxH!4*^5dzRaK|?m4te;4BDx= zvSinxYRz&9XJby+p@PlwXic*uvJf0ywpmW$Fr}@L>r!30SthM+rc4%rLvftUdE;CB zx(earTzvJ#)?w&ZY{{gIq%}?@VGXeo6*=3D+s#Olsk5Dbe4}6-~Kj(rf8? zlGq;#@GbjpI0}PiCrIyqM`_A0UHgVG`EW;EQ5<9S99JdX(FgE$Eo87a+lk+Om5o*J2iqH%}R}0b$*w%iUA!cGWMJP4FnFlPf znGaa^AuwV#=Tif0kSwd71{>T@;oDl(tU*;PRv3mvAjT)f4|fRfX=RxS(;64qKHgOs zf~%oPQ*3Szc1R9I?J zt6ALc5!|6;%$jy)fFKm791z4kfNgD9c23c;&c#5aygUq~CZM9;{2muW#4tF5VM{%U zsVlda8p|{@c(lmcu&s8F5ir^dyHP9%Xi3@i)iR%`_VqO&;GQrP!CFvOV)ZxbmQUq7 z=DZ@zk7ER_xo7dbouj#5K~?#KPNMW+h)Txkv}4NVc|4PVeE>jClBZN2nfTGzsr{({ z*9~Q<5C3OG3ax(rP6~iJV*pfLVYrb(pm>?&L7?qX zO#d{<0i%NSbE)teH5()S-GWT!VrvzO9R#}(>8t&_0PE`XlR{(90L~xDUM8VH9X35) zPpBx2lkb%Ni$|!<;CBVw$|#tSV#wEevT6=|k??qeBWG4;R67j;In~|*SkV@W+CLEC zS10&6jlSWARNhV zgh?i|8EN&LXrWlzV>fX4=Z==sFvG&FylI`%q{L~*MJ(-Er$2WJC(m6fZ!#Y?C?DT; zPiRYvkPe4mgi3YNtE4V4J>>=A(FMxGj}+i zxX$N9VtzAm4>sP|_)NC=+F_*Yq2KMWgFaIAbUq{YXXC}R@0v;KgM&1XQ!);A3L>L> zR$Z>Du?WCZ3E#mfVCHupxoxi=n#L++^|SAKI|6REj(4XobvHM~OnvVJqYE|qzD5hcSi#O>ddVrW=#YFT zF`q76X<*LFVtY0pPj3!#{3vz9c~fMk?qod0UN1Z2r|#(B9zJJe3|jcz4Ur(ZowV3J zYdmT+-*4nzaaB-0*{OZCliP4|BJ-&BxLf;bg2YaSH=CaM!i~Vbm~X-TD9A*HL5k4+i_kI_gW{VdV?c(D^2|0=;V@x zL~=K``)(q+ncKp@Te$@O-BFPJTn@jT-2K8oZHwKCCbsj7B0cEMd#CPf*1OaUl`iIE z3{?$#NV_|+XE&q1kG%=fEMvFB9@6ek?0#=J^s%>AVpqZ*((X>|(IUi7ti*1FJ*3^; zsqtL^7297JIme;0=G29W_e)MuIcKJ~E1eF_NO-!BG#tU@zlrGx9OIz&M)J#lj;55yk6iXmG2BwRJ*f_1_o^lmB&(7sE%Q|^>>=&$ zh5t;7w8b_c&i44p6L+e_WxDuAY*kj*!zTMl-QD@J*y)XC9{^D^_9xdMmQ+V+5OAg` z$j-9~?v{J7^~M&K|EV?Db-%9+(VQ=c#KmHEqhw{e_=z>>WptCOGuM388(l6YN^Yl% z>(=~Gb(97HO69&K)V1`7njlN;$yJ{?*?7|X#=Tl~p2+gA9tl6w%WhteS9PgeMnk5=t*`3I3=O2g! zPdGk8{+~C*jy}WqC+8hQL^5u+_~sfS>H%yj=0$R#R6h=%yV{dMyD%}7gxaD8J8N|t zO?g@(8SjgI11eQ2wN|HAg~AJg)mr7G-T-jZ*%xWkvwYTm42_o;5B$+;&~dGrJgv9e z^=2cN$o~O0sd>k7M1s0X@k&Oj-%dsBDxKcHQI|AZ{HZm2)#DtV(Fo|@NFTHCIp}N+ zbM{24Dx0lVsSI8GlJh_~SQ+$kw|;tBtJX`M+R5YG295^@gMYPZP3BUC|Je|!@_29~ zaj9HwO!TI6wbnfv6KG(xouNCroL{N6?n%>f-Vov%W(h=hsqZP8ryjl}Ef_`EY<@Fz z56IZr;_Ixa@*y5V!t<=jr$(t+u*!6T)2h5E{L>c zDDbo{Ko3QM6r>Y=LoB9y^Lej-#qG{O1q#NvJT3)2T4N6;;Z)j4&KJe*<#fE5oEH!F zL5yXUeax@QzIi@BFG{~R&*aIlcR5ou#F?lDXrFeUPrRv1J8`On?H<%g2%-TBi~NZ< zbfKURsNgfwf>LYij^J!4!(3VrSSZP@ zR=|BV`)6b5_UxK*0}L4-f@d`8-SF-lysSoBcSbGU6DO>HIFF32XRgMOuUU|? z`%HIZ_n8(AoJ;S?yxbeWYj~hWiW@kQt@(Xrh?f8REwQb5eo1}7SL`k3SK}$=A=P6_ zh5$;Ix%+&s1tt7j{C3(=$&yfK_4ze>QxoeeHwYz8RMbSzf9FG-zi-4)94s3#Hf8iW zLQg&admAFBfY!1orTW@qV^1SfZ4h*5k|L_nyLOd!Ny(t?{1RO6tHt%jsOJq8)t2Q@ zNCIEzhA4%C(fUvrfx3rldt5*2bjzhG99e2axSaX#3GG@^2K|CajJO(_cIo0eJ|j~B z4{FyaJ>7%!<#v}Oi8V{S^cCWc%%?o!KpvL}EqdD)2-QHj@ zg<}j3qzL`oU6wG0rXQ9xp7aNBO7J9}!E~7_^^smOQf!9scT-Xb@F>*(49kqCm%Wkq zO%-!d=6y;=VEMm95P~$MO1ku(xg*65q(AOY0HDZy(!2JCH|jG@#FVrkG*h5Fo_NpA z4KppmXNxC<(+WvR)8cs7-e6#uPhVFHLgpQKv&pchC!_{VA&wA&lsBMGk4pL(%?ZQe zx&iuWpFo?lKYN#hATQWfEe0O;E?mw3DXANUqTy^9MGu>&;A0v^r_C}9As9t~zTcFO zU=aaYIcs;Cr?5!rx+qTh$QG+c`@dQ2-)$nmWHY5xH?-8T!=JwkEp7aj%hWuiX{y*{ zK6PDRK<^-=fflJX8DETj?$HhM^~m)uuP(;ZtMPbXqR!?+ zpo|4G>K5hT1ncdO2ioL<9Q4~d$ha8I5#*y+o1(p>nuRx)_`pB=P3!Ep^1lX8P~XQd z1y@?jw-;Nn{!PZ^^k%S z*W+jYE^$O`F=7i*cYUSCUm4w)|g+?oq(Fb^9R8hpXXFiukln$zH7ULLL@U0f$o{Xt6s5`EKf zi2U!vLoZ$PB01;K1mg?vbp@WAQT%V+VZj>x@HD_x?r+e_zbQocO|ie%9|NMMNPzuy zvz+u-lK_Ki_ASD#e%D24K@8w0C*s;0HyQW#*6Y0(rfku*a zJbHI0`Geiuf9&R;3lWmsIf_W_;vE(qB3mLmFy&N|;k~n3yMvGbocmIxQ$I&^195@! zj!4w!?lo5O@4LAl>;@}(Po$20JKm{^kDCot;PipBz1|Q`C3!q#*Nj}>sc=kTPQ^#*SMQ zK5H~0mS3%%)X!`3u?`-A4kma+GBKc6_~Q++7fEqM$JW9&oD819j%IcxezHp*ePpad zGV*u?Lshhb+Ug*rN8T>{>!y*~CQ}iM?r^Em z=*}0!wi@3^%6NWAs|vbiD%hm^!gt70yN6EIUA->Iy%?r*EV3Nj8cVD1_)0pFP8=wT zMh%46!uW%kbSFd4rCY;9XA~HVd3*?;x151u2|{;;KY|@&f=ozzZY`!m#mXtkpVX*x zZ*J@#XjIi;l+(Lr8d9eMUu>Z0?#jV%XZ2diju=>}~} zH7%pLTj+0E6g)8ZJ@SF}+c#whD7@!~!yyx@wWHG63DqAOvUYrSQj*XHet3M-NuhI1 z){nIN*RDur2_q~+Yl(*E;A}juNOkg%I~V>8bOmQ2V)qTc?pL5F~i7Y8{*+XdvHHH z!0s}F>^v0dC+@s|bpkF17cke5UP^b`V;zOPrHx8%c~uu^IWUd|76 z$|Rmwu-C-=is~yvH0M2$fFiFfTp{Q zAd_izMhaU0)X$#8b+0{^j%BFch?}Y$m1^XFxGNGAs0^uCs;2h&x8E|>Rvdh5>7I_F z-Jx_($1N;t{w=XT~VQMppvXg!axg6ts>1yrV*Cw`2#)m!ENYD462 zr|PX7M_VQ(S92Vq!uAO(^B^fBFkSNoeWi;~>y`yYD?cMq^S0`%wqWotOKbjQL%gz* zRJX2Ly9TRQ%?c{3fbRsq>jPcpkU|C3@+arBBInIY^vc{pXH3WJMqQ$$T!Lf8>0Bn? z7fIg|Vmuedh>n8YC8ei&JD;T4bv;ojabD(tkppnPEq0CVLTf=M)Mk(6|7*!rmwc(wVFX%-+#d*Q@urPUl!KZOJeOJ`WJo8xn0Ss8Qst$yg629w- zPu$56%G!hrX3Db0PHdRDuYa*2US4Hu(jR0F$G%TL9djz|%~)9W9?rr&gm(&c zV7Nr3ldcK2;$op#62Uad0P1O}Q9oh;d6QM@?X$9Wkr}Q95jtmW)B_-FO>>#9F!dQ? zJLa)~;#QQ=N1;5%>)s4CUrOR5V16`^}qqT5)x#?Z$wdRDtL{!f|5;;OrWOv*+q?E*K|L*^i7wc-l}csyz0ydO!E@NT4w>x_-q z8g9*y)Ak6)!@2*7p^>ks)hhUPQZ+; z_*cOK#Engps($FAj%liNUOdgX@*4%Bg#)SRK38HZA(!Ba`Qf_GaTDqcZ_eQRZ^1yx z&LU8b2^Vj&n70-eL$A+^gQ`LHT!NSP#ok2MbyeMY&l~3dk*SZUcSWzj3M{pHo-TpU z$T*l1c!uXjtlm>qj-+q~C0`Z{*2XJC+)Z3OJcoI7gW4R^S({s{Kk5fGmo$BprEjA4 zdwfY@LzSK3exN)T9lzZj>1O^r36To?JdTHG2#ofbKOXfSh#7^Nk}}OHEGv&>J2ZD# zKFn7l!r(=YqVfT)`|q5H)Bv@QDnX&bui4_^8i5k*=CJBx$#4MFK5e_o|D~IeEw1yY z!;#dQkeVi9;jxiNFm8-A?{*%ySpAD|o>ly=!h2TP`zF61qvp4zi{rPLmn&7f51SPY zNEA>@7A%^Nko@thbv#;P&I^;k7OOWZ&C`107_two=2_>s$<}7!Ol+&AQnvZHISU4zR~P-1BfccFj8_$4O>Ql_8c}|BLC;ei;)JP zp@x~C4Y%7c1R`wn;6)DT8)t9)*5Gyk0|%EiM_hVwO%HBkf&)$Yc6Ozr?L*16 z^Ej@!7pCO=J?nbNFWzzTF#ltAygXw54>!aEdz;!9M`&gWowl!yv6w-EL{a<$MEjoZ zd#qhXeJ{~73Pxf>=zdCDkb~88i4ex5j8=SH15;6su`zlVL;sB$m!|7=RxB;{fm3Rb znv(ZQO&P+L>wC10iPrb9KtLPoCsnE#zE;n+v1Z{3fBn4WO1Q8_7L zB#->3mmdL_tQge!4e{}Css>)H^0^IS1?CuaQujwX$MxgW0`O)>cpR+BYhrE@SpGLR z#K+c%-XFt}z}M5S0Pp3T!ha>iz3`5iDt(oHAB>Efx1-YUY{K~2=?_LUZum%w!pgLn z7KTXROM9wv<1yPHmTNo(qUL%2~BZ|!&cj|#L45Iz~8BR|lWLqC`@ zEnXgP)JGvG=I;$pdwrGUfdvwU@FNKI6fIqFX*k9zy7(M)(i{wFLSJ z7z6Ub6EHwO@CJC5r=Pm&26u49!sNLMhoizkw`f-Od%DmhP12%>ST{NI#c(lIcbu6> zlpgzSx?+pTaNHY&?j<50Kp>Eq(ZU-@3a7%C{USQVYtEbX z3PLlw#tp_d?D=w2;!g&g0E9@*uGqq}4OED$!%-jx{oYxUieG(BvPen&9$~ch3{^`dD4{_I+`#e_v<*nnhWLix<%Q5puZ`f z=TDMD9it%!f8&sRGV^d(ynT;Mb{Ko=g8QgTigX}AHzKtY`ta^hJAuL@1e|Ywy9wG@ zPd(Ke&DiTtRLyxKyjs8`3RP8Pq(Kx&`uC>&DZhiP70sM*w0J+mD}`En z{Y2@O8k`7n?4Ik1NXqxc^J#v>56+{alIWgU49f0#k7L51`X!G@>uyt;$B!~@6QTi_RKRl zEp_}RB@*L<$h}Xs8IeJL%mm|c~le@aT# H!q5H}`Y4T= literal 0 HcmV?d00001 diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 30127a1..1e2332b 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -37,7 +37,8 @@ message Envelope { reserved /*updatedPni*/ 15; // Not used presently, may be used in the future optional bool story = 16; optional bytes reportingToken = 17; - // NEXT ID: 18 + reserved 18; // internal server use + // NEXT ID: 19 } message Content { diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index e9c864a..b64f824 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: StickerResources.proto @@ -18,6 +18,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -161,31 +163,8 @@ func (x *Pack_Sticker) GetContentType() string { var File_StickerResources_proto protoreflect.FileDescriptor -var file_StickerResources_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0xf3, 0x01, 0x0a, 0x04, 0x50, 0x61, 0x63, 0x6b, - 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x31, - 0x0a, 0x05, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, - 0x63, 0x6b, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x52, 0x08, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x73, 0x1a, 0x51, 0x0a, 0x07, 0x53, 0x74, - 0x69, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x12, 0x20, 0x0a, 0x0b, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x42, 0x42, 0x0a, - 0x31, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x69, 0x63, 0x6b, - 0x65, 0x72, 0x42, 0x0d, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x73, -} +//go:embed StickerResources.pb.raw +var file_StickerResources_proto_rawDesc []byte var ( file_StickerResources_proto_rawDescOnce sync.Once @@ -200,7 +179,7 @@ func file_StickerResources_proto_rawDescGZIP() []byte { } var file_StickerResources_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_StickerResources_proto_goTypes = []interface{}{ +var file_StickerResources_proto_goTypes = []any{ (*Pack)(nil), // 0: signalservice.Pack (*Pack_Sticker)(nil), // 1: signalservice.Pack.Sticker } @@ -220,7 +199,7 @@ func file_StickerResources_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_StickerResources_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_StickerResources_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Pack); i { case 0: return &v.state @@ -232,7 +211,7 @@ func file_StickerResources_proto_init() { return nil } } - file_StickerResources_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_StickerResources_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Pack_Sticker); i { case 0: return &v.state diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.raw b/pkg/signalmeow/protobuf/StickerResources.pb.raw new file mode 100644 index 0000000..03768ca --- /dev/null +++ b/pkg/signalmeow/protobuf/StickerResources.pb.raw @@ -0,0 +1,12 @@ + +StickerResources.proto signalservice"ó +Pack +title ( Rtitle +author ( Rauthor1 +cover ( 2.signalservice.Pack.StickerRcover7 +stickers ( 2.signalservice.Pack.StickerRstickersQ +Sticker +id ( Rid +emoji ( Remoji + contentType ( R contentTypeBB +1org.whispersystems.signalservice.internal.stickerB StickerProtos \ No newline at end of file diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index aeb2cbd..5f88b50 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: StorageService.proto @@ -18,6 +18,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -1992,359 +1994,8 @@ func (x *AccountRecord_PinnedConversation_Contact) GetE164() string { var File_StorageService_proto protoreflect.FileDescriptor -var file_StorageService_proto_rawDesc = []byte{ - 0x0a, 0x14, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x41, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, - 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x35, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, - 0x40, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, - 0x30, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x22, 0x29, 0x0a, 0x0d, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xc2, 0x01, 0x0a, - 0x0e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x3a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, - 0x74, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x69, - 0x6e, 0x73, 0x65, 0x72, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0a, 0x69, 0x6e, 0x73, - 0x65, 0x72, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x41, 0x6c, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x41, 0x6c, - 0x6c, 0x22, 0xe4, 0x02, 0x0a, 0x0e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, - 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x1a, 0xc7, - 0x01, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x10, 0x0a, - 0x03, 0x72, 0x61, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, - 0x41, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x61, - 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x64, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4e, 0x54, 0x41, - 0x43, 0x54, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x56, 0x31, 0x10, - 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x56, 0x32, 0x10, 0x03, 0x12, 0x0b, - 0x0a, 0x07, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x53, - 0x54, 0x4f, 0x52, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x05, 0x22, 0xe5, 0x02, 0x0a, 0x0d, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x38, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x63, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x12, 0x38, - 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, - 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x62, 0x0a, 0x15, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x48, 0x00, 0x52, - 0x15, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x22, 0xca, 0x07, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x61, 0x63, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x6e, 0x69, 0x18, - 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x6e, 0x69, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x50, 0x0a, 0x0d, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, - 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, - 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, - 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, - 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, - 0x74, 0x6f, 0x72, 0x79, 0x12, 0x38, 0x0a, 0x17, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, - 0x0a, 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x47, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, - 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x47, - 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x69, - 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x14, 0x70, 0x6e, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x3d, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x63, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x08, 0x6e, - 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, - 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x1a, 0x34, 0x0a, 0x04, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x61, 0x6d, - 0x69, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, - 0x79, 0x22, 0x3a, 0x0a, 0x0d, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, - 0x0c, 0x0a, 0x08, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, - 0x0a, 0x55, 0x4e, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x22, 0xcd, 0x01, - 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, - 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, - 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, - 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, - 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, - 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, - 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, - 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xce, 0x03, - 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, - 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, - 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, - 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x63, - 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x72, 0x63, - 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, - 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, - 0x6b, 0x65, 0x64, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6d, 0x75, 0x74, - 0x65, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x74, - 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x1c, 0x64, - 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, 0x4d, 0x65, 0x6e, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x1c, 0x64, 0x6f, 0x6e, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x6f, 0x72, - 0x4d, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x66, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x09, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x50, 0x0a, - 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x32, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, - 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x22, - 0x37, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, - 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, - 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x45, - 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x3e, - 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x22, 0x9a, - 0x12, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4b, 0x65, 0x79, - 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, - 0x0a, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, - 0x0a, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, - 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x41, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x61, 0x64, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x70, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x61, 0x64, - 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x65, 0x61, 0x6c, - 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, - 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x73, 0x65, 0x61, 0x6c, 0x65, 0x64, - 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, - 0x12, 0x2a, 0x0a, 0x10, 0x74, 0x79, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, - 0x74, 0x6f, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x74, 0x79, 0x70, 0x69, - 0x6e, 0x67, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x36, 0x0a, 0x16, - 0x6e, 0x6f, 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x64, - 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x6e, 0x6f, - 0x74, 0x65, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x55, 0x6e, - 0x72, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, - 0x69, 0x65, 0x77, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, - 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x73, 0x12, 0x6b, 0x0a, 0x16, 0x70, 0x68, 0x6f, 0x6e, - 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, - 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x16, 0x70, - 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, - 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, - 0x64, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x50, 0x68, 0x6f, 0x6e, - 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x61, 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, - 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, 0x6e, - 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x70, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, - 0x72, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x76, 0x61, 0x74, 0x61, 0x72, 0x73, 0x12, 0x33, - 0x0a, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x08, 0x70, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, - 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, - 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x53, 0x6d, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x65, 0x31, 0x36, 0x34, 0x12, 0x36, 0x0a, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, - 0x65, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x18, - 0x14, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, - 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x12, 0x22, 0x0a, - 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, 0x64, 0x18, 0x15, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x49, - 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x16, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x43, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, - 0x70, 0x6c, 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x70, 0x6c, - 0x61, 0x79, 0x42, 0x61, 0x64, 0x67, 0x65, 0x73, 0x4f, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x12, 0x44, 0x0a, 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, - 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x4d, - 0x75, 0x74, 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, - 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x75, 0x74, - 0x65, 0x64, 0x43, 0x68, 0x61, 0x74, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, - 0x36, 0x0a, 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x69, - 0x65, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x16, 0x68, 0x61, 0x73, 0x53, 0x65, 0x74, 0x4d, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, - 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x12, 0x3a, 0x0a, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, - 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x68, 0x61, 0x73, 0x56, 0x69, - 0x65, 0x77, 0x65, 0x64, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x53, 0x74, - 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x74, - 0x6f, 0x72, 0x69, 0x65, 0x73, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x57, 0x0a, - 0x18, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, - 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1b, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x52, 0x18, 0x73, 0x74, - 0x6f, 0x72, 0x79, 0x56, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x45, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x48, 0x0a, 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, - 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x1f, 0x68, 0x61, 0x73, 0x53, 0x65, 0x65, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x74, 0x6f, - 0x72, 0x79, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x65, 0x65, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x21, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x1e, - 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x22, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x67, 0x12, 0x4d, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, - 0x69, 0x6e, 0x6b, 0x1a, 0x86, 0x02, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x43, 0x6f, - 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x6e, 0x65, 0x64, - 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, - 0x26, 0x0a, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0d, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, - 0x00, 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, - 0x79, 0x1a, 0x3b, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x31, - 0x36, 0x34, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x42, 0x0c, - 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x1a, 0xf8, 0x01, 0x0a, - 0x0c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x18, 0x0a, - 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x2e, 0x43, 0x6f, - 0x6c, 0x6f, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0x6b, 0x0a, 0x05, 0x43, 0x6f, - 0x6c, 0x6f, 0x72, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x48, - 0x49, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x52, 0x45, 0x59, 0x10, 0x03, 0x12, - 0x09, 0x0a, 0x05, 0x4f, 0x4c, 0x49, 0x56, 0x45, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, - 0x45, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x52, 0x41, 0x4e, 0x47, 0x45, 0x10, - 0x06, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x4e, 0x4b, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x50, - 0x55, 0x52, 0x50, 0x4c, 0x45, 0x10, 0x08, 0x22, 0x40, 0x0a, 0x16, 0x50, 0x68, 0x6f, 0x6e, 0x65, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, - 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, - 0x0a, 0x09, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x01, 0x12, 0x0a, 0x0a, - 0x06, 0x4e, 0x4f, 0x42, 0x4f, 0x44, 0x59, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, - 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1f, 0x10, 0x20, 0x22, 0xfb, 0x01, 0x0a, 0x1b, - 0x53, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x72, 0x65, - 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x64, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x69, - 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, - 0x52, 0x65, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x34, 0x0a, 0x0c, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x4e, 0x53, - 0x45, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, - 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x42, - 0x3c, 0x0a, 0x38, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x73, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x50, 0x01, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +//go:embed StorageService.pb.raw +var file_StorageService_proto_rawDesc []byte var ( file_StorageService_proto_rawDescOnce sync.Once @@ -2360,7 +2011,7 @@ func file_StorageService_proto_rawDescGZIP() []byte { var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 6) var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 18) -var file_StorageService_proto_goTypes = []interface{}{ +var file_StorageService_proto_goTypes = []any{ (OptionalBool)(0), // 0: signalservice.OptionalBool (ManifestRecord_Identifier_Type)(0), // 1: signalservice.ManifestRecord.Identifier.Type (ContactRecord_IdentityState)(0), // 2: signalservice.ContactRecord.IdentityState @@ -2420,7 +2071,7 @@ func file_StorageService_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_StorageService_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*StorageManifest); i { case 0: return &v.state @@ -2432,7 +2083,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*StorageItem); i { case 0: return &v.state @@ -2444,7 +2095,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*StorageItems); i { case 0: return &v.state @@ -2456,7 +2107,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ReadOperation); i { case 0: return &v.state @@ -2468,7 +2119,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*WriteOperation); i { case 0: return &v.state @@ -2480,7 +2131,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ManifestRecord); i { case 0: return &v.state @@ -2492,7 +2143,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*StorageRecord); i { case 0: return &v.state @@ -2504,7 +2155,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ContactRecord); i { case 0: return &v.state @@ -2516,7 +2167,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*GroupV1Record); i { case 0: return &v.state @@ -2528,7 +2179,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*GroupV2Record); i { case 0: return &v.state @@ -2540,7 +2191,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*Payments); i { case 0: return &v.state @@ -2552,7 +2203,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*AccountRecord); i { case 0: return &v.state @@ -2564,7 +2215,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*StoryDistributionListRecord); i { case 0: return &v.state @@ -2576,7 +2227,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*ManifestRecord_Identifier); i { case 0: return &v.state @@ -2588,7 +2239,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*ContactRecord_Name); i { case 0: return &v.state @@ -2600,7 +2251,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*AccountRecord_PinnedConversation); i { case 0: return &v.state @@ -2612,7 +2263,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*AccountRecord_UsernameLink); i { case 0: return &v.state @@ -2624,7 +2275,7 @@ func file_StorageService_proto_init() { return nil } } - file_StorageService_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_StorageService_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*AccountRecord_PinnedConversation_Contact); i { case 0: return &v.state @@ -2637,14 +2288,14 @@ func file_StorageService_proto_init() { } } } - file_StorageService_proto_msgTypes[6].OneofWrappers = []interface{}{ + file_StorageService_proto_msgTypes[6].OneofWrappers = []any{ (*StorageRecord_Contact)(nil), (*StorageRecord_GroupV1)(nil), (*StorageRecord_GroupV2)(nil), (*StorageRecord_Account)(nil), (*StorageRecord_StoryDistributionList)(nil), } - file_StorageService_proto_msgTypes[15].OneofWrappers = []interface{}{ + file_StorageService_proto_msgTypes[15].OneofWrappers = []any{ (*AccountRecord_PinnedConversation_Contact_)(nil), (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw new file mode 100644 index 0000000000000000000000000000000000000000..bd966cb8940f6481e516cf67d985ee329185222f GIT binary patch literal 5605 zcmdT|+ioMr5j7=B8a6LW_sZId_Tu%}FysZyWVsvL*j!+eqO|l%B+(?b*e7GeX;Bjm zXNaDmHv9p9gg+-Q0Rkjnk^Dn|yrimouDodd>KB4tm+tDCsybCo_6LC{%n2WGachrx zZ6>_Hqh;ToxTfPPqR}AtLa}qxwXe7zP@U}Ea^c&atLL8Pj`A#8(tWaXYdUkTZvnl; z)WY~ZDTZ5g0zRcxvVFrBQnkeJ?*_H+Nhzh~)8COD8}xn9+&(JS4{I4iYbjZ#1dXpq znQ_zV&A2cFFc&QsKzJjM-v$e#rSZ2Msk{}iec8w?VbU5&}IW+SuWyXgH3Z2QOFDYYReF{x@;B#$dvBzvRon{MxIxB3w-TD|VD(Hd5B zxHx6KQUBt3bt_ratJ}C}v|7DUcUaBShvdOv*kkX0JnjsJtkWC~JH76YXRxU582{NK z>yKC@PC;`by!q_nxy+ejeOdEVaTCo@JkhMn zPq#_4zN}eCO>;c<=58P(XjQYJxQS*cPA|zPKGclGvF!)KzMNxHoxy*72ZEY?Jfk}sXRf?ill4zflRVDFSK68o(Bdm|YC8+b-jnPU1WhoYn&if7%=t^l8{cqCF91tp z(Gu_Z{u+v$1K$j|L~_$4+}9N2YcR~xi;^9$DO8N9DPY@?i&a!FNq&X~Mf(194ttNF zXgEWA3V2~oXL=b#^K2ap{csJgm9e5%gximuS0si&Zd1Tn{4lfizV9 zKYU5@D22!?gD^}fwLs%l@P%m=u8dcttSWdI(pWQ(+b50D*%0b%iD(yX);a04kD<_3 z2pM(b^_KC^94TjN8Axo|RtNy_FCDhnK5PzKL@JGK4BHSDqcC0xTdY+Y`$b`kX}LaZ zjel)N_X#U32J+OzFjegZmXL(->$)9nl1COmR@VdQUz~X29Gd{o^*dMRnB6)SB#qrE zlTB=_Q5s7nHWX9|B?InS=bpu7Fgg0Br+<*=e6mV($Oi4Kd zoJ**K8)Z=^g8&%v1-20ZFy;#^jR0SevUzI;rWgsQZwA*AwF)dtq%}e@`G?+sJ6DaU zva1wW!@*?1+72Mi?OEVUV1i^x)95$kz~?472fqXt9oMqQCP2L(hQ$Uh)>&xqYP96dYit9T9+Su6jx)Rl3|e#3aTYDp9dieZlP>*ow-BCw!}&}W?$)&# z_;DHdja1*jMZIg&AMoHDT3%1s-0utf)*LVNL#4N#3$w2doC`=lZuQ(t&lDEqm+J2x zO3jUY*|e#%V8l=b__0*EhhPCFL}dDw=n_BhoTys0!0MgK^vQo@C6Gt zM(71>jR|q#P@pRdN3#S^Hu2NN;eT_al=f2^_!W{zz>l99ca~KHH!QJuP1|H=>^Yv0 zcdLA$dZ*6=hk+VX+Qtppk!x&el7|hAvh((JXV``}4IrMf_B(jc0AlZ~ zbJ2$94EPJgcDK4i3EAzjM)$N`-9_1cr~9V5ht&Rv_0QT>&G?=iq>w5FkJ;19q|k=` z{#~Zj9lAaFKWwO=t$I{_48NaNpBn$mk%uyqmR}CkYXG)NiSxsmAVrZg434_t z2gAV&krf^a?3oQ6*g(Bjb}Sz}jb(lv3!5SJvX+@6F`Dvh4ToZjcXGrx2VOU^=lA(zBPOlrBE_IY!+<8;7P;BbvhrD(+FYntvqUd16w7 mf!&7(Of_}-OL=FzFmJ$XZ4GN7Jmso4T)&^Y+?B7nFa8hxW5W*s literal 0 HcmV?d00001 diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index fbfebf5..97d1b46 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: UnidentifiedDelivery.proto @@ -16,6 +16,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -543,82 +545,8 @@ func (x *UnidentifiedSenderMessage_Message) GetGroupId() []byte { var File_UnidentifiedDelivery_proto protoreflect.FileDescriptor -var file_UnidentifiedDelivery_proto_rawDesc = []byte{ - 0x0a, 0x1a, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x65, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x84, 0x01, 0x0a, 0x11, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x1a, 0x2f, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x22, 0xbd, 0x02, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0xe7, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, - 0x65, 0x72, 0x45, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x45, 0x31, 0x36, 0x34, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, - 0x65, 0x72, 0x55, 0x75, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x55, 0x75, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6e, 0x64, - 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, - 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x07, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x22, 0xe7, 0x04, 0x0a, 0x19, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d, - 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x6e, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x53, 0x74, - 0x61, 0x74, 0x69, 0x63, 0x12, 0x2a, 0x0a, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, - 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, - 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x1a, 0xc9, 0x03, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x49, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x6e, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x65, 0x6e, 0x64, 0x65, - 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x52, 0x11, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x12, 0x5e, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x6e, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x48, 0x69, 0x6e, 0x74, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x6e, - 0x74, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x52, 0x45, 0x4b, 0x45, 0x59, 0x5f, 0x4d, 0x45, - 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x45, 0x53, 0x53, 0x41, - 0x47, 0x45, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x4b, 0x45, - 0x59, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x50, - 0x4c, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x4e, 0x54, - 0x10, 0x08, 0x22, 0x38, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x48, 0x69, 0x6e, - 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0e, - 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x45, 0x4e, 0x44, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0c, - 0x0a, 0x08, 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x43, 0x49, 0x54, 0x10, 0x02, 0x42, 0x36, 0x0a, 0x25, - 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x73, 0x2e, 0x6c, 0x69, 0x62, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x0d, 0x57, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x73, -} +//go:embed UnidentifiedDelivery.pb.raw +var file_UnidentifiedDelivery_proto_rawDesc []byte var ( file_UnidentifiedDelivery_proto_rawDescOnce sync.Once @@ -634,7 +562,7 @@ func file_UnidentifiedDelivery_proto_rawDescGZIP() []byte { var file_UnidentifiedDelivery_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_UnidentifiedDelivery_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_UnidentifiedDelivery_proto_goTypes = []interface{}{ +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 @@ -662,7 +590,7 @@ func file_UnidentifiedDelivery_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_UnidentifiedDelivery_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_UnidentifiedDelivery_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*ServerCertificate); i { case 0: return &v.state @@ -674,7 +602,7 @@ func file_UnidentifiedDelivery_proto_init() { return nil } } - file_UnidentifiedDelivery_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_UnidentifiedDelivery_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*SenderCertificate); i { case 0: return &v.state @@ -686,7 +614,7 @@ func file_UnidentifiedDelivery_proto_init() { return nil } } - file_UnidentifiedDelivery_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_UnidentifiedDelivery_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*UnidentifiedSenderMessage); i { case 0: return &v.state @@ -698,7 +626,7 @@ func file_UnidentifiedDelivery_proto_init() { return nil } } - file_UnidentifiedDelivery_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_UnidentifiedDelivery_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ServerCertificate_Certificate); i { case 0: return &v.state @@ -710,7 +638,7 @@ func file_UnidentifiedDelivery_proto_init() { return nil } } - file_UnidentifiedDelivery_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_UnidentifiedDelivery_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*SenderCertificate_Certificate); i { case 0: return &v.state @@ -722,7 +650,7 @@ func file_UnidentifiedDelivery_proto_init() { return nil } } - file_UnidentifiedDelivery_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_UnidentifiedDelivery_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*UnidentifiedSenderMessage_Message); i { case 0: return &v.state diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.raw b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.raw new file mode 100644 index 0000000000000000000000000000000000000000..7d8db350b01354f7b5508c6ea3789823fdc2239c GIT binary patch literal 1172 zcmb_c%Wl&^6eSOm_U2J{B%}}_R9Ql*ShymBstY!G7_gdzXyORiP^I=I9pT#6*eQ6= zZ}9Wxv6DCnERa}v?zyjX@0l^QXFhY$kJ%T7?f^Y@hdePt9>f7@L~P;Dy$Jao zb5Q?Lfa9q+Bkv=Z3C=u5asoAHW3~z>h0{9CL*xk@szULSW2>nA8=!p#wS2iI6q&24 zG^jWc4N6}z$8{6pj#MeK^4D;jAPU)i2@b6GUZZJRpR7QOkYlynuEv%ROC{Tw;l>-t#e{* ziDm2wMYDMQz6_7^qNlqYVHC|5NKWAh!yCLsKKCZeYmYgZq`R<+^c|jrF}l-u9*f9S z+#}qE$#c-wP}WBcT&H_@`&S97D=rq4<0M2ypxJq~GvQxnFtU8Z7RgkVAY(XA<;dMN zMfXpe+qqkGKUGTS1b!?YPBzKPB%j55NImbE@Ji{Lo!9@&y}zj;Uem^qofkYBp#4C9+)&AQFRnxzW6L`JGhcsj&e>>4{Z((U# literal 0 HcmV?d00001 diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index df73711..cf124d4 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 +// protoc-gen-go v1.34.2 // protoc v3.21.12 // source: WebSocketResources.proto @@ -18,6 +18,8 @@ import ( sync "sync" ) +import _ "embed" + const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -307,49 +309,8 @@ func (x *WebSocketMessage) GetResponse() *WebSocketResponseMessage { var File_WebSocketResources_proto protoreflect.FileDescriptor -var file_WebSocketResources_proto_rawDesc = []byte{ - 0x0a, 0x18, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x7f, 0x0a, 0x17, 0x57, 0x65, 0x62, - 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x65, 0x72, 0x62, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x76, 0x65, 0x72, 0x62, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, - 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, - 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x8a, 0x01, 0x0a, 0x18, 0x57, - 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x83, 0x02, 0x0a, 0x10, 0x57, 0x65, 0x62, 0x53, - 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x0a, - 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, - 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x02, 0x42, 0x46, 0x0a, - 0x33, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x73, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x42, 0x0f, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x73, -} +//go:embed WebSocketResources.pb.raw +var file_WebSocketResources_proto_rawDesc []byte var ( file_WebSocketResources_proto_rawDescOnce sync.Once @@ -365,7 +326,7 @@ func file_WebSocketResources_proto_rawDescGZIP() []byte { var file_WebSocketResources_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_WebSocketResources_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_WebSocketResources_proto_goTypes = []interface{}{ +var file_WebSocketResources_proto_goTypes = []any{ (WebSocketMessage_Type)(0), // 0: signalservice.WebSocketMessage.Type (*WebSocketRequestMessage)(nil), // 1: signalservice.WebSocketRequestMessage (*WebSocketResponseMessage)(nil), // 2: signalservice.WebSocketResponseMessage @@ -388,7 +349,7 @@ func file_WebSocketResources_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_WebSocketResources_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_WebSocketResources_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*WebSocketRequestMessage); i { case 0: return &v.state @@ -400,7 +361,7 @@ func file_WebSocketResources_proto_init() { return nil } } - file_WebSocketResources_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_WebSocketResources_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*WebSocketResponseMessage); i { case 0: return &v.state @@ -412,7 +373,7 @@ func file_WebSocketResources_proto_init() { return nil } } - file_WebSocketResources_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_WebSocketResources_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*WebSocketMessage); i { case 0: return &v.state diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.raw b/pkg/signalmeow/protobuf/WebSocketResources.pb.raw new file mode 100644 index 0000000000000000000000000000000000000000..a521defa0604210f4e9dc97d2d2b08983e362deb GIT binary patch literal 645 zcmaKq%}>HW5XEh&g3E`^9<)c&81>WxUOXC1y%-B_A)H&7K%>yQvp{*VJ`ngOnS%R8uKq|r*MQ;`5TiLz zN~{g=*fF}s-8s{>nq`q#IA$?ZwVK80EO%;h)?&J*4yi97ngK`Wv|E$*s-+!bCNsy9 zT8qib{V~WMY?iJNDuhC;0JNB1k~0*MSfd7Lv$9j`mIbw@kn76!ACL-Lp_JI}w@K_> z92LX^u|%GM&Y{!0_Vxnw4&~lRYMFM>M^fjYGu6D!-pw&HD`e$LR@vwiX>dTDiT<)? z@Ami;g|2#IXLLPcDJa?`^>OeL3?_knq8jGEjs0+B8?;3l%nyfyAoOjs|4i;vKKHhZ h1T*;ua}=<|gSE*@0GD^ literal 0 HcmV?d00001 diff --git a/pkg/signalmeow/protobuf/build-protos.sh b/pkg/signalmeow/protobuf/build-protos.sh index 60b622b..7e32899 100755 --- a/pkg/signalmeow/protobuf/build-protos.sh +++ b/pkg/signalmeow/protobuf/build-protos.sh @@ -1,17 +1,11 @@ -#!/usr/bin/env bash - -# This script is used to generate the protobuf files for the project. -# It is assumed that the protoc compiler is installed and available on the path. - -# The script will generate the protobuf files for the following languages: -# - Go - +#!/bin/sh PKG_IMPORT_PATH="go.mau.fi/mautrix-signal/pkg/signalmeow/signalpb" - for file in *.proto do - protoc --go_out=. \ - --go_opt=M${file}=$PKG_IMPORT_PATH \ - --go_opt=paths=source_relative \ - $file + # Requires https://go-review.googlesource.com/c/protobuf/+/369634 + protoc --go_out=. \ + --go_opt=M${file}=$PKG_IMPORT_PATH \ + --go_opt=paths=source_relative \ + --go_opt=embed_raw=true \ + $file done diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index e6d0ea3..9735ecf 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-6c302b708a6980041ff57271f800c0b092e74ef9} -DESKTOP_GIT_REVISION=${1:-b34f2fbb99d68bd462715f8519524100580fb372} +ANDROID_GIT_REVISION=${1:-68c7ce582378b5f752e5971007b2c203e81cecbd} +DESKTOP_GIT_REVISION=${1:-faea93e5cea24893a8976dc6329faa751f59df5c} update_proto() { case "$1" in From abc6c1fa0289d9531dd93a7fa16a8dd267d02991 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Aug 2024 14:15:06 +0300 Subject: [PATCH 285/718] main: drop support for Go 1.21 --- .github/workflows/go.yml | 8 ++++---- go.mod | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 558ac4f..4e0b362 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -8,8 +8,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.21", "1.22"] - name: Lint ${{ matrix.go-version == '1.22' && '(latest)' || '(old)' }} + go-version: ["1.22", "1.23"] + name: Lint ${{ matrix.go-version == '1.23' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 @@ -37,8 +37,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.21", "1.22"] - name: Test ${{ matrix.go-version == '1.22' && '(latest)' || '(old)' }} + go-version: ["1.22", "1.23"] + name: Test ${{ matrix.go-version == '1.23' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 diff --git a/go.mod b/go.mod index 96d2b8f..1f52f2e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module go.mau.fi/mautrix-signal -go 1.21 +go 1.22 require ( github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 From ab36759bddde65c7cf4ddc3217ebb212ac12d428 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Aug 2024 14:16:54 +0300 Subject: [PATCH 286/718] dependencies: update --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 1f52f2e..7d25ca5 100644 --- a/go.mod +++ b/go.mod @@ -10,13 +10,13 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.6.1-0.20240811184504-b00aa5c5af3a + go.mau.fi/util v0.6.1-0.20240815104112-77362c9b05dd golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240811184947-e13771ff615e - nhooyr.io/websocket v1.8.11 + maunium.net/go/mautrix v0.19.1-0.20240815104211-9e031496a01c + nhooyr.io/websocket v1.8.17 ) require ( @@ -28,7 +28,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect - github.com/petermattis/goid v0.0.0-20240716203034-badd1c0974d6 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.5.0 // indirect diff --git a/go.sum b/go.sum index cc932c2..586fff1 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20240716203034-badd1c0974d6 h1:DUDJI8T/9NcGbbL+AWk6vIYlmQ8ZBS8LZqVre6zbkPQ= -github.com/petermattis/goid v0.0.0-20240716203034-badd1c0974d6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -62,8 +62,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.6.1-0.20240811184504-b00aa5c5af3a h1:A6AeueGxoDjSSf2X8Tz8X9nQ2S65uYWGVwlvTZa7Bjs= -go.mau.fi/util v0.6.1-0.20240811184504-b00aa5c5af3a/go.mod h1:ZRiX8FK4CsqVINI+3YK50nHnc+dKhfTZNf38zI31S/0= +go.mau.fi/util v0.6.1-0.20240815104112-77362c9b05dd h1:rDu4R3axIbNzv/c2Izri81dMcDXOklQil7tUGivvfNs= +go.mau.fi/util v0.6.1-0.20240815104112-77362c9b05dd/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= @@ -90,7 +90,7 @@ 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.19.1-0.20240811184947-e13771ff615e h1:Hd3zTiI/xdCsKcpn4SbEqxNYtpFM2YNEj19zQiMcb1U= -maunium.net/go/mautrix v0.19.1-0.20240811184947-e13771ff615e/go.mod h1:GtFIC8z1F1EmpwYIG2QOhhg7/TwxeTX82OBhegABr9s= -nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= -nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +maunium.net/go/mautrix v0.19.1-0.20240815104211-9e031496a01c h1:OgbLNfOibiz+nUWvqpo3dfD+4uuRekRLOynQbFq7VYU= +maunium.net/go/mautrix v0.19.1-0.20240815104211-9e031496a01c/go.mod h1:BGpUGMF+TTNyJ7s6hyZzyNYIAedqIooxHn4+YUi11Ts= +nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= +nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 30dd472ed808eaaaa61f41616a74301cad6a47db Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Aug 2024 16:56:25 +0300 Subject: [PATCH 287/718] changelog: update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2804eb4..9b29904 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # v0.7.0 (unreleased) +* Bumped minimum Go version to 1.22. * Updated to libsignal v0.55.0. * Rewrote bridge using bridgev2 architecture. * It is recommended to check the config file after upgrading. If you have From 3a32a7f46e7524220e2a10057b572c271d526a92 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Aug 2024 16:56:34 +0300 Subject: [PATCH 288/718] signalmeow: move keepalive log to trace level --- pkg/signalmeow/web/signalwebsocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 0b97b8a..8b9698b 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -300,7 +300,7 @@ func (s *SignalWebsocket) connectLoop( loopCancel(err) return } - log.Debug().Msg("Sent keepalive") + log.Trace().Msg("Sent keepalive") case <-loopCtx.Done(): return } From f43307b546e70342f3839b51499c27dbc8036c6c Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:34:05 +0200 Subject: [PATCH 289/718] groupinfo: handle promote pending/requesting member changes (#529) --- pkg/connector/groupinfo.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 5c25942..d0ecdd4 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -301,6 +301,27 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint PrevMembership: event.MembershipBan, }) } + for _, member := range groupChange.PromotePendingMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipJoin, + PrevMembership: event.MembershipInvite, + }) + } + for _, member := range groupChange.PromotePendingPniAciMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipJoin, + PrevMembership: event.MembershipInvite, + }) + } + for _, member := range groupChange.PromoteRequestingMembers { + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipJoin, + PrevMembership: event.MembershipKnock, + }) + } if len(mc) > 0 || pls != nil { ic.MemberChanges = &bridgev2.ChatMemberList{Members: mc, PowerLevels: pls} } From ec9fea1f044507999c6b20a8c041d40670940e3c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Aug 2024 15:15:08 +0300 Subject: [PATCH 290/718] Bump version to v0.7.0 --- CHANGELOG.md | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b29904..9c429db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v0.7.0 (unreleased) +# v0.7.0 (2024-08-16) * Bumped minimum Go version to 1.22. * Updated to libsignal v0.55.0. diff --git a/go.mod b/go.mod index 7d25ca5..e6f6a8e 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.6.1-0.20240815104112-77362c9b05dd + go.mau.fi/util v0.7.0 golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.1-0.20240815104211-9e031496a01c + maunium.net/go/mautrix v0.20.0 nhooyr.io/websocket v1.8.17 ) diff --git a/go.sum b/go.sum index 586fff1..c9c1c81 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.6.1-0.20240815104112-77362c9b05dd h1:rDu4R3axIbNzv/c2Izri81dMcDXOklQil7tUGivvfNs= -go.mau.fi/util v0.6.1-0.20240815104112-77362c9b05dd/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= +go.mau.fi/util v0.7.0 h1:l31z+ivrSQw+cv/9eFebEqtQW2zhxivGypn+JT0h/ws= +go.mau.fi/util v0.7.0/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= @@ -90,7 +90,7 @@ 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.19.1-0.20240815104211-9e031496a01c h1:OgbLNfOibiz+nUWvqpo3dfD+4uuRekRLOynQbFq7VYU= -maunium.net/go/mautrix v0.19.1-0.20240815104211-9e031496a01c/go.mod h1:BGpUGMF+TTNyJ7s6hyZzyNYIAedqIooxHn4+YUi11Ts= +maunium.net/go/mautrix v0.20.0 h1:bzQnVQR+LvQxV1YlAr7BSWCS8AWa0Ov0lyPhbbChM0o= +maunium.net/go/mautrix v0.20.0/go.mod h1:V725r8w7oddsS7CxnmTAp634A4nwJCFY7J3jiTMUz2c= nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 49831b6a77877f5ea50eecc4c2b7c4da233fa296 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Aug 2024 15:18:55 +0300 Subject: [PATCH 291/718] changelog: update --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c429db..3c14528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * It is recommended to check the config file after upgrading. If you have prevented the bridge from writing to the config, you should update it manually. + * Thanks to [@maltee1] for reimplementing Matrix -> Signal membership + handling in the rewrite. # v0.6.3 (2024-07-16) From 39b408ddf147bfdc1c3673e1c9241e97d63dba10 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 17 Aug 2024 14:13:39 +0300 Subject: [PATCH 292/718] signalmeow: don't use embedded pointers in SendMessageResult Fixes #533 --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/handlematrix.go | 2 +- pkg/signalmeow/sending.go | 18 +++++++++--------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index e6f6a8e..3ea65bd 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.0 + maunium.net/go/mautrix v0.20.1-0.20240817111253-2355d70426f4 nhooyr.io/websocket v1.8.17 ) diff --git a/go.sum b/go.sum index c9c1c81..3cabb48 100644 --- a/go.sum +++ b/go.sum @@ -90,7 +90,7 @@ 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.20.0 h1:bzQnVQR+LvQxV1YlAr7BSWCS8AWa0Ov0lyPhbbChM0o= -maunium.net/go/mautrix v0.20.0/go.mod h1:V725r8w7oddsS7CxnmTAp634A4nwJCFY7J3jiTMUz2c= +maunium.net/go/mautrix v0.20.1-0.20240817111253-2355d70426f4 h1:S4+mHwQC2CiCTl0cn21zd4V8JiqGYMYlsde2v7jC8bE= +maunium.net/go/mautrix v0.20.1-0.20240817111253-2355d70426f4/go.mod h1:V725r8w7oddsS7CxnmTAp634A4nwJCFY7J3jiTMUz2c= nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 888d702..87cebe2 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -247,7 +247,7 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri result := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(destination), signalmeow.ReadReceptMessageForTimestamps(messages)) cancel() if !result.WasSuccessful { - zerolog.Ctx(ctx).Err(result.FailedSendResult.Error). + zerolog.Ctx(ctx).Err(result.Error). Stringer("destination", destination). Uints64("message_ids", messages). Msg("Failed to send read receipt to Signal") diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 053e335..cc156c9 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -296,8 +296,8 @@ type FailedSendResult struct { } type SendMessageResult struct { WasSuccessful bool - *SuccessfulSendResult - *FailedSendResult + SuccessfulSendResult + FailedSendResult } type GroupMessageSendResult struct { SuccessfullySentTo []SuccessfulSendResult @@ -717,21 +717,21 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv // Treat needs PNI signature as "this is a message request" and don't send receipts/typing if needsPNISignature && (content.TypingMessage != nil || content.ReceiptMessage != nil) { zerolog.Ctx(ctx).Debug().Msg("Not sending typing/receipt message to recipient as needs PNI signature flag is set") - res := &SuccessfulSendResult{Recipient: recipientID} + res := SuccessfulSendResult{Recipient: recipientID} if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { // Still send sync messages for read receipts - cli.sendSyncCopy(ctx, content, messageTimestamp, res) + cli.sendSyncCopy(ctx, content, messageTimestamp, &res) } return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} } isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY if recipientID == cli.Store.ACIServiceID() && !isDeliveryReceipt { - res := &SuccessfulSendResult{ + res := SuccessfulSendResult{ Recipient: recipientID, Unidentified: false, } - ok := cli.sendSyncCopy(ctx, content, messageTimestamp, res) + ok := cli.sendSyncCopy(ctx, content, messageTimestamp, &res) return SendMessageResult{ WasSuccessful: ok, SuccessfulSendResult: res, @@ -743,7 +743,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv if err != nil { return SendMessageResult{ WasSuccessful: false, - FailedSendResult: &FailedSendResult{ + FailedSendResult: FailedSendResult{ Recipient: recipientID, Error: err, }, @@ -751,7 +751,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } result := SendMessageResult{ WasSuccessful: true, - SuccessfulSendResult: &SuccessfulSendResult{ + SuccessfulSendResult: SuccessfulSendResult{ Recipient: recipientID, Unidentified: sentUnidentified, }, @@ -768,7 +768,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } } - cli.sendSyncCopy(ctx, content, messageTimestamp, result.SuccessfulSendResult) + cli.sendSyncCopy(ctx, content, messageTimestamp, &result.SuccessfulSendResult) return result } From 31a4522ee66e5b1d52055ea5fd093602bb7d243e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 17 Aug 2024 23:26:25 +0300 Subject: [PATCH 293/718] legacyprovision: log out other logins when logging into new one --- cmd/mautrix-signal/legacyprovision.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmd/mautrix-signal/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go index 8e8e752..013d1bd 100644 --- a/cmd/mautrix-signal/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -17,6 +17,7 @@ package main import ( + "context" "encoding/json" "fmt" "net/http" @@ -27,6 +28,7 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" "maunium.net/go/mautrix" + "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/id" @@ -188,10 +190,20 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { UUID: string(res.CompleteParams.UserLogin.ID), Number: res.CompleteParams.UserLogin.RemoteName, }) + go handleLoginComplete(r.Context(), login.User, res.CompleteParams.UserLogin) } login.Delete() } +func handleLoginComplete(ctx context.Context, user *bridgev2.User, newLogin *bridgev2.UserLogin) { + allLogins := user.GetCachedUserLogins() + for _, login := range allLogins { + if login.ID != newLogin.ID { + login.Delete(ctx, status.BridgeState{StateEvent: status.StateLoggedOut, Reason: "LOGIN_OVERRIDDEN"}, bridgev2.DeleteOpts{}) + } + } +} + func legacyProvLogout(w http.ResponseWriter, r *http.Request) { // No-op for backwards compatibility JSONResponse(w, http.StatusOK, nil) From 7ad59f26948cead67371cf2e58c157da2d80cbc1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 21 Aug 2024 13:20:05 +0300 Subject: [PATCH 294/718] userinfo: implement `use_outdated_profiles` config option Fixes #538 --- pkg/connector/chatinfo.go | 12 ++++++++++++ pkg/connector/dbmeta.go | 4 +++- pkg/signalid/dbmeta.go | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 69af735..7bd392f 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -49,6 +49,10 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( if err != nil { return nil, err } + meta := ghost.Metadata.(*signalid.GhostMetadata) + if !s.Main.Config.UseOutdatedProfiles && meta.ProfileFetchedAt.After(contact.Profile.FetchedAt) { + return nil, nil + } return s.contactToUserInfo(contact), nil } @@ -74,6 +78,14 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use ui := &bridgev2.UserInfo{ IsBot: &isBot, Identifiers: []string{}, + ExtraUpdates: func(ctx context.Context, ghost *bridgev2.Ghost) (changed bool) { + meta := ghost.Metadata.(*signalid.GhostMetadata) + if meta.ProfileFetchedAt.Before(contact.Profile.FetchedAt) { + changed = meta.ProfileFetchedAt.IsZero() && !contact.Profile.FetchedAt.IsZero() + meta.ProfileFetchedAt.Time = contact.Profile.FetchedAt + } + return false + }, } if contact.E164 != "" { ui.Identifiers = append(ui.Identifiers, "tel:"+contact.E164) diff --git a/pkg/connector/dbmeta.go b/pkg/connector/dbmeta.go index 14f59f2..4ee3b08 100644 --- a/pkg/connector/dbmeta.go +++ b/pkg/connector/dbmeta.go @@ -27,7 +27,9 @@ func (s *SignalConnector) GetDBMetaTypes() database.MetaTypes { Portal: func() any { return &signalid.PortalMetadata{} }, - Ghost: nil, + Ghost: func() any { + return &signalid.GhostMetadata{} + }, Message: func() any { return &signalid.MessageMetadata{} }, diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index 2b5a164..5a96b07 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -16,6 +16,10 @@ package signalid +import ( + "go.mau.fi/util/jsontime" +) + type PortalMetadata struct { Revision uint32 `json:"revision,omitempty"` } @@ -23,3 +27,7 @@ type PortalMetadata struct { type MessageMetadata struct { ContainsAttachments bool `json:"contains_attachments,omitempty"` } + +type GhostMetadata struct { + ProfileFetchedAt jsontime.UnixMilli `json:"profile_fetched_at"` +} From 162cfdba68bf26fbcee1d9614ce2e2173b18964f Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:42:59 +0200 Subject: [PATCH 295/718] handlematrix: add support for power levels (#531) --- pkg/connector/handlematrix.go | 93 +++++++++++++++++++++++++++++------ pkg/signalid/ids.go | 12 +++++ 2 files changed, 91 insertions(+), 14 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 87cebe2..4984b25 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -359,25 +359,24 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 return false, nil } } - if msg.TargetGhost != nil { - targetIntent = msg.TargetGhost.Intent - targetSignalID, err = signalid.ParseUserID(msg.TargetGhost.ID) - if err != nil { - return false, fmt.Errorf("failed to parse target ghost signal id: %w", err) - } - } else if msg.TargetUserLogin != nil { - targetSignalID, err = signalid.ParseUserLoginID(msg.TargetUserLogin.ID) - if err != nil { - return false, fmt.Errorf("failed to parse target user signal id: %w", err) - } - targetIntent = msg.TargetUserLogin.User.DoublePuppet(ctx) + targetSignalID, err = signalid.ParseGhostOrUserLoginID(msg.Target) + if err != nil { + return false, fmt.Errorf("failed to parse target signal id: %w", err) + } + switch target := msg.Target.(type) { + case *bridgev2.Ghost: + targetIntent = target.Intent + case *bridgev2.UserLogin: + targetIntent = target.User.DoublePuppet(ctx) if targetIntent == nil { - ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(msg.TargetUserLogin.ID)) + ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(target.ID)) if err != nil { return false, fmt.Errorf("failed to get ghost for user: %w", err) } targetIntent = ghost.Intent } + default: + return false, fmt.Errorf("cannot get target intent: unknown type: %T", target) } log := zerolog.Ctx(ctx).With(). Str("From Membership", string(msg.Type.From)). @@ -389,7 +388,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 levels, err := msg.Portal.Bridge.Matrix.GetPowerLevels(ctx, msg.Portal.MXID) if err != nil { log.Err(err).Msg("Couldn't get power levels") - if levels.GetUserLevel(targetIntent.GetMXID()) >= 50 { + if levels.GetUserLevel(targetIntent.GetMXID()) >= moderatorPL { role = signalmeow.GroupMember_ADMINISTRATOR } } @@ -472,3 +471,69 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision return true, nil } + +func plToRole(pl int) signalmeow.GroupMemberRole { + if pl >= moderatorPL { + return signalmeow.GroupMember_ADMINISTRATOR + } else { + return signalmeow.GroupMember_DEFAULT + } +} + +func plToAccessControl(pl int) *signalmeow.AccessControl { + var accessControl signalmeow.AccessControl + if pl >= moderatorPL { + accessControl = signalmeow.AccessControl_ADMINISTRATOR + } else { + accessControl = signalmeow.AccessControl_MEMBER + } + return &accessControl +} + +func hasAdminChanged(plc *bridgev2.SinglePowerLevelChange) bool { + if plc == nil { + return false + } + return (plc.NewLevel < moderatorPL) != (plc.OrigLevel < moderatorPL) +} + +func (s *SignalClient) HandleMatrixPowerLevels(ctx context.Context, msg *bridgev2.MatrixPowerLevelChange) (bool, error) { + if msg.Portal.RoomType == database.RoomTypeDM { + return false, nil + } + log := zerolog.Ctx(ctx) + gc := &signalmeow.GroupChange{} + for _, plc := range msg.Users { + if !hasAdminChanged(&plc.SinglePowerLevelChange) { + continue + } + aci, err := signalid.ParseGhostOrUserLoginID(plc.Target) + if err != nil { + log.Err(err).Msg("Couldn't parse user id") + } + gc.ModifyMemberRoles = append(gc.ModifyMemberRoles, &signalmeow.RoleMember{ + ACI: aci, + Role: plToRole(plc.NewLevel), + }) + } + if hasAdminChanged(msg.EventsDefault) { + announcementsOnly := msg.EventsDefault.NewLevel >= moderatorPL + gc.ModifyAnnouncementsOnly = &announcementsOnly + } + if hasAdminChanged(msg.StateDefault) { + gc.ModifyAttributesAccess = plToAccessControl(msg.StateDefault.NewLevel) + } + if hasAdminChanged(msg.Invite) { + gc.ModifyMemberAccess = plToAccessControl(msg.Invite.NewLevel) + } + _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) + if err != nil || groupID == "" { + return false, err + } + revision, err := s.Client.UpdateGroup(ctx, gc, groupID) + if err != nil { + return false, err + } + msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision + return true, nil +} diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go index 99ef7b3..ec002ce 100644 --- a/pkg/signalid/ids.go +++ b/pkg/signalid/ids.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/google/uuid" + "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -47,6 +48,17 @@ func ParseUserLoginID(userLoginID networkid.UserLoginID) (uuid.UUID, error) { return userID, nil } +func ParseGhostOrUserLoginID(ghostOrUserLogin bridgev2.GhostOrUserLogin) (uuid.UUID, error) { + switch ghostOrUserLogin := ghostOrUserLogin.(type) { + case *bridgev2.UserLogin: + return ParseUserLoginID(ghostOrUserLogin.ID) + case *bridgev2.Ghost: + return ParseUserID(ghostOrUserLogin.ID) + default: + return uuid.Nil, fmt.Errorf("cannot parse ID: unknown type: %T", ghostOrUserLogin) + } +} + func ParseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { return libsignalgo.ServiceIDFromString(string(userID)) } From 460379b7d93c43a8664edcac284b039fb6d1a5c0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 23 Aug 2024 18:07:58 +0300 Subject: [PATCH 296/718] signalmeow: log all profile fetch errors at debug level --- pkg/signalmeow/contact.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index a8e8285..fdea194 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -22,7 +22,6 @@ import ( "crypto/sha256" "encoding/binary" "encoding/hex" - "errors" "fmt" "net/http" "strings" @@ -82,11 +81,7 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, profile, err := cli.RetrieveProfileByID(ctx, aci) if err != nil { - logLevel := zerolog.ErrorLevel - if errors.Is(err, errProfileKeyNotFound) { - logLevel = zerolog.DebugLevel - } - log.WithLevel(logLevel).Err(err).Msg("Failed to fetch profile") + log.Debug().Err(err).Msg("Failed to fetch profile") // Continue to return contact without profile } return cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { From e74b5cc243e16d03adc71d77e4732a75957dbc16 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 27 Aug 2024 22:14:35 +0300 Subject: [PATCH 297/718] dependencies: update mautrix-go --- go.mod | 6 ++++-- go.sum | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 3ea65bd..5a7fd59 100644 --- a/go.mod +++ b/go.mod @@ -10,16 +10,17 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.7.0 + go.mau.fi/util v0.7.1-0.20240827112829-84c63841c264 golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240817111253-2355d70426f4 + maunium.net/go/mautrix v0.20.1-0.20240827191023-f56905a27645 nhooyr.io/websocket v1.8.17 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -38,6 +39,7 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.4 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.17.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 3cabb48..026d636 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 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/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -62,8 +64,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.7.0 h1:l31z+ivrSQw+cv/9eFebEqtQW2zhxivGypn+JT0h/ws= -go.mau.fi/util v0.7.0/go.mod h1:bWYreIoTULL/UiRbZdfddPh7uWDFW5yX4YCv5FB0eE0= +go.mau.fi/util v0.7.1-0.20240827112829-84c63841c264 h1:mWujT3q8pxyJc/3BvWTgTN4+k41d1pBCvwxH56prqQA= +go.mau.fi/util v0.7.1-0.20240827112829-84c63841c264/go.mod h1:WuAOOV0O/otkxGkFUvfv/XE2ztegaoyM15ovS6SYbf4= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= @@ -72,6 +74,8 @@ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDT golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -90,7 +94,7 @@ 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.20.1-0.20240817111253-2355d70426f4 h1:S4+mHwQC2CiCTl0cn21zd4V8JiqGYMYlsde2v7jC8bE= -maunium.net/go/mautrix v0.20.1-0.20240817111253-2355d70426f4/go.mod h1:V725r8w7oddsS7CxnmTAp634A4nwJCFY7J3jiTMUz2c= +maunium.net/go/mautrix v0.20.1-0.20240827191023-f56905a27645 h1:44YDJap8wHIHJV3dt4ZIojQnnlIEd60Beh8fFP7Xsz4= +maunium.net/go/mautrix v0.20.1-0.20240827191023-f56905a27645/go.mod h1:7hh/Hx5W9lUcqL0hkSw52kMyY+6nMUPTtdDN0qVEXwI= nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 4d46dd703f7385b1eabf1fb950f11c18800028a7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Sep 2024 12:24:56 +0300 Subject: [PATCH 298/718] dependencies: update libsignal and others --- go.mod | 8 +- go.sum | 15 +-- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 163 +------------------------------- pkg/libsignalgo/version.go | 2 +- 5 files changed, 16 insertions(+), 174 deletions(-) diff --git a/go.mod b/go.mod index 5a7fd59..e4c6005 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.7.1-0.20240827112829-84c63841c264 + go.mau.fi/util v0.7.1-0.20240901193650-bf007b10eaf6 golang.org/x/crypto v0.26.0 - golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa + golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240827191023-f56905a27645 + maunium.net/go/mautrix v0.20.1-0.20240902092346-6f1a3878c452 nhooyr.io/websocket v1.8.17 ) @@ -32,7 +32,7 @@ require ( github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/rs/xid v1.5.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.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect diff --git a/go.sum b/go.sum index 026d636..2d7ba8f 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN 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= -github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= @@ -64,14 +65,14 @@ 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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.7.1-0.20240827112829-84c63841c264 h1:mWujT3q8pxyJc/3BvWTgTN4+k41d1pBCvwxH56prqQA= -go.mau.fi/util v0.7.1-0.20240827112829-84c63841c264/go.mod h1:WuAOOV0O/otkxGkFUvfv/XE2ztegaoyM15ovS6SYbf4= +go.mau.fi/util v0.7.1-0.20240901193650-bf007b10eaf6 h1:cSLCabMKbR6rTPYRGWD2XaHo210BK3BtPg+CRC4A4og= +go.mau.fi/util v0.7.1-0.20240901193650-bf007b10eaf6/go.mod h1:WuAOOV0O/otkxGkFUvfv/XE2ztegaoyM15ovS6SYbf4= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= +golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= @@ -94,7 +95,7 @@ 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.20.1-0.20240827191023-f56905a27645 h1:44YDJap8wHIHJV3dt4ZIojQnnlIEd60Beh8fFP7Xsz4= -maunium.net/go/mautrix v0.20.1-0.20240827191023-f56905a27645/go.mod h1:7hh/Hx5W9lUcqL0hkSw52kMyY+6nMUPTtdDN0qVEXwI= +maunium.net/go/mautrix v0.20.1-0.20240902092346-6f1a3878c452 h1:Yq7qZMP3y/BJ7/5aaDVPkRs9vZjtfwhcbDJuLWR8cVs= +maunium.net/go/mautrix v0.20.1-0.20240902092346-6f1a3878c452/go.mod h1:IXDDoX+dqBkNnrjDMouE3FUExiR+hhmaEFsvXG3HzfQ= nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index a8bc95b..e46841e 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit a8bc95bc7ebad76ee0bd467ece3321b886cbaef7 +Subproject commit e46841ea2c1ad03bc5113eba267ac1543689d031 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 8c443ac..c089648 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -20,8 +20,6 @@ SPDX-License-Identifier: AGPL-3.0-only */ #define SignalFourCC_ENCODED_LEN 4 -#define SignalBoxHeader_MAX_SIZE 32 - #define SignalNUM_AUTH_CRED_ATTRIBUTES 3 #define SignalNUM_PROFILE_KEY_CRED_ATTRIBUTES 4 @@ -240,10 +238,6 @@ typedef struct SignalMessageBackupKey SignalMessageBackupKey; typedef struct SignalMessageBackupValidationOutcome SignalMessageBackupValidationOutcome; -typedef struct SignalNonSuspendingBackgroundThreadRuntime SignalNonSuspendingBackgroundThreadRuntime; - -typedef struct SignalOtherTestingHandleType SignalOtherTestingHandleType; - typedef struct SignalPinHash SignalPinHash; typedef struct SignalPlaintextContent SignalPlaintextContent; @@ -263,10 +257,9 @@ typedef struct SignalProtocolAddress SignalProtocolAddress; typedef struct SignalPublicKey SignalPublicKey; -/** - * Sanitized metadata returned by the sanitizer. - */ +#if defined(SIGNAL_MEDIA_SUPPORTED) typedef struct SignalSanitizedMetadata SignalSanitizedMetadata; +#endif typedef struct SignalSenderCertificate SignalSenderCertificate; @@ -305,8 +298,6 @@ typedef struct SignalMessage SignalMessage; typedef struct SignalSignedPreKeyRecord SignalSignedPreKeyRecord; -typedef struct SignalTestingHandleType SignalTestingHandleType; - typedef struct SignalTokioAsyncContext SignalTokioAsyncContext; typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMessageContent; @@ -674,66 +665,6 @@ typedef struct { typedef SignalInputStream SignalSyncInputStream; -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const int32_t *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromisei32; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, SignalTestingHandleType *const *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseTestingHandleType; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, SignalOtherTestingHandleType *const *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseOtherTestingHandleType; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const void *const *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseRawPointer; - typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN]; void signal_print_ptr(const void *p); @@ -1586,10 +1517,6 @@ SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncCont SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); -SignalFfiError *signal_testing_chat_service_inject_raw_server_request(const SignalChat *chat, SignalBorrowedBuffer bytes); - -SignalFfiError *signal_testing_chat_service_inject_connection_interrupted(const SignalChat *chat); - SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p); SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalServerMessageAck *ack); @@ -1694,90 +1621,4 @@ SignalFfiError *signal_sanitized_metadata_get_data_offset(uint64_t *out, const S SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, const SignalSanitizedMetadata *sanitized); #endif -SignalFfiError *signal_testing_NonSuspendingBackgroundThreadRuntime_destroy(SignalNonSuspendingBackgroundThreadRuntime *p); - -SignalFfiError *signal_testing_future_success(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input); - -SignalFfiError *signal_testing_future_failure(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t _input); - -SignalFfiError *signal_testing_handle_type_destroy(SignalTestingHandleType *p); - -SignalFfiError *signal_testing_handle_type_clone(SignalTestingHandleType **new_obj, const SignalTestingHandleType *obj); - -SignalFfiError *signal_testing_testing_handle_type_get_value(uint8_t *out, const SignalTestingHandleType *handle); - -SignalFfiError *signal_testing_future_produces_pointer_type(SignalCPromiseTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input); - -SignalFfiError *signal_other_testing_handle_type_destroy(SignalOtherTestingHandleType *p); - -SignalFfiError *signal_other_testing_handle_type_clone(SignalOtherTestingHandleType **new_obj, const SignalOtherTestingHandleType *obj); - -SignalFfiError *signal_testing_other_testing_handle_type_get_value(const char **out, const SignalOtherTestingHandleType *handle); - -SignalFfiError *signal_testing_future_produces_other_pointer_type(SignalCPromiseOtherTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const char *input); - -SignalFfiError *signal_testing_panic_on_borrow_sync(const void *_input); - -SignalFfiError *signal_testing_panic_on_borrow_async(const void *_input); - -SignalFfiError *signal_testing_panic_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); - -SignalFfiError *signal_testing_error_on_borrow_sync(const void *_input); - -SignalFfiError *signal_testing_error_on_borrow_async(const void *_input); - -SignalFfiError *signal_testing_error_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); - -SignalFfiError *signal_testing_panic_on_load_sync(const void *_needs_cleanup, const void *_input); - -SignalFfiError *signal_testing_panic_on_load_async(const void *_needs_cleanup, const void *_input); - -SignalFfiError *signal_testing_panic_on_load_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup, const void *_input); - -SignalFfiError *signal_testing_panic_in_body_sync(const void *_input); - -SignalFfiError *signal_testing_panic_in_body_async(const void *_input); - -SignalFfiError *signal_testing_panic_in_body_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input); - -SignalFfiError *signal_testing_panic_on_return_sync(const void **out, const void *_needs_cleanup); - -SignalFfiError *signal_testing_panic_on_return_async(const void **out, const void *_needs_cleanup); - -SignalFfiError *signal_testing_panic_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); - -SignalFfiError *signal_testing_error_on_return_sync(const void **out, const void *_needs_cleanup); - -SignalFfiError *signal_testing_error_on_return_async(const void **out, const void *_needs_cleanup); - -SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup); - -SignalFfiError *signal_testing_return_string_array(SignalStringArray *out); - -SignalFfiError *signal_testing_process_bytestring_array(SignalBytestringArray *out, SignalBorrowedSliceOfBuffers input); - -SignalFfiError *signal_testing_input_stream_read_into_zero_length_slice(SignalOwnedBuffer *out, const SignalInputStream *caps_alphabet_input); - -SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime); - -SignalFfiError *signal_testing_only_completes_by_cancellation(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime); - -SignalFfiError *signal_testing_cdsi_lookup_error_convert(const char *error_description); - -SignalFfiError *signal_testing_chat_service_error_convert(const char *error_description); - -SignalFfiError *signal_testing_chat_service_response_convert(SignalFfiChatResponse *out, bool body_present); - -SignalFfiError *signal_testing_chat_service_debug_info_convert(SignalFfiChatServiceDebugInfo *out); - -SignalFfiError *signal_testing_chat_service_response_and_debug_info_convert(SignalFfiResponseAndDebugInfo *out); - -SignalFfiError *signal_testing_chat_request_get_method(const char **out, const SignalHttpRequest *request); - -SignalFfiError *signal_testing_chat_request_get_path(const char **out, const SignalHttpRequest *request); - -SignalFfiError *signal_testing_chat_request_get_header_value(const char **out, const SignalHttpRequest *request, const char *header_name); - -SignalFfiError *signal_testing_chat_request_get_body(SignalOwnedBuffer *out, const SignalHttpRequest *request); - #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index cb4bd77..e36a12a 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.55.0" +const Version = "v0.56.1" From 33496974088feaeef0a50b3f127a8d09f5045149 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Sep 2024 02:45:38 +0300 Subject: [PATCH 299/718] msgconv/from-matrix: convert voice messages to raw aac instead of m4a Apparently Signal iOS doesn't like ffmpeg's m4a's, but is fine with aac? --- pkg/msgconv/from-matrix.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 3b61b9f..2a282fc 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -157,12 +157,12 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. } mime := content.GetInfo().MimeType if content.MSC3245Voice != nil && ffmpeg.Supported() { - data, err = ffmpeg.ConvertBytes(ctx, data, ".m4a", []string{}, []string{"-c:a", "aac"}, mime) + data, err = ffmpeg.ConvertBytes(ctx, data, ".aac", []string{}, []string{"-c:a", "aac"}, mime) if err != nil { return nil, err } mime = "audio/aac" - fileName += ".m4a" + fileName += ".aac" } else if evt.Type == event.EventSticker { switch mime { case "image/webp", "image/png", "image/apng": From e36642bab8764f97c5ea16548c5e1a102c1fae1c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Sep 2024 03:02:50 +0300 Subject: [PATCH 300/718] signalmeow/sending: always include expiration start in sync messages --- pkg/signalmeow/sending.go | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index cc156c9..20be143 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -30,6 +30,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exfmt" + "go.mau.fi/util/ptr" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -327,9 +328,10 @@ func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - Message: dataMessage, - Timestamp: dataMessage.Timestamp, - UnidentifiedStatus: unidentifiedStatuses, + Message: dataMessage, + Timestamp: dataMessage.Timestamp, + UnidentifiedStatus: unidentifiedStatuses, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), }, }, } @@ -345,9 +347,10 @@ func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - EditMessage: editMessage, - Timestamp: editMessage.GetDataMessage().Timestamp, - UnidentifiedStatus: unidentifiedStatuses, + EditMessage: editMessage, + Timestamp: editMessage.GetDataMessage().Timestamp, + UnidentifiedStatus: unidentifiedStatuses, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), }, }, } @@ -357,10 +360,11 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - Message: dataMessage, - DestinationE164: result.RecipientE164, - DestinationServiceId: proto.String(result.Recipient.String()), - Timestamp: dataMessage.Timestamp, + Message: dataMessage, + DestinationE164: result.RecipientE164, + DestinationServiceId: proto.String(result.Recipient.String()), + Timestamp: dataMessage.Timestamp, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { DestinationServiceId: proto.String(result.Recipient.String()), @@ -377,10 +381,11 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - EditMessage: editMessage, - DestinationE164: result.RecipientE164, - DestinationServiceId: proto.String(result.Recipient.String()), - Timestamp: editMessage.DataMessage.Timestamp, + EditMessage: editMessage, + DestinationE164: result.RecipientE164, + DestinationServiceId: proto.String(result.Recipient.String()), + Timestamp: editMessage.DataMessage.Timestamp, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { DestinationServiceId: proto.String(result.Recipient.String()), From bf63aa1aa63e049373df7a62866eab6b8dfb25a0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Sep 2024 03:03:37 +0300 Subject: [PATCH 301/718] signalmeow: adjust raw data logs --- pkg/signalmeow/receiving.go | 2 +- pkg/signalmeow/sending.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index bfceca6..6f40a7f 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -643,10 +643,10 @@ func (cli *Client) handleDecryptedResult( } content := result.Content - log.Trace().Any("raw_data", content).Msg("Raw event data") name, _ := result.SenderAddress.Name() deviceId, _ := result.SenderAddress.DeviceID() + log.Trace().Any("raw_data", content).Str("sender", name).Uint("sender_device", deviceId).Msg("Raw event data") newLog := log.With(). Str("sender_name", name). Uint("sender_device_id", deviceId). diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 20be143..0236331 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -797,7 +797,7 @@ func (cli *Client) sendContent( Logger() ctx = log.WithContext(ctx) printContentFieldString(ctx, content, "Outgoing message") - log.Trace().Any("raw_content", content).Msg("Raw data of outgoing message") + log.Trace().Any("raw_content", content).Stringer("recipient", recipient).Msg("Raw data of outgoing message") // If it's a data message, add our profile key if content.DataMessage != nil { From b1bd303b0e8d75a88b69adf02348dfdcac8e336c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Sep 2024 20:12:28 +0300 Subject: [PATCH 302/718] client: register capabilities on connect --- pkg/connector/client.go | 6 ++++++ pkg/signalmeow/provisioning.go | 29 ++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 56ab59a..ebd2def 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -240,6 +240,12 @@ func (s *SignalClient) Disconnect() { } func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { + err := s.Client.RegisterCapabilities(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to register capabilities") + } else { + zerolog.Ctx(ctx).Debug().Msg("Successfully registered capabilities") + } ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index f3abb2c..160bdec 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -330,6 +330,31 @@ func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningC return provisioningMessage, err } +var signalCapabilities = map[string]any{ + "deleteSync": true, +} + +var signalCapabilitiesBody = exerrors.Must(json.Marshal(signalCapabilities)) + +func (cli *Client) RegisterCapabilities(ctx context.Context) error { + username, password := cli.Store.BasicAuthCreds() + resp, err := web.SendHTTPRequest(ctx, http.MethodPut, "/v1/devices/capabilities", &web.HTTPReqOpt{ + Body: signalCapabilitiesBody, + Username: &username, + Password: &password, + ContentType: web.ContentTypeJSON, + }) + if resp != nil { + _ = resp.Body.Close() + } + if err != nil { + return err + } else if resp.StatusCode >= 400 { + return fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + return nil +} + func confirmDevice( ctx context.Context, username string, @@ -383,9 +408,7 @@ func confirmDevice( "name": encryptedDeviceName, "registrationId": aciRegistrationID, "pniRegistrationId": pniRegistrationID, - "capabilities": map[string]any{ - "deleteSync": true, - }, + "capabilities": signalCapabilities, }, "aciSignedPreKey": aciSignedPreKeyJson, "pniSignedPreKey": pniSignedPreKeyJson, From 81841f4a822881cace1a8e527d23843a9292faaf Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Sep 2024 20:22:42 +0300 Subject: [PATCH 303/718] dbmeta: add support for expiration timer versions --- pkg/msgconv/from-matrix.go | 4 +++ pkg/msgconv/from-signal.go | 18 ++++++++-- pkg/signalid/dbmeta.go | 3 +- pkg/signalmeow/protobuf/SignalService.pb.go | 36 +++++++++++++------ pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19040 -> 19136 bytes pkg/signalmeow/protobuf/SignalService.proto | 24 +++++++------ pkg/signalmeow/protobuf/update-protos.sh | 4 +-- pkg/signalmeow/provisioning.go | 3 +- 8 files changed, 65 insertions(+), 27 deletions(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 2a282fc..cb938e7 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -78,6 +78,10 @@ func (mc *MessageConverter) ToSignal( } if portal.Disappear.Timer > 0 { dm.ExpireTimer = proto.Uint32(uint32(portal.Disappear.Timer.Seconds())) + timerVersion := portal.Metadata.(*signalid.PortalMetadata).ExpirationTimerVersion + if timerVersion > 0 { + dm.ExpireTimerVersion = &timerVersion + } } if content.MsgType == event.MsgEmote && !relaybotFormatted { content.Body = "/me " + content.Body diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 4b09e80..20dd39b 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -85,7 +85,7 @@ func (mc *MessageConverter) ToMatrix( Parts: make([]*bridgev2.ConvertedMessagePart, 0, calculateLength(dm)), } if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { - cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), true)) + cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), dm.ExpireTimerVersion, true)) // Don't allow any other parts in a disappearing timer change message return cm } @@ -151,7 +151,7 @@ func (mc *MessageConverter) ToMatrix( return cm } -func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, updatePortal bool) *bridgev2.ConvertedMessagePart { +func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, timerVersion *uint32, updatePortal bool) *bridgev2.ConvertedMessagePart { part := &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ @@ -164,12 +164,26 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C } if updatePortal { portal := getPortal(ctx) + portalMeta := portal.Metadata.(*signalid.PortalMetadata) + if timerVersion != nil && portalMeta.ExpirationTimerVersion > *timerVersion { + zerolog.Ctx(ctx).Warn(). + Uint32("current_version", portalMeta.ExpirationTimerVersion). + Uint32("new_version", *timerVersion). + Msg("Ignoring outdated disappearing timer change") + part.Content.Body += " (change ignored)" + return part + } portal.Disappear.Timer = time.Duration(timer) * time.Second if timer == 0 { portal.Disappear.Type = "" } else { portal.Disappear.Type = database.DisappearingTypeAfterRead } + if timerVersion != nil { + portalMeta.ExpirationTimerVersion = *timerVersion + } else { + portalMeta.ExpirationTimerVersion = 1 + } err := portal.Save(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index 5a96b07..f3811af 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -21,7 +21,8 @@ import ( ) type PortalMetadata struct { - Revision uint32 `json:"revision,omitempty"` + Revision uint32 `json:"revision,omitempty"` + ExpirationTimerVersion uint32 `json:"expiration_timer_version,omitempty"` } type MessageMetadata struct { diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index f382b8b..f524c90 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -2163,6 +2163,7 @@ type DataMessage struct { GroupV2 *GroupContextV2 `protobuf:"bytes,15,opt,name=groupV2" json:"groupV2,omitempty"` Flags *uint32 `protobuf:"varint,4,opt,name=flags" json:"flags,omitempty"` ExpireTimer *uint32 `protobuf:"varint,5,opt,name=expireTimer" json:"expireTimer,omitempty"` + ExpireTimerVersion *uint32 `protobuf:"varint,23,opt,name=expireTimerVersion" json:"expireTimerVersion,omitempty"` ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` Timestamp *uint64 `protobuf:"varint,7,opt,name=timestamp" json:"timestamp,omitempty"` Quote *DataMessage_Quote `protobuf:"bytes,8,opt,name=quote" json:"quote,omitempty"` @@ -2247,6 +2248,13 @@ func (x *DataMessage) GetExpireTimer() uint32 { return 0 } +func (x *DataMessage) GetExpireTimerVersion() uint32 { + if x != nil && x.ExpireTimerVersion != nil { + return *x.ExpireTimerVersion + } + return 0 +} + func (x *DataMessage) GetProfileKey() []byte { if x != nil { return x.ProfileKey @@ -3464,16 +3472,17 @@ type ContactDetails struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Number *string `protobuf:"bytes,1,opt,name=number" json:"number,omitempty"` - Aci *string `protobuf:"bytes,9,opt,name=aci" json:"aci,omitempty"` - Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - Avatar *ContactDetails_Avatar `protobuf:"bytes,3,opt,name=avatar" json:"avatar,omitempty"` - Color *string `protobuf:"bytes,4,opt,name=color" json:"color,omitempty"` - Verified *Verified `protobuf:"bytes,5,opt,name=verified" json:"verified,omitempty"` - ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` - ExpireTimer *uint32 `protobuf:"varint,8,opt,name=expireTimer" json:"expireTimer,omitempty"` - InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` - Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` + Number *string `protobuf:"bytes,1,opt,name=number" json:"number,omitempty"` + Aci *string `protobuf:"bytes,9,opt,name=aci" json:"aci,omitempty"` + Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Avatar *ContactDetails_Avatar `protobuf:"bytes,3,opt,name=avatar" json:"avatar,omitempty"` + Color *string `protobuf:"bytes,4,opt,name=color" json:"color,omitempty"` + Verified *Verified `protobuf:"bytes,5,opt,name=verified" json:"verified,omitempty"` + ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` + ExpireTimer *uint32 `protobuf:"varint,8,opt,name=expireTimer" json:"expireTimer,omitempty"` + ExpireTimerVersion *uint32 `protobuf:"varint,12,opt,name=expireTimerVersion" json:"expireTimerVersion,omitempty"` + InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` + Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` } func (x *ContactDetails) Reset() { @@ -3564,6 +3573,13 @@ func (x *ContactDetails) GetExpireTimer() uint32 { return 0 } +func (x *ContactDetails) GetExpireTimerVersion() uint32 { + if x != nil && x.ExpireTimerVersion != nil { + return *x.ExpireTimerVersion + } + return 0 +} + func (x *ContactDetails) GetInboxPosition() uint32 { if x != nil && x.InboxPosition != nil { return *x.InboxPosition diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw index 2ca3d164ba21b6b1ed160d649962a9e9d2aaeb9c..bc9a4d57969c32e0c0d280ef3808c2a3c4c70bbb 100644 GIT binary patch delta 128 zcmaDbh4H{t#tp}~7++03&UHgyk4q@Eq9C&b37uWoK~k!Hl9mj|cbIj%=o02{F{IsgCw delta 32 qcmV+*0N?+>l>y+C0kFmj0lJgN3fQyH3*tBdrL(d`8v(QZMZ*ODbPo{# diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 1e2332b..c516a1b 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -332,6 +332,7 @@ message DataMessage { optional GroupContextV2 groupV2 = 15; optional uint32 flags = 4; optional uint32 expireTimer = 5; + optional uint32 expireTimerVersion = 23; optional bytes profileKey = 6; optional uint64 timestamp = 7; optional Quote quote = 8; @@ -793,17 +794,18 @@ message ContactDetails { optional uint32 length = 2; } - optional string number = 1; - optional string aci = 9; - optional string name = 2; - optional Avatar avatar = 3; - optional string color = 4; - optional Verified verified = 5; - optional bytes profileKey = 6; - reserved /*blocked*/ 7; - optional uint32 expireTimer = 8; - optional uint32 inboxPosition = 10; - optional bool archived = 11; + optional string number = 1; + optional string aci = 9; + optional string name = 2; + optional Avatar avatar = 3; + optional string color = 4; + optional Verified verified = 5; + optional bytes profileKey = 6; + reserved /*blocked*/ 7; + optional uint32 expireTimer = 8; + optional uint32 expireTimerVersion = 12; + optional uint32 inboxPosition = 10; + optional bool archived = 11; } message GroupDetails { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 9735ecf..43790f4 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-68c7ce582378b5f752e5971007b2c203e81cecbd} -DESKTOP_GIT_REVISION=${1:-faea93e5cea24893a8976dc6329faa751f59df5c} +ANDROID_GIT_REVISION=${1:-ab7bdc3c03ecda2d746fd56cfd747f56feab7b17} +DESKTOP_GIT_REVISION=${1:-1898e964adcfc8a9096b4aaebff895813fb4f35c} update_proto() { case "$1" in diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 160bdec..5c09457 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -331,7 +331,8 @@ func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningC } var signalCapabilities = map[string]any{ - "deleteSync": true, + "deleteSync": true, + "versionedExpirationTimer": true, } var signalCapabilitiesBody = exerrors.Must(json.Marshal(signalCapabilities)) From 92d338b8ad41a2f808914b8f75dbae0bf22dbc44 Mon Sep 17 00:00:00 2001 From: 1Conan Date: Wed, 4 Sep 2024 22:52:12 +0800 Subject: [PATCH 304/718] add iOS to serviceid --- pkg/libsignalgo/serviceid_clang.go | 2 +- pkg/libsignalgo/serviceid_gcc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/serviceid_clang.go b/pkg/libsignalgo/serviceid_clang.go index 067d9d1..3e9ae17 100644 --- a/pkg/libsignalgo/serviceid_clang.go +++ b/pkg/libsignalgo/serviceid_clang.go @@ -1,4 +1,4 @@ -//go:build darwin || android +//go:build darwin || android || ios package libsignalgo diff --git a/pkg/libsignalgo/serviceid_gcc.go b/pkg/libsignalgo/serviceid_gcc.go index 0d0f5c8..9ff97bc 100644 --- a/pkg/libsignalgo/serviceid_gcc.go +++ b/pkg/libsignalgo/serviceid_gcc.go @@ -1,4 +1,4 @@ -//go:build !(darwin || android) +//go:build !(darwin || android || ios) package libsignalgo From ea8208b9e0aeb1623eb8efe9caed2e636be4a165 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 6 Sep 2024 14:04:29 +0300 Subject: [PATCH 305/718] dependencies: update mautrix-go --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- pkg/connector/handlematrix.go | 7 +++++-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index e4c6005..664b59e 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.7.1-0.20240901193650-bf007b10eaf6 + go.mau.fi/util v0.7.1-0.20240904173517-ca3b3fe376c2 golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240902092346-6f1a3878c452 + maunium.net/go/mautrix v0.20.1-0.20240906105454-33d724bf4c78 nhooyr.io/websocket v1.8.17 ) @@ -28,7 +28,7 @@ require ( github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mattn/go-sqlite3 v1.14.23 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -40,8 +40,8 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 2d7ba8f..1f7751c 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/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.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0= +github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.7.1-0.20240901193650-bf007b10eaf6 h1:cSLCabMKbR6rTPYRGWD2XaHo210BK3BtPg+CRC4A4og= -go.mau.fi/util v0.7.1-0.20240901193650-bf007b10eaf6/go.mod h1:WuAOOV0O/otkxGkFUvfv/XE2ztegaoyM15ovS6SYbf4= +go.mau.fi/util v0.7.1-0.20240904173517-ca3b3fe376c2 h1:VZQlKBbeJ7KOlYSh6BnN5uWQTY/ypn/bJv0YyEd+pXc= +go.mau.fi/util v0.7.1-0.20240904173517-ca3b3fe376c2/go.mod h1:WgYvbt9rVmoFeajP97NunQU7AjgvTPiNExN3oTHeePs= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= @@ -80,10 +80,10 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -95,7 +95,7 @@ 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.20.1-0.20240902092346-6f1a3878c452 h1:Yq7qZMP3y/BJ7/5aaDVPkRs9vZjtfwhcbDJuLWR8cVs= -maunium.net/go/mautrix v0.20.1-0.20240902092346-6f1a3878c452/go.mod h1:IXDDoX+dqBkNnrjDMouE3FUExiR+hhmaEFsvXG3HzfQ= +maunium.net/go/mautrix v0.20.1-0.20240906105454-33d724bf4c78 h1:F8ls6UNW8QlTpQ2QAnPuCN5gVB30Y3ojBYfXb9T6U64= +maunium.net/go/mautrix v0.20.1-0.20240906105454-33d724bf4c78/go.mod h1:l6nYvD5/FMSrAZ/IP1AqJV0b47SRl/0uQNRiy4CcSVk= nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 4984b25..fb3b1d9 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -83,12 +83,14 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma if err != nil { return nil, err } + msgID := signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) + msg.AddPendingToIgnore(networkid.TransactionID(msgID)) err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) if err != nil { return nil, bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } dbMsg := &database.Message{ - ID: signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()), + ID: msgID, SenderID: signalid.MakeUserID(s.Client.Store.ACI), Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), Metadata: &signalid.MessageMetadata{ @@ -96,7 +98,8 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma }, } return &bridgev2.MatrixMessageResponse{ - DB: dbMsg, + DB: dbMsg, + RemovePending: networkid.TransactionID(msgID), }, nil } From 798ebb689ff9642920871b5761533d0cf7b0a442 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Sep 2024 19:25:08 +0300 Subject: [PATCH 306/718] handlesignal: bridge decryption errors --- pkg/connector/handlesignal.go | 61 +++++++++++++++++++++++++------- pkg/signalmeow/events/message.go | 5 +-- pkg/signalmeow/receiving.go | 11 +++--- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 2f6803d..7275905 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -28,6 +28,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/bridgev2/simplevent" "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalid" @@ -40,6 +41,7 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { case *events.ChatEvent: s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) case *events.DecryptionError: + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapDecryptionError(evt)) case *events.Receipt: s.handleSignalReceipt(evt) case *events.ReadSelf: @@ -54,19 +56,22 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { } func (s *SignalClient) wrapCallEvent(evt *events.Call) bridgev2.RemoteMessage { - return &bridgev2.SimpleRemoteEvent[*events.Call]{ - Type: bridgev2.RemoteEventMessage, - LogContext: func(c zerolog.Context) zerolog.Context { - c = c.Stringer("sender_id", evt.Info.Sender) - c = c.Uint64("message_ts", evt.Timestamp) - return c + return &simplevent.Message[*events.Call]{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventMessage, + LogContext: func(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Info.Sender) + c = c.Uint64("message_ts", evt.Timestamp) + return c + }, + PortalKey: s.makePortalKey(evt.Info.ChatID), + CreatePortal: true, + Sender: s.makeEventSender(evt.Info.Sender), + Timestamp: time.UnixMilli(int64(evt.Timestamp)), }, - PortalKey: s.makePortalKey(evt.Info.ChatID), - Data: evt, - CreatePortal: true, - ID: signalid.MakeMessageID(evt.Info.Sender, evt.Timestamp), - Sender: s.makeEventSender(evt.Info.Sender), - Timestamp: time.UnixMilli(int64(evt.Timestamp)), + Data: evt, + ID: signalid.MakeMessageID(evt.Info.Sender, evt.Timestamp), + ConvertMessageFunc: convertCallEvent, } } @@ -91,6 +96,38 @@ func convertCallEvent(ctx context.Context, portal *bridgev2.Portal, intent bridg }, nil } +func (s *SignalClient) wrapDecryptionError(evt *events.DecryptionError) bridgev2.RemoteMessage { + return &simplevent.Message[*events.DecryptionError]{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventMessage, + LogContext: func(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Sender) + return c + }, + PortalKey: s.makePortalKey(evt.Sender.String()), + CreatePortal: true, + Sender: s.makeEventSender(evt.Sender), + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + }, + Data: evt, + ID: "decrypterr|" + signalid.MakeMessageID(evt.Sender, evt.Timestamp), + + ConvertMessageFunc: convertDecryptionError, + } +} + +func convertDecryptionError(_ context.Context, _ *bridgev2.Portal, _ bridgev2.MatrixAPI, _ *events.DecryptionError) (*bridgev2.ConvertedMessage, error) { + return &bridgev2.ConvertedMessage{ + Parts: []*bridgev2.ConvertedMessagePart{{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: "Message couldn't be decrypted. It may have been in this chat or a group chat. Please check your Signal app.", + }, + }}, + }, nil +} + type Bv2ChatEvent struct { *events.ChatEvent s *SignalClient diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 0db0f24..a6fcc7f 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -49,8 +49,9 @@ type ChatEvent struct { } type DecryptionError struct { - Sender uuid.UUID - Err error + Sender uuid.UUID + Err error + Timestamp uint64 } type Receipt struct { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 6f40a7f..850e204 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -276,6 +276,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) log.Trace(). Uint64("timestamp", envelope.GetTimestamp()). + Uint64("server_timestamp", envelope.GetServerTimestamp()). Str("destination_service_id", envelope.GetDestinationServiceId()). Str("source_service_id", envelope.GetSourceServiceId()). Uint32("source_device_id", envelope.GetSourceDevice()). @@ -286,7 +287,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. result := cli.decryptEnvelope(ctx, envelope) - err = cli.handleDecryptedResult(ctx, result, destinationServiceID) + err = cli.handleDecryptedResult(ctx, result, destinationServiceID, envelope.GetServerTimestamp()) if err != nil { log.Err(err).Msg("handleDecryptedResult error") return nil, err @@ -613,6 +614,7 @@ func (cli *Client) handleDecryptedResult( ctx context.Context, result DecryptionResult, destinationServiceID libsignalgo.ServiceID, + serverTimestamp uint64, ) error { log := zerolog.Ctx(ctx) if result.Content == nil { @@ -623,19 +625,20 @@ func (cli *Client) handleDecryptedResult( // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted if result.Err != nil { - log.Err(result.Err).Bool("urgent", result.Urgent).Msg("Decryption error") theirServiceID, err := result.SenderAddress.NameServiceID() if err != nil { log.Err(err).Msg("Name error handling decryption error") } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") } + log.Err(result.Err).Stringer("sender", theirServiceID).Bool("urgent", result.Urgent).Msg("Decryption error") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot if result.Urgent { cli.handleEvent(&events.DecryptionError{ - Sender: theirServiceID.UUID, - Err: result.Err, + Sender: theirServiceID.UUID, + Err: result.Err, + Timestamp: serverTimestamp, }) } // Intentionally not returning here. In most cases there's nothing besides the error so From ffd1ba34c0ff4bf6ebdf5dff3692ec74de081641 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Sep 2024 20:55:43 +0300 Subject: [PATCH 307/718] signalmeow: clean up decryption code --- pkg/connector/handlesignal.go | 3 +- pkg/libsignalgo/sealedsender.go | 5 +- pkg/libsignalgo/session_test.go | 2 +- pkg/signalmeow/receiving.go | 302 +++++++++++++++----------------- 4 files changed, 148 insertions(+), 164 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 7275905..b39f202 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -110,7 +110,8 @@ func (s *SignalClient) wrapDecryptionError(evt *events.DecryptionError) bridgev2 Timestamp: time.UnixMilli(int64(evt.Timestamp)), }, Data: evt, - ID: "decrypterr|" + signalid.MakeMessageID(evt.Sender, evt.Timestamp), + // TODO use main message id and edit it if it later becomes decryptable? + ID: "decrypterr|" + signalid.MakeMessageID(evt.Sender, evt.Timestamp), ConvertMessageFunc: convertDecryptionError, } diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index f747b35..253e512 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -24,7 +24,6 @@ import "C" import ( "context" "runtime" - "time" "github.com/google/uuid" ) @@ -113,7 +112,7 @@ func SealedSenderDecrypt( ciphertext []byte, localAddress *SealedSenderAddress, trustRoot *PublicKey, - timestamp time.Time, + timestamp uint64, sessionStore SessionStore, identityStore IdentityKeyStore, preKeyStore PreKeyStore, @@ -134,7 +133,7 @@ func SealedSenderDecrypt( &senderDeviceID, BytesToBuffer(ciphertext), trustRoot.ptr, - C.uint64_t(timestamp.UnixMilli()), + C.uint64_t(timestamp), C.CString(localAddress.E164), C.CString(localAddress.UUID.String()), C.uint32_t(localAddress.DeviceID), diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index 17ea8c9..9d108d5 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -294,7 +294,7 @@ func TestSealedSenderSession(t *testing.T) { ciphertext, recipientAddress, trustRoot.GetPublicKey(), - time.UnixMilli(31335), + 31335, bobStore, bobStore, bobStore, diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 850e204..8a40a16 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -22,7 +22,6 @@ import ( "fmt" "net/http" "strings" - "time" "github.com/google/uuid" "github.com/rs/zerolog" @@ -287,9 +286,9 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. result := cli.decryptEnvelope(ctx, envelope) - err = cli.handleDecryptedResult(ctx, result, destinationServiceID, envelope.GetServerTimestamp()) + err = cli.handleDecryptedResult(ctx, result, envelope, destinationServiceID) if err != nil { - log.Err(err).Msg("handleDecryptedResult error") + log.Err(err).Msg("Error handling decrypted result") return nil, err } @@ -307,17 +306,17 @@ func (cli *Client) decryptEnvelope( destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) if err != nil { log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") - return DecryptionResult{Err: err, Urgent: envelope.GetUrgent()} + return DecryptionResult{Err: fmt.Errorf("failed to parse destination service ID: %w", err)} } - var result *DecryptionResult switch *envelope.Type { case signalpb.Envelope_UNIDENTIFIED_SENDER: - result, err = cli.decryptUnidentifiedSenderEnvelope(ctx, destinationServiceID, envelope) + result, err := cli.decryptUnidentifiedSenderEnvelope(ctx, destinationServiceID, envelope) if err != nil { - log.Err(err).Msg("decryptUnidentifiedSenderEnvelope error") - return DecryptionResult{Err: err, Urgent: envelope.GetUrgent()} + log.Err(err).Msg("Failed to decrypt sealed sender message") + result.Err = fmt.Errorf("failed to decrypt unidentified sender envelope: %w", err) } + return result case signalpb.Envelope_PREKEY_BUNDLE: sender, err := libsignalgo.NewUUIDAddressFromString( @@ -325,44 +324,50 @@ func (cli *Client) decryptEnvelope( uint(*envelope.SourceDevice), ) if err != nil { - return DecryptionResult{Err: fmt.Errorf("NewAddress error: %v", err), Urgent: envelope.GetUrgent()} + return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} } - result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) + result, err := cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) if err != nil { - log.Err(err).Msg("Prekey bundle decryption error") - } else { - log.Trace(). - Any("sender_address", result.SenderAddress). - Any("content", result.Content). - Msg("Prekey bundle decryption result") + log.Err(err).Msg("Failed to decrypt prekey bundle message") + return DecryptionResult{Err: fmt.Errorf("failed to decrypt prekey bundle envelope: %w", err), SenderAddress: sender} } + log.Trace(). + Any("sender_address", result.SenderAddress). + Any("content", result.Content). + Msg("Prekey bundle decryption result") + return *result case signalpb.Envelope_PLAINTEXT_CONTENT: + return DecryptionResult{Err: fmt.Errorf("plaintext messages are not supported")} case signalpb.Envelope_CIPHERTEXT: - message, err := libsignalgo.DeserializeMessage(envelope.Content) - if err != nil { - log.Err(err).Msg("DeserializeMessage error") - } senderAddress, err := libsignalgo.NewUUIDAddressFromString( *envelope.SourceServiceId, uint(*envelope.SourceDevice), ) if err != nil { - return DecryptionResult{Err: fmt.Errorf("NewAddress error: %v", err), Urgent: envelope.GetUrgent()} + return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %w", err)} + } + message, err := libsignalgo.DeserializeMessage(envelope.Content) + if err != nil { + log.Err(err).Msg("Failed to deserialize ciphertext message") + return DecryptionResult{ + Err: fmt.Errorf("failed to deserialize message: %w", err), + SenderAddress: senderAddress, + } } sessionStore := cli.Store.SessionStore(destinationServiceID) if sessionStore == nil { return DecryptionResult{ - Err: fmt.Errorf("no session store for destination service ID %s", destinationServiceID), - Urgent: envelope.GetUrgent(), + Err: fmt.Errorf("no session store for destination service ID %s", destinationServiceID), + SenderAddress: senderAddress, } } identityStore := cli.Store.IdentityStore(destinationServiceID) if identityStore == nil { return DecryptionResult{ - Err: fmt.Errorf("no identity store for destination service ID %s", destinationServiceID), - Urgent: envelope.GetUrgent(), + Err: fmt.Errorf("no identity store for destination service ID %s", destinationServiceID), + SenderAddress: senderAddress, } } decryptedText, err := libsignalgo.Decrypt( @@ -374,105 +379,93 @@ func (cli *Client) decryptEnvelope( ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { - log.Info().Msg("Duplicate message, ignoring") + log.Warn().Err(err).Msg("Duplicate message error while decrypting whisper ciphertext") } else { - log.Err(err).Msg("Whisper Decryption error") - } - } else { - err = stripPadding(&decryptedText) - if err != nil { - return DecryptionResult{Err: fmt.Errorf("stripPadding error: %v", err), Urgent: envelope.GetUrgent()} - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - log.Err(err).Msg("Unmarshal error") - } - result = &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, + log.Err(err).Msg("Failed to decrypt whisper ciphertext message") } + return DecryptionResult{Err: fmt.Errorf("failed to decrypt ciphertext message: %w", err), SenderAddress: senderAddress} + } + err = stripPadding(&decryptedText) + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to strip padding: %w", err), SenderAddress: senderAddress} + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to unmarshal decrypted message: %w", err), SenderAddress: senderAddress} + } + return DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, } case signalpb.Envelope_RECEIPT: - log.Warn().Msg("Received RECEIPT envelope, not yet implemented") - // TODO: handle receipt + return DecryptionResult{Err: fmt.Errorf("receipt envelopes are not yet supported")} case signalpb.Envelope_KEY_EXCHANGE: - log.Warn().Msg("Received KEY_EXCHANGE envelope, not supported") + return DecryptionResult{Err: fmt.Errorf("key exchange envelopes are not yet supported")} case signalpb.Envelope_UNKNOWN: - log.Warn().Msg("Received UNKNOWN envelope, not supported") + return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} default: - log.Warn().Msg("Received actual unknown envelope type") + return DecryptionResult{Err: fmt.Errorf("unrecognized envelope type")} } - if result == nil { - log.Warn().Msg("Decryption result is nil") - return DecryptionResult{ - Err: fmt.Errorf("decryption result is nil"), - Urgent: envelope.GetUrgent(), - } - } - result.Urgent = envelope.GetUrgent() - return *result } -func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destinationServiceID libsignalgo.ServiceID, envelope *signalpb.Envelope) (*DecryptionResult, error) { +func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destinationServiceID libsignalgo.ServiceID, envelope *signalpb.Envelope) (result DecryptionResult, err error) { log := zerolog.Ctx(ctx) - var result *DecryptionResult if destinationServiceID != cli.Store.ACIServiceID() { log.Warn().Stringer("destination_service_id", destinationServiceID). Msg("Received UNIDENTIFIED_SENDER envelope for non-ACI destination") - // Return nil, nil to skip the rest of the handling and return 200 OK to the server - return nil, nil + return result, fmt.Errorf("received unidentified sender envelope for non-ACI destination") } usmc, err := libsignalgo.SealedSenderDecryptToUSMC( ctx, envelope.GetContent(), cli.Store.ACIIdentityStore, ) - if err != nil || usmc == nil { - if err == nil { - err = fmt.Errorf("usmc is nil") - } - log.Err(err).Msg("SealedSenderDecryptToUSMC error") - return nil, err + if err != nil { + return result, fmt.Errorf("failed to decrypt to USMC: %w", err) + } else if usmc == nil { + return result, fmt.Errorf("decrypting to USMC returned nil") } messageType, err := usmc.GetMessageType() if err != nil { - log.Err(err).Msg("GetMessageType error") + return result, fmt.Errorf("failed to get message type: %w", err) } senderCertificate, err := usmc.GetSenderCertificate() if err != nil { - log.Err(err).Msg("GetSenderCertificate error") + return result, fmt.Errorf("failed to get sender certificate: %w", err) } senderUUID, err := senderCertificate.GetSenderUUID() if err != nil { - log.Err(err).Msg("GetSenderUUID error") + return result, fmt.Errorf("failed to get sender UUID: %w", err) } senderDeviceID, err := senderCertificate.GetDeviceID() if err != nil { - log.Err(err).Msg("GetDeviceID error") + return result, fmt.Errorf("failed to get sender device ID: %w", err) } senderAddress, err := libsignalgo.NewACIServiceID(senderUUID).Address(uint(senderDeviceID)) if err != nil { - log.Err(err).Msg("NewAddress error") + return result, fmt.Errorf("failed to create sender address: %w", err) } + result.SenderAddress = senderAddress senderE164, err := senderCertificate.GetSenderE164() if err != nil { - log.Err(err).Msg("GetSenderE164 error") + return result, fmt.Errorf("failed to get sender E164: %w", err) } usmcContents, err := usmc.GetContents() if err != nil { - log.Err(err).Msg("GetContents error") + return result, fmt.Errorf("failed to get USMC contents: %w", err) } newLog := log.With(). Stringer("sender_uuid", senderUUID). Uint32("sender_device_id", senderDeviceID). Str("sender_e164", senderE164). + Uint8("sealed_sender_type", uint8(messageType)). Logger() log = &newLog ctx = log.WithContext(ctx) @@ -487,7 +480,6 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: - log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeSenderKey") decryptedText, err := libsignalgo.GroupDecrypt( ctx, usmcContents, @@ -496,39 +488,37 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin ) if err != nil { if strings.Contains(err.Error(), "message with old counter") { - log.Warn().Msg("Duplicate message, ignoring") - } else { - log.Err(err).Msg("GroupDecrypt error") - } - } else { - err = stripPadding(&decryptedText) - if err != nil { - return nil, fmt.Errorf("stripPadding error: %v", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - log.Err(err).Msg("Unmarshal error") - } - result = &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - SealedSender: true, + log.Warn().Err(err).Msg("Duplicate message error while decrypting sealed sender sender key") + return result, err } + log.Err(err).Msg("Failed to decrypt sealed sender sender key message, trying generic function") + return cli.fallbackDecryptSealedSender(ctx, result, envelope) } + err = stripPadding(&decryptedText) + if err != nil { + return result, fmt.Errorf("failed to strip padding: %w", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return result, fmt.Errorf("failed to unmarshal decrypted sender key message: %w", err) + } + result.Content = &content + return result, nil case libsignalgo.CiphertextMessageTypePreKey: - log.Trace().Msg("SealedSender messageType is CiphertextMessageTypePreKey") - result, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) + var resultPtr *DecryptionResult + resultPtr, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) if err != nil { - log.Err(err).Msg("Sealed sender prekey ciphertext decryption error") + log.Err(err).Msg("Failed to decrypt sealed sender prekey message, trying generic function") + return cli.fallbackDecryptSealedSender(ctx, result, envelope) } + return *resultPtr, nil case libsignalgo.CiphertextMessageTypeWhisper: - log.Trace().Msg("SealedSender messageType is CiphertextMessageTypeWhisper") message, err := libsignalgo.DeserializeMessage(usmcContents) if err != nil { - log.Err(err).Msg("Sealed sender whisper deserialize error") + return result, fmt.Errorf("failed to deserialize whisper message: %w", err) } decryptedText, err := libsignalgo.Decrypt( ctx, @@ -538,26 +528,23 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin cli.Store.ACIIdentityStore, ) if err != nil { - log.Err(err).Msg("Sealed sender whisper decryption error") - } else { - err = stripPadding(&decryptedText) - if err != nil { - return nil, fmt.Errorf("stripPadding error: %v", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - log.Err(err).Msg("Unmarshal error") - } - result = &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - SealedSender: true, - } + log.Err(err).Msg("Failed to decrypt whisper message, trying generic function") + return cli.fallbackDecryptSealedSender(ctx, result, envelope) } + err = stripPadding(&decryptedText) + if err != nil { + return result, fmt.Errorf("failed to strip padding: %w", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return result, fmt.Errorf("failed to unmarshal decrypted whisper message: %w", err) + } + result.Content = &content + return result, nil case libsignalgo.CiphertextMessageTypePlaintext: - log.Debug().Msg("SealedSender messageType is CiphertextMessageTypePlaintext") + log.Warn().Msg("Unsupported plaintext sealed sender message") // TODO: handle plaintext (usually DecryptionErrorMessage) and retries // when implementing SenderKey groups @@ -580,47 +567,42 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin // SealedSender: true, //} - return nil, nil + return result, fmt.Errorf("plaintext sealed sender messages are not supported") default: - log.Warn().Msg("SealedSender messageType is unknown") + log.Warn().Msg("Unrecognized sealed sender message type") + return cli.fallbackDecryptSealedSender(ctx, result, envelope) } +} - // If we couldn't decrypt with specific decryption methods, try sealedSenderDecrypt - if result == nil { - log.Debug().Msg("Didn't decrypt with specific methods, trying sealedSenderDecrypt") - var err error - result, err = cli.sealedSenderDecrypt(ctx, envelope) - if err != nil { - if strings.Contains(err.Error(), "self send of a sealed sender message") { - log.Debug().Msg("Message sent by us, ignoring") - } else if strings.Contains(err.Error(), "message with old counter") { - log.Info().Msg("Duplicate message, ignoring (sealedSenderDecrypt)") - } else { - log.Err(err).Msg("sealedSenderDecrypt error") - } +func (cli *Client) fallbackDecryptSealedSender(ctx context.Context, fallbackResult DecryptionResult, envelope *signalpb.Envelope) (DecryptionResult, error) { + log := zerolog.Ctx(ctx) + result, err := cli.sealedSenderDecrypt(ctx, envelope) + if err != nil { + if strings.Contains(err.Error(), "self send of a sealed sender message") { + log.Debug().Msg("Message sent by us, ignoring") + } else if strings.Contains(err.Error(), "message with old counter") { + log.Info().Msg("Duplicate message, ignoring (sealedSenderDecrypt)") } else { - log.Trace(). - Any("sender_address", result.SenderAddress). - Any("content", result.Content). - Msg("SealedSender decrypt result") + log.Err(err).Msg("Failed to decrypt sealed sender message with fallback method") } + return fallbackResult, fmt.Errorf("failed to decrypt unrecognized sealed sender message: %w", err) } - return result, nil + log.Trace(). + Any("sender_address", result.SenderAddress). + Any("content", result.Content). + Msg("SealedSender decrypt result") + return *result, nil } // TODO: we should split this up into multiple functions func (cli *Client) handleDecryptedResult( ctx context.Context, result DecryptionResult, + envelope *signalpb.Envelope, destinationServiceID libsignalgo.ServiceID, - serverTimestamp uint64, ) error { log := zerolog.Ctx(ctx) - if result.Content == nil { - log.Warn().Msg("Decrypted content is nil") - return nil - } // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted @@ -631,21 +613,29 @@ func (cli *Client) handleDecryptedResult( } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") } - log.Err(result.Err).Stringer("sender", theirServiceID).Bool("urgent", result.Urgent).Msg("Decryption error") + log.Err(result.Err). + Stringer("sender", theirServiceID). + Bool("urgent", envelope.GetUrgent()). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Msg("Decryption error") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot - if result.Urgent { + if envelope.GetUrgent() { cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, - Timestamp: serverTimestamp, + Timestamp: envelope.GetTimestamp(), }) } - // Intentionally not returning here. In most cases there's nothing besides the error so - // nothing else will happen, but if there is content we still want to do what we can with it + // TODO there are probably no cases with both content and an error } content := result.Content + if content == nil { + log.Warn().Msg("Decrypted content is nil") + return nil + } name, _ := result.SenderAddress.Name() deviceId, _ := result.SenderAddress.DeviceID() @@ -1055,7 +1045,6 @@ type DecryptionResult struct { Content *signalpb.Content SealedSender bool Err error - Urgent bool } const prodServerTrustRootStr = "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" @@ -1074,35 +1063,34 @@ func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.E cli.Store.ACI, uint32(cli.Store.DeviceID), ) - timestamp := time.Unix(0, int64(*envelope.Timestamp)) result, err := libsignalgo.SealedSenderDecrypt( ctx, envelope.Content, localAddress, prodServerTrustRootKey, - timestamp, + envelope.GetTimestamp(), cli.Store.ACISessionStore, cli.Store.ACIIdentityStore, cli.Store.ACIPreKeyStore, cli.Store.ACIPreKeyStore, ) if err != nil { - return nil, fmt.Errorf("SealedSenderDecrypt error: %w", err) + return nil, err } msg := result.Message err = stripPadding(&msg) if err != nil { - return nil, fmt.Errorf("stripPadding error: %w", err) + return nil, fmt.Errorf("failed to strip padding: %w", err) } address, err := libsignalgo.NewACIServiceID(result.Sender.UUID).Address(uint(result.Sender.DeviceID)) if err != nil { - return nil, fmt.Errorf("NewAddress error: %w", err) + return nil, fmt.Errorf("failed to wrap sender address: %w", err) } content := &signalpb.Content{} err = proto.Unmarshal(msg, content) if err != nil { - return nil, fmt.Errorf("Unmarshal error: %w", err) + return nil, fmt.Errorf("failed to unmarshal decrypted content: %w", err) } return &DecryptionResult{ SenderAddress: address, @@ -1141,25 +1129,21 @@ func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.Se pks, ) if err != nil { - err = fmt.Errorf("DecryptPreKey error: %v", err) - return nil, err + return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) } err = stripPadding(&data) if err != nil { - err = fmt.Errorf("stripPadding error: %v", err) - return nil, err + return nil, fmt.Errorf("failed to strip padding: %w", err) } content := &signalpb.Content{} err = proto.Unmarshal(data, content) if err != nil { - err = fmt.Errorf("Unmarshal error: %v", err) - return nil, err + return nil, fmt.Errorf("failed to unmarshal decrypted prekey message: %w", err) } - DecryptionResult := &DecryptionResult{ + return &DecryptionResult{ SenderAddress: sender, Content: content, - } - return DecryptionResult, nil + }, nil } func stripPadding(contents *[]byte) error { From 58416d1d167bfef2953472b112e494c9e2e6b28c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Sep 2024 20:56:34 +0300 Subject: [PATCH 308/718] signalmeow/web: fix unnecessary NewBuffer use --- pkg/signalmeow/web/web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index e72570a..7bcc035 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -134,7 +134,7 @@ func SendHTTPRequest(ctx context.Context, method string, path string, opt *HTTPR Logger() ctx = log.WithContext(ctx) - req, err := http.NewRequestWithContext(ctx, method, urlStr, bytes.NewBuffer(opt.Body)) + req, err := http.NewRequestWithContext(ctx, method, urlStr, bytes.NewReader(opt.Body)) if err != nil { log.Err(err).Msg("Error creating request") return nil, err From fed58c6635874d57a0c7f0ef68037d706907d5cd Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Sep 2024 13:45:22 +0300 Subject: [PATCH 309/718] handlematrix: ignore unsupported message IDs when sending read receipts --- pkg/connector/handlematrix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index fb3b1d9..a329c0c 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -229,7 +229,7 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri for _, msg := range dbMessages { userID, timestamp, err := signalid.ParseMessageID(msg.ID) if err != nil { - return fmt.Errorf("failed to parse message ID %q: %w", msg.ID, err) + continue } messagesToRead[userID] = append(messagesToRead[userID], timestamp) } From c3ac2bc0d13fe7d2f657dc7b716e1ca259c8480c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Sep 2024 21:22:18 +0300 Subject: [PATCH 310/718] config: remove pointer --- cmd/mautrix-signal/main.go | 2 +- pkg/connector/config.go | 2 +- pkg/connector/connector.go | 8 +------- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 5fe7117..93a03c7 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -40,7 +40,7 @@ var m = mxmain.BridgeMain{ Description: "A Matrix-Signal puppeting bridge.", Version: "0.7.0", - Connector: connector.NewConnector(), + Connector: &connector.SignalConnector{}, } func main() { diff --git a/pkg/connector/config.go b/pkg/connector/config.go index 0d98583..ec47f34 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -84,5 +84,5 @@ func upgradeConfig(helper up.Helper) { } func (s *SignalConnector) GetConfig() (string, any, up.Upgrader) { - return ExampleConfig, s.Config, up.SimpleUpgrader(upgradeConfig) + return ExampleConfig, &s.Config, up.SimpleUpgrader(upgradeConfig) } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index bb98238..e5995ad 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -34,18 +34,12 @@ type SignalConnector struct { MsgConv *msgconv.MessageConverter Store *store.Container Bridge *bridgev2.Bridge - Config *SignalConfig + Config SignalConfig } var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) -func NewConnector() *SignalConnector { - return &SignalConnector{ - Config: &SignalConfig{}, - } -} - var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ DisappearingMessages: true, AggressiveUpdateInfo: true, From a4301347ded63e6ccaefa5b71cd5019773608c3c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Sep 2024 22:20:44 +0300 Subject: [PATCH 311/718] signalmeow/receiving: don't panic on decryption errors with unknown sender Fixes #546 --- pkg/signalmeow/receiving.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 8a40a16..9b36b84 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -607,18 +607,21 @@ func (cli *Client) handleDecryptedResult( // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted if result.Err != nil { + logEvt := log.Err(result.Err). + Bool("urgent", envelope.GetUrgent()). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()) + if result.SenderAddress == nil { + logEvt.Msg("Decryption error with unknown sender") + return nil + } theirServiceID, err := result.SenderAddress.NameServiceID() if err != nil { log.Err(err).Msg("Name error handling decryption error") } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") } - log.Err(result.Err). - Stringer("sender", theirServiceID). - Bool("urgent", envelope.GetUrgent()). - Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). - Msg("Decryption error") + logEvt.Stringer("sender", theirServiceID).Msg("Decryption error with known sender") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot if envelope.GetUrgent() { From 53dcfc52f93649b35c592e6e74989333fd17901f Mon Sep 17 00:00:00 2001 From: Brad Murray Date: Thu, 12 Sep 2024 07:18:15 -0400 Subject: [PATCH 312/718] legacyprovision: fix start new chat for Beeper iOS clients (#547) --- .gitignore | 2 ++ cmd/mautrix-signal/legacyprovision.go | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ab00deb..7766014 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ /mautrix-signal /start /libsignal_ffi.a + +.idea diff --git a/cmd/mautrix-signal/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go index 013d1bd..43d6947 100644 --- a/cmd/mautrix-signal/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -215,7 +215,8 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, return } api := login.Client.(bridgev2.IdentifierResolvingNetworkAPI) - resp, err := api.ResolveIdentifier(r.Context(), mux.Vars(r)["phonenum"], create) + phonenum := mux.Vars(r)["phonenum"] + resp, err := api.ResolveIdentifier(r.Context(), phonenum, create) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to resolve identifier") JSONResponse(w, http.StatusInternalServerError, &Error{ @@ -234,7 +235,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, apiResp := &ResolveIdentifierResponse{ ChatID: ResolveIdentifierResponseChatID{ UUID: string(resp.UserID), - Number: "", + Number: phonenum, }, } if resp.Ghost != nil { From ac5fc5fb115ceca8ea3113c1807a025cf1a8c76d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Sep 2024 12:23:03 +0300 Subject: [PATCH 313/718] libsignal: update to v0.57.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 42 +++++++++++++++++---------------- pkg/libsignalgo/version.go | 2 +- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index e46841e..3917f60 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit e46841ea2c1ad03bc5113eba267ac1543689d031 +Subproject commit 3917f60919a987573e0599d414bb5d9d6f155fe4 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index c089648..3ed14d2 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -175,26 +175,28 @@ typedef enum { SignalErrorCodeUsernameTooLong = 126, SignalErrorCodeUsernameLinkInvalidEntropyDataLength = 127, SignalErrorCodeUsernameLinkInvalid = 128, - SignalErrorCodeUsernameDiscriminatorCannotBeEmpty = 140, - SignalErrorCodeUsernameDiscriminatorCannotBeZero = 141, - SignalErrorCodeUsernameDiscriminatorCannotBeSingleDigit = 142, - SignalErrorCodeUsernameDiscriminatorCannotHaveLeadingZeros = 143, - SignalErrorCodeUsernameDiscriminatorTooLarge = 144, - SignalErrorCodeIoError = 130, - SignalErrorCodeInvalidMediaInput = 131, - SignalErrorCodeUnsupportedMediaInput = 132, - SignalErrorCodeConnectionTimedOut = 133, - SignalErrorCodeNetworkProtocol = 134, - SignalErrorCodeRateLimited = 135, - SignalErrorCodeWebSocket = 136, - SignalErrorCodeCdsiInvalidToken = 137, - SignalErrorCodeConnectionFailed = 138, - SignalErrorCodeChatServiceInactive = 139, - SignalErrorCodeSvrDataMissing = 150, - SignalErrorCodeSvrRestoreFailed = 151, - SignalErrorCodeAppExpired = 160, - SignalErrorCodeDeviceDeregistered = 161, - SignalErrorCodeBackupValidation = 170, + SignalErrorCodeUsernameDiscriminatorCannotBeEmpty = 130, + SignalErrorCodeUsernameDiscriminatorCannotBeZero = 131, + SignalErrorCodeUsernameDiscriminatorCannotBeSingleDigit = 132, + SignalErrorCodeUsernameDiscriminatorCannotHaveLeadingZeros = 133, + SignalErrorCodeUsernameDiscriminatorTooLarge = 134, + SignalErrorCodeIoError = 140, + SignalErrorCodeInvalidMediaInput = 141, + SignalErrorCodeUnsupportedMediaInput = 142, + SignalErrorCodeConnectionTimedOut = 143, + SignalErrorCodeNetworkProtocol = 144, + SignalErrorCodeRateLimited = 145, + SignalErrorCodeWebSocket = 146, + SignalErrorCodeCdsiInvalidToken = 147, + SignalErrorCodeConnectionFailed = 148, + SignalErrorCodeChatServiceInactive = 149, + SignalErrorCodeChatServiceIntentionallyDisconnected = 150, + SignalErrorCodeSvrDataMissing = 160, + SignalErrorCodeSvrRestoreFailed = 161, + SignalErrorCodeSvrRotationMachineTooManySteps = 162, + SignalErrorCodeAppExpired = 170, + SignalErrorCodeDeviceDeregistered = 171, + SignalErrorCodeBackupValidation = 180, } SignalErrorCode; /** diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index e36a12a..c8272f5 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.56.1" +const Version = "v0.57.1" From 2ab0e9e4fe8fd6d71b27a98f9e74624c2dc21ad8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Sep 2024 12:24:50 +0300 Subject: [PATCH 314/718] dependencies: update --- go.mod | 14 ++++++++------ go.sum | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 664b59e..b8ef281 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module go.mau.fi/mautrix-signal -go 1.22 +go 1.22.0 + +toolchain go1.23.1 require ( github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 @@ -10,12 +12,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.7.1-0.20240904173517-ca3b3fe376c2 - golang.org/x/crypto v0.26.0 - golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 - golang.org/x/net v0.28.0 + go.mau.fi/util v0.7.1-0.20240913091524-7617daa66719 + golang.org/x/crypto v0.27.0 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240906105454-33d724bf4c78 + maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2 nhooyr.io/websocket v1.8.17 ) diff --git a/go.sum b/go.sum index 1f7751c..16e07ab 100644 --- a/go.sum +++ b/go.sum @@ -65,16 +65,16 @@ 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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.7.1-0.20240904173517-ca3b3fe376c2 h1:VZQlKBbeJ7KOlYSh6BnN5uWQTY/ypn/bJv0YyEd+pXc= -go.mau.fi/util v0.7.1-0.20240904173517-ca3b3fe376c2/go.mod h1:WgYvbt9rVmoFeajP97NunQU7AjgvTPiNExN3oTHeePs= +go.mau.fi/util v0.7.1-0.20240913091524-7617daa66719 h1:sg1P/f4RHY1JuAwsPOjTCsZr8ROzR9bRTtnvvBu42d4= +go.mau.fi/util v0.7.1-0.20240913091524-7617daa66719/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= -golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -95,7 +95,7 @@ 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.20.1-0.20240906105454-33d724bf4c78 h1:F8ls6UNW8QlTpQ2QAnPuCN5gVB30Y3ojBYfXb9T6U64= -maunium.net/go/mautrix v0.20.1-0.20240906105454-33d724bf4c78/go.mod h1:l6nYvD5/FMSrAZ/IP1AqJV0b47SRl/0uQNRiy4CcSVk= +maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2 h1:po9hbdGRCQq2Sb3+f5ED/TxA1RpUstmwRLTyX4ecjW4= +maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= From 4ede5dc9e183a7703468c0207af7ce4db73f3d67 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Sep 2024 12:27:26 +0300 Subject: [PATCH 315/718] dependencies: switch to new import path for websocket library --- go.mod | 2 +- go.sum | 4 ++-- pkg/signalmeow/contactdiscovery.go | 2 +- pkg/signalmeow/provisioning.go | 2 +- pkg/signalmeow/web/signalwebsocket.go | 2 +- pkg/signalmeow/wspb/wspb.go | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index b8ef281..5f8253b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.22.0 toolchain go1.23.1 require ( + github.com/coder/websocket v1.8.12 github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 @@ -18,7 +19,6 @@ require ( golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2 - nhooyr.io/websocket v1.8.17 ) require ( diff --git a/go.sum b/go.sum index 16e07ab..feffeab 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 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/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -97,5 +99,3 @@ 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.20.1-0.20240913091647-96e68fb485d2 h1:po9hbdGRCQq2Sb3+f5ED/TxA1RpUstmwRLTyX4ecjW4= maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= -nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= -nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index 660439c..b732339 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -27,12 +27,12 @@ import ( "sync" "time" + "github.com/coder/websocket" "github.com/google/uuid" "github.com/rs/zerolog" "github.com/tidwall/gjson" "go.mau.fi/util/exerrors" "google.golang.org/protobuf/proto" - "nhooyr.io/websocket" "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 5c09457..213c246 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -26,12 +26,12 @@ import ( "net/url" "time" + "github.com/coder/websocket" "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exerrors" "go.mau.fi/util/random" "google.golang.org/protobuf/proto" - "nhooyr.io/websocket" "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 8b9698b..986e17c 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -25,8 +25,8 @@ import ( "strings" "time" + "github.com/coder/websocket" "github.com/rs/zerolog" - "nhooyr.io/websocket" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" "go.mau.fi/mautrix-signal/pkg/signalmeow/wspb" diff --git a/pkg/signalmeow/wspb/wspb.go b/pkg/signalmeow/wspb/wspb.go index c58628f..2c2ccd8 100644 --- a/pkg/signalmeow/wspb/wspb.go +++ b/pkg/signalmeow/wspb/wspb.go @@ -8,8 +8,8 @@ import ( "fmt" "sync" + "github.com/coder/websocket" "google.golang.org/protobuf/proto" - "nhooyr.io/websocket" ) // Read reads a protobuf message from c into v. From adee82100658dcdf7ad37372ac122ce1b5788cb6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Sep 2024 12:32:04 +0300 Subject: [PATCH 316/718] msgconv/matrixfmt: fix trimming space from whitespace-only string --- pkg/msgconv/matrixfmt/convert_test.go | 7 +++++++ pkg/msgconv/matrixfmt/html.go | 14 +++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pkg/msgconv/matrixfmt/convert_test.go b/pkg/msgconv/matrixfmt/convert_test.go index 240ca98..1ade316 100644 --- a/pkg/msgconv/matrixfmt/convert_test.go +++ b/pkg/msgconv/matrixfmt/convert_test.go @@ -65,6 +65,13 @@ func TestParse_HTML(t *testing.T) { Length: 5, Value: signalfmt.StyleBold, }}}, + {name: "UnnecessaryWhitespace", in: " Hello , World!", out: "Hello, World!", ent: signalfmt.BodyRangeList{{ + Start: 0, + Length: 5, + Value: signalfmt.StyleBold, + }}}, + {name: "UnnecessaryWhitespaceParagraph", in: "

Hello

", out: "Hello"}, + {name: "EmptyParagraph", in: "

Hello

", out: "Hello"}, { name: "MultiBasic", in: "Hello, World!", diff --git a/pkg/msgconv/matrixfmt/html.go b/pkg/msgconv/matrixfmt/html.go index 1e3d249..5c4a37f 100644 --- a/pkg/msgconv/matrixfmt/html.go +++ b/pkg/msgconv/matrixfmt/html.go @@ -81,22 +81,26 @@ func (es *EntityString) TrimSpace() *EntityString { return nil } DebugLog("TRIMSPACE %q %+v\n", es.String, es.Entities) - var cutEnd, cutStart int - for cutStart = 0; cutStart < len(es.String); cutStart++ { + cutStart := 0 + for ; cutStart < len(es.String); cutStart++ { switch es.String[cutStart] { case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0: continue } break } - for cutEnd = len(es.String) - 1; cutEnd >= 0; cutEnd-- { - switch es.String[cutEnd] { + cutEnd := len(es.String) + for ; cutEnd > cutStart; cutEnd-- { + switch es.String[cutEnd-1] { case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0: continue } break } - cutEnd++ + if cutEnd == cutStart { + DebugLog(" -> EMPTY\n") + return NewEntityString("") + } if cutStart == 0 && cutEnd == len(es.String) { DebugLog(" -> NOOP\n") return es From 1dc480b9a097d6b321267e0168055edd6c2b271b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Sep 2024 12:56:01 +0300 Subject: [PATCH 317/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5f8253b..3213204 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2 + maunium.net/go/mautrix v0.20.1-0.20240913095532-e12ecbe82d36 ) require ( diff --git a/go.sum b/go.sum index feffeab..fe10324 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.20.1-0.20240913091647-96e68fb485d2 h1:po9hbdGRCQq2Sb3+f5ED/TxA1RpUstmwRLTyX4ecjW4= -maunium.net/go/mautrix v0.20.1-0.20240913091647-96e68fb485d2/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= +maunium.net/go/mautrix v0.20.1-0.20240913095532-e12ecbe82d36 h1:XKDqeDfRHmgke2N16A41eOckQQqezosxaEyehG/rupM= +maunium.net/go/mautrix v0.20.1-0.20240913095532-e12ecbe82d36/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= From 89373f335bea2b76da59a2c299c799d476167b43 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Sep 2024 13:12:16 +0300 Subject: [PATCH 318/718] ci: don't allow go to update itself [skip cd] --- .github/workflows/go.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4e0b362..76b76a1 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,6 +2,9 @@ name: Go on: [push, pull_request] +env: + GOTOOLCHAIN: local + jobs: lint: runs-on: ubuntu-latest From 4b7b3c5ec349198c1f16d333bce2b31b1803555f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 14 Sep 2024 12:47:40 +0300 Subject: [PATCH 319/718] ids: add support for split portals --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/id.go | 2 +- pkg/signalid/ids.go | 7 ------- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 3213204..fe20f9b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240913095532-e12ecbe82d36 + maunium.net/go/mautrix v0.20.1-0.20240914094516-d89dac594db0 ) require ( diff --git a/go.sum b/go.sum index fe10324..2ada990 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.20.1-0.20240913095532-e12ecbe82d36 h1:XKDqeDfRHmgke2N16A41eOckQQqezosxaEyehG/rupM= -maunium.net/go/mautrix v0.20.1-0.20240913095532-e12ecbe82d36/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= +maunium.net/go/mautrix v0.20.1-0.20240914094516-d89dac594db0 h1:fTX1P8TPv+oUqHGu08jj6FYH+Q/fC9jtmvkXcAw+KTo= +maunium.net/go/mautrix v0.20.1-0.20240914094516-d89dac594db0/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= diff --git a/pkg/connector/id.go b/pkg/connector/id.go index 49cebe6..16cb7dc 100644 --- a/pkg/connector/id.go +++ b/pkg/connector/id.go @@ -28,7 +28,7 @@ import ( func (s *SignalClient) makePortalKey(chatID string) networkid.PortalKey { key := networkid.PortalKey{ID: networkid.PortalID(chatID)} // For non-group chats, add receiver - if len(chatID) != 44 { + if s.Main.Bridge.Config.SplitPortals || len(chatID) != 44 { key.Receiver = s.UserLogin.ID } return key diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go index ec002ce..79ba90f 100644 --- a/pkg/signalid/ids.go +++ b/pkg/signalid/ids.go @@ -90,13 +90,6 @@ func MakeGroupPortalID(groupID types.GroupIdentifier) networkid.PortalID { return networkid.PortalID(groupID) } -func MakeGroupPortalKey(groupID types.GroupIdentifier) networkid.PortalKey { - return networkid.PortalKey{ - ID: MakeGroupPortalID(groupID), - Receiver: "", - } -} - func MakeDMPortalID(serviceID libsignalgo.ServiceID) networkid.PortalID { return networkid.PortalID(serviceID.String()) } From 09f854e86051951755b92876de6caa396dfe1032 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:06:37 +0200 Subject: [PATCH 320/718] groupinfo: skip unnecessary membership changes when banning (#537) --- pkg/connector/groupinfo.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index d0ecdd4..843a18e 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -238,7 +238,22 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint Membership: event.MembershipJoin, }) } + bannedMembers := make(map[libsignalgo.ServiceID]bool) + for _, member := range groupChange.AddBannedMembers { + aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) + if aci == nil { + continue + } + bannedMembers[member.ServiceID] = true + mc = append(mc, bridgev2.ChatMember{ + EventSender: s.makeEventSender(*aci), + Membership: event.MembershipBan, + }) + } for _, memberACI := range groupChange.DeleteMembers { + if bannedMembers[libsignalgo.NewACIServiceID(*memberACI)] { + continue + } mc = append(mc, bridgev2.ChatMember{ EventSender: s.makeEventSender(*memberACI), Membership: event.MembershipLeave, @@ -257,6 +272,9 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint }) } for _, memberServiceID := range groupChange.DeletePendingMembers { + if bannedMembers[*memberServiceID] { + continue + } aci := s.maybeResolvePNItoACI(ctx, memberServiceID) if aci == nil { continue @@ -274,22 +292,15 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint }) } for _, memberACI := range groupChange.DeleteRequestingMembers { + if bannedMembers[libsignalgo.NewACIServiceID(*memberACI)] { + continue + } mc = append(mc, bridgev2.ChatMember{ EventSender: s.makeEventSender(*memberACI), Membership: event.MembershipLeave, PrevMembership: event.MembershipKnock, }) } - for _, member := range groupChange.AddBannedMembers { - aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) - if aci == nil { - continue - } - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), - Membership: event.MembershipBan, - }) - } for _, memberServiceID := range groupChange.DeleteBannedMembers { aci := s.maybeResolvePNItoACI(ctx, memberServiceID) if aci == nil { From 99ecf9fa6c6c76491aa580478c6395adfe2cebff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 14 Sep 2024 14:33:54 +0300 Subject: [PATCH 321/718] dependencies: update mautrix-go --- cmd/mautrix-signal/main.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 93a03c7..280e97f 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 14), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 18), true, ) } diff --git a/go.mod b/go.mod index fe20f9b..e8bf58a 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240914094516-d89dac594db0 + maunium.net/go/mautrix v0.20.1-0.20240914113211-d86913bd5c51 ) require ( diff --git a/go.sum b/go.sum index 2ada990..0900e9c 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.20.1-0.20240914094516-d89dac594db0 h1:fTX1P8TPv+oUqHGu08jj6FYH+Q/fC9jtmvkXcAw+KTo= -maunium.net/go/mautrix v0.20.1-0.20240914094516-d89dac594db0/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= +maunium.net/go/mautrix v0.20.1-0.20240914113211-d86913bd5c51 h1:RN8jP+q35kH/8pbLeGP/UZRerJdA2ptb8I+2V49N7Jk= +maunium.net/go/mautrix v0.20.1-0.20240914113211-d86913bd5c51/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= From 7688e744d883ee355f5f011a38379b0ed289d131 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 14 Sep 2024 14:34:06 +0300 Subject: [PATCH 322/718] changelog: update --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c14528..5080e8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# v0.7.1 (unreleased) + +* Updated to libsignal v0.57.1. +* Added support for Matrix->Signal power level bridging (thanks to [@maltee1] in [#531]) +* Changed voice message conversion to convert to aac instead of m4a, + because Signal iOS doesn't appear to like ffmpeg's m4a files. +* Fixed outgoing sync messages not including disappearing start timestamp, + which would cause native clients to disappear messages at the wrong time. +* Re-added notices about decryption errors. + +[#531]: https://github.com/mautrix/signal/pull/531 + # v0.7.0 (2024-08-16) * Bumped minimum Go version to 1.22. From 11686cbe9606be666b1ab7da0fe19f985fd55ce4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 14 Sep 2024 19:41:01 +0300 Subject: [PATCH 323/718] signalmeow/web: log attachment download http status --- pkg/signalmeow/attachments.go | 9 +++++++++ pkg/signalmeow/web/web.go | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 64054dd..c0859b7 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -23,6 +23,7 @@ import ( "crypto/cipher" "crypto/hmac" "crypto/sha256" + "encoding/json" "errors" "fmt" "io" @@ -72,6 +73,14 @@ func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]b if err != nil { return nil, err } + if resp.StatusCode > 400 { + if json.Valid(body) && len(body) < 4096 { + zerolog.Ctx(ctx).Debug().RawJSON("response_data", body).Msg("Failed download response json") + } else if len(body) < 1024 { + zerolog.Ctx(ctx).Debug().Bytes("response_data", body).Msg("Failed download response data") + } + return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) + } return decryptAttachment(body, a.Key, a.Digest, *a.Size) } diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index 7bcc035..1119128 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -243,7 +243,10 @@ func GetAttachment(ctx context.Context, path string, cdnNumber uint32, opt *HTTP if err != nil { return nil, err } - log.Debug().Msg("Received Attachment HTTP response") + log.Debug(). + Int("status_code", resp.StatusCode). + Int64("content_length", resp.ContentLength). + Msg("Received Attachment HTTP response") return resp, err } From d144a21502a79346f644f3aa23497d5ffe79210b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Sep 2024 14:06:28 +0300 Subject: [PATCH 324/718] Bump version to v0.7.1 --- CHANGELOG.md | 6 ++++-- cmd/mautrix-signal/main.go | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5080e8e..3e780d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ -# v0.7.1 (unreleased) +# v0.7.1 (2024-09-16) * Updated to libsignal v0.57.1. -* Added support for Matrix->Signal power level bridging (thanks to [@maltee1] in [#531]) +* Dropped support for unauthenticated media on Matrix. +* Added support for Matrix->Signal power level bridging + (thanks to [@maltee1] in [#531]). * Changed voice message conversion to convert to aac instead of m4a, because Signal iOS doesn't appear to like ffmpeg's m4a files. * Fixed outgoing sync messages not including disappearing start timestamp, diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 280e97f..9bd9e23 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.0", + Version: "0.7.1", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index e8bf58a..6fa4954 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.7.1-0.20240913091524-7617daa66719 + go.mau.fi/util v0.8.0 golang.org/x/crypto v0.27.0 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.20.1-0.20240914113211-d86913bd5c51 + maunium.net/go/mautrix v0.21.0 ) require ( diff --git a/go.sum b/go.sum index 0900e9c..e0eda49 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.7.1-0.20240913091524-7617daa66719 h1:sg1P/f4RHY1JuAwsPOjTCsZr8ROzR9bRTtnvvBu42d4= -go.mau.fi/util v0.7.1-0.20240913091524-7617daa66719/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= +go.mau.fi/util v0.8.0 h1:MiSny8jgQq4XtCLAT64gDJhZVhqiDeMVIEBDFVw+M0g= +go.mau.fi/util v0.8.0/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= @@ -97,5 +97,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.20.1-0.20240914113211-d86913bd5c51 h1:RN8jP+q35kH/8pbLeGP/UZRerJdA2ptb8I+2V49N7Jk= -maunium.net/go/mautrix v0.20.1-0.20240914113211-d86913bd5c51/go.mod h1:amzKPIZVO7v1piD2JhKG1RvGZoV+5wEZfoHaEXOjjqA= +maunium.net/go/mautrix v0.21.0 h1:Z6nVu+clkJgj6ANwFYQQ1BtYeVXZPZ9lRgwuFN57gOY= +maunium.net/go/mautrix v0.21.0/go.mod h1:qm9oDhcHxF/Xby5RUuONIGpXw1SXXqLZj/GgvMxJxu0= From ebd8114db1c6c66a440e516f59dc994e65308da4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 23 Sep 2024 20:44:50 +0300 Subject: [PATCH 325/718] signalmeow/receiving: actually ignore old counter decryption erorrs Might fix #552 --- pkg/signalmeow/receiving.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 9b36b84..cf716d2 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -624,7 +624,7 @@ func (cli *Client) handleDecryptedResult( logEvt.Stringer("sender", theirServiceID).Msg("Decryption error with known sender") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot - if envelope.GetUrgent() { + if envelope.GetUrgent() && !strings.Contains(result.Err.Error(), "message with old counter") { cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, From ce665b23a4b517843fbc163660fa13ce5799f2de Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 17:19:17 +0300 Subject: [PATCH 326/718] signalmeow/receiving: don't send decryption error notice if content hint is implicit --- pkg/signalmeow/receiving.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index cf716d2..ecd33f7 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -440,6 +440,11 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin if err != nil { return result, fmt.Errorf("failed to get sender certificate: %w", err) } + contentHint, err := usmc.GetContentHint() + if err != nil { + return result, fmt.Errorf("failed to get content hint: %w", err) + } + result.ContentHint = signalpb.UnidentifiedSenderMessage_Message_ContentHint(contentHint) senderUUID, err := senderCertificate.GetSenderUUID() if err != nil { return result, fmt.Errorf("failed to get sender UUID: %w", err) @@ -609,6 +614,7 @@ func (cli *Client) handleDecryptedResult( if result.Err != nil { logEvt := log.Err(result.Err). Bool("urgent", envelope.GetUrgent()). + Stringer("content_hint", result.ContentHint). Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("client_ts", envelope.GetTimestamp()) if result.SenderAddress == nil { @@ -624,7 +630,9 @@ func (cli *Client) handleDecryptedResult( logEvt.Stringer("sender", theirServiceID).Msg("Decryption error with known sender") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot - if envelope.GetUrgent() && !strings.Contains(result.Err.Error(), "message with old counter") { + if envelope.GetUrgent() && + result.ContentHint != signalpb.UnidentifiedSenderMessage_Message_IMPLICIT && + !strings.Contains(result.Err.Error(), "message with old counter") { cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, @@ -1046,6 +1054,7 @@ func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps type DecryptionResult struct { SenderAddress *libsignalgo.Address Content *signalpb.Content + ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint SealedSender bool Err error } From 4727da48fa0b651b9dd6d55f986287280db80b44 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 17:22:43 +0300 Subject: [PATCH 327/718] signalmeow/sending: set urgent flag and content hint properly --- pkg/libsignalgo/sealedsender.go | 4 ++-- pkg/libsignalgo/session_test.go | 4 ++-- pkg/signalmeow/sending.go | 34 ++++++++++++++++++++++++++++----- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 253e512..0d12b74 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -42,7 +42,7 @@ func NewSealedSenderAddress(e164 string, uuid uuid.UUID, deviceID uint32) *Seale } } -func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { +func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHint UnidentifiedSenderMessageContentHint, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { ciphertextMessage, err := Encrypt(ctx, message, forAddress, sessionStore, identityStore) if err != nil { return nil, err @@ -51,7 +51,7 @@ func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, forAddres usmc, err := NewUnidentifiedSenderMessageContent( ciphertextMessage, fromSenderCert, - UnidentifiedSenderMessageContentHintDefault, + contentHint, nil, ) if err != nil { diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index 9d108d5..1840fc3 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -241,7 +241,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) { }() for i := 0; i < 100; i++ { message := []byte(fmt.Sprintf("%04d vision", i)) - ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, bobAddress, senderCert, aliceStore, aliceStore) + ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore) require.NoError(t, err) assert.NotNil(t, ciphertext) } @@ -279,7 +279,7 @@ func TestSealedSenderSession(t *testing.T) { assert.NoError(t, err) message := []byte("2020 vision") - ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, bobAddress, senderCert, aliceStore, aliceStore) + ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore) require.NoError(t, err) assert.NotNil(t, ciphertext) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 0236331..49b13a0 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -83,7 +83,7 @@ type MyMessage struct { } type MyMessages struct { - Timestamp int64 `json:"timestamp"` + Timestamp uint64 `json:"timestamp"` Online bool `json:"online"` Urgent bool `json:"urgent"` Messages []MyMessage `json:"messages"` @@ -212,7 +212,7 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg var envelopeType int var encryptedPayload []byte if unauthenticated { - envelopeType, encryptedPayload, err = cli.buildSSMessageToSend(ctx, recipientAddress, paddedMessage) + envelopeType, encryptedPayload, err = cli.buildSSMessageToSend(ctx, recipientAddress, paddedMessage, getContentHint(content)) } else { envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, recipientAddress, paddedMessage) } @@ -264,7 +264,7 @@ func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddres return envelopeType, encryptedPayload, nil } -func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { +func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte, contentHint libsignalgo.UnidentifiedSenderMessageContentHint) (envelopeType int, encryptedPayload []byte, err error) { cert, err := cli.senderCertificate(ctx) if err != nil { return 0, nil, err @@ -272,6 +272,7 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l encryptedPayload, err = libsignalgo.SealedSenderEncryptPlaintext( ctx, paddedMessage, + contentHint, recipientAddress, cert, cli.Store.ACISessionStore, @@ -782,6 +783,29 @@ func currentMessageTimestamp() uint64 { return uint64(time.Now().UnixMilli()) } +func isSyncMessageUrgent(content *signalpb.SyncMessage) bool { + return content.Sent != nil || content.Request != nil +} + +func isUrgent(content *signalpb.Content) bool { + return content.DataMessage != nil || + content.CallMessage != nil || + content.StoryMessage != nil || + content.EditMessage != nil || + (content.SyncMessage != nil && isSyncMessageUrgent(content.SyncMessage)) +} + +func getContentHint(content *signalpb.Content) libsignalgo.UnidentifiedSenderMessageContentHint { + if content.DataMessage != nil || content.EditMessage != nil { + // TODO add support for resending before setting this + //return libsignalgo.UnidentifiedSenderMessageContentHintResendable + } + if content.TypingMessage != nil || content.ReceiptMessage != nil { + return libsignalgo.UnidentifiedSenderMessageContentHintImplicit + } + return libsignalgo.UnidentifiedSenderMessageContentHintDefault +} + func (cli *Client) sendContent( ctx context.Context, recipient libsignalgo.ServiceID, @@ -845,9 +869,9 @@ func (cli *Client) sendContent( } outgoingMessages := MyMessages{ - Timestamp: int64(messageTimestamp), + Timestamp: messageTimestamp, Online: false, - Urgent: true, + Urgent: isUrgent(content), Messages: messages, } jsonBytes, err := json.Marshal(outgoingMessages) From 5d43fce26dacc1ae2316cad5d4f9bd3dfe85d113 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 20:02:33 +0300 Subject: [PATCH 328/718] ci: lock closed issues automatically after 90 days [skip ci] --- .github/workflows/stale.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..dfd6cbb --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,22 @@ +name: 'Lock old issues' + +on: + schedule: + - cron: '0 * * * *' + workflow_dispatch: + +permissions: + issues: write +# pull-requests: write +# discussions: write + +concurrency: + group: lock-threads + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v5 + issue-inactive-days: 90 + process-only: issues From 4efc7a7dc391f65b8e45b8f54afe7288dc77cc2c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 20:04:48 +0300 Subject: [PATCH 329/718] ci: fix workflow parameters [skip ci] --- .github/workflows/stale.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index dfd6cbb..0388eaf 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,5 +18,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v5 - issue-inactive-days: 90 - process-only: issues + with: + issue-inactive-days: 90 + process-only: issues From 500a629e5759d1610e8c569d3e9618f86ebb5b30 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 20:13:28 +0300 Subject: [PATCH 330/718] ci: log locked issues [skip ci] --- .github/workflows/stale.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 0388eaf..ee34b76 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,6 +18,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v5 + id: lock with: issue-inactive-days: 90 process-only: issues + - name: Log processed threads + run: | + if [ '${{ steps.lock.outputs.issues }}' ]; then + echo "Issues:" && echo '${{ steps.lock.outputs.issues }}' | jq . + fi From 33d3cbf10a77f9df1ca02a279d90bb7807ae7468 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 20:17:34 +0300 Subject: [PATCH 331/718] ci: make lock output nicer [skip ci] --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ee34b76..d354d3a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -25,5 +25,5 @@ jobs: - name: Log processed threads run: | if [ '${{ steps.lock.outputs.issues }}' ]; then - echo "Issues:" && echo '${{ steps.lock.outputs.issues }}' | jq . + echo "Issues:" && echo '${{ steps.lock.outputs.issues }}' | jq -r '.[] | "https://github.com/\(.owner)/\(.repo)/issues/\(.issue_number)"' fi From 84e513a2a72dade747dfeafa2ae558850f422056 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Sep 2024 20:34:03 +0300 Subject: [PATCH 332/718] ci: rename action and reduce interval [skip ci] --- .github/workflows/stale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index d354d3a..4ad4d79 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,7 +2,7 @@ name: 'Lock old issues' on: schedule: - - cron: '0 * * * *' + - cron: '0 0 * * *' workflow_dispatch: permissions: @@ -14,7 +14,7 @@ concurrency: group: lock-threads jobs: - action: + lock-stale: runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v5 From aee07ca536bccb4a187ec769c76a8c74b0a2c363 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 25 Sep 2024 16:15:35 +0300 Subject: [PATCH 333/718] msgconv/from-signal: use mautrix-go function for disappearing timer change notice --- go.mod | 2 +- go.sum | 4 ++-- pkg/msgconv/from-signal.go | 11 ++--------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 6fa4954..ab19dbc 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.21.0 + maunium.net/go/mautrix v0.21.1-0.20240925131409-0c7f701828f0 ) require ( diff --git a/go.sum b/go.sum index e0eda49..1d1e9cf 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.21.0 h1:Z6nVu+clkJgj6ANwFYQQ1BtYeVXZPZ9lRgwuFN57gOY= -maunium.net/go/mautrix v0.21.0/go.mod h1:qm9oDhcHxF/Xby5RUuONIGpXw1SXXqLZj/GgvMxJxu0= +maunium.net/go/mautrix v0.21.1-0.20240925131409-0c7f701828f0 h1:nX8gIPDHf2UXkcGMX982mtdTFXgbXtJGIDUQta+mRbE= +maunium.net/go/mautrix v0.21.1-0.20240925131409-0c7f701828f0/go.mod h1:qm9oDhcHxF/Xby5RUuONIGpXw1SXXqLZj/GgvMxJxu0= diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 20dd39b..4645dd0 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -28,7 +28,6 @@ import ( "github.com/emersion/go-vcard" "github.com/google/uuid" "github.com/rs/zerolog" - "go.mau.fi/util/exfmt" "go.mau.fi/util/exmime" "go.mau.fi/util/ffmpeg" "maunium.net/go/mautrix/bridgev2" @@ -153,14 +152,8 @@ func (mc *MessageConverter) ToMatrix( func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, timerVersion *uint32, updatePortal bool) *bridgev2.ConvertedMessagePart { part := &bridgev2.ConvertedMessagePart{ - Type: event.EventMessage, - Content: &event.MessageEventContent{ - MsgType: event.MsgNotice, - Body: fmt.Sprintf("Disappearing messages set to %s", exfmt.Duration(time.Duration(timer)*time.Second)), - }, - } - if timer == 0 { - part.Content.Body = "Disappearing messages disabled" + Type: event.EventMessage, + Content: bridgev2.DisappearingMessageNotice(time.Duration(timer)*time.Second, false), } if updatePortal { portal := getPortal(ctx) From 889c0dbcfa8e92550a32af1856df33feae90a1d7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 28 Sep 2024 18:16:39 +0300 Subject: [PATCH 334/718] ci: change cron schedule --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 4ad4d79..c2003f3 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,7 +2,7 @@ name: 'Lock old issues' on: schedule: - - cron: '0 0 * * *' + - cron: '0 12 * * *' workflow_dispatch: permissions: From d799a2b89549d2e31b6bec4323dc783fdba03b8c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 30 Sep 2024 21:11:41 +0300 Subject: [PATCH 335/718] msgconv/urlpreview: don't try to re-decrypt preview images --- pkg/msgconv/urlpreview.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/msgconv/urlpreview.go b/pkg/msgconv/urlpreview.go index d2d3b23..5731a0b 100644 --- a/pkg/msgconv/urlpreview.go +++ b/pkg/msgconv/urlpreview.go @@ -78,13 +78,6 @@ func (mc *MessageConverter) convertURLPreviewToSignal(ctx context.Context, conte zerolog.Ctx(ctx).Err(err).Int("preview_index", i).Msg("Failed to download URL preview image") continue } - if preview.ImageEncryption != nil { - err = preview.ImageEncryption.DecryptInPlace(data) - if err != nil { - zerolog.Ctx(ctx).Err(err).Int("preview_index", i).Msg("Failed to decrypt URL preview image") - continue - } - } uploaded, err := getClient(ctx).UploadAttachment(ctx, data) if err != nil { zerolog.Ctx(ctx).Err(err).Int("preview_index", i).Msg("Failed to reupload URL preview image") From 922c6d1a2cf2e04bfc1d80dbb6248fc346d0211e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 30 Sep 2024 21:12:30 +0300 Subject: [PATCH 336/718] dependencies: update mautrix-go --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index ab19dbc..876e05f 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.8.0 + go.mau.fi/util v0.8.1-0.20240927174413-000d30f9a02a golang.org/x/crypto v0.27.0 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.21.1-0.20240925131409-0c7f701828f0 + maunium.net/go/mautrix v0.21.1-0.20240930142122-741b4e823ffb ) require ( diff --git a/go.sum b/go.sum index 1d1e9cf..d76e998 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.0 h1:MiSny8jgQq4XtCLAT64gDJhZVhqiDeMVIEBDFVw+M0g= -go.mau.fi/util v0.8.0/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= +go.mau.fi/util v0.8.1-0.20240927174413-000d30f9a02a h1:4TrWJ0ooHT9YssDBUgXNU8FiR2cwi9jEAjtaVur4f0M= +go.mau.fi/util v0.8.1-0.20240927174413-000d30f9a02a/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= @@ -97,5 +97,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.21.1-0.20240925131409-0c7f701828f0 h1:nX8gIPDHf2UXkcGMX982mtdTFXgbXtJGIDUQta+mRbE= -maunium.net/go/mautrix v0.21.1-0.20240925131409-0c7f701828f0/go.mod h1:qm9oDhcHxF/Xby5RUuONIGpXw1SXXqLZj/GgvMxJxu0= +maunium.net/go/mautrix v0.21.1-0.20240930142122-741b4e823ffb h1:X19nOFvy3GINE6TbSshH5OiOgqbZqEgfu8e0Nsi2iAk= +maunium.net/go/mautrix v0.21.1-0.20240930142122-741b4e823ffb/go.mod h1:qN4yYKm3brOUWN8dlR0KPbKwSBGXQ4am/kzSQt/kLmY= From b943ce71dd4633ea26cc9d1745b794b364e4fcc0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 30 Sep 2024 23:26:14 +0300 Subject: [PATCH 337/718] legacyprovision: fix context in login complete handler --- cmd/mautrix-signal/legacyprovision.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/mautrix-signal/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go index 43d6947..177d4a5 100644 --- a/cmd/mautrix-signal/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -190,7 +190,7 @@ func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { UUID: string(res.CompleteParams.UserLogin.ID), Number: res.CompleteParams.UserLogin.RemoteName, }) - go handleLoginComplete(r.Context(), login.User, res.CompleteParams.UserLogin) + go handleLoginComplete(context.WithoutCancel(r.Context()), login.User, res.CompleteParams.UserLogin) } login.Delete() } From da8c612034d6999fbc3f03f3fe08e1ed0010d806 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 2 Oct 2024 20:39:47 +0300 Subject: [PATCH 338/718] signalmeow: use correct sender certificate based on account settings --- pkg/signalmeow/client.go | 15 ++--- pkg/signalmeow/sending.go | 59 ++++++++++++------- pkg/signalmeow/storageservice.go | 8 ++- pkg/signalmeow/store/container.go | 29 +++++++-- pkg/signalmeow/store/device.go | 2 + pkg/signalmeow/store/upgrades/00-latest.sql | 5 +- .../upgrades/17-store-account-record.sql | 2 + 7 files changed, 85 insertions(+), 35 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/17-store-account-record.sql diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 128e6db..14db3b7 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -34,13 +34,14 @@ import ( type Client struct { Store *store.Device - SenderCertificate *libsignalgo.SenderCertificate - GroupCredentials *GroupCredentials - GroupCache *GroupCache - ProfileCache *ProfileCache - GroupCallCache *map[string]bool - LastContactRequestTime time.Time - SyncContactsOnConnect bool + SenderCertificateWithE164 *libsignalgo.SenderCertificate + SenderCertificateNoE164 *libsignalgo.SenderCertificate + GroupCredentials *GroupCredentials + GroupCache *GroupCache + ProfileCache *ProfileCache + GroupCallCache *map[string]bool + LastContactRequestTime time.Time + SyncContactsOnConnect bool encryptionLock sync.Mutex diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 49b13a0..902818d 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -41,16 +41,27 @@ import ( // Sending -func (cli *Client) senderCertificate(ctx context.Context) (*libsignalgo.SenderCertificate, error) { - if cli.SenderCertificate != nil { - expiry, err := cli.SenderCertificate.GetExpiration() +func (cli *Client) senderCertificate(ctx context.Context, e164 bool) (*libsignalgo.SenderCertificate, error) { + cached := cli.SenderCertificateNoE164 + if e164 { + cached = cli.SenderCertificateWithE164 + } + setCache := func(val *libsignalgo.SenderCertificate) { + if e164 { + cli.SenderCertificateWithE164 = val + } else { + cli.SenderCertificateNoE164 = val + } + } + if cached != nil { + expiry, err := cached.GetExpiration() if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to check sender certificate expiry") } else if time.Until(expiry) < 1*exfmt.Day { zerolog.Ctx(ctx).Debug().Msg("Sender certificate expired, fetching new one") - cli.SenderCertificate = nil + setCache(nil) } else { - return cli.SenderCertificate, nil + return cached, nil } } @@ -61,7 +72,11 @@ func (cli *Client) senderCertificate(ctx context.Context) (*libsignalgo.SenderCe username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/certificate/delivery", opts) + var query string + if !e164 { + query = "?includeE164=false" + } + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/certificate/delivery"+query, opts) if err != nil { return nil, err } @@ -71,7 +86,7 @@ func (cli *Client) senderCertificate(ctx context.Context) (*libsignalgo.SenderCe } cert, err := libsignalgo.DeserializeSenderCertificate(r.Certificate) - cli.SenderCertificate = cert + setCache(cert) return cert, err } @@ -164,7 +179,7 @@ func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { return otherDevices } -func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalgo.ServiceID, content *signalpb.Content, unauthenticated bool) ([]MyMessage, error) { +func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalgo.ServiceID, content *signalpb.Content, unauthenticated, isGroup bool) ([]MyMessage, error) { // We need to prevent multiple encryption operations from happening at once, or else ratchets can race cli.encryptionLock.Lock() defer cli.encryptionLock.Unlock() @@ -212,7 +227,10 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg var envelopeType int var encryptedPayload []byte if unauthenticated { - envelopeType, encryptedPayload, err = cli.buildSSMessageToSend(ctx, recipientAddress, paddedMessage, getContentHint(content)) + includeE164 := !isGroup && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY + envelopeType, encryptedPayload, err = cli.buildSSMessageToSend( + ctx, recipientAddress, paddedMessage, getContentHint(content), includeE164, + ) } else { envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, recipientAddress, paddedMessage) } @@ -264,8 +282,8 @@ func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddres return envelopeType, encryptedPayload, nil } -func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte, contentHint libsignalgo.UnidentifiedSenderMessageContentHint) (envelopeType int, encryptedPayload []byte, err error) { - cert, err := cli.senderCertificate(ctx) +func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte, contentHint libsignalgo.UnidentifiedSenderMessageContentHint, includeE164 bool) (envelopeType int, encryptedPayload []byte, err error) { + cert, err := cli.senderCertificate(ctx, includeE164) if err != nil { return 0, nil, err } @@ -444,7 +462,7 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), }, }, - }, 0, false) + }, 0, false, false) if err != nil { log.Err(err).Msg("Failed to send contact sync request message to myself") return err @@ -464,7 +482,7 @@ func (cli *Client) SendStorageMasterKeyRequest(ctx context.Context) error { Type: signalpb.SyncMessage_Request_KEYS.Enum(), }, }, - }, 0, false) + }, 0, false, false) if err != nil { log.Err(err).Msg("Failed to send key sync request message to myself") return err @@ -617,7 +635,7 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.Se } log := zerolog.Ctx(ctx).With().Stringer("member", *recipient).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, *recipient, messageTimestamp, content, 0, true) + sentUnidentified, err := cli.sendContent(ctx, *recipient, messageTimestamp, content, 0, true, true) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ Recipient: *recipient, @@ -641,7 +659,7 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.Se } else if content.GetEditMessage() != nil { syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) } - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true, true) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } @@ -670,7 +688,7 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) } if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, false) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } else { @@ -745,7 +763,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } // Send to the recipient - sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0, true) + sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0, true, false) if err != nil { return SendMessageResult{ WasSuccessful: false, @@ -813,6 +831,7 @@ func (cli *Client) sendContent( content *signalpb.Content, retryCount int, useUnidentifiedSender bool, + isGroup bool, ) (sentUnidentified bool, err error) { log := zerolog.Ctx(ctx).With(). Str("action", "send content"). @@ -862,7 +881,7 @@ func (cli *Client) sendContent( } var messages []MyMessage - messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender) + messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, isGroup) if err != nil { log.Err(err).Msg("Error building messages to send") return false, err @@ -931,7 +950,7 @@ func (cli *Client) sendContent( return false, err } // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, sentUnidentified) + sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, sentUnidentified, isGroup) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err @@ -939,7 +958,7 @@ func (cli *Client) sendContent( } else if *response.Status == 401 && useUnidentifiedSender { log.Debug().Msg("Retrying send without sealed sender") // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, false) + sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, false, isGroup) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index a78f964..fab5eed 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -102,7 +102,13 @@ func (cli *Client) SyncStorage(ctx context.Context) { } case *signalpb.StorageRecord_Account: log.Trace().Any("account_record", data.Account).Msg("Found account record") - // There's probably some useful data here + cli.Store.AccountRecord = data.Account + err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + if err != nil { + log.Err(err).Msg("Failed to save device after receiving account record") + } else { + log.Debug().Msg("Saved device after receiving account record") + } case *signalpb.StorageRecord_GroupV1, *signalpb.StorageRecord_StoryDistributionList: // irrelevant data default: diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index a08b42d..8f81490 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -9,8 +9,10 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/dbutil" + "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/store/upgrades" ) @@ -35,7 +37,7 @@ const getAllDevicesQuery = ` SELECT aci_uuid, aci_identity_key_pair, registration_id, pni_uuid, pni_identity_key_pair, pni_registration_id, - device_id, number, password, master_key + device_id, number, password, master_key, account_record FROM signalmeow_device ` @@ -48,12 +50,13 @@ func (c *Container) Upgrade(ctx context.Context) error { func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { var device Device - var aciIdentityKeyPair, pniIdentityKeyPair []byte + var aciIdentityKeyPair, pniIdentityKeyPair, accountRecordBytes []byte err := row.Scan( &device.ACI, &aciIdentityKeyPair, &device.ACIRegistrationID, &device.PNI, &pniIdentityKeyPair, &device.PNIRegistrationID, &device.DeviceID, &device.Number, &device.Password, &device.MasterKey, + &accountRecordBytes, ) if err != nil { return nil, fmt.Errorf("failed to scan session: %w", err) @@ -70,6 +73,13 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { if len(device.MasterKey) == 0 { device.MasterKey = nil } + if len(accountRecordBytes) > 0 { + device.AccountRecord = &signalpb.AccountRecord{} + err = proto.Unmarshal(accountRecordBytes, device.AccountRecord) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal account record: %w", err) + } + } baseStore := &sqlStore{Container: c, AccountID: device.ACI} aciStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.ACIServiceID()} pniStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.PNIServiceID()} @@ -137,9 +147,9 @@ const ( INSERT INTO signalmeow_device ( aci_uuid, aci_identity_key_pair, registration_id, pni_uuid, pni_identity_key_pair, pni_registration_id, - device_id, number, password, master_key + device_id, number, password, master_key, account_record ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ON CONFLICT (aci_uuid) DO UPDATE SET aci_identity_key_pair=excluded.aci_identity_key_pair, registration_id=excluded.registration_id, @@ -149,7 +159,8 @@ const ( device_id=excluded.device_id, number=excluded.number, password=excluded.password, - master_key=excluded.master_key + master_key=excluded.master_key, + account_record=excluded.account_record ` deleteDeviceQuery = `DELETE FROM signalmeow_device WHERE aci_uuid=$1` ) @@ -172,10 +183,18 @@ func (c *Container) PutDevice(ctx context.Context, device *DeviceData) error { zerolog.Ctx(ctx).Err(err).Msg("failed to serialize pni identity key pair") return err } + var accountRecordBytes []byte + if device.AccountRecord != nil { + accountRecordBytes, err = proto.Marshal(device.AccountRecord) + if err != nil { + return fmt.Errorf("failed to marshal account record: %w", err) + } + } _, err = c.db.Exec(ctx, insertDeviceQuery, device.ACI, aciIdentityKeyPair, device.ACIRegistrationID, device.PNI, pniIdentityKeyPair, device.PNIRegistrationID, device.DeviceID, device.Number, device.Password, device.MasterKey, + accountRecordBytes, ) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("failed to insert device") diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index 2c8d54a..eb823c8 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -9,6 +9,7 @@ import ( "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) type sqlStore struct { @@ -35,6 +36,7 @@ type DeviceData struct { Number string Password string MasterKey []byte + AccountRecord *signalpb.AccountRecord } func (d *DeviceData) ACIServiceID() libsignalgo.ServiceID { diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 40afbfb..38ed5b2 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v16 (compatible with v13+): Latest revision +-- v0 -> v17 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -13,7 +13,8 @@ CREATE TABLE signalmeow_device ( number TEXT NOT NULL DEFAULT '', password TEXT NOT NULL DEFAULT '', - master_key bytea + master_key bytea, + account_record bytea ); CREATE TABLE signalmeow_pre_keys ( diff --git a/pkg/signalmeow/store/upgrades/17-store-account-record.sql b/pkg/signalmeow/store/upgrades/17-store-account-record.sql new file mode 100644 index 0000000..6d8b0db --- /dev/null +++ b/pkg/signalmeow/store/upgrades/17-store-account-record.sql @@ -0,0 +1,2 @@ +-- v17 (compatible with v13+): Store account config +ALTER TABLE signalmeow_device ADD COLUMN account_record bytea; From 59acb7e4dd861a1ea075cae4bcfbadaf75d7b902 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 2 Oct 2024 21:24:47 +0300 Subject: [PATCH 339/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/SignalService.pb.go | 3 - pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19136 -> 19130 bytes pkg/signalmeow/protobuf/SignalService.proto | 24 +-- pkg/signalmeow/protobuf/StorageService.pb.go | 173 ++++++++++++++---- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 5605 -> 5814 bytes pkg/signalmeow/protobuf/StorageService.proto | 8 + pkg/signalmeow/protobuf/update-protos.sh | 4 +- 7 files changed, 156 insertions(+), 56 deletions(-) diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index f524c90..f96f5d8 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -1467,18 +1467,15 @@ type SyncMessage_CallLinkUpdate_Type int32 const ( SyncMessage_CallLinkUpdate_UPDATE SyncMessage_CallLinkUpdate_Type = 0 - SyncMessage_CallLinkUpdate_DELETE SyncMessage_CallLinkUpdate_Type = 1 ) // Enum value maps for SyncMessage_CallLinkUpdate_Type. var ( SyncMessage_CallLinkUpdate_Type_name = map[int32]string{ 0: "UPDATE", - 1: "DELETE", } SyncMessage_CallLinkUpdate_Type_value = map[string]int32{ "UPDATE": 0, - "DELETE": 1, } ) diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw index bc9a4d57969c32e0c0d280ef3808c2a3c4c70bbb..322d177c380305a0f2efe3ed65c91c4405103817 100644 GIT binary patch delta 51 zcmV-30L=ful>xey0kGpD0qV2lB9IgTtdn&&louEZ1XOu&WfBSs231f*K~zN$03rkk J0kbAJniBEO5AFZ} delta 57 zcmdlrmGQt-#tn~^7(Z-&qBKE-ans~d^C_}&Tr44#1*t+@Tx_8ME{-9t0t_Iwi>r@o Li0ftri&;VdSeFs7 diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index c516a1b..177018f 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -630,7 +630,7 @@ message SyncMessage { message CallLinkUpdate { enum Type { UPDATE = 0; - DELETE = 1; + reserved 1; // was DELETE, superseded by storage service } optional bytes rootKey = 1; @@ -819,17 +819,17 @@ message GroupDetails { optional string e164 = 2; } - optional bytes id = 1; - optional string name = 2; - repeated string membersE164 = 3; - repeated Member members = 9; - optional Avatar avatar = 4; - optional bool active = 5 [default = true]; - optional uint32 expireTimer = 6; - optional string color = 7; - optional bool blocked = 8; - optional uint32 inboxPosition = 10; - optional bool archived = 11; + optional bytes id = 1; + optional string name = 2; + repeated string membersE164 = 3; + repeated Member members = 9; + optional Avatar avatar = 4; + optional bool active = 5 [default = true]; + optional uint32 expireTimer = 6; + optional string color = 7; + optional bool blocked = 8; + optional uint32 inboxPosition = 10; + optional bool archived = 11; } message PaymentAddress { diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 5f88b50..788cb41 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -85,6 +85,7 @@ const ( ManifestRecord_Identifier_GROUPV2 ManifestRecord_Identifier_Type = 3 ManifestRecord_Identifier_ACCOUNT ManifestRecord_Identifier_Type = 4 ManifestRecord_Identifier_STORY_DISTRIBUTION_LIST ManifestRecord_Identifier_Type = 5 + ManifestRecord_Identifier_CALL_LINK ManifestRecord_Identifier_Type = 7 ) // Enum value maps for ManifestRecord_Identifier_Type. @@ -96,6 +97,7 @@ var ( 3: "GROUPV2", 4: "ACCOUNT", 5: "STORY_DISTRIBUTION_LIST", + 7: "CALL_LINK", } ManifestRecord_Identifier_Type_value = map[string]int32{ "UNKNOWN": 0, @@ -104,6 +106,7 @@ var ( "GROUPV2": 3, "ACCOUNT": 4, "STORY_DISTRIBUTION_LIST": 5, + "CALL_LINK": 7, } ) @@ -698,6 +701,7 @@ type StorageRecord struct { // *StorageRecord_GroupV2 // *StorageRecord_Account // *StorageRecord_StoryDistributionList + // *StorageRecord_CallLink Record isStorageRecord_Record `protobuf_oneof:"record"` } @@ -775,6 +779,13 @@ func (x *StorageRecord) GetStoryDistributionList() *StoryDistributionListRecord return nil } +func (x *StorageRecord) GetCallLink() *CallLinkRecord { + if x, ok := x.GetRecord().(*StorageRecord_CallLink); ok { + return x.CallLink + } + return nil +} + type isStorageRecord_Record interface { isStorageRecord_Record() } @@ -799,6 +810,10 @@ type StorageRecord_StoryDistributionList struct { StoryDistributionList *StoryDistributionListRecord `protobuf:"bytes,5,opt,name=storyDistributionList,proto3,oneof"` } +type StorageRecord_CallLink struct { + CallLink *CallLinkRecord `protobuf:"bytes,7,opt,name=callLink,proto3,oneof"` +} + func (*StorageRecord_Contact) isStorageRecord_Record() {} func (*StorageRecord_GroupV1) isStorageRecord_Record() {} @@ -809,6 +824,8 @@ func (*StorageRecord_Account) isStorageRecord_Record() {} func (*StorageRecord_StoryDistributionList) isStorageRecord_Record() {} +func (*StorageRecord_CallLink) isStorageRecord_Record() {} + type ContactRecord struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1667,6 +1684,69 @@ func (x *StoryDistributionListRecord) GetIsBlockList() bool { return false } +type CallLinkRecord struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` + AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` + DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` +} + +func (x *CallLinkRecord) Reset() { + *x = CallLinkRecord{} + if protoimpl.UnsafeEnabled { + mi := &file_StorageService_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CallLinkRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallLinkRecord) ProtoMessage() {} + +func (x *CallLinkRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CallLinkRecord.ProtoReflect.Descriptor instead. +func (*CallLinkRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{13} +} + +func (x *CallLinkRecord) GetRootKey() []byte { + if x != nil { + return x.RootKey + } + return nil +} + +func (x *CallLinkRecord) GetAdminPasskey() []byte { + if x != nil { + return x.AdminPasskey + } + return nil +} + +func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 { + if x != nil { + return x.DeletedAtTimestampMs + } + return 0 +} + type ManifestRecord_Identifier struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1679,7 +1759,7 @@ type ManifestRecord_Identifier struct { func (x *ManifestRecord_Identifier) Reset() { *x = ManifestRecord_Identifier{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[13] + mi := &file_StorageService_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1692,7 +1772,7 @@ func (x *ManifestRecord_Identifier) String() string { func (*ManifestRecord_Identifier) ProtoMessage() {} func (x *ManifestRecord_Identifier) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[13] + mi := &file_StorageService_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1734,7 +1814,7 @@ type ContactRecord_Name struct { func (x *ContactRecord_Name) Reset() { *x = ContactRecord_Name{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1747,7 +1827,7 @@ func (x *ContactRecord_Name) String() string { func (*ContactRecord_Name) ProtoMessage() {} func (x *ContactRecord_Name) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1793,7 +1873,7 @@ type AccountRecord_PinnedConversation struct { func (x *AccountRecord_PinnedConversation) Reset() { *x = AccountRecord_PinnedConversation{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1806,7 +1886,7 @@ func (x *AccountRecord_PinnedConversation) String() string { func (*AccountRecord_PinnedConversation) ProtoMessage() {} func (x *AccountRecord_PinnedConversation) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1887,7 +1967,7 @@ type AccountRecord_UsernameLink struct { func (x *AccountRecord_UsernameLink) Reset() { *x = AccountRecord_UsernameLink{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1900,7 +1980,7 @@ func (x *AccountRecord_UsernameLink) String() string { func (*AccountRecord_UsernameLink) ProtoMessage() {} func (x *AccountRecord_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1949,7 +2029,7 @@ type AccountRecord_PinnedConversation_Contact struct { func (x *AccountRecord_PinnedConversation_Contact) Reset() { *x = AccountRecord_PinnedConversation_Contact{} if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[17] + mi := &file_StorageService_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1962,7 +2042,7 @@ func (x *AccountRecord_PinnedConversation_Contact) String() string { func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[17] + mi := &file_StorageService_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2010,7 +2090,7 @@ func file_StorageService_proto_rawDescGZIP() []byte { } var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 18) +var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_StorageService_proto_goTypes = []any{ (OptionalBool)(0), // 0: signalservice.OptionalBool (ManifestRecord_Identifier_Type)(0), // 1: signalservice.ManifestRecord.Identifier.Type @@ -2031,38 +2111,40 @@ var file_StorageService_proto_goTypes = []any{ (*Payments)(nil), // 16: signalservice.Payments (*AccountRecord)(nil), // 17: signalservice.AccountRecord (*StoryDistributionListRecord)(nil), // 18: signalservice.StoryDistributionListRecord - (*ManifestRecord_Identifier)(nil), // 19: signalservice.ManifestRecord.Identifier - (*ContactRecord_Name)(nil), // 20: signalservice.ContactRecord.Name - (*AccountRecord_PinnedConversation)(nil), // 21: signalservice.AccountRecord.PinnedConversation - (*AccountRecord_UsernameLink)(nil), // 22: signalservice.AccountRecord.UsernameLink - (*AccountRecord_PinnedConversation_Contact)(nil), // 23: signalservice.AccountRecord.PinnedConversation.Contact + (*CallLinkRecord)(nil), // 19: signalservice.CallLinkRecord + (*ManifestRecord_Identifier)(nil), // 20: signalservice.ManifestRecord.Identifier + (*ContactRecord_Name)(nil), // 21: signalservice.ContactRecord.Name + (*AccountRecord_PinnedConversation)(nil), // 22: signalservice.AccountRecord.PinnedConversation + (*AccountRecord_UsernameLink)(nil), // 23: signalservice.AccountRecord.UsernameLink + (*AccountRecord_PinnedConversation_Contact)(nil), // 24: signalservice.AccountRecord.PinnedConversation.Contact } var file_StorageService_proto_depIdxs = []int32{ 7, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem 6, // 1: signalservice.WriteOperation.manifest:type_name -> signalservice.StorageManifest 7, // 2: signalservice.WriteOperation.insertItem:type_name -> signalservice.StorageItem - 19, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier + 20, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier 13, // 4: signalservice.StorageRecord.contact:type_name -> signalservice.ContactRecord 14, // 5: signalservice.StorageRecord.groupV1:type_name -> signalservice.GroupV1Record 15, // 6: signalservice.StorageRecord.groupV2:type_name -> signalservice.GroupV2Record 17, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord 18, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord - 2, // 9: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState - 20, // 10: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name - 3, // 11: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode - 4, // 12: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode - 21, // 13: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation - 16, // 14: signalservice.AccountRecord.payments:type_name -> signalservice.Payments - 0, // 15: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool - 22, // 16: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink - 1, // 17: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type - 23, // 18: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact - 5, // 19: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color - 20, // [20:20] is the sub-list for method output_type - 20, // [20:20] is the sub-list for method input_type - 20, // [20:20] is the sub-list for extension type_name - 20, // [20:20] is the sub-list for extension extendee - 0, // [0:20] is the sub-list for field type_name + 19, // 9: signalservice.StorageRecord.callLink:type_name -> signalservice.CallLinkRecord + 2, // 10: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState + 21, // 11: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name + 3, // 12: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode + 4, // 13: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode + 22, // 14: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation + 16, // 15: signalservice.AccountRecord.payments:type_name -> signalservice.Payments + 0, // 16: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool + 23, // 17: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink + 1, // 18: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type + 24, // 19: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact + 5, // 20: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color + 21, // [21:21] is the sub-list for method output_type + 21, // [21:21] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_StorageService_proto_init() } @@ -2228,7 +2310,7 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*ManifestRecord_Identifier); i { + switch v := v.(*CallLinkRecord); i { case 0: return &v.state case 1: @@ -2240,7 +2322,7 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*ContactRecord_Name); i { + switch v := v.(*ManifestRecord_Identifier); i { case 0: return &v.state case 1: @@ -2252,7 +2334,7 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*AccountRecord_PinnedConversation); i { + switch v := v.(*ContactRecord_Name); i { case 0: return &v.state case 1: @@ -2264,7 +2346,7 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*AccountRecord_UsernameLink); i { + switch v := v.(*AccountRecord_PinnedConversation); i { case 0: return &v.state case 1: @@ -2276,6 +2358,18 @@ func file_StorageService_proto_init() { } } file_StorageService_proto_msgTypes[17].Exporter = func(v any, i int) any { + switch v := v.(*AccountRecord_UsernameLink); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_StorageService_proto_msgTypes[18].Exporter = func(v any, i int) any { switch v := v.(*AccountRecord_PinnedConversation_Contact); i { case 0: return &v.state @@ -2294,8 +2388,9 @@ func file_StorageService_proto_init() { (*StorageRecord_GroupV2)(nil), (*StorageRecord_Account)(nil), (*StorageRecord_StoryDistributionList)(nil), + (*StorageRecord_CallLink)(nil), } - file_StorageService_proto_msgTypes[15].OneofWrappers = []any{ + file_StorageService_proto_msgTypes[16].OneofWrappers = []any{ (*AccountRecord_PinnedConversation_Contact_)(nil), (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), @@ -2306,7 +2401,7 @@ func file_StorageService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_StorageService_proto_rawDesc, NumEnums: 6, - NumMessages: 18, + NumMessages: 19, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw index bd966cb8940f6481e516cf67d985ee329185222f..2dea02fae9b6d83f802dedf2454956c05857ef2e 100644 GIT binary patch delta 255 zcmaE=y-jz+B}T^2lP@#QVZ1iEfGL@=c=8pd6d@sAE>34hAD?(1Pd{$~cBMtko2{9n z8Eu8Exj2#&b8>t#^Rgw_6&N+Rjb!zTGt=`DbBa@o$}*Ev^_-#7L8;04MJXN(L2wP5 zr?FfXs8?!YzCkVzBQsUxCOv%m63rH+3&IU>|fu&Kz rgp9aEQc`nLOHxxDOF}YpQ;SOya|?WnC76L~S%T2y*dUUVGev6vbz)HK delta 43 zcmV+`0M!4sE#)h)(g6YFlhXm50mqYY0%HMWlhgua10v-Dvq}S70kh%+(-4z77JQJu B5d;7L diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index ac26d38..304e73f 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -50,6 +50,7 @@ message ManifestRecord { GROUPV2 = 3; ACCOUNT = 4; STORY_DISTRIBUTION_LIST = 5; + CALL_LINK = 7; } bytes raw = 1; @@ -69,6 +70,7 @@ message StorageRecord { GroupV2Record groupV2 = 3; AccountRecord account = 4; StoryDistributionListRecord storyDistributionList = 5; + CallLinkRecord callLink = 7; } } @@ -227,3 +229,9 @@ message StoryDistributionListRecord { bool allowsReplies = 5; bool isBlockList = 6; } + +message CallLinkRecord { + bytes rootKey = 1; + bytes adminPasskey = 2; + uint64 deletedAtTimestampMs = 3; +} diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 43790f4..87eb1ec 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-ab7bdc3c03ecda2d746fd56cfd747f56feab7b17} -DESKTOP_GIT_REVISION=${1:-1898e964adcfc8a9096b4aaebff895813fb4f35c} +ANDROID_GIT_REVISION=${1:-69e1146e2c5bbd6f2773dfe12f723e7cc88064be} +DESKTOP_GIT_REVISION=${1:-2640c34bd3eb6d338fbf32621fdf839d2ca3d155} update_proto() { case "$1" in From 8cde7b350ea42fa7a899502617f1d0b5d37a05a0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 2 Oct 2024 21:25:09 +0300 Subject: [PATCH 340/718] signalmeow/storageservice: don't stop reading records on error --- pkg/signalmeow/storageservice.go | 33 +++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index fab5eed..f062f12 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -252,29 +252,44 @@ func (cli *Client) fetchStorageRecords(ctx context.Context, storageKey []byte, i } items = append(items, itemChunk...) } - records := make([]*DecryptedStorageRecord, len(items)) + records := make([]*DecryptedStorageRecord, 0, len(items)) + log := zerolog.Ctx(ctx) for i, encryptedItem := range items { base64Key := base64.StdEncoding.EncodeToString(encryptedItem.GetKey()) + itemType, ok := inputRecords[base64Key] + if !ok { + log.Warn().Int("item_index", i).Str("item_key", base64Key).Msg("Received unexpected storage item") + continue + } itemKey := deriveStorageItemKey(storageKey, base64Key) decryptedItemBytes, err := decryptBytes(itemKey, encryptedItem.GetValue()) if err != nil { - return nil, nil, fmt.Errorf("failed to decrypt storage item #%d (%s): %w", i+1, base64Key, err) + log.Warn().Err(err). + Stringer("item_type", itemType). + Int("item_index", i). + Str("item_key", base64Key). + Msg("Failed to decrypt storage item") + continue } var decryptedItem signalpb.StorageRecord err = proto.Unmarshal(decryptedItemBytes, &decryptedItem) if err != nil { - return nil, nil, fmt.Errorf("failed to unmarshal decrypted storage item #%d (%s): %w", i+1, base64Key, err) - } - itemType, ok := inputRecords[base64Key] - if !ok { - return nil, nil, fmt.Errorf("received unexpected storage item at index #%d: %s", i+1, base64Key) + logEvt := log.Warn().Err(err). + Stringer("item_type", itemType). + Int("item_index", i). + Str("item_key", base64Key) + if log.GetLevel() == zerolog.TraceLevel { + logEvt.Str("item_data", base64.StdEncoding.EncodeToString(decryptedItemBytes)) + } + logEvt.Msg("Failed to unmarshal storage item") + continue } delete(inputRecords, base64Key) - records[i] = &DecryptedStorageRecord{ + records = append(records, &DecryptedStorageRecord{ ItemType: itemType, StorageID: base64Key, StorageRecord: &decryptedItem, - } + }) } missingKeys := maps.Keys(inputRecords) return records, missingKeys, nil From b73c822a25245d2742b7b0dccd4387e83abee0e2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 2 Oct 2024 21:57:32 +0300 Subject: [PATCH 341/718] signalmeow/storageservice: improve logging when syncing storage --- pkg/connector/connector.go | 1 + pkg/signalmeow/client.go | 1 + pkg/signalmeow/storageservice.go | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index e5995ad..8cdb368 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -100,6 +100,7 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use if device != nil { sc.Client = &signalmeow.Client{ Store: device, + Log: sc.UserLogin.Log.With().Str("component", "signalmeow").Logger(), EventHandler: sc.handleSignalEvent, SyncContactsOnConnect: s.Config.SyncContactsOnStartup, diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 14db3b7..fcb463a 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -33,6 +33,7 @@ import ( type Client struct { Store *store.Device + Log zerolog.Logger SenderCertificateWithE164 *libsignalgo.SenderCertificate SenderCertificateNoE164 *libsignalgo.SenderCertificate diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index f062f12..f2385f3 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -40,7 +40,8 @@ import ( ) func (cli *Client) SyncStorage(ctx context.Context) { - log := zerolog.Ctx(ctx).With().Str("action", "sync storage").Logger() + log := cli.Log.With().Str("action", "sync storage").Logger() + ctx = log.WithContext(ctx) // TODO only fetch changed entries update, err := cli.FetchStorage(ctx, cli.Store.MasterKey, 0, nil) if err != nil { @@ -112,7 +113,7 @@ func (cli *Client) SyncStorage(ctx context.Context) { case *signalpb.StorageRecord_GroupV1, *signalpb.StorageRecord_StoryDistributionList: // irrelevant data default: - log.Warn().Str("type", fmt.Sprintf("%T", data)).Msg("Unknown storage record type") + log.Warn().Type("type", data).Str("item_id", record.StorageID).Msg("Unknown storage record type") } } } From 9c492d0d27caf630b7c1da1ead9b405496207f85 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 2 Oct 2024 21:57:50 +0300 Subject: [PATCH 342/718] signalmeow/storageservice: fix decrypting items --- pkg/signalmeow/profile.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 81a6c86..1a7571c 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -17,6 +17,7 @@ package signalmeow import ( + "bytes" "context" "crypto/aes" "crypto/cipher" @@ -281,25 +282,19 @@ func decryptBytes(key []byte, encryptedText []byte) ([]byte, error) { } nonce := encryptedText[:NONCE_LENGTH] ciphertext := encryptedText[NONCE_LENGTH:] - padded, err := AesgcmDecrypt(key, nonce, ciphertext, []byte{}) + decrypted, err := AesgcmDecrypt(key, nonce, ciphertext, []byte{}) if err != nil { return nil, err } - paddedLength := len(padded) - plaintextLength := 0 - for i := paddedLength - 1; i >= 0; i-- { - if padded[i] != byte(0) { - plaintextLength = i + 1 - break - } - } - returnString := padded[:plaintextLength] - return returnString, nil + return decrypted, nil } func decryptString(key *libsignalgo.ProfileKey, encryptedText []byte) (string, error) { data, err := decryptBytes(key[:], encryptedText) - return string(data), err + if err != nil { + return "", err + } + return string(bytes.TrimRight(data, "\x00")), nil } func encryptString(key libsignalgo.ProfileKey, plaintext string, paddedLength int) ([]byte, error) { From ce776bc1a086ad851d2979380b922fdf3c703fae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 3 Oct 2024 11:54:10 +0300 Subject: [PATCH 343/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 876e05f..089636c 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.21.1-0.20240930142122-741b4e823ffb + maunium.net/go/mautrix v0.21.1-0.20241002213655-b9fdcd0dcefb ) require ( diff --git a/go.sum b/go.sum index d76e998..40815cb 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.21.1-0.20240930142122-741b4e823ffb h1:X19nOFvy3GINE6TbSshH5OiOgqbZqEgfu8e0Nsi2iAk= -maunium.net/go/mautrix v0.21.1-0.20240930142122-741b4e823ffb/go.mod h1:qN4yYKm3brOUWN8dlR0KPbKwSBGXQ4am/kzSQt/kLmY= +maunium.net/go/mautrix v0.21.1-0.20241002213655-b9fdcd0dcefb h1:mhJibm/mFfC/lHtySTA/e0J2pa/6p4Dy8r/TQv6DpDw= +maunium.net/go/mautrix v0.21.1-0.20241002213655-b9fdcd0dcefb/go.mod h1:qN4yYKm3brOUWN8dlR0KPbKwSBGXQ4am/kzSQt/kLmY= From bf96f62eec8acc79de8b2d4a20e2f354fddb7199 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 3 Oct 2024 12:39:02 +0300 Subject: [PATCH 344/718] libsignal: update to v0.58.1 --- go.mod | 8 +++---- go.sum | 12 +++++----- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 40 ++++++++++++++++++++++----------- pkg/libsignalgo/version.go | 2 +- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 089636c..283e984 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.22.0 -toolchain go1.23.1 +toolchain go1.23.2 require ( github.com/coder/websocket v1.8.12 @@ -12,13 +12,13 @@ require ( github.com/mattn/go-pointer v0.0.1 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 - github.com/tidwall/gjson v1.17.3 - go.mau.fi/util v0.8.1-0.20240927174413-000d30f9a02a + github.com/tidwall/gjson v1.18.0 + go.mau.fi/util v0.8.1-0.20241003092848-3b49d3e0b9ee golang.org/x/crypto v0.27.0 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.29.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.21.1-0.20241002213655-b9fdcd0dcefb + maunium.net/go/mautrix v0.21.1-0.20241003093300-7e041c6e76a5 ) require ( diff --git a/go.sum b/go.sum index 40815cb..c8e86e0 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= -github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.1-0.20240927174413-000d30f9a02a h1:4TrWJ0ooHT9YssDBUgXNU8FiR2cwi9jEAjtaVur4f0M= -go.mau.fi/util v0.8.1-0.20240927174413-000d30f9a02a/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ= +go.mau.fi/util v0.8.1-0.20241003092848-3b49d3e0b9ee h1:/BGpUK7fzVyFgy5KBiyP7ktEDn20vzz/5FTngrXtIEE= +go.mau.fi/util v0.8.1-0.20241003092848-3b49d3e0b9ee/go.mod h1:L9qnqEkhe4KpuYmILrdttKTXL79MwGLyJ4EOskWxO3I= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= @@ -97,5 +97,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.21.1-0.20241002213655-b9fdcd0dcefb h1:mhJibm/mFfC/lHtySTA/e0J2pa/6p4Dy8r/TQv6DpDw= -maunium.net/go/mautrix v0.21.1-0.20241002213655-b9fdcd0dcefb/go.mod h1:qN4yYKm3brOUWN8dlR0KPbKwSBGXQ4am/kzSQt/kLmY= +maunium.net/go/mautrix v0.21.1-0.20241003093300-7e041c6e76a5 h1:d5xUAixcJkxv9O3Ly/Ga2cU1Ez+WjS9gPIGD872wslw= +maunium.net/go/mautrix v0.21.1-0.20241003093300-7e041c6e76a5/go.mod h1:+fF5qsmXRCEXQZgW5ececC0PI3c7gISHTLcyftP4Bh0= diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 3917f60..5de6300 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 3917f60919a987573e0599d414bb5d9d6f155fe4 +Subproject commit 5de6300ab21b34984dd0f79214aa6f3c08ac755d diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 3ed14d2..60015ea 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -212,7 +212,9 @@ typedef struct SignalAes256GcmSiv SignalAes256GcmSiv; typedef struct SignalCdsiLookup SignalCdsiLookup; -typedef struct SignalChat SignalChat; +typedef struct SignalChatAuthChatService SignalChatAuthChatService; + +typedef struct SignalChatUnauthChatService SignalChatUnauthChatService; typedef struct SignalCiphertextMessage SignalCiphertextMessage; @@ -567,6 +569,10 @@ typedef struct { SignalCancellationId cancellation_id; } SignalCPromiseFfiCdsiLookupResponse; +typedef SignalChatAuthChatService SignalAuthChat; + +typedef SignalChatUnauthChatService SignalUnauthChat; + typedef struct { uint8_t raw_ip_type; double duration_secs; @@ -634,7 +640,7 @@ typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envel typedef void (*SignalReceivedQueueEmpty)(void *ctx); -typedef void (*SignalConnectionInterrupted)(void *ctx); +typedef void (*SignalConnectionInterrupted)(void *ctx, SignalFfiError *error); typedef void (*SignalDestroyChatListener)(void *ctx); @@ -1467,6 +1473,8 @@ SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalFfiError *signal_svr3_remove(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *enclave_password); +SignalFfiError *signal_svr3_rotate(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); + SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); SignalFfiError *signal_lookup_request_new(SignalLookupRequest **out); @@ -1489,7 +1497,9 @@ SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, const SignalCds SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalCdsiLookup *lookup); -SignalFfiError *signal_chat_destroy(SignalChat *p); +SignalFfiError *signal_auth_chat_destroy(SignalAuthChat *p); + +SignalFfiError *signal_unauth_chat_destroy(SignalUnauthChat *p); SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); @@ -1499,25 +1509,29 @@ SignalFfiError *signal_http_request_new_without_body(SignalHttpRequest **out, co SignalFfiError *signal_http_request_add_header(const SignalHttpRequest *request, const char *name, const char *value); -SignalFfiError *signal_chat_service_new(SignalChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password, bool receive_stories); +SignalFfiError *signal_chat_service_new_unauth(SignalUnauthChat **out, const SignalConnectionManager *connection_manager); -SignalFfiError *signal_chat_service_disconnect(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); +SignalFfiError *signal_chat_service_new_auth(SignalAuthChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password, bool receive_stories); -SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); +SignalFfiError *signal_chat_service_disconnect_unauth(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat); -SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat); +SignalFfiError *signal_chat_service_disconnect_auth(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat); -SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat); -SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat); -SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); +SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); +SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); + +SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncContext *runtime, const SignalAuthChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); + +SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalUnauthChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index c8272f5..a15914c 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.57.1" +const Version = "v0.58.1" From c4c57a8fe0c2fcfef6de487bb43cd75087d4ee0b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 14 Oct 2024 12:37:15 +0300 Subject: [PATCH 345/718] .github: update bug report template --- .github/ISSUE_TEMPLATE/bug.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 02ed284..18862a5 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -5,3 +5,10 @@ about: If something is definitely wrong in the bridge (rather than just a setup labels: bug --- + + From b9dc3d4707b061f4943f4c5fbf2035bb17c20915 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 14 Oct 2024 12:37:30 +0300 Subject: [PATCH 346/718] signalmeow/receiving: add timestamp for call messages --- pkg/signalmeow/receiving.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index ecd33f7..1961709 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -836,6 +836,8 @@ func (cli *Client) handleDecryptedResult( Sender: theirServiceID.UUID, ChatID: theirServiceID.String(), }, + // CallMessage doesn't have its own timestamp, use one from the envelope + Timestamp: envelope.GetTimestamp(), IsRinging: content.CallMessage.Offer != nil, }) } From 97e8f3eb5afa58b45e10e6aadc34edcf1f40cdae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Oct 2024 17:08:56 +0300 Subject: [PATCH 347/718] signalmeow: update protobufs --- pkg/msgconv/from-signal.go | 6 +- .../protobuf/ContactDiscovery.pb.go | 48 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 26 +- pkg/signalmeow/protobuf/Groups.pb.go | 884 ++------ pkg/signalmeow/protobuf/Provisioning.pb.go | 70 +- pkg/signalmeow/protobuf/SignalService.pb.go | 1804 +++-------------- pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19130 -> 19130 bytes pkg/signalmeow/protobuf/SignalService.proto | 3 +- .../protobuf/StickerResources.pb.go | 48 +- pkg/signalmeow/protobuf/StorageService.pb.go | 438 +--- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 5814 -> 5934 bytes pkg/signalmeow/protobuf/StorageService.proto | 2 + .../protobuf/UnidentifiedDelivery.pb.go | 136 +- .../protobuf/WebSocketResources.pb.go | 70 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 15 files changed, 671 insertions(+), 2868 deletions(-) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 4645dd0..9b27c07 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -237,8 +237,8 @@ func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact * HonorificSuffix: name.GetSuffix(), }) } - if name.GetDisplayName() != "" { - card.SetValue(vcard.FieldFormattedName, name.GetDisplayName()) + if name.GetNickname() != "" { + card.SetValue(vcard.FieldNickname, name.GetNickname()) } if contact.GetOrganization() != "" { card.SetValue(vcard.FieldOrganization, contact.GetOrganization()) @@ -320,7 +320,7 @@ func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact } } data := buf.Bytes() - displayName := contact.GetName().GetDisplayName() + displayName := contact.GetName().GetNickname() if displayName == "" { displayName = contact.GetName().GetGivenName() if contact.GetName().GetFamilyName() != "" { diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index f15eba4..6fd86ab 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: ContactDiscovery.proto @@ -54,11 +54,9 @@ type CDSClientRequest struct { func (x *CDSClientRequest) Reset() { *x = CDSClientRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ContactDiscovery_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ContactDiscovery_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CDSClientRequest) String() string { @@ -69,7 +67,7 @@ func (*CDSClientRequest) ProtoMessage() {} func (x *CDSClientRequest) ProtoReflect() protoreflect.Message { mi := &file_ContactDiscovery_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -166,11 +164,9 @@ type CDSClientResponse struct { func (x *CDSClientResponse) Reset() { *x = CDSClientResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ContactDiscovery_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ContactDiscovery_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CDSClientResponse) String() string { @@ -181,7 +177,7 @@ func (*CDSClientResponse) ProtoMessage() {} func (x *CDSClientResponse) ProtoReflect() protoreflect.Message { mi := &file_ContactDiscovery_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -245,32 +241,6 @@ func file_ContactDiscovery_proto_init() { if File_ContactDiscovery_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_ContactDiscovery_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*CDSClientRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ContactDiscovery_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*CDSClientResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 27dada3..8207918 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: DeviceName.proto @@ -37,11 +37,9 @@ type DeviceName struct { func (x *DeviceName) Reset() { *x = DeviceName{} - if protoimpl.UnsafeEnabled { - mi := &file_DeviceName_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_DeviceName_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeviceName) String() string { @@ -52,7 +50,7 @@ func (*DeviceName) ProtoMessage() {} func (x *DeviceName) ProtoReflect() protoreflect.Message { mi := &file_DeviceName_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -122,20 +120,6 @@ func file_DeviceName_proto_init() { if File_DeviceName_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_DeviceName_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*DeviceName); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index e76b7c1..b10d66a 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: Groups.proto @@ -147,11 +147,9 @@ type AvatarUploadAttributes struct { func (x *AvatarUploadAttributes) Reset() { *x = AvatarUploadAttributes{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AvatarUploadAttributes) String() string { @@ -162,7 +160,7 @@ func (*AvatarUploadAttributes) ProtoMessage() {} func (x *AvatarUploadAttributes) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -240,11 +238,9 @@ type Member struct { func (x *Member) Reset() { *x = Member{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Member) String() string { @@ -255,7 +251,7 @@ func (*Member) ProtoMessage() {} func (x *Member) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -317,11 +313,9 @@ type PendingMember struct { func (x *PendingMember) Reset() { *x = PendingMember{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PendingMember) String() string { @@ -332,7 +326,7 @@ func (*PendingMember) ProtoMessage() {} func (x *PendingMember) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -381,11 +375,9 @@ type RequestingMember struct { func (x *RequestingMember) Reset() { *x = RequestingMember{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RequestingMember) String() string { @@ -396,7 +388,7 @@ func (*RequestingMember) ProtoMessage() {} func (x *RequestingMember) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -450,11 +442,9 @@ type BannedMember struct { func (x *BannedMember) Reset() { *x = BannedMember{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BannedMember) String() string { @@ -465,7 +455,7 @@ func (*BannedMember) ProtoMessage() {} func (x *BannedMember) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -506,11 +496,9 @@ type AccessControl struct { func (x *AccessControl) Reset() { *x = AccessControl{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AccessControl) String() string { @@ -521,7 +509,7 @@ func (*AccessControl) ProtoMessage() {} func (x *AccessControl) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -579,11 +567,9 @@ type Group struct { func (x *Group) Reset() { *x = Group{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Group) String() string { @@ -594,7 +580,7 @@ func (*Group) ProtoMessage() {} func (x *Group) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -712,11 +698,9 @@ type GroupChange struct { func (x *GroupChange) Reset() { *x = GroupChange{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange) String() string { @@ -727,7 +711,7 @@ func (*GroupChange) ProtoMessage() {} func (x *GroupChange) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -774,11 +758,9 @@ type GroupResponse struct { func (x *GroupResponse) Reset() { *x = GroupResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupResponse) String() string { @@ -789,7 +771,7 @@ func (*GroupResponse) ProtoMessage() {} func (x *GroupResponse) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -829,11 +811,9 @@ type GroupChanges struct { func (x *GroupChanges) Reset() { *x = GroupChanges{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChanges) String() string { @@ -844,7 +824,7 @@ func (*GroupChanges) ProtoMessage() {} func (x *GroupChanges) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -884,11 +864,9 @@ type GroupChangeResponse struct { func (x *GroupChangeResponse) Reset() { *x = GroupChangeResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChangeResponse) String() string { @@ -899,7 +877,7 @@ func (*GroupChangeResponse) ProtoMessage() {} func (x *GroupChangeResponse) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -944,11 +922,9 @@ type GroupAttributeBlob struct { func (x *GroupAttributeBlob) Reset() { *x = GroupAttributeBlob{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupAttributeBlob) String() string { @@ -959,7 +935,7 @@ func (*GroupAttributeBlob) ProtoMessage() {} func (x *GroupAttributeBlob) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1050,11 +1026,9 @@ type GroupInviteLink struct { func (x *GroupInviteLink) Reset() { *x = GroupInviteLink{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupInviteLink) String() string { @@ -1065,7 +1039,7 @@ func (*GroupInviteLink) ProtoMessage() {} func (x *GroupInviteLink) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1121,11 +1095,9 @@ type GroupJoinInfo struct { func (x *GroupJoinInfo) Reset() { *x = GroupJoinInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupJoinInfo) String() string { @@ -1136,7 +1108,7 @@ func (*GroupJoinInfo) ProtoMessage() {} func (x *GroupJoinInfo) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1217,11 +1189,9 @@ type GroupExternalCredential struct { func (x *GroupExternalCredential) Reset() { *x = GroupExternalCredential{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupExternalCredential) String() string { @@ -1232,7 +1202,7 @@ func (*GroupExternalCredential) ProtoMessage() {} func (x *GroupExternalCredential) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1287,11 +1257,9 @@ type GroupChange_Actions struct { func (x *GroupChange_Actions) Reset() { *x = GroupChange_Actions{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions) String() string { @@ -1302,7 +1270,7 @@ func (*GroupChange_Actions) ProtoMessage() {} func (x *GroupChange_Actions) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1496,11 +1464,9 @@ type GroupChange_Actions_AddMemberAction struct { func (x *GroupChange_Actions_AddMemberAction) Reset() { *x = GroupChange_Actions_AddMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_AddMemberAction) String() string { @@ -1511,7 +1477,7 @@ func (*GroupChange_Actions_AddMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1550,11 +1516,9 @@ type GroupChange_Actions_DeleteMemberAction struct { func (x *GroupChange_Actions_DeleteMemberAction) Reset() { *x = GroupChange_Actions_DeleteMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_DeleteMemberAction) String() string { @@ -1565,7 +1529,7 @@ func (*GroupChange_Actions_DeleteMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1598,11 +1562,9 @@ type GroupChange_Actions_ModifyMemberRoleAction struct { func (x *GroupChange_Actions_ModifyMemberRoleAction) Reset() { *x = GroupChange_Actions_ModifyMemberRoleAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyMemberRoleAction) String() string { @@ -1613,7 +1575,7 @@ func (*GroupChange_Actions_ModifyMemberRoleAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMemberRoleAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1654,11 +1616,9 @@ type GroupChange_Actions_ModifyMemberProfileKeyAction struct { func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) Reset() { *x = GroupChange_Actions_ModifyMemberProfileKeyAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) String() string { @@ -1669,7 +1629,7 @@ func (*GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1715,11 +1675,9 @@ type GroupChange_Actions_AddPendingMemberAction struct { func (x *GroupChange_Actions_AddPendingMemberAction) Reset() { *x = GroupChange_Actions_AddPendingMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_AddPendingMemberAction) String() string { @@ -1730,7 +1688,7 @@ func (*GroupChange_Actions_AddPendingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddPendingMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1762,11 +1720,9 @@ type GroupChange_Actions_DeletePendingMemberAction struct { func (x *GroupChange_Actions_DeletePendingMemberAction) Reset() { *x = GroupChange_Actions_DeletePendingMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_DeletePendingMemberAction) String() string { @@ -1777,7 +1733,7 @@ func (*GroupChange_Actions_DeletePendingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeletePendingMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1811,11 +1767,9 @@ type GroupChange_Actions_PromotePendingMemberAction struct { func (x *GroupChange_Actions_PromotePendingMemberAction) Reset() { *x = GroupChange_Actions_PromotePendingMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_PromotePendingMemberAction) String() string { @@ -1826,7 +1780,7 @@ func (*GroupChange_Actions_PromotePendingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_PromotePendingMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1875,11 +1829,9 @@ type GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction struct { func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) Reset() { *x = GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) String() string { @@ -1890,7 +1842,7 @@ func (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoMess func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1943,11 +1895,9 @@ type GroupChange_Actions_AddRequestingMemberAction struct { func (x *GroupChange_Actions_AddRequestingMemberAction) Reset() { *x = GroupChange_Actions_AddRequestingMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_AddRequestingMemberAction) String() string { @@ -1958,7 +1908,7 @@ func (*GroupChange_Actions_AddRequestingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddRequestingMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1990,11 +1940,9 @@ type GroupChange_Actions_DeleteRequestingMemberAction struct { func (x *GroupChange_Actions_DeleteRequestingMemberAction) Reset() { *x = GroupChange_Actions_DeleteRequestingMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_DeleteRequestingMemberAction) String() string { @@ -2005,7 +1953,7 @@ func (*GroupChange_Actions_DeleteRequestingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteRequestingMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2038,11 +1986,9 @@ type GroupChange_Actions_PromoteRequestingMemberAction struct { func (x *GroupChange_Actions_PromoteRequestingMemberAction) Reset() { *x = GroupChange_Actions_PromoteRequestingMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_PromoteRequestingMemberAction) String() string { @@ -2053,7 +1999,7 @@ func (*GroupChange_Actions_PromoteRequestingMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_PromoteRequestingMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2092,11 +2038,9 @@ type GroupChange_Actions_AddBannedMemberAction struct { func (x *GroupChange_Actions_AddBannedMemberAction) Reset() { *x = GroupChange_Actions_AddBannedMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_AddBannedMemberAction) String() string { @@ -2107,7 +2051,7 @@ func (*GroupChange_Actions_AddBannedMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddBannedMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2139,11 +2083,9 @@ type GroupChange_Actions_DeleteBannedMemberAction struct { func (x *GroupChange_Actions_DeleteBannedMemberAction) Reset() { *x = GroupChange_Actions_DeleteBannedMemberAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_DeleteBannedMemberAction) String() string { @@ -2154,7 +2096,7 @@ func (*GroupChange_Actions_DeleteBannedMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteBannedMemberAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2186,11 +2128,9 @@ type GroupChange_Actions_ModifyTitleAction struct { func (x *GroupChange_Actions_ModifyTitleAction) Reset() { *x = GroupChange_Actions_ModifyTitleAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyTitleAction) String() string { @@ -2201,7 +2141,7 @@ func (*GroupChange_Actions_ModifyTitleAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyTitleAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2233,11 +2173,9 @@ type GroupChange_Actions_ModifyDescriptionAction struct { func (x *GroupChange_Actions_ModifyDescriptionAction) Reset() { *x = GroupChange_Actions_ModifyDescriptionAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyDescriptionAction) String() string { @@ -2248,7 +2186,7 @@ func (*GroupChange_Actions_ModifyDescriptionAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyDescriptionAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2280,11 +2218,9 @@ type GroupChange_Actions_ModifyAvatarAction struct { func (x *GroupChange_Actions_ModifyAvatarAction) Reset() { *x = GroupChange_Actions_ModifyAvatarAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyAvatarAction) String() string { @@ -2295,7 +2231,7 @@ func (*GroupChange_Actions_ModifyAvatarAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAvatarAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2327,11 +2263,9 @@ type GroupChange_Actions_ModifyDisappearingMessagesTimerAction struct { func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) Reset() { *x = GroupChange_Actions_ModifyDisappearingMessagesTimerAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) String() string { @@ -2342,7 +2276,7 @@ func (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoMessage() func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2374,11 +2308,9 @@ type GroupChange_Actions_ModifyAttributesAccessControlAction struct { func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyAttributesAccessControlAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) String() string { @@ -2389,7 +2321,7 @@ func (*GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoMessage() { func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2421,11 +2353,9 @@ type GroupChange_Actions_ModifyMembersAccessControlAction struct { func (x *GroupChange_Actions_ModifyMembersAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyMembersAccessControlAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyMembersAccessControlAction) String() string { @@ -2436,7 +2366,7 @@ func (*GroupChange_Actions_ModifyMembersAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMembersAccessControlAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2468,11 +2398,9 @@ type GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction struct { func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) String() string { @@ -2483,7 +2411,7 @@ func (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoMess func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2515,11 +2443,9 @@ type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() { *x = GroupChange_Actions_ModifyInviteLinkPasswordAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) String() string { @@ -2530,7 +2456,7 @@ func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2562,11 +2488,9 @@ type GroupChange_Actions_ModifyAnnouncementsOnlyAction struct { func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() { *x = GroupChange_Actions_ModifyAnnouncementsOnlyAction{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) String() string { @@ -2577,7 +2501,7 @@ func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2610,11 +2534,9 @@ type GroupChanges_GroupChangeState struct { func (x *GroupChanges_GroupChangeState) Reset() { *x = GroupChanges_GroupChangeState{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupChanges_GroupChangeState) String() string { @@ -2625,7 +2547,7 @@ func (*GroupChanges_GroupChangeState) ProtoMessage() {} func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2665,11 +2587,9 @@ type GroupInviteLink_GroupInviteLinkContentsV1 struct { func (x *GroupInviteLink_GroupInviteLinkContentsV1) Reset() { *x = GroupInviteLink_GroupInviteLinkContentsV1{} - if protoimpl.UnsafeEnabled { - mi := &file_Groups_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Groups_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupInviteLink_GroupInviteLinkContentsV1) String() string { @@ -2680,7 +2600,7 @@ func (*GroupInviteLink_GroupInviteLinkContentsV1) ProtoMessage() {} func (x *GroupInviteLink_GroupInviteLinkContentsV1) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2833,488 +2753,6 @@ func file_Groups_proto_init() { if File_Groups_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_Groups_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*AvatarUploadAttributes); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*Member); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*PendingMember); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*RequestingMember); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*BannedMember); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*AccessControl); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*Group); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*GroupResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*GroupChanges); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*GroupChangeResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*GroupAttributeBlob); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*GroupInviteLink); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*GroupJoinInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*GroupExternalCredential); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_AddMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_DeleteMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyMemberRoleAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyMemberProfileKeyAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_AddPendingMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_DeletePendingMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_PromotePendingMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_AddRequestingMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_DeleteRequestingMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_PromoteRequestingMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_AddBannedMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_DeleteBannedMemberAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyTitleAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyDescriptionAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyAvatarAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[32].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyDisappearingMessagesTimerAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[33].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyAttributesAccessControlAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[34].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyMembersAccessControlAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[35].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[36].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyInviteLinkPasswordAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[37].Exporter = func(v any, i int) any { - switch v := v.(*GroupChange_Actions_ModifyAnnouncementsOnlyAction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[38].Exporter = func(v any, i int) any { - switch v := v.(*GroupChanges_GroupChangeState); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Groups_proto_msgTypes[39].Exporter = func(v any, i int) any { - switch v := v.(*GroupInviteLink_GroupInviteLinkContentsV1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } file_Groups_proto_msgTypes[11].OneofWrappers = []any{ (*GroupAttributeBlob_Title)(nil), (*GroupAttributeBlob_Avatar)(nil), diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index efde7da..7a866f3 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: Provisioning.proto @@ -96,11 +96,9 @@ type ProvisioningUuid struct { func (x *ProvisioningUuid) Reset() { *x = ProvisioningUuid{} - if protoimpl.UnsafeEnabled { - mi := &file_Provisioning_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Provisioning_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProvisioningUuid) String() string { @@ -111,7 +109,7 @@ func (*ProvisioningUuid) ProtoMessage() {} func (x *ProvisioningUuid) ProtoReflect() protoreflect.Message { mi := &file_Provisioning_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -144,11 +142,9 @@ type ProvisionEnvelope struct { func (x *ProvisionEnvelope) Reset() { *x = ProvisionEnvelope{} - if protoimpl.UnsafeEnabled { - mi := &file_Provisioning_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Provisioning_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProvisionEnvelope) String() string { @@ -159,7 +155,7 @@ func (*ProvisionEnvelope) ProtoMessage() {} func (x *ProvisionEnvelope) ProtoReflect() protoreflect.Message { mi := &file_Provisioning_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -210,11 +206,9 @@ type ProvisionMessage struct { func (x *ProvisionMessage) Reset() { *x = ProvisionMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_Provisioning_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Provisioning_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ProvisionMessage) String() string { @@ -225,7 +219,7 @@ func (*ProvisionMessage) ProtoMessage() {} func (x *ProvisionMessage) ProtoReflect() protoreflect.Message { mi := &file_Provisioning_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -369,44 +363,6 @@ func file_Provisioning_proto_init() { if File_Provisioning_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_Provisioning_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*ProvisioningUuid); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Provisioning_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*ProvisionEnvelope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Provisioning_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*ProvisionMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index f96f5d8..9ce328c 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: SignalService.proto @@ -1724,11 +1724,9 @@ const ( func (x *Envelope) Reset() { *x = Envelope{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Envelope) String() string { @@ -1739,7 +1737,7 @@ func (*Envelope) ProtoMessage() {} func (x *Envelope) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1851,11 +1849,9 @@ type Content struct { func (x *Content) Reset() { *x = Content{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Content) String() string { @@ -1866,7 +1862,7 @@ func (*Content) ProtoMessage() {} func (x *Content) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1974,11 +1970,9 @@ type CallMessage struct { func (x *CallMessage) Reset() { *x = CallMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage) String() string { @@ -1989,7 +1983,7 @@ func (*CallMessage) ProtoMessage() {} func (x *CallMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2069,11 +2063,9 @@ type BodyRange struct { func (x *BodyRange) Reset() { *x = BodyRange{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BodyRange) String() string { @@ -2084,7 +2076,7 @@ func (*BodyRange) ProtoMessage() {} func (x *BodyRange) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2180,11 +2172,9 @@ type DataMessage struct { func (x *DataMessage) Reset() { *x = DataMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage) String() string { @@ -2195,7 +2185,7 @@ func (*DataMessage) ProtoMessage() {} func (x *DataMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2367,11 +2357,9 @@ type NullMessage struct { func (x *NullMessage) Reset() { *x = NullMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *NullMessage) String() string { @@ -2382,7 +2370,7 @@ func (*NullMessage) ProtoMessage() {} func (x *NullMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2415,11 +2403,9 @@ type ReceiptMessage struct { func (x *ReceiptMessage) Reset() { *x = ReceiptMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReceiptMessage) String() string { @@ -2430,7 +2416,7 @@ func (*ReceiptMessage) ProtoMessage() {} func (x *ReceiptMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2471,11 +2457,9 @@ type TypingMessage struct { func (x *TypingMessage) Reset() { *x = TypingMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TypingMessage) String() string { @@ -2486,7 +2470,7 @@ func (*TypingMessage) ProtoMessage() {} func (x *TypingMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2540,11 +2524,9 @@ type StoryMessage struct { func (x *StoryMessage) Reset() { *x = StoryMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StoryMessage) String() string { @@ -2555,7 +2537,7 @@ func (*StoryMessage) ProtoMessage() {} func (x *StoryMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2649,11 +2631,9 @@ type Preview struct { func (x *Preview) Reset() { *x = Preview{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Preview) String() string { @@ -2664,7 +2644,7 @@ func (*Preview) ProtoMessage() {} func (x *Preview) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2733,11 +2713,9 @@ type TextAttachment struct { func (x *TextAttachment) Reset() { *x = TextAttachment{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TextAttachment) String() string { @@ -2748,7 +2726,7 @@ func (*TextAttachment) ProtoMessage() {} func (x *TextAttachment) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2848,11 +2826,9 @@ type Verified struct { func (x *Verified) Reset() { *x = Verified{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Verified) String() string { @@ -2863,7 +2839,7 @@ func (*Verified) ProtoMessage() {} func (x *Verified) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2935,11 +2911,9 @@ type SyncMessage struct { func (x *SyncMessage) Reset() { *x = SyncMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage) String() string { @@ -2950,7 +2924,7 @@ func (*SyncMessage) ProtoMessage() {} func (x *SyncMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3135,11 +3109,9 @@ type AttachmentPointer struct { func (x *AttachmentPointer) Reset() { *x = AttachmentPointer{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AttachmentPointer) String() string { @@ -3150,7 +3122,7 @@ func (*AttachmentPointer) ProtoMessage() {} func (x *AttachmentPointer) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3329,11 +3301,9 @@ type GroupContext struct { func (x *GroupContext) Reset() { *x = GroupContext{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupContext) String() string { @@ -3344,7 +3314,7 @@ func (*GroupContext) ProtoMessage() {} func (x *GroupContext) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3413,11 +3383,9 @@ type GroupContextV2 struct { func (x *GroupContextV2) Reset() { *x = GroupContextV2{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupContextV2) String() string { @@ -3428,7 +3396,7 @@ func (*GroupContextV2) ProtoMessage() {} func (x *GroupContextV2) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3484,11 +3452,9 @@ type ContactDetails struct { func (x *ContactDetails) Reset() { *x = ContactDetails{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ContactDetails) String() string { @@ -3499,7 +3465,7 @@ func (*ContactDetails) ProtoMessage() {} func (x *ContactDetails) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3616,11 +3582,9 @@ const ( func (x *GroupDetails) Reset() { *x = GroupDetails{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupDetails) String() string { @@ -3631,7 +3595,7 @@ func (*GroupDetails) ProtoMessage() {} func (x *GroupDetails) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3736,11 +3700,9 @@ type PaymentAddress struct { func (x *PaymentAddress) Reset() { *x = PaymentAddress{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PaymentAddress) String() string { @@ -3751,7 +3713,7 @@ func (*PaymentAddress) ProtoMessage() {} func (x *PaymentAddress) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3802,11 +3764,9 @@ type DecryptionErrorMessage struct { func (x *DecryptionErrorMessage) Reset() { *x = DecryptionErrorMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DecryptionErrorMessage) String() string { @@ -3817,7 +3777,7 @@ func (*DecryptionErrorMessage) ProtoMessage() {} func (x *DecryptionErrorMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3864,11 +3824,9 @@ type PniSignatureMessage struct { func (x *PniSignatureMessage) Reset() { *x = PniSignatureMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PniSignatureMessage) String() string { @@ -3879,7 +3837,7 @@ func (*PniSignatureMessage) ProtoMessage() {} func (x *PniSignatureMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3919,11 +3877,9 @@ type EditMessage struct { func (x *EditMessage) Reset() { *x = EditMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *EditMessage) String() string { @@ -3934,7 +3890,7 @@ func (*EditMessage) ProtoMessage() {} func (x *EditMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -3975,11 +3931,9 @@ type CallMessage_Offer struct { func (x *CallMessage_Offer) Reset() { *x = CallMessage_Offer{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage_Offer) String() string { @@ -3990,7 +3944,7 @@ func (*CallMessage_Offer) ProtoMessage() {} func (x *CallMessage_Offer) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4037,11 +3991,9 @@ type CallMessage_Answer struct { func (x *CallMessage_Answer) Reset() { *x = CallMessage_Answer{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage_Answer) String() string { @@ -4052,7 +4004,7 @@ func (*CallMessage_Answer) ProtoMessage() {} func (x *CallMessage_Answer) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4092,11 +4044,9 @@ type CallMessage_IceUpdate struct { func (x *CallMessage_IceUpdate) Reset() { *x = CallMessage_IceUpdate{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage_IceUpdate) String() string { @@ -4107,7 +4057,7 @@ func (*CallMessage_IceUpdate) ProtoMessage() {} func (x *CallMessage_IceUpdate) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4146,11 +4096,9 @@ type CallMessage_Busy struct { func (x *CallMessage_Busy) Reset() { *x = CallMessage_Busy{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage_Busy) String() string { @@ -4161,7 +4109,7 @@ func (*CallMessage_Busy) ProtoMessage() {} func (x *CallMessage_Busy) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4195,11 +4143,9 @@ type CallMessage_Hangup struct { func (x *CallMessage_Hangup) Reset() { *x = CallMessage_Hangup{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage_Hangup) String() string { @@ -4210,7 +4156,7 @@ func (*CallMessage_Hangup) ProtoMessage() {} func (x *CallMessage_Hangup) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4257,11 +4203,9 @@ type CallMessage_Opaque struct { func (x *CallMessage_Opaque) Reset() { *x = CallMessage_Opaque{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallMessage_Opaque) String() string { @@ -4272,7 +4216,7 @@ func (*CallMessage_Opaque) ProtoMessage() {} func (x *CallMessage_Opaque) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4316,11 +4260,9 @@ type DataMessage_Quote struct { func (x *DataMessage_Quote) Reset() { *x = DataMessage_Quote{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Quote) String() string { @@ -4331,7 +4273,7 @@ func (*DataMessage_Quote) ProtoMessage() {} func (x *DataMessage_Quote) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4403,11 +4345,9 @@ type DataMessage_Contact struct { func (x *DataMessage_Contact) Reset() { *x = DataMessage_Contact{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Contact) String() string { @@ -4418,7 +4358,7 @@ func (*DataMessage_Contact) ProtoMessage() {} func (x *DataMessage_Contact) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4489,11 +4429,9 @@ type DataMessage_Sticker struct { func (x *DataMessage_Sticker) Reset() { *x = DataMessage_Sticker{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Sticker) String() string { @@ -4504,7 +4442,7 @@ func (*DataMessage_Sticker) ProtoMessage() {} func (x *DataMessage_Sticker) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4567,11 +4505,9 @@ type DataMessage_Reaction struct { func (x *DataMessage_Reaction) Reset() { *x = DataMessage_Reaction{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Reaction) String() string { @@ -4582,7 +4518,7 @@ func (*DataMessage_Reaction) ProtoMessage() {} func (x *DataMessage_Reaction) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4635,11 +4571,9 @@ type DataMessage_Delete struct { func (x *DataMessage_Delete) Reset() { *x = DataMessage_Delete{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Delete) String() string { @@ -4650,7 +4584,7 @@ func (*DataMessage_Delete) ProtoMessage() {} func (x *DataMessage_Delete) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4682,11 +4616,9 @@ type DataMessage_GroupCallUpdate struct { func (x *DataMessage_GroupCallUpdate) Reset() { *x = DataMessage_GroupCallUpdate{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_GroupCallUpdate) String() string { @@ -4697,7 +4629,7 @@ func (*DataMessage_GroupCallUpdate) ProtoMessage() {} func (x *DataMessage_GroupCallUpdate) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4730,11 +4662,9 @@ type DataMessage_StoryContext struct { func (x *DataMessage_StoryContext) Reset() { *x = DataMessage_StoryContext{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_StoryContext) String() string { @@ -4745,7 +4675,7 @@ func (*DataMessage_StoryContext) ProtoMessage() {} func (x *DataMessage_StoryContext) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4788,11 +4718,9 @@ type DataMessage_Payment struct { func (x *DataMessage_Payment) Reset() { *x = DataMessage_Payment{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Payment) String() string { @@ -4803,7 +4731,7 @@ func (*DataMessage_Payment) ProtoMessage() {} func (x *DataMessage_Payment) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4865,11 +4793,9 @@ type DataMessage_GiftBadge struct { func (x *DataMessage_GiftBadge) Reset() { *x = DataMessage_GiftBadge{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_GiftBadge) String() string { @@ -4880,7 +4806,7 @@ func (*DataMessage_GiftBadge) ProtoMessage() {} func (x *DataMessage_GiftBadge) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4914,11 +4840,9 @@ type DataMessage_Quote_QuotedAttachment struct { func (x *DataMessage_Quote_QuotedAttachment) Reset() { *x = DataMessage_Quote_QuotedAttachment{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Quote_QuotedAttachment) String() string { @@ -4929,7 +4853,7 @@ func (*DataMessage_Quote_QuotedAttachment) ProtoMessage() {} func (x *DataMessage_Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -4970,21 +4894,19 @@ type DataMessage_Contact_Name struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - GivenName *string `protobuf:"bytes,1,opt,name=givenName" json:"givenName,omitempty"` - FamilyName *string `protobuf:"bytes,2,opt,name=familyName" json:"familyName,omitempty"` - Prefix *string `protobuf:"bytes,3,opt,name=prefix" json:"prefix,omitempty"` - Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` - MiddleName *string `protobuf:"bytes,5,opt,name=middleName" json:"middleName,omitempty"` - DisplayName *string `protobuf:"bytes,6,opt,name=displayName" json:"displayName,omitempty"` + GivenName *string `protobuf:"bytes,1,opt,name=givenName" json:"givenName,omitempty"` + FamilyName *string `protobuf:"bytes,2,opt,name=familyName" json:"familyName,omitempty"` + Prefix *string `protobuf:"bytes,3,opt,name=prefix" json:"prefix,omitempty"` + Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` + MiddleName *string `protobuf:"bytes,5,opt,name=middleName" json:"middleName,omitempty"` + Nickname *string `protobuf:"bytes,7,opt,name=nickname" json:"nickname,omitempty"` } func (x *DataMessage_Contact_Name) Reset() { *x = DataMessage_Contact_Name{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Contact_Name) String() string { @@ -4995,7 +4917,7 @@ func (*DataMessage_Contact_Name) ProtoMessage() {} func (x *DataMessage_Contact_Name) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5045,9 +4967,9 @@ func (x *DataMessage_Contact_Name) GetMiddleName() string { return "" } -func (x *DataMessage_Contact_Name) GetDisplayName() string { - if x != nil && x.DisplayName != nil { - return *x.DisplayName +func (x *DataMessage_Contact_Name) GetNickname() string { + if x != nil && x.Nickname != nil { + return *x.Nickname } return "" } @@ -5064,11 +4986,9 @@ type DataMessage_Contact_Phone struct { func (x *DataMessage_Contact_Phone) Reset() { *x = DataMessage_Contact_Phone{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Contact_Phone) String() string { @@ -5079,7 +4999,7 @@ func (*DataMessage_Contact_Phone) ProtoMessage() {} func (x *DataMessage_Contact_Phone) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5127,11 +5047,9 @@ type DataMessage_Contact_Email struct { func (x *DataMessage_Contact_Email) Reset() { *x = DataMessage_Contact_Email{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Contact_Email) String() string { @@ -5142,7 +5060,7 @@ func (*DataMessage_Contact_Email) ProtoMessage() {} func (x *DataMessage_Contact_Email) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5196,11 +5114,9 @@ type DataMessage_Contact_PostalAddress struct { func (x *DataMessage_Contact_PostalAddress) Reset() { *x = DataMessage_Contact_PostalAddress{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Contact_PostalAddress) String() string { @@ -5211,7 +5127,7 @@ func (*DataMessage_Contact_PostalAddress) ProtoMessage() {} func (x *DataMessage_Contact_PostalAddress) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5300,11 +5216,9 @@ type DataMessage_Contact_Avatar struct { func (x *DataMessage_Contact_Avatar) Reset() { *x = DataMessage_Contact_Avatar{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Contact_Avatar) String() string { @@ -5315,7 +5229,7 @@ func (*DataMessage_Contact_Avatar) ProtoMessage() {} func (x *DataMessage_Contact_Avatar) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[42] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5357,11 +5271,9 @@ type DataMessage_Payment_Amount struct { func (x *DataMessage_Payment_Amount) Reset() { *x = DataMessage_Payment_Amount{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Payment_Amount) String() string { @@ -5372,7 +5284,7 @@ func (*DataMessage_Payment_Amount) ProtoMessage() {} func (x *DataMessage_Payment_Amount) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5425,11 +5337,9 @@ type DataMessage_Payment_Notification struct { func (x *DataMessage_Payment_Notification) Reset() { *x = DataMessage_Payment_Notification{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Payment_Notification) String() string { @@ -5440,7 +5350,7 @@ func (*DataMessage_Payment_Notification) ProtoMessage() {} func (x *DataMessage_Payment_Notification) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5497,11 +5407,9 @@ type DataMessage_Payment_Activation struct { func (x *DataMessage_Payment_Activation) Reset() { *x = DataMessage_Payment_Activation{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Payment_Activation) String() string { @@ -5512,7 +5420,7 @@ func (*DataMessage_Payment_Activation) ProtoMessage() {} func (x *DataMessage_Payment_Activation) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[45] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5544,11 +5452,9 @@ type DataMessage_Payment_Amount_MobileCoin struct { func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { *x = DataMessage_Payment_Amount_MobileCoin{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Payment_Amount_MobileCoin) String() string { @@ -5559,7 +5465,7 @@ func (*DataMessage_Payment_Amount_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Amount_MobileCoin) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[46] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5591,11 +5497,9 @@ type DataMessage_Payment_Notification_MobileCoin struct { func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { *x = DataMessage_Payment_Notification_MobileCoin{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[47] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DataMessage_Payment_Notification_MobileCoin) String() string { @@ -5606,7 +5510,7 @@ func (*DataMessage_Payment_Notification_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Notification_MobileCoin) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[47] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5642,11 +5546,9 @@ type TextAttachment_Gradient struct { func (x *TextAttachment_Gradient) Reset() { *x = TextAttachment_Gradient{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[48] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TextAttachment_Gradient) String() string { @@ -5657,7 +5559,7 @@ func (*TextAttachment_Gradient) ProtoMessage() {} func (x *TextAttachment_Gradient) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[48] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5731,11 +5633,9 @@ const ( func (x *SyncMessage_Sent) Reset() { *x = SyncMessage_Sent{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[49] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Sent) String() string { @@ -5746,7 +5646,7 @@ func (*SyncMessage_Sent) ProtoMessage() {} func (x *SyncMessage_Sent) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[49] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5847,11 +5747,9 @@ const ( func (x *SyncMessage_Contacts) Reset() { *x = SyncMessage_Contacts{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[50] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Contacts) String() string { @@ -5862,7 +5760,7 @@ func (*SyncMessage_Contacts) ProtoMessage() {} func (x *SyncMessage_Contacts) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[50] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5903,11 +5801,9 @@ type SyncMessage_Blocked struct { func (x *SyncMessage_Blocked) Reset() { *x = SyncMessage_Blocked{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[51] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Blocked) String() string { @@ -5918,7 +5814,7 @@ func (*SyncMessage_Blocked) ProtoMessage() {} func (x *SyncMessage_Blocked) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[51] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -5964,11 +5860,9 @@ type SyncMessage_Request struct { func (x *SyncMessage_Request) Reset() { *x = SyncMessage_Request{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[52] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Request) String() string { @@ -5979,7 +5873,7 @@ func (*SyncMessage_Request) ProtoMessage() {} func (x *SyncMessage_Request) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[52] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6012,11 +5906,9 @@ type SyncMessage_Read struct { func (x *SyncMessage_Read) Reset() { *x = SyncMessage_Read{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[53] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Read) String() string { @@ -6027,7 +5919,7 @@ func (*SyncMessage_Read) ProtoMessage() {} func (x *SyncMessage_Read) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[53] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6067,11 +5959,9 @@ type SyncMessage_Viewed struct { func (x *SyncMessage_Viewed) Reset() { *x = SyncMessage_Viewed{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[54] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Viewed) String() string { @@ -6082,7 +5972,7 @@ func (*SyncMessage_Viewed) ProtoMessage() {} func (x *SyncMessage_Viewed) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[54] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6125,11 +6015,9 @@ type SyncMessage_Configuration struct { func (x *SyncMessage_Configuration) Reset() { *x = SyncMessage_Configuration{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[55] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Configuration) String() string { @@ -6140,7 +6028,7 @@ func (*SyncMessage_Configuration) ProtoMessage() {} func (x *SyncMessage_Configuration) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[55] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6202,11 +6090,9 @@ type SyncMessage_StickerPackOperation struct { func (x *SyncMessage_StickerPackOperation) Reset() { *x = SyncMessage_StickerPackOperation{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[56] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_StickerPackOperation) String() string { @@ -6217,7 +6103,7 @@ func (*SyncMessage_StickerPackOperation) ProtoMessage() {} func (x *SyncMessage_StickerPackOperation) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[56] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6264,11 +6150,9 @@ type SyncMessage_ViewOnceOpen struct { func (x *SyncMessage_ViewOnceOpen) Reset() { *x = SyncMessage_ViewOnceOpen{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[57] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_ViewOnceOpen) String() string { @@ -6279,7 +6163,7 @@ func (*SyncMessage_ViewOnceOpen) ProtoMessage() {} func (x *SyncMessage_ViewOnceOpen) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[57] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6318,11 +6202,9 @@ type SyncMessage_FetchLatest struct { func (x *SyncMessage_FetchLatest) Reset() { *x = SyncMessage_FetchLatest{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[58] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_FetchLatest) String() string { @@ -6333,7 +6215,7 @@ func (*SyncMessage_FetchLatest) ProtoMessage() {} func (x *SyncMessage_FetchLatest) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[58] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6367,11 +6249,9 @@ type SyncMessage_Keys struct { func (x *SyncMessage_Keys) Reset() { *x = SyncMessage_Keys{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[59] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Keys) String() string { @@ -6382,7 +6262,7 @@ func (*SyncMessage_Keys) ProtoMessage() {} func (x *SyncMessage_Keys) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[59] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6423,11 +6303,9 @@ type SyncMessage_MessageRequestResponse struct { func (x *SyncMessage_MessageRequestResponse) Reset() { *x = SyncMessage_MessageRequestResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[60] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_MessageRequestResponse) String() string { @@ -6438,7 +6316,7 @@ func (*SyncMessage_MessageRequestResponse) ProtoMessage() {} func (x *SyncMessage_MessageRequestResponse) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[60] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6489,11 +6367,9 @@ type SyncMessage_OutgoingPayment struct { func (x *SyncMessage_OutgoingPayment) Reset() { *x = SyncMessage_OutgoingPayment{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[61] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_OutgoingPayment) String() string { @@ -6504,7 +6380,7 @@ func (*SyncMessage_OutgoingPayment) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[61] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6571,11 +6447,9 @@ type SyncMessage_PniChangeNumber struct { func (x *SyncMessage_PniChangeNumber) Reset() { *x = SyncMessage_PniChangeNumber{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[62] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_PniChangeNumber) String() string { @@ -6586,7 +6460,7 @@ func (*SyncMessage_PniChangeNumber) ProtoMessage() {} func (x *SyncMessage_PniChangeNumber) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[62] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6651,11 +6525,9 @@ type SyncMessage_CallEvent struct { func (x *SyncMessage_CallEvent) Reset() { *x = SyncMessage_CallEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[63] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_CallEvent) String() string { @@ -6666,7 +6538,7 @@ func (*SyncMessage_CallEvent) ProtoMessage() {} func (x *SyncMessage_CallEvent) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[63] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6735,11 +6607,9 @@ type SyncMessage_CallLinkUpdate struct { func (x *SyncMessage_CallLinkUpdate) Reset() { *x = SyncMessage_CallLinkUpdate{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[64] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_CallLinkUpdate) String() string { @@ -6750,7 +6620,7 @@ func (*SyncMessage_CallLinkUpdate) ProtoMessage() {} func (x *SyncMessage_CallLinkUpdate) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[64] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6804,11 +6674,9 @@ type SyncMessage_CallLogEvent struct { func (x *SyncMessage_CallLogEvent) Reset() { *x = SyncMessage_CallLogEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[65] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_CallLogEvent) String() string { @@ -6819,7 +6687,7 @@ func (*SyncMessage_CallLogEvent) ProtoMessage() {} func (x *SyncMessage_CallLogEvent) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[65] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6875,11 +6743,9 @@ type SyncMessage_DeleteForMe struct { func (x *SyncMessage_DeleteForMe) Reset() { *x = SyncMessage_DeleteForMe{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[66] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe) String() string { @@ -6890,7 +6756,7 @@ func (*SyncMessage_DeleteForMe) ProtoMessage() {} func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[66] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -6945,11 +6811,9 @@ type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[67] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { @@ -6960,7 +6824,7 @@ func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[67] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7008,11 +6872,9 @@ type SyncMessage_Sent_StoryMessageRecipient struct { func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[68] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { @@ -7023,7 +6885,7 @@ func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[68] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7079,11 +6941,9 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[69] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { @@ -7094,7 +6954,7 @@ func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[69] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7180,11 +7040,9 @@ type SyncMessage_DeleteForMe_ConversationIdentifier struct { func (x *SyncMessage_DeleteForMe_ConversationIdentifier) Reset() { *x = SyncMessage_DeleteForMe_ConversationIdentifier{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[70] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe_ConversationIdentifier) String() string { @@ -7195,7 +7053,7 @@ func (*SyncMessage_DeleteForMe_ConversationIdentifier) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationIdentifier) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[70] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7278,11 +7136,9 @@ type SyncMessage_DeleteForMe_AddressableMessage struct { func (x *SyncMessage_DeleteForMe_AddressableMessage) Reset() { *x = SyncMessage_DeleteForMe_AddressableMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[71] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe_AddressableMessage) String() string { @@ -7293,7 +7149,7 @@ func (*SyncMessage_DeleteForMe_AddressableMessage) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AddressableMessage) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[71] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7365,11 +7221,9 @@ type SyncMessage_DeleteForMe_MessageDeletes struct { func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { *x = SyncMessage_DeleteForMe_MessageDeletes{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[72] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { @@ -7380,7 +7234,7 @@ func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[72] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7423,11 +7277,9 @@ type SyncMessage_DeleteForMe_AttachmentDelete struct { func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { *x = SyncMessage_DeleteForMe_AttachmentDelete{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[73] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { @@ -7438,7 +7290,7 @@ func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[73] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7501,11 +7353,9 @@ type SyncMessage_DeleteForMe_ConversationDelete struct { func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[74] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { @@ -7516,7 +7366,7 @@ func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[74] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7569,11 +7419,9 @@ type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[75] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { @@ -7584,7 +7432,7 @@ func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[75] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7616,11 +7464,9 @@ type GroupContext_Member struct { func (x *GroupContext_Member) Reset() { *x = GroupContext_Member{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[76] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupContext_Member) String() string { @@ -7631,7 +7477,7 @@ func (*GroupContext_Member) ProtoMessage() {} func (x *GroupContext_Member) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[76] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7664,11 +7510,9 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[77] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ContactDetails_Avatar) String() string { @@ -7679,7 +7523,7 @@ func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[77] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7719,11 +7563,9 @@ type GroupDetails_Avatar struct { func (x *GroupDetails_Avatar) Reset() { *x = GroupDetails_Avatar{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[78] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupDetails_Avatar) String() string { @@ -7734,7 +7576,7 @@ func (*GroupDetails_Avatar) ProtoMessage() {} func (x *GroupDetails_Avatar) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[78] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7773,11 +7615,9 @@ type GroupDetails_Member struct { func (x *GroupDetails_Member) Reset() { *x = GroupDetails_Member{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[79] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupDetails_Member) String() string { @@ -7788,7 +7628,7 @@ func (*GroupDetails_Member) ProtoMessage() {} func (x *GroupDetails_Member) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[79] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -7821,11 +7661,9 @@ type PaymentAddress_MobileCoinAddress struct { func (x *PaymentAddress_MobileCoinAddress) Reset() { *x = PaymentAddress_MobileCoinAddress{} - if protoimpl.UnsafeEnabled { - mi := &file_SignalService_proto_msgTypes[80] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_SignalService_proto_msgTypes[80] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PaymentAddress_MobileCoinAddress) String() string { @@ -7836,7 +7674,7 @@ func (*PaymentAddress_MobileCoinAddress) ProtoMessage() {} func (x *PaymentAddress_MobileCoinAddress) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[80] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -8126,980 +7964,6 @@ func file_SignalService_proto_init() { if File_SignalService_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_SignalService_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*Envelope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*Content); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*BodyRange); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*NullMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*ReceiptMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*TypingMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*StoryMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*Preview); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*TextAttachment); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*Verified); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*AttachmentPointer); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*GroupContext); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*GroupContextV2); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*ContactDetails); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*GroupDetails); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*PaymentAddress); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*DecryptionErrorMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*PniSignatureMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*EditMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage_Offer); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage_Answer); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage_IceUpdate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage_Busy); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage_Hangup); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*CallMessage_Opaque); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Quote); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Contact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Sticker); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Reaction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[32].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Delete); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[33].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_GroupCallUpdate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[34].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_StoryContext); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[35].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Payment); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[36].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_GiftBadge); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[37].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Quote_QuotedAttachment); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[38].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Contact_Name); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[39].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Contact_Phone); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[40].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Contact_Email); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[41].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Contact_PostalAddress); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[42].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Contact_Avatar); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[43].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Payment_Amount); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[44].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Payment_Notification); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[45].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Payment_Activation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[46].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Payment_Amount_MobileCoin); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[47].Exporter = func(v any, i int) any { - switch v := v.(*DataMessage_Payment_Notification_MobileCoin); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[48].Exporter = func(v any, i int) any { - switch v := v.(*TextAttachment_Gradient); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[49].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Sent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[50].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Contacts); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[51].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Blocked); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[52].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Request); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[53].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Read); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[54].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Viewed); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[55].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Configuration); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[56].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_StickerPackOperation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[57].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_ViewOnceOpen); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[58].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_FetchLatest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[59].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Keys); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[60].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_MessageRequestResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[61].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_OutgoingPayment); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[62].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_PniChangeNumber); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[63].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_CallEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[64].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_CallLinkUpdate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[65].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_CallLogEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[66].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[67].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Sent_UnidentifiedDeliveryStatus); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[68].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_Sent_StoryMessageRecipient); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[69].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_OutgoingPayment_MobileCoin); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[70].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe_ConversationIdentifier); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[71].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe_AddressableMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[72].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe_MessageDeletes); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[73].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe_AttachmentDelete); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[74].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe_ConversationDelete); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[75].Exporter = func(v any, i int) any { - switch v := v.(*SyncMessage_DeleteForMe_LocalOnlyConversationDelete); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[76].Exporter = func(v any, i int) any { - switch v := v.(*GroupContext_Member); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[77].Exporter = func(v any, i int) any { - switch v := v.(*ContactDetails_Avatar); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[78].Exporter = func(v any, i int) any { - switch v := v.(*GroupDetails_Avatar); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[79].Exporter = func(v any, i int) any { - switch v := v.(*GroupDetails_Member); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_SignalService_proto_msgTypes[80].Exporter = func(v any, i int) any { - switch v := v.(*PaymentAddress_MobileCoinAddress); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } file_SignalService_proto_msgTypes[3].OneofWrappers = []any{ (*BodyRange_MentionAci)(nil), (*BodyRange_Style_)(nil), diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw index 322d177c380305a0f2efe3ed65c91c4405103817..45c938aa97b57244e0ce9953a01cc7c33bc05a03 100644 GIT binary patch delta 48 wcmdlrm2uZp#tj0(ic(x0d6~)Cd5O8H66^|$8k|9Jz84Dzn*jS}L*Y(y09|1XLI3~& delta 48 tcmdlrm2uZp#tj0(iV9rZDVfCuIf<2iiMgo~YzmAToI%J!n+=6K%>i}04?F+> diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 177018f..aa0a752 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -177,7 +177,8 @@ message DataMessage { optional string prefix = 3; optional string suffix = 4; optional string middleName = 5; - optional string displayName = 6; + reserved /*displayName*/ 6; + optional string nickname = 7; } message Phone { diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index b64f824..0da3266 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: StickerResources.proto @@ -40,11 +40,9 @@ type Pack struct { func (x *Pack) Reset() { *x = Pack{} - if protoimpl.UnsafeEnabled { - mi := &file_StickerResources_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StickerResources_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Pack) String() string { @@ -55,7 +53,7 @@ func (*Pack) ProtoMessage() {} func (x *Pack) ProtoReflect() protoreflect.Message { mi := &file_StickerResources_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -110,11 +108,9 @@ type Pack_Sticker struct { func (x *Pack_Sticker) Reset() { *x = Pack_Sticker{} - if protoimpl.UnsafeEnabled { - mi := &file_StickerResources_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StickerResources_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Pack_Sticker) String() string { @@ -125,7 +121,7 @@ func (*Pack_Sticker) ProtoMessage() {} func (x *Pack_Sticker) ProtoReflect() protoreflect.Message { mi := &file_StickerResources_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -198,32 +194,6 @@ func file_StickerResources_proto_init() { if File_StickerResources_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_StickerResources_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*Pack); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StickerResources_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*Pack_Sticker); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 788cb41..269354a 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: StorageService.proto @@ -362,11 +362,9 @@ type StorageManifest struct { func (x *StorageManifest) Reset() { *x = StorageManifest{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StorageManifest) String() string { @@ -377,7 +375,7 @@ func (*StorageManifest) ProtoMessage() {} func (x *StorageManifest) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -417,11 +415,9 @@ type StorageItem struct { func (x *StorageItem) Reset() { *x = StorageItem{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StorageItem) String() string { @@ -432,7 +428,7 @@ func (*StorageItem) ProtoMessage() {} func (x *StorageItem) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -471,11 +467,9 @@ type StorageItems struct { func (x *StorageItems) Reset() { *x = StorageItems{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StorageItems) String() string { @@ -486,7 +480,7 @@ func (*StorageItems) ProtoMessage() {} func (x *StorageItems) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -518,11 +512,9 @@ type ReadOperation struct { func (x *ReadOperation) Reset() { *x = ReadOperation{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReadOperation) String() string { @@ -533,7 +525,7 @@ func (*ReadOperation) ProtoMessage() {} func (x *ReadOperation) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -568,11 +560,9 @@ type WriteOperation struct { func (x *WriteOperation) Reset() { *x = WriteOperation{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *WriteOperation) String() string { @@ -583,7 +573,7 @@ func (*WriteOperation) ProtoMessage() {} func (x *WriteOperation) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -638,11 +628,9 @@ type ManifestRecord struct { func (x *ManifestRecord) Reset() { *x = ManifestRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ManifestRecord) String() string { @@ -653,7 +641,7 @@ func (*ManifestRecord) ProtoMessage() {} func (x *ManifestRecord) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -707,11 +695,9 @@ type StorageRecord struct { func (x *StorageRecord) Reset() { *x = StorageRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StorageRecord) String() string { @@ -722,7 +708,7 @@ func (*StorageRecord) ProtoMessage() {} func (x *StorageRecord) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -858,11 +844,9 @@ type ContactRecord struct { func (x *ContactRecord) Reset() { *x = ContactRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ContactRecord) String() string { @@ -873,7 +857,7 @@ func (*ContactRecord) ProtoMessage() {} func (x *ContactRecord) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1064,11 +1048,9 @@ type GroupV1Record struct { func (x *GroupV1Record) Reset() { *x = GroupV1Record{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupV1Record) String() string { @@ -1079,7 +1061,7 @@ func (*GroupV1Record) ProtoMessage() {} func (x *GroupV1Record) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1154,11 +1136,9 @@ type GroupV2Record struct { func (x *GroupV2Record) Reset() { *x = GroupV2Record{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GroupV2Record) String() string { @@ -1169,7 +1149,7 @@ func (*GroupV2Record) ProtoMessage() {} func (x *GroupV2Record) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1258,11 +1238,9 @@ type Payments struct { func (x *Payments) Reset() { *x = Payments{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Payments) String() string { @@ -1273,7 +1251,7 @@ func (*Payments) ProtoMessage() {} func (x *Payments) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1339,15 +1317,15 @@ type AccountRecord struct { Username string `protobuf:"bytes,33,opt,name=username,proto3" json:"username,omitempty"` HasCompletedUsernameOnboarding bool `protobuf:"varint,34,opt,name=hasCompletedUsernameOnboarding,proto3" json:"hasCompletedUsernameOnboarding,omitempty"` UsernameLink *AccountRecord_UsernameLink `protobuf:"bytes,35,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` + BackupsSubscriberId []byte `protobuf:"bytes,36,opt,name=backupsSubscriberId,proto3" json:"backupsSubscriberId,omitempty"` + BackupsSubscriberCurrencyCode string `protobuf:"bytes,37,opt,name=backupsSubscriberCurrencyCode,proto3" json:"backupsSubscriberCurrencyCode,omitempty"` } func (x *AccountRecord) Reset() { *x = AccountRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AccountRecord) String() string { @@ -1358,7 +1336,7 @@ func (*AccountRecord) ProtoMessage() {} func (x *AccountRecord) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1597,6 +1575,20 @@ func (x *AccountRecord) GetUsernameLink() *AccountRecord_UsernameLink { return nil } +func (x *AccountRecord) GetBackupsSubscriberId() []byte { + if x != nil { + return x.BackupsSubscriberId + } + return nil +} + +func (x *AccountRecord) GetBackupsSubscriberCurrencyCode() string { + if x != nil { + return x.BackupsSubscriberCurrencyCode + } + return "" +} + type StoryDistributionListRecord struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1612,11 +1604,9 @@ type StoryDistributionListRecord struct { func (x *StoryDistributionListRecord) Reset() { *x = StoryDistributionListRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StoryDistributionListRecord) String() string { @@ -1627,7 +1617,7 @@ func (*StoryDistributionListRecord) ProtoMessage() {} func (x *StoryDistributionListRecord) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1696,11 +1686,9 @@ type CallLinkRecord struct { func (x *CallLinkRecord) Reset() { *x = CallLinkRecord{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CallLinkRecord) String() string { @@ -1711,7 +1699,7 @@ func (*CallLinkRecord) ProtoMessage() {} func (x *CallLinkRecord) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1758,11 +1746,9 @@ type ManifestRecord_Identifier struct { func (x *ManifestRecord_Identifier) Reset() { *x = ManifestRecord_Identifier{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ManifestRecord_Identifier) String() string { @@ -1773,7 +1759,7 @@ func (*ManifestRecord_Identifier) ProtoMessage() {} func (x *ManifestRecord_Identifier) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1813,11 +1799,9 @@ type ContactRecord_Name struct { func (x *ContactRecord_Name) Reset() { *x = ContactRecord_Name{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ContactRecord_Name) String() string { @@ -1828,7 +1812,7 @@ func (*ContactRecord_Name) ProtoMessage() {} func (x *ContactRecord_Name) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1872,11 +1856,9 @@ type AccountRecord_PinnedConversation struct { func (x *AccountRecord_PinnedConversation) Reset() { *x = AccountRecord_PinnedConversation{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AccountRecord_PinnedConversation) String() string { @@ -1887,7 +1869,7 @@ func (*AccountRecord_PinnedConversation) ProtoMessage() {} func (x *AccountRecord_PinnedConversation) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1966,11 +1948,9 @@ type AccountRecord_UsernameLink struct { func (x *AccountRecord_UsernameLink) Reset() { *x = AccountRecord_UsernameLink{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AccountRecord_UsernameLink) String() string { @@ -1981,7 +1961,7 @@ func (*AccountRecord_UsernameLink) ProtoMessage() {} func (x *AccountRecord_UsernameLink) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2028,11 +2008,9 @@ type AccountRecord_PinnedConversation_Contact struct { func (x *AccountRecord_PinnedConversation_Contact) Reset() { *x = AccountRecord_PinnedConversation_Contact{} - if protoimpl.UnsafeEnabled { - mi := &file_StorageService_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_StorageService_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *AccountRecord_PinnedConversation_Contact) String() string { @@ -2043,7 +2021,7 @@ func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { mi := &file_StorageService_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -2152,236 +2130,6 @@ func file_StorageService_proto_init() { if File_StorageService_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_StorageService_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*StorageManifest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*StorageItem); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*StorageItems); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*ReadOperation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*WriteOperation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*ManifestRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*StorageRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*ContactRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*GroupV1Record); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*GroupV2Record); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*Payments); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*AccountRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*StoryDistributionListRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*CallLinkRecord); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*ManifestRecord_Identifier); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*ContactRecord_Name); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*AccountRecord_PinnedConversation); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*AccountRecord_UsernameLink); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_StorageService_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*AccountRecord_PinnedConversation_Contact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } file_StorageService_proto_msgTypes[6].OneofWrappers = []any{ (*StorageRecord_Contact)(nil), (*StorageRecord_GroupV1)(nil), diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw index 2dea02fae9b6d83f802dedf2454956c05857ef2e..c4befd576011672424b415535ef42449380d7931 100644 GIT binary patch delta 108 zcmdm{yH0PzY;LAW!kg!EA7Zl;GT;(UN=(i!Ehr8yO)5?<%1lZv@=TFXQDD^I3Bo2N cwODo`zF5Q^aDc%g6>0JjMu_W%F@ delta 20 ccmZ3dw@r7$Y;LAmLYwDuA7a~lT_~Id09UpL-T(jq diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index 304e73f..7b2fa3a 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -219,6 +219,8 @@ message AccountRecord { string username = 33; bool hasCompletedUsernameOnboarding = 34; UsernameLink usernameLink = 35; + bytes backupsSubscriberId = 36; + string backupsSubscriberCurrencyCode = 37; } message StoryDistributionListRecord { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index 97d1b46..b42ca6f 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: UnidentifiedDelivery.proto @@ -160,11 +160,9 @@ type ServerCertificate struct { func (x *ServerCertificate) Reset() { *x = ServerCertificate{} - if protoimpl.UnsafeEnabled { - mi := &file_UnidentifiedDelivery_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_UnidentifiedDelivery_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ServerCertificate) String() string { @@ -175,7 +173,7 @@ func (*ServerCertificate) ProtoMessage() {} func (x *ServerCertificate) ProtoReflect() protoreflect.Message { mi := &file_UnidentifiedDelivery_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -215,11 +213,9 @@ type SenderCertificate struct { func (x *SenderCertificate) Reset() { *x = SenderCertificate{} - if protoimpl.UnsafeEnabled { - mi := &file_UnidentifiedDelivery_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_UnidentifiedDelivery_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SenderCertificate) String() string { @@ -230,7 +226,7 @@ func (*SenderCertificate) ProtoMessage() {} func (x *SenderCertificate) ProtoReflect() protoreflect.Message { mi := &file_UnidentifiedDelivery_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -271,11 +267,9 @@ type UnidentifiedSenderMessage struct { func (x *UnidentifiedSenderMessage) Reset() { *x = UnidentifiedSenderMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_UnidentifiedDelivery_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_UnidentifiedDelivery_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UnidentifiedSenderMessage) String() string { @@ -286,7 +280,7 @@ func (*UnidentifiedSenderMessage) ProtoMessage() {} func (x *UnidentifiedSenderMessage) ProtoReflect() protoreflect.Message { mi := &file_UnidentifiedDelivery_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -333,11 +327,9 @@ type ServerCertificate_Certificate struct { func (x *ServerCertificate_Certificate) Reset() { *x = ServerCertificate_Certificate{} - if protoimpl.UnsafeEnabled { - mi := &file_UnidentifiedDelivery_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_UnidentifiedDelivery_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ServerCertificate_Certificate) String() string { @@ -348,7 +340,7 @@ func (*ServerCertificate_Certificate) ProtoMessage() {} func (x *ServerCertificate_Certificate) ProtoReflect() protoreflect.Message { mi := &file_UnidentifiedDelivery_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -392,11 +384,9 @@ type SenderCertificate_Certificate struct { func (x *SenderCertificate_Certificate) Reset() { *x = SenderCertificate_Certificate{} - if protoimpl.UnsafeEnabled { - mi := &file_UnidentifiedDelivery_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_UnidentifiedDelivery_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SenderCertificate_Certificate) String() string { @@ -407,7 +397,7 @@ func (*SenderCertificate_Certificate) ProtoMessage() {} func (x *SenderCertificate_Certificate) ProtoReflect() protoreflect.Message { mi := &file_UnidentifiedDelivery_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -478,11 +468,9 @@ type UnidentifiedSenderMessage_Message struct { func (x *UnidentifiedSenderMessage_Message) Reset() { *x = UnidentifiedSenderMessage_Message{} - if protoimpl.UnsafeEnabled { - mi := &file_UnidentifiedDelivery_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_UnidentifiedDelivery_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UnidentifiedSenderMessage_Message) String() string { @@ -493,7 +481,7 @@ func (*UnidentifiedSenderMessage_Message) ProtoMessage() {} func (x *UnidentifiedSenderMessage_Message) ProtoReflect() protoreflect.Message { mi := &file_UnidentifiedDelivery_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -589,80 +577,6 @@ func file_UnidentifiedDelivery_proto_init() { if File_UnidentifiedDelivery_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_UnidentifiedDelivery_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*ServerCertificate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_UnidentifiedDelivery_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*SenderCertificate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_UnidentifiedDelivery_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*UnidentifiedSenderMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_UnidentifiedDelivery_proto_msgTypes[3].Exporter = func(v any, i int) any { - switch v := v.(*ServerCertificate_Certificate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_UnidentifiedDelivery_proto_msgTypes[4].Exporter = func(v any, i int) any { - switch v := v.(*SenderCertificate_Certificate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_UnidentifiedDelivery_proto_msgTypes[5].Exporter = func(v any, i int) any { - switch v := v.(*UnidentifiedSenderMessage_Message); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index cf124d4..b3514e6 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 +// protoc-gen-go v1.35.1 // protoc v3.21.12 // source: WebSocketResources.proto @@ -100,11 +100,9 @@ type WebSocketRequestMessage struct { func (x *WebSocketRequestMessage) Reset() { *x = WebSocketRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_WebSocketResources_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_WebSocketResources_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *WebSocketRequestMessage) String() string { @@ -115,7 +113,7 @@ func (*WebSocketRequestMessage) ProtoMessage() {} func (x *WebSocketRequestMessage) ProtoReflect() protoreflect.Message { mi := &file_WebSocketResources_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -179,11 +177,9 @@ type WebSocketResponseMessage struct { func (x *WebSocketResponseMessage) Reset() { *x = WebSocketResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_WebSocketResources_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_WebSocketResources_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *WebSocketResponseMessage) String() string { @@ -194,7 +190,7 @@ func (*WebSocketResponseMessage) ProtoMessage() {} func (x *WebSocketResponseMessage) ProtoReflect() protoreflect.Message { mi := &file_WebSocketResources_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -256,11 +252,9 @@ type WebSocketMessage struct { func (x *WebSocketMessage) Reset() { *x = WebSocketMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_WebSocketResources_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_WebSocketResources_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *WebSocketMessage) String() string { @@ -271,7 +265,7 @@ func (*WebSocketMessage) ProtoMessage() {} func (x *WebSocketMessage) ProtoReflect() protoreflect.Message { mi := &file_WebSocketResources_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -348,44 +342,6 @@ func file_WebSocketResources_proto_init() { if File_WebSocketResources_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_WebSocketResources_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*WebSocketRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_WebSocketResources_proto_msgTypes[1].Exporter = func(v any, i int) any { - switch v := v.(*WebSocketResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_WebSocketResources_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*WebSocketMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 87eb1ec..4faa611 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-69e1146e2c5bbd6f2773dfe12f723e7cc88064be} -DESKTOP_GIT_REVISION=${1:-2640c34bd3eb6d338fbf32621fdf839d2ca3d155} +ANDROID_GIT_REVISION=${1:-551cda13b7dbfaa168f8c1a577b29cdf075e7b3f} +DESKTOP_GIT_REVISION=${1:-76a77a9b7fde3fc21b86e29071eb4e93b5e12ff1} update_proto() { case "$1" in From bec70b6537d49573c326678697a774881a511d1f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Oct 2024 17:10:07 +0300 Subject: [PATCH 348/718] libsignal: update to v0.58.3 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 2 ++ pkg/libsignalgo/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 5de6300..29d3270 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 5de6300ab21b34984dd0f79214aa6f3c08ac755d +Subproject commit 29d32702b5cb0dc302ca2fa08377cddaaaacb60c diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 60015ea..5b13971 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1559,6 +1559,8 @@ SignalFfiError *signal_pin_local_hash(const char **out, SignalBorrowedBuffer pin SignalFfiError *signal_pin_verify_local_hash(bool *out, const char *encoded_hash, SignalBorrowedBuffer pin); +SignalFfiError *signal_account_entropy_pool_generate(const char **out); + SignalFfiError *signal_svr2_client_new(SignalSgxClientState **out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); SignalFfiError *signal_incremental_mac_destroy(SignalIncrementalMac *p); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index a15914c..e7c4740 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.58.1" +const Version = "v0.58.3" From 08c491ad7dbd158ae3b7ebc739b11451609a833e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Oct 2024 17:10:57 +0300 Subject: [PATCH 349/718] dependencies: update --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 283e984..61f382c 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.1-0.20241003092848-3b49d3e0b9ee - golang.org/x/crypto v0.27.0 - golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 - golang.org/x/net v0.29.0 - google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.21.1-0.20241003093300-7e041c6e76a5 + go.mau.fi/util v0.8.1-0.20241015132414-c3f7e22b3de9 + golang.org/x/crypto v0.28.0 + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c + golang.org/x/net v0.30.0 + google.golang.org/protobuf v1.35.1 + maunium.net/go/mautrix v0.21.1-0.20241015140451-df65202dacf0 ) require ( @@ -30,7 +30,7 @@ require ( github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.23 // indirect + github.com/mattn/go-sqlite3 v1.14.24 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -39,11 +39,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.4 // indirect + github.com/yuin/goldmark v1.7.7 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index c8e86e0..5e88b13 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/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.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0= -github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -65,29 +65,29 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/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.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= -github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.1-0.20241003092848-3b49d3e0b9ee h1:/BGpUK7fzVyFgy5KBiyP7ktEDn20vzz/5FTngrXtIEE= -go.mau.fi/util v0.8.1-0.20241003092848-3b49d3e0b9ee/go.mod h1:L9qnqEkhe4KpuYmILrdttKTXL79MwGLyJ4EOskWxO3I= +github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU= +github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.mau.fi/util v0.8.1-0.20241015132414-c3f7e22b3de9 h1:DnZ0keW636LpkkQKA1LQilYglEjNbxwXOnsJw0fuNIo= +go.mau.fi/util v0.8.1-0.20241015132414-c3f7e22b3de9/go.mod h1:T1u/rD2rzidVrBLyaUdPpZiJdP/rsyi+aTzn0D+Q6wc= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -97,5 +97,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.21.1-0.20241003093300-7e041c6e76a5 h1:d5xUAixcJkxv9O3Ly/Ga2cU1Ez+WjS9gPIGD872wslw= -maunium.net/go/mautrix v0.21.1-0.20241003093300-7e041c6e76a5/go.mod h1:+fF5qsmXRCEXQZgW5ececC0PI3c7gISHTLcyftP4Bh0= +maunium.net/go/mautrix v0.21.1-0.20241015140451-df65202dacf0 h1:HJpNwgwsibEVVxLlLVkoPiHw6qA32jpGeSmPrRv8ArA= +maunium.net/go/mautrix v0.21.1-0.20241015140451-df65202dacf0/go.mod h1:biYqPccrQnnoVFoBe7JBHX6JDkFHGwGfKAem38LeXEs= From 3def5415eee866a8a2caaa0adad33dc3ff7f96b5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 16 Oct 2024 10:17:55 +0300 Subject: [PATCH 350/718] changelog: update [skip ci] --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e780d7..9bd123c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +# v0.7.2 (unreleased) + +* Updated to libsignal v0.58.3. +* Fixed spurious decryption error notices for Signal messages when the + websocket reconnects and receives old already-bridged messages. +* Fixed signalmeow not respecting account settings for choosing sender + certificate. +* Fixed bugs in storage service decryption, which could cause issues with + missing contact names among other things. +* Fixed call start notices only working once per direct chat. + # v0.7.1 (2024-09-16) * Updated to libsignal v0.57.1. @@ -22,6 +33,8 @@ manually. * Thanks to [@maltee1] for reimplementing Matrix -> Signal membership handling in the rewrite. + * If you are still somehow using a pre-v0.5.0 versions, upgrading to v0.6.3 + is required before upgrading to v0.7.0 or higher. # v0.6.3 (2024-07-16) From 0feadb1474d6bfaf92c3cc57f080aa8167cad443 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 16 Oct 2024 13:53:36 +0300 Subject: [PATCH 351/718] Bump version to v0.7.2 --- CHANGELOG.md | 2 +- cmd/mautrix-signal/main.go | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd123c..743c281 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v0.7.2 (unreleased) +# v0.7.2 (2024-10-16) * Updated to libsignal v0.58.3. * Fixed spurious decryption error notices for Signal messages when the diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 9bd9e23..51dc76e 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.1", + Version: "0.7.2", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 61f382c..0760b6f 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.1-0.20241015132414-c3f7e22b3de9 + go.mau.fi/util v0.8.1 golang.org/x/crypto v0.28.0 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c golang.org/x/net v0.30.0 google.golang.org/protobuf v1.35.1 - maunium.net/go/mautrix v0.21.1-0.20241015140451-df65202dacf0 + maunium.net/go/mautrix v0.21.1 ) require ( diff --git a/go.sum b/go.sum index 5e88b13..05f90ef 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU= github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.1-0.20241015132414-c3f7e22b3de9 h1:DnZ0keW636LpkkQKA1LQilYglEjNbxwXOnsJw0fuNIo= -go.mau.fi/util v0.8.1-0.20241015132414-c3f7e22b3de9/go.mod h1:T1u/rD2rzidVrBLyaUdPpZiJdP/rsyi+aTzn0D+Q6wc= +go.mau.fi/util v0.8.1 h1:Ga43cz6esQBYqcjZ/onRoVnYWoUwjWbsxVeJg2jOTSo= +go.mau.fi/util v0.8.1/go.mod h1:T1u/rD2rzidVrBLyaUdPpZiJdP/rsyi+aTzn0D+Q6wc= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= @@ -97,5 +97,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.21.1-0.20241015140451-df65202dacf0 h1:HJpNwgwsibEVVxLlLVkoPiHw6qA32jpGeSmPrRv8ArA= -maunium.net/go/mautrix v0.21.1-0.20241015140451-df65202dacf0/go.mod h1:biYqPccrQnnoVFoBe7JBHX6JDkFHGwGfKAem38LeXEs= +maunium.net/go/mautrix v0.21.1 h1:Z+e448jtlY977iC1kokNJTH5kg2WmDpcQCqn+v9oZOA= +maunium.net/go/mautrix v0.21.1/go.mod h1:7F/S6XAdyc/6DW+Q7xyFXRSPb6IjfqMb1OMepQ8C8OE= From b09995a892c9930628e1669532d9c1283a4938c8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 17 Oct 2024 22:33:11 +0300 Subject: [PATCH 352/718] signalmeow/attachments: update upload path --- pkg/signalmeow/attachments.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index c0859b7..8cd796e 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -149,7 +149,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb encryptedWithMAC := appendMAC(keys[32:], encrypted) // Get upload attributes from Signal server - attributesPath := "/v3/attachments/form/upload" + attributesPath := "/v4/attachments/form/upload" username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{Username: &username, Password: &password} resp, err := web.SendHTTPRequest(ctx, http.MethodGet, attributesPath, opts) From 96221b6fb41ad4d19b13681bdabbd06638845a24 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 17 Oct 2024 22:33:21 +0300 Subject: [PATCH 353/718] ci: update pre-commit action version --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 76b76a1..c2496f6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -33,7 +33,7 @@ jobs: export PATH="$HOME/go/bin:$PATH" - name: Run pre-commit - uses: pre-commit/action@v3.0.0 + uses: pre-commit/action@v3.0.1 test: runs-on: ubuntu-latest From 58dacbd6ac291a961d9b47913030335f10f048c8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 18 Oct 2024 14:55:31 +0300 Subject: [PATCH 354/718] signalmeow/attachments: add basic support for TUS uploads --- pkg/signalmeow/attachments.go | 117 +++++++++++++++++++++++----------- pkg/signalmeow/web/web.go | 7 +- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 8cd796e..e8ffe0b 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -23,6 +23,7 @@ import ( "crypto/cipher" "crypto/hmac" "crypto/sha256" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -105,7 +106,7 @@ func decryptAttachment(body, key, digest []byte, size uint32) ([]byte, error) { return decrypted[:size], nil } -type attachmentV3UploadAttributes struct { +type attachmentV4UploadAttributes struct { Cdn uint32 `json:"cdn"` Key string `json:"key"` Headers map[string]string `json:"headers"` @@ -154,49 +155,26 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb opts := &web.HTTPReqOpt{Username: &username, Password: &password} resp, err := web.SendHTTPRequest(ctx, http.MethodGet, attributesPath, opts) if err != nil { - log.Err(err).Msg("Error sending request fetching upload attributes") - return nil, err + log.Err(err).Msg("Failed to request upload attributes") + return nil, fmt.Errorf("failed to request upload attributes: %w", err) } - var uploadAttributes attachmentV3UploadAttributes + var uploadAttributes attachmentV4UploadAttributes err = web.DecodeHTTPResponseBody(ctx, &uploadAttributes, resp) if err != nil { - log.Err(err).Msg("Error decoding response body fetching upload attributes") - return nil, err + log.Err(err).Msg("Failed to decode upload attributes") + return nil, fmt.Errorf("failed to decode upload attributes: %w", err) + } + if uploadAttributes.Cdn == 3 { + log.Trace().Msg("Using TUS upload") + err = cli.uploadAttachmentTUS(ctx, uploadAttributes, encryptedWithMAC, username, password) + } else { + log.Trace().Msg("Using legacy upload") + err = cli.uploadAttachmentLegacy(ctx, uploadAttributes, encryptedWithMAC, username, password) } - - // Allocate attachment on CDN - resp, err = web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ - OverrideURL: uploadAttributes.SignedUploadLocation, - ContentType: web.ContentTypeOctetStream, - Headers: uploadAttributes.Headers, - Username: &username, - Password: &password, - }) if err != nil { - log.Err(err).Msg("Error sending request allocating attachment") + log.Err(err).Msg("Failed to upload attachment") return nil, err } - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - log.Error().Int("status_code", resp.StatusCode).Msg("Error allocating attachment") - return nil, fmt.Errorf("error allocating attachment: %s", resp.Status) - } - - // Upload attachment to CDN - resp, err = web.SendHTTPRequest(ctx, http.MethodPut, "", &web.HTTPReqOpt{ - OverrideURL: resp.Header.Get("Location"), - Body: encryptedWithMAC, - ContentType: web.ContentTypeOctetStream, - Username: &username, - Password: &password, - }) - if err != nil { - log.Err(err).Msg("Error sending request uploading attachment") - return nil, err - } - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - log.Error().Int("status_code", resp.StatusCode).Msg("Error uploading attachment") - return nil, fmt.Errorf("error uploading attachment: %s", resp.Status) - } digest := sha256.Sum256(encryptedWithMAC) @@ -213,6 +191,71 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb return attachmentPointer, nil } +func (cli *Client) uploadAttachmentLegacy( + ctx context.Context, + uploadAttributes attachmentV4UploadAttributes, + encryptedWithMAC []byte, + username string, + password string, +) error { + // Allocate attachment on CDN + resp, err := web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ + OverrideURL: uploadAttributes.SignedUploadLocation, + ContentType: web.ContentTypeOctetStream, + Headers: uploadAttributes.Headers, + Username: &username, + Password: &password, + }) + if err != nil { + return fmt.Errorf("failed to send allocate request: %w", err) + } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("allocate request returned HTTP %d", resp.StatusCode) + } + + // Upload attachment to CDN + resp, err = web.SendHTTPRequest(ctx, http.MethodPut, "", &web.HTTPReqOpt{ + OverrideURL: resp.Header.Get("Location"), + Body: encryptedWithMAC, + ContentType: web.ContentTypeOctetStream, + Username: &username, + Password: &password, + }) + if err != nil { + return fmt.Errorf("failed to send upload request: %w", err) + } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("upload request returned HTTP %d", resp.StatusCode) + } + return nil +} + +func (cli *Client) uploadAttachmentTUS( + ctx context.Context, + uploadAttributes attachmentV4UploadAttributes, + encryptedWithMAC []byte, + username string, + password string, +) error { + uploadAttributes.Headers["Tus-Resumable"] = "1.0.0" + uploadAttributes.Headers["Upload-Length"] = fmt.Sprintf("%d", len(encryptedWithMAC)) + uploadAttributes.Headers["Upload-Metadata"] = "filename " + base64.StdEncoding.EncodeToString([]byte(uploadAttributes.Key)) + + resp, err := web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ + OverrideURL: uploadAttributes.SignedUploadLocation, + Body: encryptedWithMAC, + ContentType: web.ContentTypeOffsetOctetStream, + Headers: uploadAttributes.Headers, + Username: &username, + Password: &password, + }) + // TODO actually support resuming on error + if err != nil { + return fmt.Errorf("failed to send upload request: %w", err) + } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("upload request returned HTTP %d", resp.StatusCode) + } + return nil +} + func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier) (*string, error) { log := zerolog.Ctx(ctx) groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index 1119128..3644451 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -95,9 +95,10 @@ func init() { type ContentType string const ( - ContentTypeJSON ContentType = "application/json" - ContentTypeProtobuf ContentType = "application/x-protobuf" - ContentTypeOctetStream ContentType = "application/octet-stream" + ContentTypeJSON ContentType = "application/json" + ContentTypeProtobuf ContentType = "application/x-protobuf" + ContentTypeOctetStream ContentType = "application/octet-stream" + ContentTypeOffsetOctetStream ContentType = "application/offset+octet-stream" ) type HTTPReqOpt struct { From ad41c86f116f484a57b7df07bc082f33fc12d908 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 19 Oct 2024 23:29:34 +0300 Subject: [PATCH 355/718] signalmeow/receiving: handle missing era ID in group call updates --- pkg/signalmeow/receiving.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 1961709..38a4e00 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -1025,7 +1025,7 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp } // Hacky special case for group calls to cache the state if dataMessage.GroupCallUpdate != nil { - isRinging := cli.UpdateActiveCalls(groupID, *dataMessage.GroupCallUpdate.EraId) + isRinging := cli.UpdateActiveCalls(groupID, dataMessage.GroupCallUpdate.GetEraId()) cli.handleEvent(&events.Call{ Info: evtInfo, Timestamp: dataMessage.GetTimestamp(), From 1af3acb1302eb05b017ec643e1d77d1da73f029e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 13 Nov 2024 15:46:55 +0200 Subject: [PATCH 356/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/Provisioning.pb.go | 26 +++++++++++++++++++- pkg/signalmeow/protobuf/Provisioning.pb.raw | Bin 804 -> 948 bytes pkg/signalmeow/protobuf/Provisioning.proto | 5 +++- pkg/signalmeow/protobuf/update-protos.sh | 4 +-- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 7a866f3..e7b7585 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -201,7 +201,10 @@ type ProvisionMessage struct { ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"` ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` - MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` // NEXT ID: 14 + MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` + EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes + AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` + MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes } func (x *ProvisionMessage) Reset() { @@ -325,6 +328,27 @@ func (x *ProvisionMessage) GetMasterKey() []byte { return nil } +func (x *ProvisionMessage) GetEphemeralBackupKey() []byte { + if x != nil { + return x.EphemeralBackupKey + } + return nil +} + +func (x *ProvisionMessage) GetAccountEntropyPool() string { + if x != nil && x.AccountEntropyPool != nil { + return *x.AccountEntropyPool + } + return "" +} + +func (x *ProvisionMessage) GetMediaRootBackupKey() []byte { + if x != nil { + return x.MediaRootBackupKey + } + return nil +} + var File_Provisioning_proto protoreflect.FileDescriptor //go:embed Provisioning.pb.raw diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.raw b/pkg/signalmeow/protobuf/Provisioning.pb.raw index 2ffce6fe9f767e9912d00644eafb26c9f454953e..385bc0221e1cce3935b116e6241b0b4d697c8df3 100644 GIT binary patch delta 159 zcmZ3&wuODdWTpwM3#T&G3+ZtQr50qQ=B5@U<~SuLXO|Xur&dbvDKKjA1YwZ@sZUH! z&M(a?am_0!$}gx4$j{G_;0LPb48kG Date: Wed, 13 Nov 2024 16:36:24 +0200 Subject: [PATCH 357/718] dependencies: update --- go.mod | 24 ++++++++++++------------ go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 0760b6f..4e31e51 100644 --- a/go.mod +++ b/go.mod @@ -2,23 +2,23 @@ module go.mau.fi/mautrix-signal go 1.22.0 -toolchain go1.23.2 +toolchain go1.23.3 require ( github.com/coder/websocket v1.8.12 - github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 + github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/mattn/go-pointer v0.0.1 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.1 - golang.org/x/crypto v0.28.0 - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c - golang.org/x/net v0.30.0 + go.mau.fi/util v0.8.2-0.20241113135441-636f8643f367 + golang.org/x/crypto v0.29.0 + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f + golang.org/x/net v0.31.0 google.golang.org/protobuf v1.35.1 - maunium.net/go/mautrix v0.21.1 + maunium.net/go/mautrix v0.21.2-0.20241113135638-b22764aa170a ) require ( @@ -31,7 +31,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.24 // indirect - github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect + github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -39,11 +39,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.7 // indirect + github.com/yuin/goldmark v1.7.8 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 05f90ef..590bd3d 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV 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-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA= -github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= +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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -38,8 +38,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= -github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 h1:qli3BGQK0tYDkSEvZ/FzZTi9ZrOX86Q6CIhKLGc489A= +github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -65,27 +65,27 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/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.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU= -github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.1 h1:Ga43cz6esQBYqcjZ/onRoVnYWoUwjWbsxVeJg2jOTSo= -go.mau.fi/util v0.8.1/go.mod h1:T1u/rD2rzidVrBLyaUdPpZiJdP/rsyi+aTzn0D+Q6wc= +github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= +github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.mau.fi/util v0.8.2-0.20241113135441-636f8643f367 h1:GU0TYiAOU79p6r3jf3e4k5cdgnPxOcJWkWeWampdAjw= +go.mau.fi/util v0.8.2-0.20241113135441-636f8643f367/go.mod h1:SVzC++wSl8Yq4YVQRClLPa1frNpSVDVP6mfkw/OvDbc= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -97,5 +97,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.21.1 h1:Z+e448jtlY977iC1kokNJTH5kg2WmDpcQCqn+v9oZOA= -maunium.net/go/mautrix v0.21.1/go.mod h1:7F/S6XAdyc/6DW+Q7xyFXRSPb6IjfqMb1OMepQ8C8OE= +maunium.net/go/mautrix v0.21.2-0.20241113135638-b22764aa170a h1:+hOkf85qhGRoAPpoCk7AiqKxlNvCCizb6urJVmgk0+8= +maunium.net/go/mautrix v0.21.2-0.20241113135638-b22764aa170a/go.mod h1:X7VB/wOIUo6c3wACyVwA//v2k8BpMLFB2rvaX2Y0984= From d011d23c1c3cdcd75dae86c7e879590ce114e3a7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 13 Nov 2024 16:36:53 +0200 Subject: [PATCH 358/718] libsignal: update to v0.61.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 48 ++++++++++++++++++++++++++++++--- pkg/libsignalgo/version.go | 2 +- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 29d3270..0a06f69 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 29d32702b5cb0dc302ca2fa08377cddaaaacb60c +Subproject commit 0a06f69bce222c184a8d4022b8cf4202b02b9001 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 5b13971..627dfd6 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -15,6 +15,20 @@ SPDX-License-Identifier: AGPL-3.0-only #include #include +#define SignalSVR_KEY_LEN 32 + +#define SignalBACKUP_KEY_LEN 32 + +#define SignalLOCAL_BACKUP_METADATA_KEY_LEN 32 + +#define SignalMEDIA_ID_LEN 15 + +#define SignalMEDIA_ENCRYPTION_KEY_LEN (32 + 32) + +#define SignalBackupKey_MASTER_KEY_LEN SignalSVR_KEY_LEN + +#define SignalBackupId_LEN 16 + /** * The encoded length of a [`FourCC`], in bytes. */ @@ -1399,7 +1413,7 @@ SignalFfiError *signal_backup_auth_credential_request_context_get_request(Signal SignalFfiError *signal_backup_auth_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes); -SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint8_t backup_level, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); +SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint8_t backup_level, uint8_t credential_type, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); SignalFfiError *signal_backup_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); @@ -1411,6 +1425,8 @@ SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalFfiError *signal_backup_auth_credential_get_backup_level(uint8_t *out, SignalBorrowedBuffer credential_bytes); +SignalFfiError *signal_backup_auth_credential_get_type(uint8_t *out, SignalBorrowedBuffer credential_bytes); + SignalFfiError *signal_backup_auth_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, SignalBorrowedBuffer server_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); SignalFfiError *signal_backup_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); @@ -1449,8 +1465,6 @@ SignalFfiError *signal_group_send_full_token_get_expiration(uint64_t *out, Signa SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalBorrowedBuffer user_ids, uint64_t now, SignalBorrowedBuffer key_pair); -SignalFfiError *signal_verify_signature(bool *out, SignalBorrowedBuffer cert_pem, SignalBorrowedBuffer body, SignalBorrowedBuffer signature, uint64_t current_timestamp); - SignalFfiError *signal_connection_manager_destroy(SignalConnectionManager *p); SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment, const char *user_agent); @@ -1459,6 +1473,8 @@ SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManage SignalFfiError *signal_connection_manager_clear_proxy(const SignalConnectionManager *connection_manager); +SignalFfiError *signal_connection_manager_set_censorship_circumvention_enabled(const SignalConnectionManager *connection_manager, bool enabled); + SignalFfiError *signal_connection_manager_on_network_change(const SignalConnectionManager *connection_manager); SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); @@ -1561,6 +1577,22 @@ SignalFfiError *signal_pin_verify_local_hash(bool *out, const char *encoded_hash SignalFfiError *signal_account_entropy_pool_generate(const char **out); +SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy); + +SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy); + +SignalFfiError *signal_backup_key_derive_backup_id(uint8_t (*out)[16], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_backup_key_derive_ec_key(SignalPrivateKey **out, const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_backup_key_derive_local_backup_metadata_key(uint8_t (*out)[SignalLOCAL_BACKUP_METADATA_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN]); + +SignalFfiError *signal_backup_key_derive_media_id(uint8_t (*out)[SignalMEDIA_ID_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const char *media_name); + +SignalFfiError *signal_backup_key_derive_media_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); + +SignalFfiError *signal_backup_key_derive_thumbnail_transit_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); + SignalFfiError *signal_svr2_client_new(SignalSgxClientState **out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); SignalFfiError *signal_incremental_mac_destroy(SignalIncrementalMac *p); @@ -1585,7 +1617,15 @@ SignalFfiError *signal_message_backup_key_destroy(SignalMessageBackupKey *p); SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMessageBackupValidationOutcome *p); -SignalFfiError *signal_message_backup_key_new(SignalMessageBackupKey **out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_message_backup_key_from_master_key(SignalMessageBackupKey **out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMessageBackupKey **out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMessageBackupKey **out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16]); + +SignalFfiError *signal_message_backup_key_get_hmac_key(uint8_t (*out)[32], const SignalMessageBackupKey *key); + +SignalFfiError *signal_message_backup_key_get_aes_key(uint8_t (*out)[32], const SignalMessageBackupKey *key); SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, const SignalMessageBackupValidationOutcome *outcome); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index e7c4740..4bd3b99 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.58.3" +const Version = "v0.61.0" From a0389f98621f5987bcf8d79617058a2d6d93cb21 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 13 Nov 2024 16:38:12 +0200 Subject: [PATCH 359/718] login: save master key from provisioning message --- pkg/connector/login.go | 5 +++++ pkg/signalmeow/provisioning.go | 1 + 2 files changed, 6 insertions(+) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 2e79933..5636339 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/google/uuid" + "github.com/rs/zerolog" "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -175,6 +176,10 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err if err != nil { return nil, fmt.Errorf("failed to connect after login: %w", err) } + if signalClient := ul.Client.(*SignalClient).Client; signalClient.Store.MasterKey != nil { + zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") + go signalClient.SyncStorage(ctx) + } return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, StepID: LoginStepComplete, diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 213c246..75bb6df 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -164,6 +164,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev DeviceID: deviceId, Number: *provisioningMessage.Number, Password: password, + MasterKey: provisioningMessage.GetMasterKey(), } // Store the provisioning data From b0966abd3eb31e1232917399def5fdbf90cc3c3e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 13 Nov 2024 16:38:24 +0200 Subject: [PATCH 360/718] attachments: log data when TUS upload fails --- pkg/signalmeow/attachments.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index e8ffe0b..8a4b618 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -251,6 +251,10 @@ func (cli *Client) uploadAttachmentTUS( if err != nil { return fmt.Errorf("failed to send upload request: %w", err) } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { + zerolog.Ctx(ctx).Debug(). + Any("headers", uploadAttributes.Headers). + Str("location", uploadAttributes.SignedUploadLocation). + Msg("TUS upload failed") return fmt.Errorf("upload request returned HTTP %d", resp.StatusCode) } return nil From 3c31749fb2802a16e0e497bd3223102178c50d36 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Wed, 13 Nov 2024 16:20:28 -0500 Subject: [PATCH 361/718] handlesignal: add ServerTimestamp remote stream order on incoming messages (#550) --- pkg/connector/handlesignal.go | 23 ++++++++++++-------- pkg/signalmeow/events/message.go | 3 ++- pkg/signalmeow/receiving.go | 36 ++++++++++++++++++-------------- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index b39f202..2d863ac 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -135,15 +135,16 @@ type Bv2ChatEvent struct { } var ( - _ bridgev2.RemoteMessage = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteEdit = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteEventWithTimestamp = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteReaction = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteTyping = (*Bv2ChatEvent)(nil) - _ bridgev2.RemotePreHandler = (*Bv2ChatEvent)(nil) - _ bridgev2.RemoteChatInfoChange = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteMessage = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEdit = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEventWithTimestamp = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReaction = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteReactionRemove = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteMessageRemove = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteTyping = (*Bv2ChatEvent)(nil) + _ bridgev2.RemotePreHandler = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteChatInfoChange = (*Bv2ChatEvent)(nil) + _ bridgev2.RemoteEventWithStreamOrder = (*Bv2ChatEvent)(nil) ) func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { @@ -337,6 +338,10 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta }, nil } +func (evt *Bv2ChatEvent) GetStreamOrder() int64 { + return int64(evt.Info.ServerTimestamp) +} + type Bv2Receipt struct { Type signalpb.ReceiptMessage_Type Chat networkid.PortalKey diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index a6fcc7f..0038657 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -40,7 +40,8 @@ type MessageInfo struct { Sender uuid.UUID ChatID string - GroupRevision uint32 + GroupRevision uint32 + ServerTimestamp uint64 } type ChatEvent struct { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 38a4e00..1bebf77 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -752,9 +752,9 @@ func (cli *Client) handleDecryptedResult( log.Warn().Msg("sync message sent destination is nil") } else if content.SyncMessage.Sent.Message != nil { // TODO handle expiration start ts, and maybe the sync message ts? - cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, syncDestinationServiceID) + cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) } else if content.SyncMessage.Sent.EditMessage != nil { - cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID) + cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) } } if content.SyncMessage.Contacts != nil { @@ -802,9 +802,9 @@ func (cli *Client) handleDecryptedResult( var sendDeliveryReceipt bool if content.DataMessage != nil { - sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID) + sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) } else if content.EditMessage != nil { - sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID) + sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) } if sendDeliveryReceipt { // TODO send delivery receipts after actually bridging instead of here @@ -822,8 +822,9 @@ func (cli *Client) handleDecryptedResult( } cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ - Sender: theirServiceID.UUID, - ChatID: groupOrUserID(groupID, theirServiceID), + Sender: theirServiceID.UUID, + ChatID: groupOrUserID(groupID, theirServiceID), + ServerTimestamp: envelope.GetServerTimestamp(), }, Event: content.TypingMessage, }) @@ -833,8 +834,9 @@ func (cli *Client) handleDecryptedResult( if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { cli.handleEvent(&events.Call{ Info: events.MessageInfo{ - Sender: theirServiceID.UUID, - ChatID: theirServiceID.String(), + Sender: theirServiceID.UUID, + ChatID: theirServiceID.String(), + ServerTimestamp: envelope.GetServerTimestamp(), }, // CallMessage doesn't have its own timestamp, use one from the envelope Timestamp: envelope.GetTimestamp(), @@ -964,7 +966,7 @@ func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsign return nil } -func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID) bool { +func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID, serverTimestamp uint64) bool { // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier var groupRevision uint32 @@ -982,16 +984,17 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp } cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ - Sender: messageSenderACI, - ChatID: groupOrUserID(groupID, chatRecipient), - GroupRevision: groupRevision, + Sender: messageSenderACI, + ChatID: groupOrUserID(groupID, chatRecipient), + GroupRevision: groupRevision, + ServerTimestamp: serverTimestamp, }, Event: editMessage, }) return true } -func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID) bool { +func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID, serverTimestamp uint64) bool { // If there's a profile key, save it if dataMessage.ProfileKey != nil { profileKey := libsignalgo.ProfileKey(dataMessage.ProfileKey) @@ -1019,9 +1022,10 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp } evtInfo := events.MessageInfo{ - Sender: messageSenderACI, - ChatID: groupOrUserID(groupID, chatRecipient), - GroupRevision: groupRevision, + Sender: messageSenderACI, + ChatID: groupOrUserID(groupID, chatRecipient), + GroupRevision: groupRevision, + ServerTimestamp: serverTimestamp, } // Hacky special case for group calls to cache the state if dataMessage.GroupCallUpdate != nil { From b538f47bff3902a1367937e0bdd1d40feea4d072 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 14 Nov 2024 17:23:10 +0200 Subject: [PATCH 362/718] signalmeow/attachments: log response headers for TUS uploads --- pkg/signalmeow/attachments.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 8a4b618..4fc106f 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -252,7 +252,8 @@ func (cli *Client) uploadAttachmentTUS( return fmt.Errorf("failed to send upload request: %w", err) } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { zerolog.Ctx(ctx).Debug(). - Any("headers", uploadAttributes.Headers). + Any("request_headers", uploadAttributes.Headers). + Any("response_headers", resp.Header). Str("location", uploadAttributes.SignedUploadLocation). Msg("TUS upload failed") return fmt.Errorf("upload request returned HTTP %d", resp.StatusCode) From 33ac0b4fcaf8bbfe08e2f2bd1641dc5a01c11b57 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 14 Nov 2024 18:03:05 +0200 Subject: [PATCH 363/718] signalmeow/attachments: remove auth from TUS upload request --- pkg/signalmeow/attachments.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 4fc106f..ca56634 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -166,7 +166,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb } if uploadAttributes.Cdn == 3 { log.Trace().Msg("Using TUS upload") - err = cli.uploadAttachmentTUS(ctx, uploadAttributes, encryptedWithMAC, username, password) + err = cli.uploadAttachmentTUS(ctx, uploadAttributes, encryptedWithMAC) } else { log.Trace().Msg("Using legacy upload") err = cli.uploadAttachmentLegacy(ctx, uploadAttributes, encryptedWithMAC, username, password) @@ -232,8 +232,6 @@ func (cli *Client) uploadAttachmentTUS( ctx context.Context, uploadAttributes attachmentV4UploadAttributes, encryptedWithMAC []byte, - username string, - password string, ) error { uploadAttributes.Headers["Tus-Resumable"] = "1.0.0" uploadAttributes.Headers["Upload-Length"] = fmt.Sprintf("%d", len(encryptedWithMAC)) @@ -244,8 +242,6 @@ func (cli *Client) uploadAttachmentTUS( Body: encryptedWithMAC, ContentType: web.ContentTypeOffsetOctetStream, Headers: uploadAttributes.Headers, - Username: &username, - Password: &password, }) // TODO actually support resuming on error if err != nil { From 45f97de8db3f44537ec40544f57b0c4cd786f2ee Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 15 Nov 2024 12:53:53 +0200 Subject: [PATCH 364/718] libsignal: update to v0.62.0 --- CHANGELOG.md | 5 +++++ pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 16 +++++++++++----- pkg/libsignalgo/logging.go | 8 ++++---- pkg/libsignalgo/setup_test.go | 3 +-- pkg/libsignalgo/version.go | 2 +- pkg/signalmeow/misc.go | 3 +-- 7 files changed, 24 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 743c281..2aff2f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v0.7.3 (unreleased) + +* Updated libsignal to v0.62.0. +* Added basic support for Signal's new file upload protocol. + # v0.7.2 (2024-10-16) * Updated to libsignal v0.58.3. diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 0a06f69..90ba453 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 0a06f69bce222c184a8d4022b8cf4202b02b9001 +Subproject commit 90ba45384073a467422d44783bc22a1152acd4c4 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 627dfd6..0af848b 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -445,7 +445,7 @@ typedef struct { SignalStoreSignedPreKey store_signed_pre_key; } SignalSignedPreKeyStore; -typedef void (*SignalLogCallback)(void *ctx, const char *target, SignalLogLevel level, const char *file, uint32_t line, const char *message); +typedef void (*SignalLogCallback)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); typedef void (*SignalLogFlushCallback)(void *ctx); @@ -664,6 +664,14 @@ typedef void (*SignalDestroyChatListener)(void *ctx); * Callbacks will be serialized (i.e. two calls will not come in at the same time), but may not * always happen on the same thread. Calls should be responded to promptly to avoid blocking later * messages. + * + * # Safety + * + * This type contains raw pointers. Code that constructs an instance of this type must ensure + * memory safety assuming that + * - the callback function pointer fields are called with `ctx` as an argument; + * - the `destroy` function pointer field is called with `ctx` as an argument; + * - no function pointer fields are called after `destroy` is called. */ typedef struct { void *ctx; @@ -673,8 +681,6 @@ typedef struct { SignalDestroyChatListener destroy; } SignalFfiChatListenerStruct; -typedef SignalFfiChatListenerStruct SignalFfiMakeChatListenerStruct; - typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); typedef int (*SignalSkip)(void *ctx, uint64_t amount); @@ -1545,9 +1551,9 @@ SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *pro SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncContext *runtime, const SignalAuthChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); +SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncContext *runtime, const SignalAuthChat *chat, const SignalFfiChatListenerStruct *listener); -SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalUnauthChat *chat, const SignalFfiMakeChatListenerStruct *make_listener); +SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalUnauthChat *chat, const SignalFfiChatListenerStruct *listener); SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p); diff --git a/pkg/libsignalgo/logging.go b/pkg/libsignalgo/logging.go index 2cbee01..e0a2351 100644 --- a/pkg/libsignalgo/logging.go +++ b/pkg/libsignalgo/logging.go @@ -20,7 +20,7 @@ package libsignalgo #cgo LDFLAGS: -lsignal_ffi -ldl -lm #include <./libsignal-ffi.h> -extern void signal_log_callback(void *ctx, char *target, SignalLogLevel level, char *file, uint32_t line, char *message); +extern void signal_log_callback(void *ctx, SignalLogLevel level, char *file, uint32_t line, char *message); extern void signal_log_flush_callback(void *ctx); */ import "C" @@ -32,8 +32,8 @@ import ( var ffiLogger Logger //export signal_log_callback -func signal_log_callback(ctx unsafe.Pointer, target *C.char, level C.SignalLogLevel, file *C.char, line C.uint32_t, message *C.char) { - ffiLogger.Log(C.GoString(target), LogLevel(int(level)), C.GoString(file), uint(line), C.GoString(message)) +func signal_log_callback(ctx unsafe.Pointer, level C.SignalLogLevel, file *C.char, line C.uint32_t, message *C.char) { + ffiLogger.Log(LogLevel(int(level)), C.GoString(file), uint(line), C.GoString(message)) } //export signal_log_flush_callback @@ -52,7 +52,7 @@ const ( ) type Logger interface { - Log(target string, level LogLevel, file string, line uint, message string) + Log(level LogLevel, file string, line uint, message string) Flush() } diff --git a/pkg/libsignalgo/setup_test.go b/pkg/libsignalgo/setup_test.go index 397238b..c22149d 100644 --- a/pkg/libsignalgo/setup_test.go +++ b/pkg/libsignalgo/setup_test.go @@ -29,7 +29,7 @@ type FFILogger struct{} func (FFILogger) Enabled(target string, level libsignalgo.LogLevel) bool { return true } -func (FFILogger) Log(target string, level libsignalgo.LogLevel, file string, line uint, message string) { +func (FFILogger) Log(level libsignalgo.LogLevel, file string, line uint, message string) { var evt *zerolog.Event switch level { case libsignalgo.LogLevelError: @@ -47,7 +47,6 @@ func (FFILogger) Log(target string, level libsignalgo.LogLevel, file string, lin } evt.Str("component", "libsignal"). - Str("target", target). Str("file", file). Uint("line", line). Msg(message) diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 4bd3b99..47fc072 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.61.0" +const Version = "v0.62.0" diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 1062dcb..1bf88a3 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -41,7 +41,7 @@ type FFILogger struct { logger zerolog.Logger } -func (l FFILogger) Log(target string, level libsignalgo.LogLevel, file string, line uint, message string) { +func (l FFILogger) Log(level libsignalgo.LogLevel, file string, line uint, message string) { var evt *zerolog.Event switch level { case libsignalgo.LogLevelError: @@ -59,7 +59,6 @@ func (l FFILogger) Log(target string, level libsignalgo.LogLevel, file string, l } evt.Str("component", "libsignal"). - Str("target", target). Str("file", file). Uint("line", line). Msg(message) From cf216cba7ab253da48dcfb352e54adc05d81ef69 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 16 Nov 2024 17:21:20 +0200 Subject: [PATCH 365/718] Bump version to v0.7.3 --- CHANGELOG.md | 6 +++++- cmd/mautrix-signal/main.go | 2 +- go.mod | 6 +++--- go.sum | 12 ++++++------ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aff2f4..8321abe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ -# v0.7.3 (unreleased) +# v0.7.3 (2024-11-16) * Updated libsignal to v0.62.0. + * Note for bridges running in systemd: the new version of libsignal may be + incompatible with the `MemoryDenyWriteExecute=true` option (see [#750]). * Added basic support for Signal's new file upload protocol. +[#750]: https://github.com/mautrix/signal/issues/570 + # v0.7.2 (2024-10-16) * Updated to libsignal v0.58.3. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 51dc76e..92121cb 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.2", + Version: "0.7.3", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 4e31e51..af76c4d 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.2-0.20241113135441-636f8643f367 + go.mau.fi/util v0.8.2 golang.org/x/crypto v0.29.0 golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f golang.org/x/net v0.31.0 - google.golang.org/protobuf v1.35.1 - maunium.net/go/mautrix v0.21.2-0.20241113135638-b22764aa170a + google.golang.org/protobuf v1.35.2 + maunium.net/go/mautrix v0.22.0 ) require ( diff --git a/go.sum b/go.sum index 590bd3d..69e3105 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.2-0.20241113135441-636f8643f367 h1:GU0TYiAOU79p6r3jf3e4k5cdgnPxOcJWkWeWampdAjw= -go.mau.fi/util v0.8.2-0.20241113135441-636f8643f367/go.mod h1:SVzC++wSl8Yq4YVQRClLPa1frNpSVDVP6mfkw/OvDbc= +go.mau.fi/util v0.8.2 h1:zWbVHwdRKwI6U9AusmZ8bwgcLosikwbb4GGqLrNr1YE= +go.mau.fi/util v0.8.2/go.mod h1:BHHC9R2WLMJd1bwTZfTcFxUgRFmUgUmiWcT4RbzUgiA= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= @@ -86,8 +86,8 @@ golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -97,5 +97,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.21.2-0.20241113135638-b22764aa170a h1:+hOkf85qhGRoAPpoCk7AiqKxlNvCCizb6urJVmgk0+8= -maunium.net/go/mautrix v0.21.2-0.20241113135638-b22764aa170a/go.mod h1:X7VB/wOIUo6c3wACyVwA//v2k8BpMLFB2rvaX2Y0984= +maunium.net/go/mautrix v0.22.0 h1:nLrnLYiMyFV6qZPqpkNogkOPgm2dQTYiQXlu9Nc3rz8= +maunium.net/go/mautrix v0.22.0/go.mod h1:oqwf9WYC/brqucM+heYk4gX11O59nP+ljvyxVhndFIM= From 29d55ebbde24d008f8c12f6f1d50d2916c5f949b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 18 Nov 2024 15:18:44 +0200 Subject: [PATCH 366/718] signalmeow: add support for ssre2 Corresponds to https://github.com/signalapp/Signal-Desktop/commit/a338bc5a6717eed455673c631f4077ad4ce47436 --- pkg/libsignalgo/accountentropy.go | 55 ++++++++++++++++++ .../protobuf/ContactDiscovery.pb.go | 2 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 2 +- pkg/signalmeow/protobuf/Groups.pb.go | 2 +- pkg/signalmeow/protobuf/Provisioning.pb.go | 2 +- pkg/signalmeow/protobuf/SignalService.pb.go | 22 ++++++- pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19130 -> 19227 bytes pkg/signalmeow/protobuf/SignalService.proto | 2 + .../protobuf/StickerResources.pb.go | 2 +- pkg/signalmeow/protobuf/StorageService.pb.go | 13 ++++- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 5934 -> 5983 bytes pkg/signalmeow/protobuf/StorageService.proto | 2 + .../protobuf/UnidentifiedDelivery.pb.go | 2 +- .../protobuf/WebSocketResources.pb.go | 2 +- pkg/signalmeow/provisioning.go | 9 +++ pkg/signalmeow/receiving.go | 17 ++++++ pkg/signalmeow/storageservice.go | 30 +++++++--- 17 files changed, 145 insertions(+), 19 deletions(-) create mode 100644 pkg/libsignalgo/accountentropy.go diff --git a/pkg/libsignalgo/accountentropy.go b/pkg/libsignalgo/accountentropy.go new file mode 100644 index 0000000..3160d64 --- /dev/null +++ b/pkg/libsignalgo/accountentropy.go @@ -0,0 +1,55 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#cgo LDFLAGS: -lsignal_ffi -ldl -lm +#include "./libsignal-ffi.h" +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type AccountEntropyPool string + +func (aep AccountEntropyPool) DeriveSVRKey() ([]byte, error) { + var out [C.SignalSVR_KEY_LEN]byte + signalFfiError := C.signal_account_entropy_pool_derive_svr_key( + (*[C.SignalSVR_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)), + C.CString(string(aep)), + ) + runtime.KeepAlive(aep) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return out[:], nil +} + +func (aep AccountEntropyPool) DeriveBackupKey() ([]byte, error) { + var out [C.SignalBACKUP_KEY_LEN]byte + signalFfiError := C.signal_account_entropy_pool_derive_backup_key( + (*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)), + C.CString(string(aep)), + ) + runtime.KeepAlive(aep) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return out[:], nil +} diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 6fd86ab..3c3d5b1 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: ContactDiscovery.proto diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 8207918..9721926 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: DeviceName.proto diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index b10d66a..b6d2280 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: Groups.proto diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index e7b7585..24e3a64 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: Provisioning.proto diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index 9ce328c..f9abde1 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: SignalService.proto @@ -6243,8 +6243,10 @@ type SyncMessage_Keys struct { unknownFields protoimpl.UnknownFields // @deprecated - StorageService []byte `protobuf:"bytes,1,opt,name=storageService" json:"storageService,omitempty"` - Master []byte `protobuf:"bytes,2,opt,name=master" json:"master,omitempty"` + StorageService []byte `protobuf:"bytes,1,opt,name=storageService" json:"storageService,omitempty"` + Master []byte `protobuf:"bytes,2,opt,name=master" json:"master,omitempty"` + AccountEntropyPool *string `protobuf:"bytes,3,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` // Copied manually from Signal Desktop + MediaRootBackupKey []byte `protobuf:"bytes,4,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // Copied manually from Signal Desktop } func (x *SyncMessage_Keys) Reset() { @@ -6291,6 +6293,20 @@ func (x *SyncMessage_Keys) GetMaster() []byte { return nil } +func (x *SyncMessage_Keys) GetAccountEntropyPool() string { + if x != nil && x.AccountEntropyPool != nil { + return *x.AccountEntropyPool + } + return "" +} + +func (x *SyncMessage_Keys) GetMediaRootBackupKey() []byte { + if x != nil { + return x.MediaRootBackupKey + } + return nil +} + type SyncMessage_MessageRequestResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw index 45c938aa97b57244e0ce9953a01cc7c33bc05a03..0212283ad7d460eef2666a29af7587664d4aa392 100644 GIT binary patch delta 135 zcmdlrm2vho#tn~^m`+=7eyXI#$Fz)bGLNBKs*oO+P-1d&eraBbYhFoFenDkGetwPw zvjU?AXAl+{kow%zl+47S{QMH9#N_PK0`JsH2^OGwo**nTQhiKZVv{czifzs{^pykv DJtQp= delta 38 ucmbO|jd9mh#tn~^m|j_JeyXI#$LKbh*U*hss*j0FY_g$|*yeMFzLEeG1`M45 diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index aa0a752..8a4bca8 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -547,6 +547,8 @@ message SyncMessage { // @deprecated optional bytes storageService = 1; optional bytes master = 2; + optional string accountEntropyPool = 3; // Copied manually from Signal Desktop + optional bytes mediaRootBackupKey = 4; // Copied manually from Signal Desktop } message MessageRequestResponse { diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index 0da3266..d49db13 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: StickerResources.proto diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 269354a..88b890a 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: StorageService.proto @@ -623,7 +623,8 @@ type ManifestRecord struct { Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` SourceDevice uint32 `protobuf:"varint,3,opt,name=sourceDevice,proto3" json:"sourceDevice,omitempty"` - Identifiers []*ManifestRecord_Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` // Next ID: 4 + Identifiers []*ManifestRecord_Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` // Next ID: 4 + RecordIkm []byte `protobuf:"bytes,4,opt,name=recordIkm,proto3,oneof" json:"recordIkm,omitempty"` // Copied manually from Signal Desktop } func (x *ManifestRecord) Reset() { @@ -677,6 +678,13 @@ func (x *ManifestRecord) GetIdentifiers() []*ManifestRecord_Identifier { return nil } +func (x *ManifestRecord) GetRecordIkm() []byte { + if x != nil { + return x.RecordIkm + } + return nil +} + type StorageRecord struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2130,6 +2138,7 @@ func file_StorageService_proto_init() { if File_StorageService_proto != nil { return } + file_StorageService_proto_msgTypes[5].OneofWrappers = []any{} file_StorageService_proto_msgTypes[6].OneofWrappers = []any{ (*StorageRecord_Contact)(nil), (*StorageRecord_GroupV1)(nil), diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw index c4befd576011672424b415535ef42449380d7931..cee69e5c54315ecf9be610cfc5e7d8a70dc60c01 100644 GIT binary patch delta 74 zcmZ3dcVBPAB}S$t%#*J$&QcaqE`AN=I6oyf#wR0 diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index 7b2fa3a..c8f4582 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -61,6 +61,8 @@ message ManifestRecord { uint32 sourceDevice = 3; repeated Identifier identifiers = 2; // Next ID: 4 + + optional bytes recordIkm = 4; // Copied manually from Signal Desktop } message StorageRecord { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index b42ca6f..e4eda97 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: UnidentifiedDelivery.proto diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index b3514e6..157c802 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 +// protoc-gen-go v1.35.2 // protoc v3.21.12 // source: WebSocketResources.proto diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 75bb6df..c997959 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -166,6 +166,14 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev Password: password, MasterKey: provisioningMessage.GetMasterKey(), } + if provisioningMessage.GetMasterKey() == nil && provisioningMessage.GetAccountEntropyPool() != "" { + data.MasterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey() + if err != nil { + log.Err(err).Msg("Failed to derive master key from account entropy pool") + } else { + log.Debug().Msg("Derived master key from account entropy pool") + } + } // Store the provisioning data err = deviceStore.PutDevice(ctx, data) @@ -334,6 +342,7 @@ func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningC var signalCapabilities = map[string]any{ "deleteSync": true, "versionedExpirationTimer": true, + "ssre2": true, } var signalCapabilitiesBody = exerrors.Must(json.Marshal(signalCapabilities)) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 1bebf77..aa07431 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -17,6 +17,7 @@ package signalmeow import ( + "bytes" "context" "encoding/base64" "fmt" @@ -718,7 +719,23 @@ func (cli *Client) handleDecryptedResult( // TODO: handle more sync messages if content.SyncMessage != nil { if content.SyncMessage.Keys != nil { + aep := libsignalgo.AccountEntropyPool(content.SyncMessage.Keys.GetAccountEntropyPool()) cli.Store.MasterKey = content.SyncMessage.Keys.GetMaster() + if aep != "" { + aepMasterKey, err := aep.DeriveSVRKey() + if err != nil { + log.Err(err).Msg("Failed to derive master key from account entropy pool") + } else if cli.Store.MasterKey == nil { + cli.Store.MasterKey = aepMasterKey + log.Debug().Msg("Derived master key from account entropy pool (no master key in sync message)") + } else if !bytes.Equal(aepMasterKey, cli.Store.MasterKey) { + log.Warn().Msg("Derived master key doesn't match one in sync message") + } else { + log.Debug().Msg("Derived master key matches one in sync message") + } + } else { + log.Debug().Msg("No account entropy pool in sync message") + } err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) if err != nil { log.Err(err).Msg("Failed to save device after receiving master key") diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index f2385f3..1902c4b 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -29,6 +29,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exerrors" + "golang.org/x/crypto/hkdf" "golang.org/x/exp/maps" "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" @@ -146,7 +147,7 @@ func (cli *Client) FetchStorage(ctx context.Context, masterKey []byte, currentVe } delete(newKeys, key) } - newRecords, missingKeys, err := cli.fetchStorageRecords(ctx, storageKey, newKeys) + newRecords, missingKeys, err := cli.fetchStorageRecords(ctx, storageKey, manifest.GetRecordIkm(), newKeys) if err != nil { return nil, err } @@ -178,10 +179,20 @@ func deriveStorageManifestKey(storageKey []byte, version uint64) []byte { return h.Sum(nil) } -func deriveStorageItemKey(storageKey []byte, itemID string) []byte { - h := hmac.New(sha256.New, storageKey) - exerrors.Must(fmt.Fprintf(h, "Item_%s", itemID)) - return h.Sum(nil) +const storageServiceItemKeyInfoPrefix = "20240801_SIGNAL_STORAGE_SERVICE_ITEM_" +const storageServiceItemKeyLen = 32 + +func deriveStorageItemKey(storageKey, recordIKM []byte, itemID string) []byte { + if recordIKM == nil { + h := hmac.New(sha256.New, storageKey) + exerrors.Must(fmt.Fprintf(h, "Item_%s", itemID)) + return h.Sum(nil) + } else { + h := hkdf.New(sha256.New, recordIKM, []byte{}, append([]byte(storageServiceItemKeyInfoPrefix), itemID...)) + out := make([]byte, storageServiceItemKeyLen) + exerrors.Must(io.ReadFull(h, out)) + return out + } } // MaxReadStorageRecords is the maximum number of storage records to fetch at once @@ -231,7 +242,12 @@ func (cli *Client) fetchStorageManifest(ctx context.Context, storageKey []byte, } } -func (cli *Client) fetchStorageRecords(ctx context.Context, storageKey []byte, inputRecords map[string]signalpb.ManifestRecord_Identifier_Type) ([]*DecryptedStorageRecord, []string, error) { +func (cli *Client) fetchStorageRecords( + ctx context.Context, + storageKey []byte, + recordIKM []byte, + inputRecords map[string]signalpb.ManifestRecord_Identifier_Type, +) ([]*DecryptedStorageRecord, []string, error) { recordKeys := make([][]byte, 0, len(inputRecords)) for key := range inputRecords { decoded, err := base64.StdEncoding.DecodeString(key) @@ -262,7 +278,7 @@ func (cli *Client) fetchStorageRecords(ctx context.Context, storageKey []byte, i log.Warn().Int("item_index", i).Str("item_key", base64Key).Msg("Received unexpected storage item") continue } - itemKey := deriveStorageItemKey(storageKey, base64Key) + itemKey := deriveStorageItemKey(storageKey, recordIKM, base64Key) decryptedItemBytes, err := decryptBytes(itemKey, encryptedItem.GetValue()) if err != nil { log.Warn().Err(err). From 958aa33a747dec560ac850c42bdc0be280cbd65b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Dec 2024 13:09:48 +0200 Subject: [PATCH 367/718] pre-commit: update hooks --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a667b3..1f3f910 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace exclude_types: [markdown] @@ -22,7 +22,7 @@ repos: # TODO: reenable this and fix all the problems - repo: https://github.com/beeper/pre-commit-go - rev: v0.3.1 + rev: v0.4.2 hooks: - id: zerolog-ban-msgf - id: zerolog-use-stringer From 39116d9e43d735cd795f9d746b3a3cd4d5d4a416 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Dec 2024 13:14:44 +0200 Subject: [PATCH 368/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/Provisioning.pb.go | 32 +++++++++--------- pkg/signalmeow/protobuf/Provisioning.pb.raw | Bin 948 -> 957 bytes pkg/signalmeow/protobuf/Provisioning.proto | 4 +-- pkg/signalmeow/protobuf/SignalService.pb.go | 7 ++-- pkg/signalmeow/protobuf/SignalService.proto | 7 ++-- pkg/signalmeow/protobuf/StorageService.pb.go | 5 ++- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 5983 -> 5964 bytes pkg/signalmeow/protobuf/StorageService.proto | 5 ++- pkg/signalmeow/protobuf/update-protos.sh | 4 +-- pkg/signalmeow/provisioning.go | 7 ++-- 10 files changed, 36 insertions(+), 35 deletions(-) diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 24e3a64..a1d3f0b 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -86,28 +86,28 @@ func (ProvisioningVersion) EnumDescriptor() ([]byte, []int) { return file_Provisioning_proto_rawDescGZIP(), []int{0} } -type ProvisioningUuid struct { +type ProvisioningAddress struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Uuid *string `protobuf:"bytes,1,opt,name=uuid" json:"uuid,omitempty"` + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` } -func (x *ProvisioningUuid) Reset() { - *x = ProvisioningUuid{} +func (x *ProvisioningAddress) Reset() { + *x = ProvisioningAddress{} mi := &file_Provisioning_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ProvisioningUuid) String() string { +func (x *ProvisioningAddress) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ProvisioningUuid) ProtoMessage() {} +func (*ProvisioningAddress) ProtoMessage() {} -func (x *ProvisioningUuid) ProtoReflect() protoreflect.Message { +func (x *ProvisioningAddress) ProtoReflect() protoreflect.Message { mi := &file_Provisioning_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -119,14 +119,14 @@ func (x *ProvisioningUuid) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ProvisioningUuid.ProtoReflect.Descriptor instead. -func (*ProvisioningUuid) Descriptor() ([]byte, []int) { +// Deprecated: Use ProvisioningAddress.ProtoReflect.Descriptor instead. +func (*ProvisioningAddress) Descriptor() ([]byte, []int) { return file_Provisioning_proto_rawDescGZIP(), []int{0} } -func (x *ProvisioningUuid) GetUuid() string { - if x != nil && x.Uuid != nil { - return *x.Uuid +func (x *ProvisioningAddress) GetAddress() string { + if x != nil && x.Address != nil { + return *x.Address } return "" } @@ -369,10 +369,10 @@ func file_Provisioning_proto_rawDescGZIP() []byte { var file_Provisioning_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_Provisioning_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_Provisioning_proto_goTypes = []any{ - (ProvisioningVersion)(0), // 0: signalservice.ProvisioningVersion - (*ProvisioningUuid)(nil), // 1: signalservice.ProvisioningUuid - (*ProvisionEnvelope)(nil), // 2: signalservice.ProvisionEnvelope - (*ProvisionMessage)(nil), // 3: signalservice.ProvisionMessage + (ProvisioningVersion)(0), // 0: signalservice.ProvisioningVersion + (*ProvisioningAddress)(nil), // 1: signalservice.ProvisioningAddress + (*ProvisionEnvelope)(nil), // 2: signalservice.ProvisionEnvelope + (*ProvisionMessage)(nil), // 3: signalservice.ProvisionMessage } var file_Provisioning_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.raw b/pkg/signalmeow/protobuf/Provisioning.pb.raw index 385bc0221e1cce3935b116e6241b0b4d697c8df3..874538c7f1185b2aa7736feabcfdb3e4125f025d 100644 GIT binary patch delta 59 zcmdnOzL$N1ih(|ta6nOhS!Qu&eqLr?x?@U8QEG9qkOUWdB7`ZysKBVf83f~Q^v+}k E06uXNumAu6 delta 50 zcmdnXzJ+~)in Date: Mon, 2 Dec 2024 18:44:53 +0200 Subject: [PATCH 369/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 5 ++--- pkg/connector/login.go | 5 +---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index af76c4d..5b56c84 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f golang.org/x/net v0.31.0 google.golang.org/protobuf v1.35.2 - maunium.net/go/mautrix v0.22.0 + maunium.net/go/mautrix v0.22.1-0.20241202131110-166ba04aae02 ) require ( diff --git a/go.sum b/go.sum index 69e3105..8df0f41 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.22.0 h1:nLrnLYiMyFV6qZPqpkNogkOPgm2dQTYiQXlu9Nc3rz8= -maunium.net/go/mautrix v0.22.0/go.mod h1:oqwf9WYC/brqucM+heYk4gX11O59nP+ljvyxVhndFIM= +maunium.net/go/mautrix v0.22.1-0.20241202131110-166ba04aae02 h1:g8L4GpOhyg5EuXtASDKyU9Cg79ZjATlUnh+giFumQgc= +maunium.net/go/mautrix v0.22.1-0.20241202131110-166ba04aae02/go.mod h1:oqwf9WYC/brqucM+heYk4gX11O59nP+ljvyxVhndFIM= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index ebd2def..8a8d415 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -219,14 +219,13 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } } -func (s *SignalClient) Connect(ctx context.Context) error { +func (s *SignalClient) Connect(ctx context.Context) { if s.Client == nil { s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You're not logged into Signal"}) - return nil + return } s.updateRemoteProfile(ctx, false) s.tryConnect(ctx, 0) - return nil } func (s *SignalClient) Disconnect() { diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 5636339..525d14a 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -172,10 +172,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err return nil, fmt.Errorf("failed to create user login: %w", err) } backgroundCtx := ul.Log.WithContext(context.Background()) - err = ul.Client.Connect(backgroundCtx) - if err != nil { - return nil, fmt.Errorf("failed to connect after login: %w", err) - } + ul.Client.Connect(backgroundCtx) if signalClient := ul.Client.(*SignalClient).Client; signalClient.Store.MasterKey != nil { zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") go signalClient.SyncStorage(ctx) From 1f5fb4119fac45ec9da4c9821bbfd0a8bf2ca997 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Dec 2024 17:44:34 +0200 Subject: [PATCH 370/718] signalmeow/receiving: log envelope timestamps when decrypting is successful --- pkg/signalmeow/receiving.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index aa07431..b1dddea 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -659,7 +659,10 @@ func (cli *Client) handleDecryptedResult( Logger() log = &newLog ctx = log.WithContext(ctx) - log.Debug().Msg("Decrypted message") + log.Debug(). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Msg("Decrypted message") printContentFieldString(ctx, content, "Decrypted content fields") // If there's a sender key distribution message, process it From 66a5a5163035b5318eb720a89129c6034676f82d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Dec 2024 14:46:19 +0200 Subject: [PATCH 371/718] signalmeow: read receipt and typing settings from account record --- pkg/signalmeow/sending.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 902818d..b6a8a43 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -747,6 +747,16 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv cli.sendSyncCopy(ctx, content, messageTimestamp, &res) } return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} + } else if content.TypingMessage != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() { + zerolog.Ctx(ctx).Debug().Msg("Not sending typing message as typing indicators are disabled") + res := SuccessfulSendResult{Recipient: recipientID} + return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} + } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ && !cli.Store.DeviceData.AccountRecord.GetReadReceipts() { + zerolog.Ctx(ctx).Debug().Msg("Not sending receipt message as read receipts are disabled") + res := SuccessfulSendResult{Recipient: recipientID} + // Still send sync messages for read receipts + cli.sendSyncCopy(ctx, content, messageTimestamp, &res) + return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} } isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY From e13fa634306d65773fe56a56a7c4d3deae134ab8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Dec 2024 14:50:54 +0200 Subject: [PATCH 372/718] libsignal: update to v0.64.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 12 ++++++++++-- pkg/libsignalgo/version.go | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 90ba453..4b78ebf 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 90ba45384073a467422d44783bc22a1152acd4c4 +Subproject commit 4b78ebfeeaec42e1f37c87ecb67b0e480b15f03a diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 0af848b..b16aca6 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -256,6 +256,8 @@ typedef struct SignalMessageBackupKey SignalMessageBackupKey; typedef struct SignalMessageBackupValidationOutcome SignalMessageBackupValidationOutcome; +typedef struct SignalOnlineBackupValidator SignalOnlineBackupValidator; + typedef struct SignalPinHash SignalPinHash; typedef struct SignalPlaintextContent SignalPlaintextContent; @@ -1509,8 +1511,6 @@ SignalFfiError *signal_lookup_request_set_token(const SignalLookupRequest *reque SignalFfiError *signal_lookup_request_add_aci_and_access_key(const SignalLookupRequest *request, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer access_key); -SignalFfiError *signal_lookup_request_set_return_acis_without_uaks(const SignalLookupRequest *request, bool return_acis_without_uaks); - SignalFfiError *signal_cdsi_lookup_destroy(SignalCdsiLookup *p); SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request); @@ -1639,6 +1639,14 @@ SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(Sign SignalFfiError *signal_message_backup_validator_validate(SignalMessageBackupValidationOutcome **out, const SignalMessageBackupKey *key, const SignalInputStream *first_stream, const SignalInputStream *second_stream, uint64_t len, uint8_t purpose); +SignalFfiError *signal_online_backup_validator_destroy(SignalOnlineBackupValidator *p); + +SignalFfiError *signal_online_backup_validator_new(SignalOnlineBackupValidator **out, SignalBorrowedBuffer backup_info_frame, uint8_t purpose); + +SignalFfiError *signal_online_backup_validator_add_frame(SignalOnlineBackupValidator *backup, SignalBorrowedBuffer frame); + +SignalFfiError *signal_online_backup_validator_finalize(SignalOnlineBackupValidator *backup); + SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); SignalFfiError *signal_username_proof(SignalOwnedBuffer *out, const char *username, SignalBorrowedBuffer randomness); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 47fc072..5bcef1b 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.62.0" +const Version = "v0.64.1" From d17cd5f01ec5b0a3dbd1b7ae9c725da742c5f4c1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Dec 2024 14:51:43 +0200 Subject: [PATCH 373/718] docker: update to Alpine 3.21 --- Dockerfile | 4 ++-- Dockerfile.ci | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 16c7d5b..a022666 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ ARG DBG=0 RUN ./build-rust.sh # -- Build mautrix-signal (with Go) -- -FROM golang:1-alpine3.20 AS go-builder +FROM golang:1-alpine3.21 AS go-builder RUN apk add --no-cache git ca-certificates build-base olm-dev WORKDIR /build @@ -39,7 +39,7 @@ EOF RUN ./build-go.sh # -- Run mautrix-signal -- -FROM alpine:3.20 +FROM alpine:3.21 ENV UID=1337 \ GID=1337 diff --git a/Dockerfile.ci b/Dockerfile.ci index e98ad03..556dfc1 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 ENV UID=1337 \ GID=1337 From 77edbf31df51fef24b904a2d765f7602e3f60a7f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Dec 2024 15:14:22 +0200 Subject: [PATCH 374/718] login: fix syncing storage after login --- pkg/connector/login.go | 2 +- pkg/signalmeow/sending.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 525d14a..da1b66a 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -175,7 +175,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err ul.Client.Connect(backgroundCtx) if signalClient := ul.Client.(*SignalClient).Client; signalClient.Store.MasterKey != nil { zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") - go signalClient.SyncStorage(ctx) + go signalClient.SyncStorage(backgroundCtx) } return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index b6a8a43..555cbc2 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -747,11 +747,11 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv cli.sendSyncCopy(ctx, content, messageTimestamp, &res) } return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} - } else if content.TypingMessage != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() { + } else if content.TypingMessage != nil && cli.Store.DeviceData.AccountRecord != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() { zerolog.Ctx(ctx).Debug().Msg("Not sending typing message as typing indicators are disabled") res := SuccessfulSendResult{Recipient: recipientID} return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} - } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ && !cli.Store.DeviceData.AccountRecord.GetReadReceipts() { + } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ && cli.Store.DeviceData.AccountRecord != nil && !cli.Store.DeviceData.AccountRecord.GetReadReceipts() { zerolog.Ctx(ctx).Debug().Msg("Not sending receipt message as read receipts are disabled") res := SuccessfulSendResult{Recipient: recipientID} // Still send sync messages for read receipts From f8bde3991de27725f55e179dbe8ab3a17d547965 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 11 Dec 2024 19:57:03 +0200 Subject: [PATCH 375/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/Groups.pb.go | 8 + pkg/signalmeow/protobuf/Groups.pb.raw | Bin 7313 -> 7339 bytes pkg/signalmeow/protobuf/Groups.proto | 1 + pkg/signalmeow/protobuf/SignalService.pb.go | 275 +++++++++++-------- pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19227 -> 19370 bytes pkg/signalmeow/protobuf/SignalService.proto | 6 + pkg/signalmeow/protobuf/update-protos.sh | 4 +- 7 files changed, 182 insertions(+), 112 deletions(-) diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index b6d2280..de4a1ae 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -1230,6 +1230,7 @@ type GroupChange_Actions struct { unknownFields protoimpl.UnknownFields SourceServiceId []byte `protobuf:"bytes,1,opt,name=sourceServiceId,proto3" json:"sourceServiceId,omitempty"` + GroupId []byte `protobuf:"bytes,25,opt,name=groupId,proto3" json:"groupId,omitempty"` // Only set when receiving from server Revision uint32 `protobuf:"varint,2,opt,name=revision,proto3" json:"revision,omitempty"` AddMembers []*GroupChange_Actions_AddMemberAction `protobuf:"bytes,3,rep,name=addMembers,proto3" json:"addMembers,omitempty"` DeleteMembers []*GroupChange_Actions_DeleteMemberAction `protobuf:"bytes,4,rep,name=deleteMembers,proto3" json:"deleteMembers,omitempty"` @@ -1292,6 +1293,13 @@ func (x *GroupChange_Actions) GetSourceServiceId() []byte { return nil } +func (x *GroupChange_Actions) GetGroupId() []byte { + if x != nil { + return x.GroupId + } + return nil +} + func (x *GroupChange_Actions) GetRevision() uint32 { if x != nil { return x.Revision diff --git a/pkg/signalmeow/protobuf/Groups.pb.raw b/pkg/signalmeow/protobuf/Groups.pb.raw index 7549d560184e776c7a26830944fac136320946a9..dceda274eece491e05fbb427b8eb4b191fdc755d 100644 GIT binary patch delta 48 zcmbPex!Q6=F&pEv$t7&1j2|YyVlx$&;9^fN$}cVOOp%aOVAS9Vf^av>u$PJg0G=cd AZ~y=R delta 24 gcmZ2&Ini=MF&pEV$t7&1jMpZ=Vl&-r$zCK10D58xFaQ7m diff --git a/pkg/signalmeow/protobuf/Groups.proto b/pkg/signalmeow/protobuf/Groups.proto index 63970c7..e202eb2 100644 --- a/pkg/signalmeow/protobuf/Groups.proto +++ b/pkg/signalmeow/protobuf/Groups.proto @@ -183,6 +183,7 @@ message GroupChange { } bytes sourceServiceId = 1; + bytes groupId = 25; // Only set when receiving from server uint32 revision = 2; repeated AddMemberAction addMembers = 3; repeated DeleteMemberAction deleteMembers = 4; diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index a8686db..a633e85 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -2907,6 +2907,7 @@ type SyncMessage struct { CallLinkUpdate *SyncMessage_CallLinkUpdate `protobuf:"bytes,20,opt,name=callLinkUpdate" json:"callLinkUpdate,omitempty"` CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent" json:"callLogEvent,omitempty"` DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe" json:"deleteForMe,omitempty"` + DeviceNameChange *SyncMessage_DeviceNameChange `protobuf:"bytes,23,opt,name=deviceNameChange" json:"deviceNameChange,omitempty"` } func (x *SyncMessage) Reset() { @@ -3079,6 +3080,13 @@ func (x *SyncMessage) GetDeleteForMe() *SyncMessage_DeleteForMe { return nil } +func (x *SyncMessage) GetDeviceNameChange() *SyncMessage_DeviceNameChange { + if x != nil { + return x.DeviceNameChange + } + return nil +} + type AttachmentPointer struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6816,6 +6824,51 @@ func (x *SyncMessage_DeleteForMe) GetAttachmentDeletes() []*SyncMessage_DeleteFo return nil } +type SyncMessage_DeviceNameChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceId *uint32 `protobuf:"varint,2,opt,name=deviceId" json:"deviceId,omitempty"` +} + +func (x *SyncMessage_DeviceNameChange) Reset() { + *x = SyncMessage_DeviceNameChange{} + mi := &file_SignalService_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SyncMessage_DeviceNameChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_DeviceNameChange) ProtoMessage() {} + +func (x *SyncMessage_DeviceNameChange) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[67] + 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 SyncMessage_DeviceNameChange.ProtoReflect.Descriptor instead. +func (*SyncMessage_DeviceNameChange) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{12, 18} +} + +func (x *SyncMessage_DeviceNameChange) GetDeviceId() uint32 { + if x != nil && x.DeviceId != nil { + return *x.DeviceId + } + return 0 +} + type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6828,7 +6881,7 @@ type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6840,7 +6893,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6889,7 +6942,7 @@ type SyncMessage_Sent_StoryMessageRecipient struct { func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6901,7 +6954,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6958,7 +7011,7 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6970,7 +7023,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7057,7 +7110,7 @@ type SyncMessage_DeleteForMe_ConversationIdentifier struct { func (x *SyncMessage_DeleteForMe_ConversationIdentifier) Reset() { *x = SyncMessage_DeleteForMe_ConversationIdentifier{} - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7069,7 +7122,7 @@ func (x *SyncMessage_DeleteForMe_ConversationIdentifier) String() string { func (*SyncMessage_DeleteForMe_ConversationIdentifier) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationIdentifier) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7153,7 +7206,7 @@ type SyncMessage_DeleteForMe_AddressableMessage struct { func (x *SyncMessage_DeleteForMe_AddressableMessage) Reset() { *x = SyncMessage_DeleteForMe_AddressableMessage{} - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7165,7 +7218,7 @@ func (x *SyncMessage_DeleteForMe_AddressableMessage) String() string { func (*SyncMessage_DeleteForMe_AddressableMessage) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AddressableMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7238,7 +7291,7 @@ type SyncMessage_DeleteForMe_MessageDeletes struct { func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { *x = SyncMessage_DeleteForMe_MessageDeletes{} - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7250,7 +7303,7 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7294,7 +7347,7 @@ type SyncMessage_DeleteForMe_AttachmentDelete struct { func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { *x = SyncMessage_DeleteForMe_AttachmentDelete{} - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7306,7 +7359,7 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7370,7 +7423,7 @@ type SyncMessage_DeleteForMe_ConversationDelete struct { func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7382,7 +7435,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7436,7 +7489,7 @@ type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7448,7 +7501,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7481,7 +7534,7 @@ type GroupContext_Member struct { func (x *GroupContext_Member) Reset() { *x = GroupContext_Member{} - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7493,7 +7546,7 @@ func (x *GroupContext_Member) String() string { func (*GroupContext_Member) ProtoMessage() {} func (x *GroupContext_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7527,7 +7580,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7539,7 +7592,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7580,7 +7633,7 @@ type GroupDetails_Avatar struct { func (x *GroupDetails_Avatar) Reset() { *x = GroupDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7592,7 +7645,7 @@ func (x *GroupDetails_Avatar) String() string { func (*GroupDetails_Avatar) ProtoMessage() {} func (x *GroupDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7632,7 +7685,7 @@ type GroupDetails_Member struct { func (x *GroupDetails_Member) Reset() { *x = GroupDetails_Member{} - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7644,7 +7697,7 @@ func (x *GroupDetails_Member) String() string { func (*GroupDetails_Member) ProtoMessage() {} func (x *GroupDetails_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7678,7 +7731,7 @@ type PaymentAddress_MobileCoinAddress struct { func (x *PaymentAddress_MobileCoinAddress) Reset() { *x = PaymentAddress_MobileCoinAddress{} - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7690,7 +7743,7 @@ func (x *PaymentAddress_MobileCoinAddress) String() string { func (*PaymentAddress_MobileCoinAddress) ProtoMessage() {} func (x *PaymentAddress_MobileCoinAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7738,7 +7791,7 @@ func file_SignalService_proto_rawDescGZIP() []byte { } var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 27) -var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 81) +var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 82) var file_SignalService_proto_goTypes = []any{ (Envelope_Type)(0), // 0: signalservice.Envelope.Type (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type @@ -7834,20 +7887,21 @@ var file_SignalService_proto_goTypes = []any{ (*SyncMessage_CallLinkUpdate)(nil), // 91: signalservice.SyncMessage.CallLinkUpdate (*SyncMessage_CallLogEvent)(nil), // 92: signalservice.SyncMessage.CallLogEvent (*SyncMessage_DeleteForMe)(nil), // 93: signalservice.SyncMessage.DeleteForMe - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 94: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 95: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 96: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*SyncMessage_DeleteForMe_ConversationIdentifier)(nil), // 97: signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - (*SyncMessage_DeleteForMe_AddressableMessage)(nil), // 98: signalservice.SyncMessage.DeleteForMe.AddressableMessage - (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 99: signalservice.SyncMessage.DeleteForMe.MessageDeletes - (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 100: signalservice.SyncMessage.DeleteForMe.AttachmentDelete - (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 101: signalservice.SyncMessage.DeleteForMe.ConversationDelete - (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 102: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - (*GroupContext_Member)(nil), // 103: signalservice.GroupContext.Member - (*ContactDetails_Avatar)(nil), // 104: signalservice.ContactDetails.Avatar - (*GroupDetails_Avatar)(nil), // 105: signalservice.GroupDetails.Avatar - (*GroupDetails_Member)(nil), // 106: signalservice.GroupDetails.Member - (*PaymentAddress_MobileCoinAddress)(nil), // 107: signalservice.PaymentAddress.MobileCoinAddress + (*SyncMessage_DeviceNameChange)(nil), // 94: signalservice.SyncMessage.DeviceNameChange + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 95: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 96: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 97: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*SyncMessage_DeleteForMe_ConversationIdentifier)(nil), // 98: signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + (*SyncMessage_DeleteForMe_AddressableMessage)(nil), // 99: signalservice.SyncMessage.DeleteForMe.AddressableMessage + (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 100: signalservice.SyncMessage.DeleteForMe.MessageDeletes + (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 101: signalservice.SyncMessage.DeleteForMe.AttachmentDelete + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 102: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 103: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*GroupContext_Member)(nil), // 104: signalservice.GroupContext.Member + (*ContactDetails_Avatar)(nil), // 105: signalservice.ContactDetails.Avatar + (*GroupDetails_Avatar)(nil), // 106: signalservice.GroupDetails.Avatar + (*GroupDetails_Member)(nil), // 107: signalservice.GroupDetails.Member + (*PaymentAddress_MobileCoinAddress)(nil), // 108: signalservice.PaymentAddress.MobileCoinAddress } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type @@ -7910,70 +7964,71 @@ var file_SignalService_proto_depIdxs = []int32{ 91, // 57: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate 92, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent 93, // 59: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe - 26, // 60: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type - 103, // 61: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member - 40, // 62: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer - 104, // 63: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 38, // 64: signalservice.ContactDetails.verified:type_name -> signalservice.Verified - 106, // 65: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member - 105, // 66: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar - 107, // 67: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress - 31, // 68: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 1, // 69: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 70: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 71: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 64, // 72: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 30, // 73: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 74: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 65, // 75: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 66, // 76: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 67, // 77: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 68, // 78: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 69, // 79: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 40, // 80: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 71, // 81: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 72, // 82: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 40, // 83: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 84: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 85: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 86: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 40, // 87: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 73, // 88: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 74, // 89: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 11, // 90: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 31, // 91: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 94, // 92: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 35, // 93: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 95, // 94: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 48, // 95: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 40, // 96: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 16, // 97: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 17, // 98: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 18, // 99: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 19, // 100: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 96, // 101: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 20, // 102: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 21, // 103: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 22, // 104: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 23, // 105: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type - 24, // 106: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 99, // 107: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes - 101, // 108: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete - 102, // 109: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - 100, // 110: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete - 97, // 111: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 98, // 112: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 97, // 113: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 98, // 114: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 97, // 115: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 98, // 116: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 98, // 117: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 97, // 118: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 119, // [119:119] is the sub-list for method output_type - 119, // [119:119] is the sub-list for method input_type - 119, // [119:119] is the sub-list for extension type_name - 119, // [119:119] is the sub-list for extension extendee - 0, // [0:119] is the sub-list for field type_name + 94, // 60: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange + 26, // 61: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type + 104, // 62: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member + 40, // 63: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer + 105, // 64: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 38, // 65: signalservice.ContactDetails.verified:type_name -> signalservice.Verified + 107, // 66: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member + 106, // 67: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar + 108, // 68: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress + 31, // 69: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 1, // 70: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 71: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 72: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 64, // 73: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 30, // 74: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 75: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 65, // 76: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 66, // 77: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 67, // 78: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 68, // 79: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 69, // 80: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 81: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 71, // 82: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 72, // 83: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 40, // 84: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 85: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 86: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 87: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 40, // 88: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 73, // 89: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 74, // 90: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 11, // 91: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 31, // 92: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 95, // 93: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 94: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 96, // 95: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 48, // 96: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 97: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 16, // 98: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 17, // 99: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 18, // 100: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 19, // 101: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 97, // 102: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 20, // 103: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 21, // 104: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 22, // 105: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 23, // 106: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 24, // 107: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 100, // 108: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes + 102, // 109: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 103, // 110: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 101, // 111: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete + 98, // 112: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 99, // 113: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 98, // 114: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 99, // 115: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 98, // 116: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 99, // 117: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 99, // 118: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage + 98, // 119: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier + 120, // [120:120] is the sub-list for method output_type + 120, // [120:120] is the sub-list for method input_type + 120, // [120:120] is the sub-list for extension type_name + 120, // [120:120] is the sub-list for extension extendee + 0, // [0:120] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -8013,12 +8068,12 @@ func file_SignalService_proto_init() { file_SignalService_proto_msgTypes[61].OneofWrappers = []any{ (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[70].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[71].OneofWrappers = []any{ (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId)(nil), (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId)(nil), (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164)(nil), } - file_SignalService_proto_msgTypes[71].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[72].OneofWrappers = []any{ (*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId)(nil), (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164)(nil), } @@ -8028,7 +8083,7 @@ func file_SignalService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_SignalService_proto_rawDesc, NumEnums: 27, - NumMessages: 81, + NumMessages: 82, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw index 0212283ad7d460eef2666a29af7587664d4aa392..ef74a34b022885779472ea55468cec2136898678 100644 GIT binary patch delta 147 zcmbO|jd9g<#tn~^m~Po@eyY^MDkT)oC6JO@mYJODmzbOCoROH9o+=@(z^K7JxxqkI z(FIK^2wm~!3=JCzGbs};0d%E8Qd}GmlRZ-;n1Cko2EqAWEF6piOq-WDlyd<9WnnJ2 delta 27 jcmZ2AopJUw#tn~^m`+=7eyY^My7`cXwZvv)$8s(Jr}zsE diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index f5cecb0..bd841ae 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -707,6 +707,11 @@ message SyncMessage { repeated AttachmentDelete attachmentDeletes = 4; } + message DeviceNameChange { + reserved /*name*/ 1; + optional uint32 deviceId = 2; + } + optional Sent sent = 1; optional Contacts contacts = 2; reserved /*groups*/ 3; @@ -729,6 +734,7 @@ message SyncMessage { optional CallLinkUpdate callLinkUpdate = 20; optional CallLogEvent callLogEvent = 21; optional DeleteForMe deleteForMe = 22; + optional DeviceNameChange deviceNameChange = 23; } message AttachmentPointer { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 7d59dea..cf36fdc 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-f5a68aa7aeccba3efba71e9868475a2483c5fa28} -DESKTOP_GIT_REVISION=${1:-5d899d740b236491d8cad6fe187bb9806ff95ccf} +ANDROID_GIT_REVISION=${1:-e47861796e3af0879dfd3a67f549674efb9c0c33} +DESKTOP_GIT_REVISION=${1:-94dba11bcb3973b98784b0a7aaefa6ea03c330ea} update_proto() { case "$1" in From 60fa2e75b5d4a1b56ae90178c12e4ac8716767ae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 15 Dec 2024 12:51:10 +0200 Subject: [PATCH 376/718] dependencies: update --- go.mod | 22 +++++++++++----------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 5b56c84..e95b307 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.22.0 -toolchain go1.23.3 +toolchain go1.23.4 require ( github.com/coder/websocket v1.8.12 @@ -11,14 +11,14 @@ require ( github.com/gorilla/mux v1.8.0 github.com/mattn/go-pointer v0.0.1 github.com/rs/zerolog v1.33.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.2 - golang.org/x/crypto v0.29.0 - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f - golang.org/x/net v0.31.0 + go.mau.fi/util v0.8.3-0.20241212004537-24c1a9b1d8f6 + golang.org/x/crypto v0.31.0 + golang.org/x/exp v0.0.0-20241210194714-1829a127f884 + golang.org/x/net v0.32.0 google.golang.org/protobuf v1.35.2 - maunium.net/go/mautrix v0.22.1-0.20241202131110-166ba04aae02 + maunium.net/go/mautrix v0.22.1-0.20241215103154-351b49f8a893 ) require ( @@ -31,7 +31,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.24 // indirect - github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 // indirect + github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -41,9 +41,9 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.8 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 8df0f41..4d23cfe 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 h1:qli3BGQK0tYDkSEvZ/FzZTi9ZrOX86Q6CIhKLGc489A= -github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 h1:ah1dvbqPMN5+ocrg/ZSgZ6k8bOk+kcZQ7fnyx6UvOm4= +github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -54,8 +54,8 @@ github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -67,25 +67,25 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.2 h1:zWbVHwdRKwI6U9AusmZ8bwgcLosikwbb4GGqLrNr1YE= -go.mau.fi/util v0.8.2/go.mod h1:BHHC9R2WLMJd1bwTZfTcFxUgRFmUgUmiWcT4RbzUgiA= +go.mau.fi/util v0.8.3-0.20241212004537-24c1a9b1d8f6 h1:s4aQJQBBMkjkHTdThRRNp2E35wqmMJVGkOAXG4b0X8c= +go.mau.fi/util v0.8.3-0.20241212004537-24c1a9b1d8f6/go.mod h1:sWpI/kFgk/QP4BDJJwSjjBsuAT7oUsj9VlFhvUo+34I= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= +golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -97,5 +97,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.22.1-0.20241202131110-166ba04aae02 h1:g8L4GpOhyg5EuXtASDKyU9Cg79ZjATlUnh+giFumQgc= -maunium.net/go/mautrix v0.22.1-0.20241202131110-166ba04aae02/go.mod h1:oqwf9WYC/brqucM+heYk4gX11O59nP+ljvyxVhndFIM= +maunium.net/go/mautrix v0.22.1-0.20241215103154-351b49f8a893 h1:nwV01xjyCMINMjHl+0diuWzuhHqkTWG/kXvlm2EWIOw= +maunium.net/go/mautrix v0.22.1-0.20241215103154-351b49f8a893/go.mod h1:bjPXzRi5r1eY4n3fvm9k1UrppoSDoqq7McoRPpBR8YM= From 06756933070eb3da01550cdb8324bedf15cc3125 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Dec 2024 16:27:14 +0200 Subject: [PATCH 377/718] Bump version to v0.7.4 --- CHANGELOG.md | 7 +++++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 6 +++--- go.sum | 12 ++++++------ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8321abe..7c2ef6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v0.7.4 (2024-12-16) + +* Fixed syncing server-side storage after Signal login. +* Added support for new SSRE2 method of receiving the server-side storage key. +* Updated libsignal to v0.64.1. +* Updated Docker image to Alpine 3.21. + # v0.7.3 (2024-11-16) * Updated libsignal to v0.62.0. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 92121cb..61d22dd 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.3", + Version: "0.7.4", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index e95b307..7eec39d 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.3-0.20241212004537-24c1a9b1d8f6 + go.mau.fi/util v0.8.3 golang.org/x/crypto v0.31.0 - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 + golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e golang.org/x/net v0.32.0 google.golang.org/protobuf v1.35.2 - maunium.net/go/mautrix v0.22.1-0.20241215103154-351b49f8a893 + maunium.net/go/mautrix v0.22.1 ) require ( diff --git a/go.sum b/go.sum index 4d23cfe..b211283 100644 --- a/go.sum +++ b/go.sum @@ -67,14 +67,14 @@ 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.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.3-0.20241212004537-24c1a9b1d8f6 h1:s4aQJQBBMkjkHTdThRRNp2E35wqmMJVGkOAXG4b0X8c= -go.mau.fi/util v0.8.3-0.20241212004537-24c1a9b1d8f6/go.mod h1:sWpI/kFgk/QP4BDJJwSjjBsuAT7oUsj9VlFhvUo+34I= +go.mau.fi/util v0.8.3 h1:sulhXtfquMrQjsOP67x9CzWVBYUwhYeoo8hNQIpCWZ4= +go.mau.fi/util v0.8.3/go.mod h1:c00Db8xog70JeIsEvhdHooylTkTkakgnAOsZ04hplQY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= +golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= @@ -97,5 +97,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.22.1-0.20241215103154-351b49f8a893 h1:nwV01xjyCMINMjHl+0diuWzuhHqkTWG/kXvlm2EWIOw= -maunium.net/go/mautrix v0.22.1-0.20241215103154-351b49f8a893/go.mod h1:bjPXzRi5r1eY4n3fvm9k1UrppoSDoqq7McoRPpBR8YM= +maunium.net/go/mautrix v0.22.1 h1:2lCM37vmVzZGE0tWD7UOySMtAuC5hq6Pw33KlY2VU/c= +maunium.net/go/mautrix v0.22.1/go.mod h1:1rhqwH34Rz54ZqzdQYkmNW6rQUymNeTdaLA4l9LK6AI= From 710068e90cd7609af77535570ce707438a360973 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 17 Dec 2024 12:39:43 +0200 Subject: [PATCH 378/718] signalmeow/web: clean up websocket code slightly --- pkg/signalmeow/web/signalwebsocket.go | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 986e17c..df284d8 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -134,6 +134,7 @@ func (s *SignalWebsocket) connectLoop( cancel() }() + const initialBackoff = 2 * time.Second const backoffIncrement = 5 * time.Second const maxBackoff = 60 * time.Second @@ -181,7 +182,7 @@ func (s *SignalWebsocket) connectLoop( // Main connection loop - if there's a problem with anything just // kill everything (including the websocket) and build it all up again - backoff := backoffIncrement + backoff := initialBackoff retrying := false errorCount := 0 for { @@ -257,14 +258,14 @@ func (s *SignalWebsocket) connectLoop( } s.ws = ws retrying = false - backoff = backoffIncrement + backoff = initialBackoff responseChannels := make(map[uint64]chan *signalpb.WebSocketResponseMessage) loopCtx, loopCancel := context.WithCancelCause(ctx) // Read loop (for reading incoming reqeusts and responses to outgoing requests) go func() { - err := readLoop(loopCtx, ws, incomingRequestChan, &responseChannels) + err := readLoop(loopCtx, ws, incomingRequestChan, responseChannels) // Don't want to put an err into loopCancel if we don't have one if err != nil { err = fmt.Errorf("error in readLoop: %w", err) @@ -275,7 +276,7 @@ func (s *SignalWebsocket) connectLoop( // Write loop (for sending outgoing requests and responses to incoming requests) go func() { - err := writeLoop(loopCtx, ws, s.sendChannel, &responseChannels) + err := writeLoop(loopCtx, ws, s.sendChannel, responseChannels) // Don't want to put an err into loopCancel if we don't have one if err != nil { err = fmt.Errorf("error in writeLoop: %w", err) @@ -346,7 +347,7 @@ func (s *SignalWebsocket) connectLoop( log.Info().Msg("Read or write loop exited") // Clean up - ws.Close(200, "Done") + ws.Close(websocket.StatusGoingAway, "Going away") for _, responseChannel := range responseChannels { close(responseChannel) } @@ -365,7 +366,7 @@ func readLoop( ctx context.Context, ws *websocket.Conn, incomingRequestChan chan *signalpb.WebSocketRequestMessage, - responseChannels *(map[uint64]chan *signalpb.WebSocketResponseMessage), + responseChannels map[uint64]chan *signalpb.WebSocketResponseMessage, ) error { log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_read_loop"). @@ -380,8 +381,7 @@ func readLoop( if err != nil { if err == context.Canceled { log.Info().Msg("readLoop context canceled") - } - if strings.Contains(err.Error(), "StatusNormalClosure") { + } else if websocket.CloseStatus(err) == websocket.StatusNormalClosure { log.Info().Msg("readLoop received StatusNormalClosure") return nil } @@ -406,7 +406,7 @@ func readLoop( if msg.Response.Id == nil { log.Fatal().Msg("Received response with no id") } - responseChannel, ok := (*responseChannels)[*msg.Response.Id] + responseChannel, ok := responseChannels[*msg.Response.Id] if !ok { log.Warn(). Uint64("response_id", *msg.Response.Id). @@ -418,7 +418,7 @@ func readLoop( Uint32("response_status", *msg.Response.Status). Msg("Received WS response") responseChannel <- msg.Response - delete(*responseChannels, *msg.Response.Id) + delete(responseChannels, *msg.Response.Id) log.Debug(). Uint64("response_id", *msg.Response.Id). Msg("Deleted response channel for ID") @@ -445,7 +445,7 @@ func writeLoop( ctx context.Context, ws *websocket.Conn, sendChannel chan SignalWebsocketSendMessage, - responseChannels *(map[uint64]chan *signalpb.WebSocketResponseMessage), + responseChannels map[uint64]chan *signalpb.WebSocketResponseMessage, ) error { log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_write_loop"). @@ -459,7 +459,7 @@ func writeLoop( return nil case request, ok := <-sendChannel: if !ok { - return errors.New("Send channel closed") + return errors.New("send channel closed") } if request.RequestMessage != nil && request.ResponseChannel != nil { msgType := signalpb.WebSocketMessage_REQUEST @@ -468,15 +468,15 @@ func writeLoop( Request: request.RequestMessage, } request.RequestMessage.Id = &i - (*responseChannels)[i] = request.ResponseChannel + responseChannels[i] = request.ResponseChannel path := *request.RequestMessage.Path if len(path) > 30 { path = path[:40] } - if request.RequestTime != (time.Time{}) { + if !request.RequestTime.IsZero() { elapsed := time.Since(request.RequestTime) if elapsed > 1*time.Minute { - return fmt.Errorf("Took too long, not sending (elapsed: %v)", elapsed) + return fmt.Errorf("request too old (%v), not sending", elapsed) } else if elapsed > 10*time.Second { log.Warn(). Uint64("request_id", i). From b01a912320d081f7f704c0b60b765ecf52d4fd91 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 17 Dec 2024 12:41:35 +0200 Subject: [PATCH 379/718] signalmeow/web: wait for all websocket loops to close --- pkg/signalmeow/web/signalwebsocket.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index df284d8..4ac1bf0 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -23,6 +23,7 @@ import ( "fmt" "net/http" "strings" + "sync" "time" "github.com/coder/websocket" @@ -262,9 +263,12 @@ func (s *SignalWebsocket) connectLoop( responseChannels := make(map[uint64]chan *signalpb.WebSocketResponseMessage) loopCtx, loopCancel := context.WithCancelCause(ctx) + var wg sync.WaitGroup + wg.Add(3) // Read loop (for reading incoming reqeusts and responses to outgoing requests) go func() { + defer wg.Done() err := readLoop(loopCtx, ws, incomingRequestChan, responseChannels) // Don't want to put an err into loopCancel if we don't have one if err != nil { @@ -276,6 +280,7 @@ func (s *SignalWebsocket) connectLoop( // Write loop (for sending outgoing requests and responses to incoming requests) go func() { + defer wg.Done() err := writeLoop(loopCtx, ws, s.sendChannel, responseChannels) // Don't want to put an err into loopCancel if we don't have one if err != nil { @@ -287,6 +292,7 @@ func (s *SignalWebsocket) connectLoop( // Ping loop (send a keepalive Ping every 30s) go func() { + defer wg.Done() ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() @@ -352,6 +358,7 @@ func (s *SignalWebsocket) connectLoop( close(responseChannel) } loopCancel(nil) + wg.Wait() log.Debug().Msg("Finished websocket cleanup") if errorCount > 500 { // Something is really wrong, we better panic. From 4b634863890e7818febc8b9b8341da52ccf61cb6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 17 Dec 2024 12:48:56 +0200 Subject: [PATCH 380/718] signalmeow/web: add small sleep for all reconnects --- pkg/signalmeow/web/signalwebsocket.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 4ac1bf0..3b192fb 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -186,6 +186,7 @@ func (s *SignalWebsocket) connectLoop( backoff := initialBackoff retrying := false errorCount := 0 + isFirstConnect := true for { if retrying { if backoff > maxBackoff { @@ -194,11 +195,14 @@ func (s *SignalWebsocket) connectLoop( log.Warn().Dur("backoff", backoff).Msg("Failed to connect, waiting to retry...") time.Sleep(backoff) backoff += backoffIncrement + } else if !isFirstConnect { + time.Sleep(1 * time.Second) } if ctx.Err() != nil { log.Info().Msg("ctx done, stopping connection loop") return } + isFirstConnect = false ws, resp, err := OpenWebsocket(ctx, s.path) if resp != nil { From 192b5a79ca30fd86b1ad5073023c3c154d9f2629 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 20 Dec 2024 13:18:52 +0200 Subject: [PATCH 381/718] msgconv/from-signal: add option to make view-once messages disappear --- pkg/connector/config.go | 2 ++ pkg/connector/connector.go | 4 +++- pkg/connector/example-config.yaml | 2 ++ pkg/connector/handlesignal.go | 4 +++- pkg/msgconv/from-signal.go | 13 +++++++++++++ pkg/msgconv/msgconv.go | 10 +++++----- 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/pkg/connector/config.go b/pkg/connector/config.go index ec47f34..1f583c5 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -39,6 +39,7 @@ type SignalConfig struct { DeviceName string `yaml:"device_name"` NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` LocationFormat string `yaml:"location_format"` + DisappearViewOnce bool `yaml:"disappear_view_once"` displaynameTemplate *template.Template `yaml:"-"` } @@ -81,6 +82,7 @@ func upgradeConfig(helper up.Helper) { helper.Copy(up.Str, "device_name") helper.Copy(up.Str, "note_to_self_avatar") helper.Copy(up.Str, "location_format") + helper.Copy(up.Bool, "disappear_view_once") } func (s *SignalConnector) GetConfig() (string, any, up.Upgrader) { diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 8cdb368..1072983 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -69,7 +69,9 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { } s.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "signalmeow").Logger())) s.Bridge = bridge - s.MsgConv = msgconv.NewMessageConverter(bridge, s.Config.LocationFormat) + s.MsgConv = msgconv.NewMessageConverter(bridge) + s.MsgConv.LocationFormat = s.Config.LocationFormat + s.MsgConv.DisappearViewOnce = s.Config.DisappearViewOnce } func (s *SignalConnector) SetMaxFileSize(maxSize int64) { diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml index eea81f2..8c0a61e 100644 --- a/pkg/connector/example-config.yaml +++ b/pkg/connector/example-config.yaml @@ -21,3 +21,5 @@ note_to_self_avatar: mxc://maunium.net/REBIVrqjZwmaWpssCZpBlmlL # Google Maps: 'https://www.google.com/maps/place/%[1]s,%[2]s' # OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]s' location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s' +# Should view-once messages disappear shortly after sending a read receipt on Matrix? +disappear_view_once: false diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 2d863ac..1984862 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -314,7 +314,9 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, dataMsg) if converted.Disappear.Type != "" { evtTS := evt.GetTimestamp() - portal.UpdateDisappearingSetting(ctx, converted.Disappear, nil, evtTS, true, true) + if !dataMsg.GetIsViewOnce() { + portal.UpdateDisappearingSetting(ctx, converted.Disappear, nil, evtTS, true, true) + } if evt.Info.Sender == evt.s.Client.Store.ACI { converted.Disappear.DisappearAt = evtTS.Add(converted.Disappear.Timer) } diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 9b27c07..486bde1 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -68,6 +68,8 @@ func CanConvertSignal(dm *signalpb.DataMessage) bool { return calculateLength(dm) > 0 } +const ViewOnceDisappearTimer = 5 * time.Minute + func (mc *MessageConverter) ToMatrix( ctx context.Context, client *signalmeow.Client, @@ -130,6 +132,17 @@ func (mc *MessageConverter) ToMatrix( }, }) } + if dm.GetIsViewOnce() && mc.DisappearViewOnce && (cm.Disappear.Timer == 0 || cm.Disappear.Timer > ViewOnceDisappearTimer) { + cm.Disappear.Type = database.DisappearingTypeAfterRead + cm.Disappear.Timer = ViewOnceDisappearTimer + cm.Parts = append(cm.Parts, &bridgev2.ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgText, + Body: "This is a view-once message. It will disappear in 5 minutes.", + }, + }) + } cm.MergeCaption() for i, part := range cm.Parts { part.ID = signalid.MakeMessagePartID(i) diff --git a/pkg/msgconv/msgconv.go b/pkg/msgconv/msgconv.go index 1d1fee8..80717fc 100644 --- a/pkg/msgconv/msgconv.go +++ b/pkg/msgconv/msgconv.go @@ -44,11 +44,12 @@ type MessageConverter struct { SignalFmtParams *signalfmt.FormatParams MatrixFmtParams *matrixfmt.HTMLParser - MaxFileSize int64 - LocationFormat string + MaxFileSize int64 + LocationFormat string + DisappearViewOnce bool } -func NewMessageConverter(br *bridgev2.Bridge, locationFormat string) *MessageConverter { +func NewMessageConverter(br *bridgev2.Bridge) *MessageConverter { return &MessageConverter{ Bridge: br, SignalFmtParams: &signalfmt.FormatParams{ @@ -89,8 +90,7 @@ func NewMessageConverter(br *bridgev2.Bridge, locationFormat string) *MessageCon return uuid.Nil }, }, - MaxFileSize: 50 * 1024 * 1024, - LocationFormat: locationFormat, + MaxFileSize: 50 * 1024 * 1024, } } From 7ed141bfadabd92340d97dde32ec685b18186fbe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 7 Jan 2025 13:59:43 +0200 Subject: [PATCH 382/718] dependencies: update --- go.mod | 14 +- go.sum | 28 +- .../protobuf/ContactDiscovery.pb.go | 18 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 15 +- pkg/signalmeow/protobuf/Groups.pb.go | 438 ++++--- pkg/signalmeow/protobuf/Provisioning.pb.go | 57 +- pkg/signalmeow/protobuf/SignalService.pb.go | 1076 ++++++++--------- .../protobuf/StickerResources.pb.go | 26 +- pkg/signalmeow/protobuf/StorageService.pb.go | 267 ++-- .../protobuf/UnidentifiedDelivery.pb.go | 66 +- .../protobuf/WebSocketResources.pb.go | 43 +- 11 files changed, 978 insertions(+), 1070 deletions(-) diff --git a/go.mod b/go.mod index 7eec39d..554048c 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.3 - golang.org/x/crypto v0.31.0 - golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e - golang.org/x/net v0.32.0 - google.golang.org/protobuf v1.35.2 - maunium.net/go/mautrix v0.22.1 + go.mau.fi/util v0.8.4-0.20250106152331-30b8c95e7d7a + golang.org/x/crypto v0.32.0 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 + golang.org/x/net v0.34.0 + google.golang.org/protobuf v1.36.2 + maunium.net/go/mautrix v0.22.2-0.20250107114437-ceb9c7b866e1 ) require ( @@ -42,7 +42,7 @@ require ( github.com/yuin/goldmark v1.7.8 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index b211283..4d10fa9 100644 --- a/go.sum +++ b/go.sum @@ -67,27 +67,27 @@ 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.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.3 h1:sulhXtfquMrQjsOP67x9CzWVBYUwhYeoo8hNQIpCWZ4= -go.mau.fi/util v0.8.3/go.mod h1:c00Db8xog70JeIsEvhdHooylTkTkakgnAOsZ04hplQY= +go.mau.fi/util v0.8.4-0.20250106152331-30b8c95e7d7a h1:D9RCHBFjxah9F/YB7amvRJjT2IEOFWcz8jpcEY8dBV0= +go.mau.fi/util v0.8.4-0.20250106152331-30b8c95e7d7a/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4= -golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= +google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -97,5 +97,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.22.1 h1:2lCM37vmVzZGE0tWD7UOySMtAuC5hq6Pw33KlY2VU/c= -maunium.net/go/mautrix v0.22.1/go.mod h1:1rhqwH34Rz54ZqzdQYkmNW6rQUymNeTdaLA4l9LK6AI= +maunium.net/go/mautrix v0.22.2-0.20250107114437-ceb9c7b866e1 h1:ECwjKJLKKsTp/gnp0Qd5GojeZOK/MLVFF0Tf7C6gZDQ= +maunium.net/go/mautrix v0.22.2-0.20250107114437-ceb9c7b866e1/go.mod h1:FmwzK7RSzrd1OfGDgJzFWXl7nYmYm8/P0Y77sy/A1Uw= diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 3c3d5b1..020c413 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: ContactDiscovery.proto @@ -26,10 +26,7 @@ const ( ) type CDSClientRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Each ACI/UAK pair is a 32-byte buffer, containing the 16-byte ACI followed // by its 16-byte UAK. AciUakPairs []byte `protobuf:"bytes,1,opt,name=aci_uak_pairs,json=aciUakPairs" json:"aci_uak_pairs,omitempty"` @@ -50,6 +47,8 @@ type CDSClientRequest struct { // Request that, if the server allows, both ACI and PNI be returned even // if the aci_uak_pairs don't match. ReturnAcisWithoutUaks *bool `protobuf:"varint,8,opt,name=return_acis_without_uaks,json=returnAcisWithoutUaks" json:"return_acis_without_uaks,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CDSClientRequest) Reset() { @@ -139,10 +138,7 @@ func (x *CDSClientRequest) GetReturnAcisWithoutUaks() bool { } type CDSClientResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Each triple is an 8-byte e164, a 16-byte PNI, and a 16-byte ACI. // If the e164 was not found, PNI and ACI are all zeros. If the PNI // was found but the ACI was not, the PNI will be non-zero and the ACI @@ -159,7 +155,9 @@ type CDSClientResponse struct { // A token which allows subsequent calls' rate limiting to discount the // e164s sent up in this request, only counting those in the next // request's new_e164s. - Token []byte `protobuf:"bytes,3,opt,name=token" json:"token,omitempty"` + Token []byte `protobuf:"bytes,3,opt,name=token" json:"token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CDSClientResponse) Reset() { diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 9721926..dbc3df8 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: DeviceName.proto @@ -26,13 +26,12 @@ const ( ) type DeviceName struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EphemeralPublic []byte `protobuf:"bytes,1,opt,name=ephemeralPublic" json:"ephemeralPublic,omitempty"` - SyntheticIv []byte `protobuf:"bytes,2,opt,name=syntheticIv" json:"syntheticIv,omitempty"` - Ciphertext []byte `protobuf:"bytes,3,opt,name=ciphertext" json:"ciphertext,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + EphemeralPublic []byte `protobuf:"bytes,1,opt,name=ephemeralPublic" json:"ephemeralPublic,omitempty"` + SyntheticIv []byte `protobuf:"bytes,2,opt,name=syntheticIv" json:"syntheticIv,omitempty"` + Ciphertext []byte `protobuf:"bytes,3,opt,name=ciphertext" json:"ciphertext,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeviceName) Reset() { diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index de4a1ae..212d5a3 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: Groups.proto @@ -132,17 +132,16 @@ func (AccessControl_AccessRequired) EnumDescriptor() ([]byte, []int) { } type AvatarUploadAttributes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Credential string `protobuf:"bytes,2,opt,name=credential,proto3" json:"credential,omitempty"` + Acl string `protobuf:"bytes,3,opt,name=acl,proto3" json:"acl,omitempty"` + Algorithm string `protobuf:"bytes,4,opt,name=algorithm,proto3" json:"algorithm,omitempty"` + Date string `protobuf:"bytes,5,opt,name=date,proto3" json:"date,omitempty"` + Policy string `protobuf:"bytes,6,opt,name=policy,proto3" json:"policy,omitempty"` + Signature string `protobuf:"bytes,7,opt,name=signature,proto3" json:"signature,omitempty"` unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Credential string `protobuf:"bytes,2,opt,name=credential,proto3" json:"credential,omitempty"` - Acl string `protobuf:"bytes,3,opt,name=acl,proto3" json:"acl,omitempty"` - Algorithm string `protobuf:"bytes,4,opt,name=algorithm,proto3" json:"algorithm,omitempty"` - Date string `protobuf:"bytes,5,opt,name=date,proto3" json:"date,omitempty"` - Policy string `protobuf:"bytes,6,opt,name=policy,proto3" json:"policy,omitempty"` - Signature string `protobuf:"bytes,7,opt,name=signature,proto3" json:"signature,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AvatarUploadAttributes) Reset() { @@ -225,15 +224,14 @@ func (x *AvatarUploadAttributes) GetSignature() string { } type Member struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` - ProfileKey []byte `protobuf:"bytes,3,opt,name=profileKey,proto3" json:"profileKey,omitempty"` - Presentation []byte `protobuf:"bytes,4,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - JoinedAtRevision uint32 `protobuf:"varint,5,opt,name=joinedAtRevision,proto3" json:"joinedAtRevision,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` + ProfileKey []byte `protobuf:"bytes,3,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + Presentation []byte `protobuf:"bytes,4,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server + JoinedAtRevision uint32 `protobuf:"varint,5,opt,name=joinedAtRevision,proto3" json:"joinedAtRevision,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Member) Reset() { @@ -302,13 +300,12 @@ func (x *Member) GetJoinedAtRevision() uint32 { } type PendingMember struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Member *Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` + AddedByUserId []byte `protobuf:"bytes,2,opt,name=addedByUserId,proto3" json:"addedByUserId,omitempty"` + Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - Member *Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` - AddedByUserId []byte `protobuf:"bytes,2,opt,name=addedByUserId,proto3" json:"addedByUserId,omitempty"` - Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PendingMember) Reset() { @@ -363,14 +360,13 @@ func (x *PendingMember) GetTimestamp() uint64 { } type RequestingMember struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + ProfileKey []byte `protobuf:"bytes,2,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + Presentation []byte `protobuf:"bytes,3,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server + Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - ProfileKey []byte `protobuf:"bytes,2,opt,name=profileKey,proto3" json:"profileKey,omitempty"` - Presentation []byte `protobuf:"bytes,3,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RequestingMember) Reset() { @@ -432,12 +428,11 @@ func (x *RequestingMember) GetTimestamp() uint64 { } type BannedMember struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BannedMember) Reset() { @@ -485,13 +480,12 @@ func (x *BannedMember) GetTimestamp() uint64 { } type AccessControl struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Attributes AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=AccessControl_AccessRequired" json:"attributes,omitempty"` Members AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=AccessControl_AccessRequired" json:"members,omitempty"` AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccessControl) Reset() { @@ -546,23 +540,22 @@ func (x *AccessControl) GetAddFromInviteLink() AccessControl_AccessRequired { } type Group struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` - Title []byte `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` - DisappearingMessagesTimer []byte `protobuf:"bytes,4,opt,name=disappearingMessagesTimer,proto3" json:"disappearingMessagesTimer,omitempty"` - AccessControl *AccessControl `protobuf:"bytes,5,opt,name=accessControl,proto3" json:"accessControl,omitempty"` - Revision uint32 `protobuf:"varint,6,opt,name=revision,proto3" json:"revision,omitempty"` - Members []*Member `protobuf:"bytes,7,rep,name=members,proto3" json:"members,omitempty"` - PendingMembers []*PendingMember `protobuf:"bytes,8,rep,name=pendingMembers,proto3" json:"pendingMembers,omitempty"` - RequestingMembers []*RequestingMember `protobuf:"bytes,9,rep,name=requestingMembers,proto3" json:"requestingMembers,omitempty"` - InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` - Description []byte `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` - AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcementsOnly,proto3" json:"announcementsOnly,omitempty"` - BannedMembers []*BannedMember `protobuf:"bytes,13,rep,name=bannedMembers,proto3" json:"bannedMembers,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` + Title []byte `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` + DisappearingMessagesTimer []byte `protobuf:"bytes,4,opt,name=disappearingMessagesTimer,proto3" json:"disappearingMessagesTimer,omitempty"` + AccessControl *AccessControl `protobuf:"bytes,5,opt,name=accessControl,proto3" json:"accessControl,omitempty"` + Revision uint32 `protobuf:"varint,6,opt,name=revision,proto3" json:"revision,omitempty"` + Members []*Member `protobuf:"bytes,7,rep,name=members,proto3" json:"members,omitempty"` + PendingMembers []*PendingMember `protobuf:"bytes,8,rep,name=pendingMembers,proto3" json:"pendingMembers,omitempty"` + RequestingMembers []*RequestingMember `protobuf:"bytes,9,rep,name=requestingMembers,proto3" json:"requestingMembers,omitempty"` + InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + Description []byte `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` + AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcementsOnly,proto3" json:"announcementsOnly,omitempty"` + BannedMembers []*BannedMember `protobuf:"bytes,13,rep,name=bannedMembers,proto3" json:"bannedMembers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Group) Reset() { @@ -687,13 +680,12 @@ func (x *Group) GetBannedMembers() []*BannedMember { } type GroupChange struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Actions []byte `protobuf:"bytes,1,opt,name=actions,proto3" json:"actions,omitempty"` - ServerSignature []byte `protobuf:"bytes,2,opt,name=serverSignature,proto3" json:"serverSignature,omitempty"` - ChangeEpoch uint32 `protobuf:"varint,3,opt,name=changeEpoch,proto3" json:"changeEpoch,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Actions []byte `protobuf:"bytes,1,opt,name=actions,proto3" json:"actions,omitempty"` + ServerSignature []byte `protobuf:"bytes,2,opt,name=serverSignature,proto3" json:"serverSignature,omitempty"` + ChangeEpoch uint32 `protobuf:"varint,3,opt,name=changeEpoch,proto3" json:"changeEpoch,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange) Reset() { @@ -748,12 +740,11 @@ func (x *GroupChange) GetChangeEpoch() uint32 { } type GroupResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupResponse) Reset() { @@ -801,12 +792,11 @@ func (x *GroupResponse) GetGroupSendEndorsementsResponse() []byte { } type GroupChanges struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` GroupChanges []*GroupChanges_GroupChangeState `protobuf:"bytes,1,rep,name=groupChanges,proto3" json:"groupChanges,omitempty"` GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChanges) Reset() { @@ -854,12 +844,11 @@ func (x *GroupChanges) GetGroupSendEndorsementsResponse() []byte { } type GroupChangeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` - GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChangeResponse) Reset() { @@ -907,17 +896,16 @@ func (x *GroupChangeResponse) GetGroupSendEndorsementsResponse() []byte { } type GroupAttributeBlob struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Content: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Content: // // *GroupAttributeBlob_Title // *GroupAttributeBlob_Avatar // *GroupAttributeBlob_DisappearingMessagesDuration // *GroupAttributeBlob_Description - Content isGroupAttributeBlob_Content `protobuf_oneof:"content"` + Content isGroupAttributeBlob_Content `protobuf_oneof:"content"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupAttributeBlob) Reset() { @@ -950,37 +938,45 @@ func (*GroupAttributeBlob) Descriptor() ([]byte, []int) { return file_Groups_proto_rawDescGZIP(), []int{11} } -func (m *GroupAttributeBlob) GetContent() isGroupAttributeBlob_Content { - if m != nil { - return m.Content +func (x *GroupAttributeBlob) GetContent() isGroupAttributeBlob_Content { + if x != nil { + return x.Content } return nil } func (x *GroupAttributeBlob) GetTitle() string { - if x, ok := x.GetContent().(*GroupAttributeBlob_Title); ok { - return x.Title + if x != nil { + if x, ok := x.Content.(*GroupAttributeBlob_Title); ok { + return x.Title + } } return "" } func (x *GroupAttributeBlob) GetAvatar() []byte { - if x, ok := x.GetContent().(*GroupAttributeBlob_Avatar); ok { - return x.Avatar + if x != nil { + if x, ok := x.Content.(*GroupAttributeBlob_Avatar); ok { + return x.Avatar + } } return nil } func (x *GroupAttributeBlob) GetDisappearingMessagesDuration() uint32 { - if x, ok := x.GetContent().(*GroupAttributeBlob_DisappearingMessagesDuration); ok { - return x.DisappearingMessagesDuration + if x != nil { + if x, ok := x.Content.(*GroupAttributeBlob_DisappearingMessagesDuration); ok { + return x.DisappearingMessagesDuration + } } return 0 } func (x *GroupAttributeBlob) GetDescription() string { - if x, ok := x.GetContent().(*GroupAttributeBlob_Description); ok { - return x.Description + if x != nil { + if x, ok := x.Content.(*GroupAttributeBlob_Description); ok { + return x.Description + } } return "" } @@ -1014,14 +1010,13 @@ func (*GroupAttributeBlob_DisappearingMessagesDuration) isGroupAttributeBlob_Con func (*GroupAttributeBlob_Description) isGroupAttributeBlob_Content() {} type GroupInviteLink struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Contents: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Contents: // // *GroupInviteLink_V1Contents - Contents isGroupInviteLink_Contents `protobuf_oneof:"contents"` + Contents isGroupInviteLink_Contents `protobuf_oneof:"contents"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupInviteLink) Reset() { @@ -1054,16 +1049,18 @@ func (*GroupInviteLink) Descriptor() ([]byte, []int) { return file_Groups_proto_rawDescGZIP(), []int{12} } -func (m *GroupInviteLink) GetContents() isGroupInviteLink_Contents { - if m != nil { - return m.Contents +func (x *GroupInviteLink) GetContents() isGroupInviteLink_Contents { + if x != nil { + return x.Contents } return nil } func (x *GroupInviteLink) GetV1Contents() *GroupInviteLink_GroupInviteLinkContentsV1 { - if x, ok := x.GetContents().(*GroupInviteLink_V1Contents); ok { - return x.V1Contents + if x != nil { + if x, ok := x.Contents.(*GroupInviteLink_V1Contents); ok { + return x.V1Contents + } } return nil } @@ -1079,10 +1076,7 @@ type GroupInviteLink_V1Contents struct { func (*GroupInviteLink_V1Contents) isGroupInviteLink_Contents() {} type GroupJoinInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` Title []byte `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` @@ -1091,6 +1085,8 @@ type GroupJoinInfo struct { Revision uint32 `protobuf:"varint,6,opt,name=revision,proto3" json:"revision,omitempty"` PendingAdminApproval bool `protobuf:"varint,7,opt,name=pendingAdminApproval,proto3" json:"pendingAdminApproval,omitempty"` Description []byte `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupJoinInfo) Reset() { @@ -1180,11 +1176,10 @@ func (x *GroupJoinInfo) GetDescription() []byte { } type GroupExternalCredential struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` unknownFields protoimpl.UnknownFields - - Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupExternalCredential) Reset() { @@ -1225,10 +1220,7 @@ func (x *GroupExternalCredential) GetToken() string { } type GroupChange_Actions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` SourceServiceId []byte `protobuf:"bytes,1,opt,name=sourceServiceId,proto3" json:"sourceServiceId,omitempty"` GroupId []byte `protobuf:"bytes,25,opt,name=groupId,proto3" json:"groupId,omitempty"` // Only set when receiving from server Revision uint32 `protobuf:"varint,2,opt,name=revision,proto3" json:"revision,omitempty"` @@ -1254,6 +1246,8 @@ type GroupChange_Actions struct { AddBannedMembers []*GroupChange_Actions_AddBannedMemberAction `protobuf:"bytes,22,rep,name=addBannedMembers,proto3" json:"addBannedMembers,omitempty"` DeleteBannedMembers []*GroupChange_Actions_DeleteBannedMemberAction `protobuf:"bytes,23,rep,name=deleteBannedMembers,proto3" json:"deleteBannedMembers,omitempty"` PromotePendingPniAciMembers []*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction `protobuf:"bytes,24,rep,name=promotePendingPniAciMembers,proto3" json:"promotePendingPniAciMembers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions) Reset() { @@ -1462,12 +1456,11 @@ func (x *GroupChange_Actions) GetPromotePendingPniAciMembers() []*GroupChange_Ac } type GroupChange_Actions_AddMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Added *Member `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` - JoinFromInviteLink bool `protobuf:"varint,2,opt,name=joinFromInviteLink,proto3" json:"joinFromInviteLink,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Added *Member `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` + JoinFromInviteLink bool `protobuf:"varint,2,opt,name=joinFromInviteLink,proto3" json:"joinFromInviteLink,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_AddMemberAction) Reset() { @@ -1515,11 +1508,10 @@ func (x *GroupChange_Actions_AddMemberAction) GetJoinFromInviteLink() bool { } type GroupChange_Actions_DeleteMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields - - DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_DeleteMemberAction) Reset() { @@ -1560,12 +1552,11 @@ func (x *GroupChange_Actions_DeleteMemberAction) GetDeletedUserId() []byte { } type GroupChange_Actions_ModifyMemberRoleAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` unknownFields protoimpl.UnknownFields - - UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyMemberRoleAction) Reset() { @@ -1613,13 +1604,12 @@ func (x *GroupChange_Actions_ModifyMemberRoleAction) GetRole() Member_Role { } type GroupChange_Actions_ModifyMemberProfileKeyAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server + UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // Only set when receiving from server + ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` // Only set when receiving from server unknownFields protoimpl.UnknownFields - - Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // Only set when receiving from server - ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` // Only set when receiving from server + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) Reset() { @@ -1674,11 +1664,10 @@ func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) GetProfileKey() []byt } type GroupChange_Actions_AddPendingMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Added *PendingMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` unknownFields protoimpl.UnknownFields - - Added *PendingMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_AddPendingMemberAction) Reset() { @@ -1719,11 +1708,10 @@ func (x *GroupChange_Actions_AddPendingMemberAction) GetAdded() *PendingMember { } type GroupChange_Actions_DeletePendingMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields - - DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_DeletePendingMemberAction) Reset() { @@ -1764,13 +1752,12 @@ func (x *GroupChange_Actions_DeletePendingMemberAction) GetDeletedUserId() []byt } type GroupChange_Actions_PromotePendingMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server + UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // Only set when receiving from server + ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` // Only set when receiving from server unknownFields protoimpl.UnknownFields - - Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // Only set when receiving from server - ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` // Only set when receiving from server + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_PromotePendingMemberAction) Reset() { @@ -1825,14 +1812,13 @@ func (x *GroupChange_Actions_PromotePendingMemberAction) GetProfileKey() []byte } type GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server + UserId []byte `protobuf:"bytes,2,opt,name=userId,proto3" json:"userId,omitempty"` // Only set when receiving from server + Pni []byte `protobuf:"bytes,3,opt,name=pni,proto3" json:"pni,omitempty"` // Only set when receiving from server + ProfileKey []byte `protobuf:"bytes,4,opt,name=profileKey,proto3" json:"profileKey,omitempty"` // Only set when receiving from server unknownFields protoimpl.UnknownFields - - Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - UserId []byte `protobuf:"bytes,2,opt,name=userId,proto3" json:"userId,omitempty"` // Only set when receiving from server - Pni []byte `protobuf:"bytes,3,opt,name=pni,proto3" json:"pni,omitempty"` // Only set when receiving from server - ProfileKey []byte `protobuf:"bytes,4,opt,name=profileKey,proto3" json:"profileKey,omitempty"` // Only set when receiving from server + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) Reset() { @@ -1894,11 +1880,10 @@ func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) GetProf } type GroupChange_Actions_AddRequestingMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Added *RequestingMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` unknownFields protoimpl.UnknownFields - - Added *RequestingMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_AddRequestingMemberAction) Reset() { @@ -1939,11 +1924,10 @@ func (x *GroupChange_Actions_AddRequestingMemberAction) GetAdded() *RequestingMe } type GroupChange_Actions_DeleteRequestingMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields - - DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_DeleteRequestingMemberAction) Reset() { @@ -1984,12 +1968,11 @@ func (x *GroupChange_Actions_DeleteRequestingMemberAction) GetDeletedUserId() [] } type GroupChange_Actions_PromoteRequestingMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` unknownFields protoimpl.UnknownFields - - UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_PromoteRequestingMemberAction) Reset() { @@ -2037,11 +2020,10 @@ func (x *GroupChange_Actions_PromoteRequestingMemberAction) GetRole() Member_Rol } type GroupChange_Actions_AddBannedMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Added *BannedMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` unknownFields protoimpl.UnknownFields - - Added *BannedMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_AddBannedMemberAction) Reset() { @@ -2082,11 +2064,10 @@ func (x *GroupChange_Actions_AddBannedMemberAction) GetAdded() *BannedMember { } type GroupChange_Actions_DeleteBannedMemberAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields - - DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_DeleteBannedMemberAction) Reset() { @@ -2127,11 +2108,10 @@ func (x *GroupChange_Actions_DeleteBannedMemberAction) GetDeletedUserId() []byte } type GroupChange_Actions_ModifyTitleAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Title []byte `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` unknownFields protoimpl.UnknownFields - - Title []byte `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyTitleAction) Reset() { @@ -2172,11 +2152,10 @@ func (x *GroupChange_Actions_ModifyTitleAction) GetTitle() []byte { } type GroupChange_Actions_ModifyDescriptionAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Description []byte `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` unknownFields protoimpl.UnknownFields - - Description []byte `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyDescriptionAction) Reset() { @@ -2217,11 +2196,10 @@ func (x *GroupChange_Actions_ModifyDescriptionAction) GetDescription() []byte { } type GroupChange_Actions_ModifyAvatarAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Avatar string `protobuf:"bytes,1,opt,name=avatar,proto3" json:"avatar,omitempty"` unknownFields protoimpl.UnknownFields - - Avatar string `protobuf:"bytes,1,opt,name=avatar,proto3" json:"avatar,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAvatarAction) Reset() { @@ -2262,11 +2240,10 @@ func (x *GroupChange_Actions_ModifyAvatarAction) GetAvatar() string { } type GroupChange_Actions_ModifyDisappearingMessagesTimerAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Timer []byte `protobuf:"bytes,1,opt,name=timer,proto3" json:"timer,omitempty"` unknownFields protoimpl.UnknownFields - - Timer []byte `protobuf:"bytes,1,opt,name=timer,proto3" json:"timer,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) Reset() { @@ -2307,11 +2284,10 @@ func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) GetTimer() [ } type GroupChange_Actions_ModifyAttributesAccessControlAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` AttributesAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributesAccess,proto3,enum=AccessControl_AccessRequired" json:"attributesAccess,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) Reset() { @@ -2352,11 +2328,10 @@ func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) GetAttributesA } type GroupChange_Actions_ModifyMembersAccessControlAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` MembersAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=membersAccess,proto3,enum=AccessControl_AccessRequired" json:"membersAccess,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyMembersAccessControlAction) Reset() { @@ -2397,11 +2372,10 @@ func (x *GroupChange_Actions_ModifyMembersAccessControlAction) GetMembersAccess( } type GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` AddFromInviteLinkAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=addFromInviteLinkAccess,proto3,enum=AccessControl_AccessRequired" json:"addFromInviteLinkAccess,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) Reset() { @@ -2442,11 +2416,10 @@ func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) GetAddF } type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - InviteLinkPassword []byte `protobuf:"bytes,1,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + InviteLinkPassword []byte `protobuf:"bytes,1,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() { @@ -2487,11 +2460,10 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) GetInviteLinkPasswo } type GroupChange_Actions_ModifyAnnouncementsOnlyAction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AnnouncementsOnly bool `protobuf:"varint,1,opt,name=announcementsOnly,proto3" json:"announcementsOnly,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + AnnouncementsOnly bool `protobuf:"varint,1,opt,name=announcementsOnly,proto3" json:"announcementsOnly,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() { @@ -2532,12 +2504,11 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly } type GroupChanges_GroupChangeState struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` + GroupState *Group `protobuf:"bytes,2,opt,name=groupState,proto3" json:"groupState,omitempty"` unknownFields protoimpl.UnknownFields - - GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` - GroupState *Group `protobuf:"bytes,2,opt,name=groupState,proto3" json:"groupState,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupChanges_GroupChangeState) Reset() { @@ -2585,12 +2556,11 @@ func (x *GroupChanges_GroupChangeState) GetGroupState() *Group { } type GroupInviteLink_GroupInviteLinkContentsV1 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - GroupMasterKey []byte `protobuf:"bytes,1,opt,name=groupMasterKey,proto3" json:"groupMasterKey,omitempty"` - InviteLinkPassword []byte `protobuf:"bytes,2,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + GroupMasterKey []byte `protobuf:"bytes,1,opt,name=groupMasterKey,proto3" json:"groupMasterKey,omitempty"` + InviteLinkPassword []byte `protobuf:"bytes,2,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupInviteLink_GroupInviteLinkContentsV1) Reset() { diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index a1d3f0b..97c5adc 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: Provisioning.proto @@ -87,11 +87,10 @@ func (ProvisioningVersion) EnumDescriptor() ([]byte, []int) { } type ProvisioningAddress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` unknownFields protoimpl.UnknownFields - - Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ProvisioningAddress) Reset() { @@ -132,12 +131,11 @@ func (x *ProvisioningAddress) GetAddress() string { } type ProvisionEnvelope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"` + Body []byte `protobuf:"bytes,2,opt,name=body" json:"body,omitempty"` // Encrypted ProvisionMessage unknownFields protoimpl.UnknownFields - - PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"` - Body []byte `protobuf:"bytes,2,opt,name=body" json:"body,omitempty"` // Encrypted ProvisionMessage + sizeCache protoimpl.SizeCache } func (x *ProvisionEnvelope) Reset() { @@ -185,26 +183,25 @@ func (x *ProvisionEnvelope) GetBody() []byte { } type ProvisionMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AciIdentityKeyPublic []byte `protobuf:"bytes,1,opt,name=aciIdentityKeyPublic" json:"aciIdentityKeyPublic,omitempty"` - AciIdentityKeyPrivate []byte `protobuf:"bytes,2,opt,name=aciIdentityKeyPrivate" json:"aciIdentityKeyPrivate,omitempty"` - PniIdentityKeyPublic []byte `protobuf:"bytes,11,opt,name=pniIdentityKeyPublic" json:"pniIdentityKeyPublic,omitempty"` - PniIdentityKeyPrivate []byte `protobuf:"bytes,12,opt,name=pniIdentityKeyPrivate" json:"pniIdentityKeyPrivate,omitempty"` - Aci *string `protobuf:"bytes,8,opt,name=aci" json:"aci,omitempty"` - Pni *string `protobuf:"bytes,10,opt,name=pni" json:"pni,omitempty"` - Number *string `protobuf:"bytes,3,opt,name=number" json:"number,omitempty"` - ProvisioningCode *string `protobuf:"bytes,4,opt,name=provisioningCode" json:"provisioningCode,omitempty"` - UserAgent *string `protobuf:"bytes,5,opt,name=userAgent" json:"userAgent,omitempty"` - ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` - ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"` - ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` - MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` - EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes - AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` - MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes + state protoimpl.MessageState `protogen:"open.v1"` + AciIdentityKeyPublic []byte `protobuf:"bytes,1,opt,name=aciIdentityKeyPublic" json:"aciIdentityKeyPublic,omitempty"` + AciIdentityKeyPrivate []byte `protobuf:"bytes,2,opt,name=aciIdentityKeyPrivate" json:"aciIdentityKeyPrivate,omitempty"` + PniIdentityKeyPublic []byte `protobuf:"bytes,11,opt,name=pniIdentityKeyPublic" json:"pniIdentityKeyPublic,omitempty"` + PniIdentityKeyPrivate []byte `protobuf:"bytes,12,opt,name=pniIdentityKeyPrivate" json:"pniIdentityKeyPrivate,omitempty"` + Aci *string `protobuf:"bytes,8,opt,name=aci" json:"aci,omitempty"` + Pni *string `protobuf:"bytes,10,opt,name=pni" json:"pni,omitempty"` + Number *string `protobuf:"bytes,3,opt,name=number" json:"number,omitempty"` + ProvisioningCode *string `protobuf:"bytes,4,opt,name=provisioningCode" json:"provisioningCode,omitempty"` + UserAgent *string `protobuf:"bytes,5,opt,name=userAgent" json:"userAgent,omitempty"` + ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` + ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"` + ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` + MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` + EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes + AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` + MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ProvisionMessage) Reset() { diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index a633e85..aed9592 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: SignalService.proto @@ -1700,21 +1700,20 @@ func (GroupContext_Type) EnumDescriptor() ([]byte, []int) { } type Envelope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Type *Envelope_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.Envelope_Type" json:"type,omitempty"` - SourceServiceId *string `protobuf:"bytes,11,opt,name=sourceServiceId" json:"sourceServiceId,omitempty"` - SourceDevice *uint32 `protobuf:"varint,7,opt,name=sourceDevice" json:"sourceDevice,omitempty"` - DestinationServiceId *string `protobuf:"bytes,13,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Timestamp *uint64 `protobuf:"varint,5,opt,name=timestamp" json:"timestamp,omitempty"` - Content []byte `protobuf:"bytes,8,opt,name=content" json:"content,omitempty"` // Contains an encrypted Content - ServerGuid *string `protobuf:"bytes,9,opt,name=serverGuid" json:"serverGuid,omitempty"` - ServerTimestamp *uint64 `protobuf:"varint,10,opt,name=serverTimestamp" json:"serverTimestamp,omitempty"` - Urgent *bool `protobuf:"varint,14,opt,name=urgent,def=1" json:"urgent,omitempty"` - Story *bool `protobuf:"varint,16,opt,name=story" json:"story,omitempty"` - ReportingToken []byte `protobuf:"bytes,17,opt,name=reportingToken" json:"reportingToken,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Type *Envelope_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.Envelope_Type" json:"type,omitempty"` + SourceServiceId *string `protobuf:"bytes,11,opt,name=sourceServiceId" json:"sourceServiceId,omitempty"` + SourceDevice *uint32 `protobuf:"varint,7,opt,name=sourceDevice" json:"sourceDevice,omitempty"` + DestinationServiceId *string `protobuf:"bytes,13,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Timestamp *uint64 `protobuf:"varint,5,opt,name=timestamp" json:"timestamp,omitempty"` + Content []byte `protobuf:"bytes,8,opt,name=content" json:"content,omitempty"` // Contains an encrypted Content + ServerGuid *string `protobuf:"bytes,9,opt,name=serverGuid" json:"serverGuid,omitempty"` + ServerTimestamp *uint64 `protobuf:"varint,10,opt,name=serverTimestamp" json:"serverTimestamp,omitempty"` + Urgent *bool `protobuf:"varint,14,opt,name=urgent,def=1" json:"urgent,omitempty"` + Story *bool `protobuf:"varint,16,opt,name=story" json:"story,omitempty"` + ReportingToken []byte `protobuf:"bytes,17,opt,name=reportingToken" json:"reportingToken,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } // Default values for Envelope fields. @@ -1830,21 +1829,20 @@ func (x *Envelope) GetReportingToken() []byte { } type Content struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DataMessage *DataMessage `protobuf:"bytes,1,opt,name=dataMessage" json:"dataMessage,omitempty"` - SyncMessage *SyncMessage `protobuf:"bytes,2,opt,name=syncMessage" json:"syncMessage,omitempty"` - CallMessage *CallMessage `protobuf:"bytes,3,opt,name=callMessage" json:"callMessage,omitempty"` - NullMessage *NullMessage `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` - ReceiptMessage *ReceiptMessage `protobuf:"bytes,5,opt,name=receiptMessage" json:"receiptMessage,omitempty"` - TypingMessage *TypingMessage `protobuf:"bytes,6,opt,name=typingMessage" json:"typingMessage,omitempty"` - SenderKeyDistributionMessage []byte `protobuf:"bytes,7,opt,name=senderKeyDistributionMessage" json:"senderKeyDistributionMessage,omitempty"` - DecryptionErrorMessage []byte `protobuf:"bytes,8,opt,name=decryptionErrorMessage" json:"decryptionErrorMessage,omitempty"` - StoryMessage *StoryMessage `protobuf:"bytes,9,opt,name=storyMessage" json:"storyMessage,omitempty"` - PniSignatureMessage *PniSignatureMessage `protobuf:"bytes,10,opt,name=pniSignatureMessage" json:"pniSignatureMessage,omitempty"` - EditMessage *EditMessage `protobuf:"bytes,11,opt,name=editMessage" json:"editMessage,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + DataMessage *DataMessage `protobuf:"bytes,1,opt,name=dataMessage" json:"dataMessage,omitempty"` + SyncMessage *SyncMessage `protobuf:"bytes,2,opt,name=syncMessage" json:"syncMessage,omitempty"` + CallMessage *CallMessage `protobuf:"bytes,3,opt,name=callMessage" json:"callMessage,omitempty"` + NullMessage *NullMessage `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` + ReceiptMessage *ReceiptMessage `protobuf:"bytes,5,opt,name=receiptMessage" json:"receiptMessage,omitempty"` + TypingMessage *TypingMessage `protobuf:"bytes,6,opt,name=typingMessage" json:"typingMessage,omitempty"` + SenderKeyDistributionMessage []byte `protobuf:"bytes,7,opt,name=senderKeyDistributionMessage" json:"senderKeyDistributionMessage,omitempty"` + DecryptionErrorMessage []byte `protobuf:"bytes,8,opt,name=decryptionErrorMessage" json:"decryptionErrorMessage,omitempty"` + StoryMessage *StoryMessage `protobuf:"bytes,9,opt,name=storyMessage" json:"storyMessage,omitempty"` + PniSignatureMessage *PniSignatureMessage `protobuf:"bytes,10,opt,name=pniSignatureMessage" json:"pniSignatureMessage,omitempty"` + EditMessage *EditMessage `protobuf:"bytes,11,opt,name=editMessage" json:"editMessage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Content) Reset() { @@ -1955,10 +1953,7 @@ func (x *Content) GetEditMessage() *EditMessage { } type CallMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Offer *CallMessage_Offer `protobuf:"bytes,1,opt,name=offer" json:"offer,omitempty"` Answer *CallMessage_Answer `protobuf:"bytes,2,opt,name=answer" json:"answer,omitempty"` IceUpdate []*CallMessage_IceUpdate `protobuf:"bytes,3,rep,name=iceUpdate" json:"iceUpdate,omitempty"` @@ -1966,6 +1961,8 @@ type CallMessage struct { Hangup *CallMessage_Hangup `protobuf:"bytes,7,opt,name=hangup" json:"hangup,omitempty"` DestinationDeviceId *uint32 `protobuf:"varint,9,opt,name=destinationDeviceId" json:"destinationDeviceId,omitempty"` Opaque *CallMessage_Opaque `protobuf:"bytes,10,opt,name=opaque" json:"opaque,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CallMessage) Reset() { @@ -2048,17 +2045,16 @@ func (x *CallMessage) GetOpaque() *CallMessage_Opaque { } type BodyRange struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Start *uint32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` - // Types that are assignable to AssociatedValue: + state protoimpl.MessageState `protogen:"open.v1"` + Start *uint32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` + // Types that are valid to be assigned to AssociatedValue: // // *BodyRange_MentionAci // *BodyRange_Style_ AssociatedValue isBodyRange_AssociatedValue `protobuf_oneof:"associatedValue"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *BodyRange) Reset() { @@ -2105,23 +2101,27 @@ func (x *BodyRange) GetLength() uint32 { return 0 } -func (m *BodyRange) GetAssociatedValue() isBodyRange_AssociatedValue { - if m != nil { - return m.AssociatedValue +func (x *BodyRange) GetAssociatedValue() isBodyRange_AssociatedValue { + if x != nil { + return x.AssociatedValue } return nil } func (x *BodyRange) GetMentionAci() string { - if x, ok := x.GetAssociatedValue().(*BodyRange_MentionAci); ok { - return x.MentionAci + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_MentionAci); ok { + return x.MentionAci + } } return "" } func (x *BodyRange) GetStyle() BodyRange_Style { - if x, ok := x.GetAssociatedValue().(*BodyRange_Style_); ok { - return x.Style + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_Style_); ok { + return x.Style + } } return BodyRange_NONE } @@ -2143,10 +2143,7 @@ func (*BodyRange_MentionAci) isBodyRange_AssociatedValue() {} func (*BodyRange_Style_) isBodyRange_AssociatedValue() {} type DataMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Body *string `protobuf:"bytes,1,opt,name=body" json:"body,omitempty"` Attachments []*AttachmentPointer `protobuf:"bytes,2,rep,name=attachments" json:"attachments,omitempty"` GroupV2 *GroupContextV2 `protobuf:"bytes,15,opt,name=groupV2" json:"groupV2,omitempty"` @@ -2168,6 +2165,8 @@ type DataMessage struct { Payment *DataMessage_Payment `protobuf:"bytes,20,opt,name=payment" json:"payment,omitempty"` StoryContext *DataMessage_StoryContext `protobuf:"bytes,21,opt,name=storyContext" json:"storyContext,omitempty"` GiftBadge *DataMessage_GiftBadge `protobuf:"bytes,22,opt,name=giftBadge" json:"giftBadge,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage) Reset() { @@ -2348,11 +2347,10 @@ func (x *DataMessage) GetGiftBadge() *DataMessage_GiftBadge { } type NullMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Padding []byte `protobuf:"bytes,1,opt,name=padding" json:"padding,omitempty"` unknownFields protoimpl.UnknownFields - - Padding []byte `protobuf:"bytes,1,opt,name=padding" json:"padding,omitempty"` + sizeCache protoimpl.SizeCache } func (x *NullMessage) Reset() { @@ -2393,12 +2391,11 @@ func (x *NullMessage) GetPadding() []byte { } type ReceiptMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *ReceiptMessage_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.ReceiptMessage_Type" json:"type,omitempty"` + Timestamp []uint64 `protobuf:"varint,2,rep,name=timestamp" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - Type *ReceiptMessage_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.ReceiptMessage_Type" json:"type,omitempty"` - Timestamp []uint64 `protobuf:"varint,2,rep,name=timestamp" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ReceiptMessage) Reset() { @@ -2446,13 +2443,12 @@ func (x *ReceiptMessage) GetTimestamp() []uint64 { } type TypingMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Timestamp *uint64 `protobuf:"varint,1,opt,name=timestamp" json:"timestamp,omitempty"` + Action *TypingMessage_Action `protobuf:"varint,2,opt,name=action,enum=signalservice.TypingMessage_Action" json:"action,omitempty"` + GroupId []byte `protobuf:"bytes,3,opt,name=groupId" json:"groupId,omitempty"` unknownFields protoimpl.UnknownFields - - Timestamp *uint64 `protobuf:"varint,1,opt,name=timestamp" json:"timestamp,omitempty"` - Action *TypingMessage_Action `protobuf:"varint,2,opt,name=action,enum=signalservice.TypingMessage_Action" json:"action,omitempty"` - GroupId []byte `protobuf:"bytes,3,opt,name=groupId" json:"groupId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TypingMessage) Reset() { @@ -2507,19 +2503,18 @@ func (x *TypingMessage) GetGroupId() []byte { } type StoryMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey" json:"profileKey,omitempty"` - Group *GroupContextV2 `protobuf:"bytes,2,opt,name=group" json:"group,omitempty"` - // Types that are assignable to Attachment: + state protoimpl.MessageState `protogen:"open.v1"` + ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey" json:"profileKey,omitempty"` + Group *GroupContextV2 `protobuf:"bytes,2,opt,name=group" json:"group,omitempty"` + // Types that are valid to be assigned to Attachment: // // *StoryMessage_FileAttachment // *StoryMessage_TextAttachment Attachment isStoryMessage_Attachment `protobuf_oneof:"attachment"` AllowsReplies *bool `protobuf:"varint,5,opt,name=allowsReplies" json:"allowsReplies,omitempty"` BodyRanges []*BodyRange `protobuf:"bytes,6,rep,name=bodyRanges" json:"bodyRanges,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StoryMessage) Reset() { @@ -2566,23 +2561,27 @@ func (x *StoryMessage) GetGroup() *GroupContextV2 { return nil } -func (m *StoryMessage) GetAttachment() isStoryMessage_Attachment { - if m != nil { - return m.Attachment +func (x *StoryMessage) GetAttachment() isStoryMessage_Attachment { + if x != nil { + return x.Attachment } return nil } func (x *StoryMessage) GetFileAttachment() *AttachmentPointer { - if x, ok := x.GetAttachment().(*StoryMessage_FileAttachment); ok { - return x.FileAttachment + if x != nil { + if x, ok := x.Attachment.(*StoryMessage_FileAttachment); ok { + return x.FileAttachment + } } return nil } func (x *StoryMessage) GetTextAttachment() *TextAttachment { - if x, ok := x.GetAttachment().(*StoryMessage_TextAttachment); ok { - return x.TextAttachment + if x != nil { + if x, ok := x.Attachment.(*StoryMessage_TextAttachment); ok { + return x.TextAttachment + } } return nil } @@ -2618,15 +2617,14 @@ func (*StoryMessage_FileAttachment) isStoryMessage_Attachment() {} func (*StoryMessage_TextAttachment) isStoryMessage_Attachment() {} type Preview struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Url *string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` + Title *string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` + Image *AttachmentPointer `protobuf:"bytes,3,opt,name=image" json:"image,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + Date *uint64 `protobuf:"varint,5,opt,name=date" json:"date,omitempty"` unknownFields protoimpl.UnknownFields - - Url *string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` - Title *string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` - Image *AttachmentPointer `protobuf:"bytes,3,opt,name=image" json:"image,omitempty"` - Description *string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` - Date *uint64 `protobuf:"varint,5,opt,name=date" json:"date,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Preview) Reset() { @@ -2695,20 +2693,19 @@ func (x *Preview) GetDate() uint64 { } type TextAttachment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Text *string `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"` - TextStyle *TextAttachment_Style `protobuf:"varint,2,opt,name=textStyle,enum=signalservice.TextAttachment_Style" json:"textStyle,omitempty"` - TextForegroundColor *uint32 `protobuf:"varint,3,opt,name=textForegroundColor" json:"textForegroundColor,omitempty"` // integer representation of hex color - TextBackgroundColor *uint32 `protobuf:"varint,4,opt,name=textBackgroundColor" json:"textBackgroundColor,omitempty"` - Preview *Preview `protobuf:"bytes,5,opt,name=preview" json:"preview,omitempty"` - // Types that are assignable to Background: + state protoimpl.MessageState `protogen:"open.v1"` + Text *string `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"` + TextStyle *TextAttachment_Style `protobuf:"varint,2,opt,name=textStyle,enum=signalservice.TextAttachment_Style" json:"textStyle,omitempty"` + TextForegroundColor *uint32 `protobuf:"varint,3,opt,name=textForegroundColor" json:"textForegroundColor,omitempty"` // integer representation of hex color + TextBackgroundColor *uint32 `protobuf:"varint,4,opt,name=textBackgroundColor" json:"textBackgroundColor,omitempty"` + Preview *Preview `protobuf:"bytes,5,opt,name=preview" json:"preview,omitempty"` + // Types that are valid to be assigned to Background: // // *TextAttachment_Gradient_ // *TextAttachment_Color - Background isTextAttachment_Background `protobuf_oneof:"background"` + Background isTextAttachment_Background `protobuf_oneof:"background"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TextAttachment) Reset() { @@ -2776,23 +2773,27 @@ func (x *TextAttachment) GetPreview() *Preview { return nil } -func (m *TextAttachment) GetBackground() isTextAttachment_Background { - if m != nil { - return m.Background +func (x *TextAttachment) GetBackground() isTextAttachment_Background { + if x != nil { + return x.Background } return nil } func (x *TextAttachment) GetGradient() *TextAttachment_Gradient { - if x, ok := x.GetBackground().(*TextAttachment_Gradient_); ok { - return x.Gradient + if x != nil { + if x, ok := x.Background.(*TextAttachment_Gradient_); ok { + return x.Gradient + } } return nil } func (x *TextAttachment) GetColor() uint32 { - if x, ok := x.GetBackground().(*TextAttachment_Color); ok { - return x.Color + if x != nil { + if x, ok := x.Background.(*TextAttachment_Color); ok { + return x.Color + } } return 0 } @@ -2814,14 +2815,13 @@ func (*TextAttachment_Gradient_) isTextAttachment_Background() {} func (*TextAttachment_Color) isTextAttachment_Background() {} type Verified struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DestinationAci *string `protobuf:"bytes,5,opt,name=destinationAci" json:"destinationAci,omitempty"` - IdentityKey []byte `protobuf:"bytes,2,opt,name=identityKey" json:"identityKey,omitempty"` - State *Verified_State `protobuf:"varint,3,opt,name=state,enum=signalservice.Verified_State" json:"state,omitempty"` - NullMessage []byte `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + DestinationAci *string `protobuf:"bytes,5,opt,name=destinationAci" json:"destinationAci,omitempty"` + IdentityKey []byte `protobuf:"bytes,2,opt,name=identityKey" json:"identityKey,omitempty"` + State *Verified_State `protobuf:"varint,3,opt,name=state,enum=signalservice.Verified_State" json:"state,omitempty"` + NullMessage []byte `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Verified) Reset() { @@ -2883,10 +2883,7 @@ func (x *Verified) GetNullMessage() []byte { } type SyncMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Sent *SyncMessage_Sent `protobuf:"bytes,1,opt,name=sent" json:"sent,omitempty"` Contacts *SyncMessage_Contacts `protobuf:"bytes,2,opt,name=contacts" json:"contacts,omitempty"` Request *SyncMessage_Request `protobuf:"bytes,4,opt,name=request" json:"request,omitempty"` @@ -2908,6 +2905,8 @@ type SyncMessage struct { CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent" json:"callLogEvent,omitempty"` DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe" json:"deleteForMe,omitempty"` DeviceNameChange *SyncMessage_DeviceNameChange `protobuf:"bytes,23,opt,name=deviceNameChange" json:"deviceNameChange,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage) Reset() { @@ -3088,11 +3087,8 @@ func (x *SyncMessage) GetDeviceNameChange() *SyncMessage_DeviceNameChange { } type AttachmentPointer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to AttachmentIdentifier: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to AttachmentIdentifier: // // *AttachmentPointer_CdnId // *AttachmentPointer_CdnKey @@ -3113,6 +3109,8 @@ type AttachmentPointer struct { UploadTimestamp *uint64 `protobuf:"varint,13,opt,name=uploadTimestamp" json:"uploadTimestamp,omitempty"` CdnNumber *uint32 `protobuf:"varint,14,opt,name=cdnNumber" json:"cdnNumber,omitempty"` Uuid []byte `protobuf:"bytes,20,opt,name=uuid" json:"uuid,omitempty"` // Next ID: 21 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AttachmentPointer) Reset() { @@ -3145,23 +3143,27 @@ func (*AttachmentPointer) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{13} } -func (m *AttachmentPointer) GetAttachmentIdentifier() isAttachmentPointer_AttachmentIdentifier { - if m != nil { - return m.AttachmentIdentifier +func (x *AttachmentPointer) GetAttachmentIdentifier() isAttachmentPointer_AttachmentIdentifier { + if x != nil { + return x.AttachmentIdentifier } return nil } func (x *AttachmentPointer) GetCdnId() uint64 { - if x, ok := x.GetAttachmentIdentifier().(*AttachmentPointer_CdnId); ok { - return x.CdnId + if x != nil { + if x, ok := x.AttachmentIdentifier.(*AttachmentPointer_CdnId); ok { + return x.CdnId + } } return 0 } func (x *AttachmentPointer) GetCdnKey() string { - if x, ok := x.GetAttachmentIdentifier().(*AttachmentPointer_CdnKey); ok { - return x.CdnKey + if x != nil { + if x, ok := x.AttachmentIdentifier.(*AttachmentPointer_CdnKey); ok { + return x.CdnKey + } } return "" } @@ -3295,16 +3297,15 @@ func (*AttachmentPointer_CdnId) isAttachmentPointer_AttachmentIdentifier() {} func (*AttachmentPointer_CdnKey) isAttachmentPointer_AttachmentIdentifier() {} type GroupContext struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Type *GroupContext_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.GroupContext_Type" json:"type,omitempty"` + Name *string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + MembersE164 []string `protobuf:"bytes,4,rep,name=membersE164" json:"membersE164,omitempty"` + Members []*GroupContext_Member `protobuf:"bytes,6,rep,name=members" json:"members,omitempty"` + Avatar *AttachmentPointer `protobuf:"bytes,5,opt,name=avatar" json:"avatar,omitempty"` unknownFields protoimpl.UnknownFields - - Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Type *GroupContext_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.GroupContext_Type" json:"type,omitempty"` - Name *string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` - MembersE164 []string `protobuf:"bytes,4,rep,name=membersE164" json:"membersE164,omitempty"` - Members []*GroupContext_Member `protobuf:"bytes,6,rep,name=members" json:"members,omitempty"` - Avatar *AttachmentPointer `protobuf:"bytes,5,opt,name=avatar" json:"avatar,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupContext) Reset() { @@ -3380,13 +3381,12 @@ func (x *GroupContext) GetAvatar() *AttachmentPointer { } type GroupContextV2 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + MasterKey []byte `protobuf:"bytes,1,opt,name=masterKey" json:"masterKey,omitempty"` + Revision *uint32 `protobuf:"varint,2,opt,name=revision" json:"revision,omitempty"` + GroupChange []byte `protobuf:"bytes,3,opt,name=groupChange" json:"groupChange,omitempty"` unknownFields protoimpl.UnknownFields - - MasterKey []byte `protobuf:"bytes,1,opt,name=masterKey" json:"masterKey,omitempty"` - Revision *uint32 `protobuf:"varint,2,opt,name=revision" json:"revision,omitempty"` - GroupChange []byte `protobuf:"bytes,3,opt,name=groupChange" json:"groupChange,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupContextV2) Reset() { @@ -3441,10 +3441,7 @@ func (x *GroupContextV2) GetGroupChange() []byte { } type ContactDetails struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Number *string `protobuf:"bytes,1,opt,name=number" json:"number,omitempty"` Aci *string `protobuf:"bytes,9,opt,name=aci" json:"aci,omitempty"` Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` @@ -3456,6 +3453,8 @@ type ContactDetails struct { ExpireTimerVersion *uint32 `protobuf:"varint,12,opt,name=expireTimerVersion" json:"expireTimerVersion,omitempty"` InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ContactDetails) Reset() { @@ -3566,10 +3565,7 @@ func (x *ContactDetails) GetArchived() bool { } type GroupDetails struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` MembersE164 []string `protobuf:"bytes,3,rep,name=membersE164" json:"membersE164,omitempty"` @@ -3581,6 +3577,8 @@ type GroupDetails struct { Blocked *bool `protobuf:"varint,8,opt,name=blocked" json:"blocked,omitempty"` InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } // Default values for GroupDetails fields. @@ -3696,14 +3694,13 @@ func (x *GroupDetails) GetArchived() bool { } type PaymentAddress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Address: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Address: // // *PaymentAddress_MobileCoinAddress_ - Address isPaymentAddress_Address `protobuf_oneof:"Address"` + Address isPaymentAddress_Address `protobuf_oneof:"Address"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PaymentAddress) Reset() { @@ -3736,16 +3733,18 @@ func (*PaymentAddress) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{18} } -func (m *PaymentAddress) GetAddress() isPaymentAddress_Address { - if m != nil { - return m.Address +func (x *PaymentAddress) GetAddress() isPaymentAddress_Address { + if x != nil { + return x.Address } return nil } func (x *PaymentAddress) GetMobileCoinAddress() *PaymentAddress_MobileCoinAddress { - if x, ok := x.GetAddress().(*PaymentAddress_MobileCoinAddress_); ok { - return x.MobileCoinAddress + if x != nil { + if x, ok := x.Address.(*PaymentAddress_MobileCoinAddress_); ok { + return x.MobileCoinAddress + } } return nil } @@ -3761,13 +3760,12 @@ type PaymentAddress_MobileCoinAddress_ struct { func (*PaymentAddress_MobileCoinAddress_) isPaymentAddress_Address() {} type DecryptionErrorMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + RatchetKey []byte `protobuf:"bytes,1,opt,name=ratchetKey" json:"ratchetKey,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + DeviceId *uint32 `protobuf:"varint,3,opt,name=deviceId" json:"deviceId,omitempty"` unknownFields protoimpl.UnknownFields - - RatchetKey []byte `protobuf:"bytes,1,opt,name=ratchetKey" json:"ratchetKey,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` - DeviceId *uint32 `protobuf:"varint,3,opt,name=deviceId" json:"deviceId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DecryptionErrorMessage) Reset() { @@ -3822,12 +3820,11 @@ func (x *DecryptionErrorMessage) GetDeviceId() uint32 { } type PniSignatureMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Pni []byte `protobuf:"bytes,1,opt,name=pni" json:"pni,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` unknownFields protoimpl.UnknownFields - - Pni []byte `protobuf:"bytes,1,opt,name=pni" json:"pni,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PniSignatureMessage) Reset() { @@ -3875,12 +3872,11 @@ func (x *PniSignatureMessage) GetSignature() []byte { } type EditMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` - DataMessage *DataMessage `protobuf:"bytes,2,opt,name=dataMessage" json:"dataMessage,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + DataMessage *DataMessage `protobuf:"bytes,2,opt,name=dataMessage" json:"dataMessage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EditMessage) Reset() { @@ -3928,13 +3924,12 @@ func (x *EditMessage) GetDataMessage() *DataMessage { } type CallMessage_Offer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Type *CallMessage_Offer_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.CallMessage_Offer_Type" json:"type,omitempty"` + Opaque []byte `protobuf:"bytes,4,opt,name=opaque" json:"opaque,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Type *CallMessage_Offer_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.CallMessage_Offer_Type" json:"type,omitempty"` - Opaque []byte `protobuf:"bytes,4,opt,name=opaque" json:"opaque,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CallMessage_Offer) Reset() { @@ -3989,12 +3984,11 @@ func (x *CallMessage_Offer) GetOpaque() []byte { } type CallMessage_Answer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Opaque []byte `protobuf:"bytes,3,opt,name=opaque" json:"opaque,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Opaque []byte `protobuf:"bytes,3,opt,name=opaque" json:"opaque,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CallMessage_Answer) Reset() { @@ -4042,12 +4036,11 @@ func (x *CallMessage_Answer) GetOpaque() []byte { } type CallMessage_IceUpdate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Opaque []byte `protobuf:"bytes,5,opt,name=opaque" json:"opaque,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Opaque []byte `protobuf:"bytes,5,opt,name=opaque" json:"opaque,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CallMessage_IceUpdate) Reset() { @@ -4095,11 +4088,10 @@ func (x *CallMessage_IceUpdate) GetOpaque() []byte { } type CallMessage_Busy struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CallMessage_Busy) Reset() { @@ -4140,13 +4132,12 @@ func (x *CallMessage_Busy) GetId() uint64 { } type CallMessage_Hangup struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Type *CallMessage_Hangup_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.CallMessage_Hangup_Type" json:"type,omitempty"` + DeviceId *uint32 `protobuf:"varint,3,opt,name=deviceId" json:"deviceId,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Type *CallMessage_Hangup_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.CallMessage_Hangup_Type" json:"type,omitempty"` - DeviceId *uint32 `protobuf:"varint,3,opt,name=deviceId" json:"deviceId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CallMessage_Hangup) Reset() { @@ -4201,12 +4192,11 @@ func (x *CallMessage_Hangup) GetDeviceId() uint32 { } type CallMessage_Opaque struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` + Urgency *CallMessage_Opaque_Urgency `protobuf:"varint,2,opt,name=urgency,enum=signalservice.CallMessage_Opaque_Urgency" json:"urgency,omitempty"` unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` - Urgency *CallMessage_Opaque_Urgency `protobuf:"varint,2,opt,name=urgency,enum=signalservice.CallMessage_Opaque_Urgency" json:"urgency,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CallMessage_Opaque) Reset() { @@ -4254,16 +4244,15 @@ func (x *CallMessage_Opaque) GetUrgency() CallMessage_Opaque_Urgency { } type DataMessage_Quote struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + AuthorAci *string `protobuf:"bytes,5,opt,name=authorAci" json:"authorAci,omitempty"` + Text *string `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"` + Attachments []*DataMessage_Quote_QuotedAttachment `protobuf:"bytes,4,rep,name=attachments" json:"attachments,omitempty"` + BodyRanges []*BodyRange `protobuf:"bytes,6,rep,name=bodyRanges" json:"bodyRanges,omitempty"` + Type *DataMessage_Quote_Type `protobuf:"varint,7,opt,name=type,enum=signalservice.DataMessage_Quote_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - AuthorAci *string `protobuf:"bytes,5,opt,name=authorAci" json:"authorAci,omitempty"` - Text *string `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"` - Attachments []*DataMessage_Quote_QuotedAttachment `protobuf:"bytes,4,rep,name=attachments" json:"attachments,omitempty"` - BodyRanges []*BodyRange `protobuf:"bytes,6,rep,name=bodyRanges" json:"bodyRanges,omitempty"` - Type *DataMessage_Quote_Type `protobuf:"varint,7,opt,name=type,enum=signalservice.DataMessage_Quote_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Quote) Reset() { @@ -4339,16 +4328,15 @@ func (x *DataMessage_Quote) GetType() DataMessage_Quote_Type { } type DataMessage_Contact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Name *DataMessage_Contact_Name `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Number []*DataMessage_Contact_Phone `protobuf:"bytes,3,rep,name=number" json:"number,omitempty"` + Email []*DataMessage_Contact_Email `protobuf:"bytes,4,rep,name=email" json:"email,omitempty"` + Address []*DataMessage_Contact_PostalAddress `protobuf:"bytes,5,rep,name=address" json:"address,omitempty"` + Avatar *DataMessage_Contact_Avatar `protobuf:"bytes,6,opt,name=avatar" json:"avatar,omitempty"` + Organization *string `protobuf:"bytes,7,opt,name=organization" json:"organization,omitempty"` unknownFields protoimpl.UnknownFields - - Name *DataMessage_Contact_Name `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Number []*DataMessage_Contact_Phone `protobuf:"bytes,3,rep,name=number" json:"number,omitempty"` - Email []*DataMessage_Contact_Email `protobuf:"bytes,4,rep,name=email" json:"email,omitempty"` - Address []*DataMessage_Contact_PostalAddress `protobuf:"bytes,5,rep,name=address" json:"address,omitempty"` - Avatar *DataMessage_Contact_Avatar `protobuf:"bytes,6,opt,name=avatar" json:"avatar,omitempty"` - Organization *string `protobuf:"bytes,7,opt,name=organization" json:"organization,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Contact) Reset() { @@ -4424,15 +4412,14 @@ func (x *DataMessage_Contact) GetOrganization() string { } type DataMessage_Sticker struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PackId []byte `protobuf:"bytes,1,opt,name=packId" json:"packId,omitempty"` + PackKey []byte `protobuf:"bytes,2,opt,name=packKey" json:"packKey,omitempty"` + StickerId *uint32 `protobuf:"varint,3,opt,name=stickerId" json:"stickerId,omitempty"` + Data *AttachmentPointer `protobuf:"bytes,4,opt,name=data" json:"data,omitempty"` + Emoji *string `protobuf:"bytes,5,opt,name=emoji" json:"emoji,omitempty"` unknownFields protoimpl.UnknownFields - - PackId []byte `protobuf:"bytes,1,opt,name=packId" json:"packId,omitempty"` - PackKey []byte `protobuf:"bytes,2,opt,name=packKey" json:"packKey,omitempty"` - StickerId *uint32 `protobuf:"varint,3,opt,name=stickerId" json:"stickerId,omitempty"` - Data *AttachmentPointer `protobuf:"bytes,4,opt,name=data" json:"data,omitempty"` - Emoji *string `protobuf:"bytes,5,opt,name=emoji" json:"emoji,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Sticker) Reset() { @@ -4501,14 +4488,13 @@ func (x *DataMessage_Sticker) GetEmoji() string { } type DataMessage_Reaction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Emoji *string `protobuf:"bytes,1,opt,name=emoji" json:"emoji,omitempty"` - Remove *bool `protobuf:"varint,2,opt,name=remove" json:"remove,omitempty"` - TargetAuthorAci *string `protobuf:"bytes,4,opt,name=targetAuthorAci" json:"targetAuthorAci,omitempty"` - TargetSentTimestamp *uint64 `protobuf:"varint,5,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Emoji *string `protobuf:"bytes,1,opt,name=emoji" json:"emoji,omitempty"` + Remove *bool `protobuf:"varint,2,opt,name=remove" json:"remove,omitempty"` + TargetAuthorAci *string `protobuf:"bytes,4,opt,name=targetAuthorAci" json:"targetAuthorAci,omitempty"` + TargetSentTimestamp *uint64 `protobuf:"varint,5,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Reaction) Reset() { @@ -4570,11 +4556,10 @@ func (x *DataMessage_Reaction) GetTargetSentTimestamp() uint64 { } type DataMessage_Delete struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Delete) Reset() { @@ -4615,11 +4600,10 @@ func (x *DataMessage_Delete) GetTargetSentTimestamp() uint64 { } type DataMessage_GroupCallUpdate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + EraId *string `protobuf:"bytes,1,opt,name=eraId" json:"eraId,omitempty"` unknownFields protoimpl.UnknownFields - - EraId *string `protobuf:"bytes,1,opt,name=eraId" json:"eraId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_GroupCallUpdate) Reset() { @@ -4660,12 +4644,11 @@ func (x *DataMessage_GroupCallUpdate) GetEraId() string { } type DataMessage_StoryContext struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + AuthorAci *string `protobuf:"bytes,1,opt,name=authorAci" json:"authorAci,omitempty"` + SentTimestamp *uint64 `protobuf:"varint,2,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` unknownFields protoimpl.UnknownFields - - AuthorAci *string `protobuf:"bytes,1,opt,name=authorAci" json:"authorAci,omitempty"` - SentTimestamp *uint64 `protobuf:"varint,2,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_StoryContext) Reset() { @@ -4713,15 +4696,14 @@ func (x *DataMessage_StoryContext) GetSentTimestamp() uint64 { } type DataMessage_Payment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Item: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Item: // // *DataMessage_Payment_Notification_ // *DataMessage_Payment_Activation_ - Item isDataMessage_Payment_Item `protobuf_oneof:"Item"` + Item isDataMessage_Payment_Item `protobuf_oneof:"Item"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Payment) Reset() { @@ -4754,23 +4736,27 @@ func (*DataMessage_Payment) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{4, 7} } -func (m *DataMessage_Payment) GetItem() isDataMessage_Payment_Item { - if m != nil { - return m.Item +func (x *DataMessage_Payment) GetItem() isDataMessage_Payment_Item { + if x != nil { + return x.Item } return nil } func (x *DataMessage_Payment) GetNotification() *DataMessage_Payment_Notification { - if x, ok := x.GetItem().(*DataMessage_Payment_Notification_); ok { - return x.Notification + if x != nil { + if x, ok := x.Item.(*DataMessage_Payment_Notification_); ok { + return x.Notification + } } return nil } func (x *DataMessage_Payment) GetActivation() *DataMessage_Payment_Activation { - if x, ok := x.GetItem().(*DataMessage_Payment_Activation_); ok { - return x.Activation + if x != nil { + if x, ok := x.Item.(*DataMessage_Payment_Activation_); ok { + return x.Activation + } } return nil } @@ -4792,11 +4778,10 @@ func (*DataMessage_Payment_Notification_) isDataMessage_Payment_Item() {} func (*DataMessage_Payment_Activation_) isDataMessage_Payment_Item() {} type DataMessage_GiftBadge struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ReceiptCredentialPresentation []byte `protobuf:"bytes,1,opt,name=receiptCredentialPresentation" json:"receiptCredentialPresentation,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ReceiptCredentialPresentation []byte `protobuf:"bytes,1,opt,name=receiptCredentialPresentation" json:"receiptCredentialPresentation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_GiftBadge) Reset() { @@ -4837,13 +4822,12 @@ func (x *DataMessage_GiftBadge) GetReceiptCredentialPresentation() []byte { } type DataMessage_Quote_QuotedAttachment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` + FileName *string `protobuf:"bytes,2,opt,name=fileName" json:"fileName,omitempty"` + Thumbnail *AttachmentPointer `protobuf:"bytes,3,opt,name=thumbnail" json:"thumbnail,omitempty"` unknownFields protoimpl.UnknownFields - - ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` - FileName *string `protobuf:"bytes,2,opt,name=fileName" json:"fileName,omitempty"` - Thumbnail *AttachmentPointer `protobuf:"bytes,3,opt,name=thumbnail" json:"thumbnail,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Quote_QuotedAttachment) Reset() { @@ -4898,16 +4882,15 @@ func (x *DataMessage_Quote_QuotedAttachment) GetThumbnail() *AttachmentPointer { } type DataMessage_Contact_Name struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + GivenName *string `protobuf:"bytes,1,opt,name=givenName" json:"givenName,omitempty"` + FamilyName *string `protobuf:"bytes,2,opt,name=familyName" json:"familyName,omitempty"` + Prefix *string `protobuf:"bytes,3,opt,name=prefix" json:"prefix,omitempty"` + Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` + MiddleName *string `protobuf:"bytes,5,opt,name=middleName" json:"middleName,omitempty"` + Nickname *string `protobuf:"bytes,7,opt,name=nickname" json:"nickname,omitempty"` unknownFields protoimpl.UnknownFields - - GivenName *string `protobuf:"bytes,1,opt,name=givenName" json:"givenName,omitempty"` - FamilyName *string `protobuf:"bytes,2,opt,name=familyName" json:"familyName,omitempty"` - Prefix *string `protobuf:"bytes,3,opt,name=prefix" json:"prefix,omitempty"` - Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` - MiddleName *string `protobuf:"bytes,5,opt,name=middleName" json:"middleName,omitempty"` - Nickname *string `protobuf:"bytes,7,opt,name=nickname" json:"nickname,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Contact_Name) Reset() { @@ -4983,13 +4966,12 @@ func (x *DataMessage_Contact_Name) GetNickname() string { } type DataMessage_Contact_Phone struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Value *string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Type *DataMessage_Contact_Phone_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.DataMessage_Contact_Phone_Type" json:"type,omitempty"` + Label *string `protobuf:"bytes,3,opt,name=label" json:"label,omitempty"` unknownFields protoimpl.UnknownFields - - Value *string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` - Type *DataMessage_Contact_Phone_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.DataMessage_Contact_Phone_Type" json:"type,omitempty"` - Label *string `protobuf:"bytes,3,opt,name=label" json:"label,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Contact_Phone) Reset() { @@ -5044,13 +5026,12 @@ func (x *DataMessage_Contact_Phone) GetLabel() string { } type DataMessage_Contact_Email struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Value *string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` + Type *DataMessage_Contact_Email_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.DataMessage_Contact_Email_Type" json:"type,omitempty"` + Label *string `protobuf:"bytes,3,opt,name=label" json:"label,omitempty"` unknownFields protoimpl.UnknownFields - - Value *string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` - Type *DataMessage_Contact_Email_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.DataMessage_Contact_Email_Type" json:"type,omitempty"` - Label *string `protobuf:"bytes,3,opt,name=label" json:"label,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Contact_Email) Reset() { @@ -5105,19 +5086,18 @@ func (x *DataMessage_Contact_Email) GetLabel() string { } type DataMessage_Contact_PostalAddress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *DataMessage_Contact_PostalAddress_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.DataMessage_Contact_PostalAddress_Type" json:"type,omitempty"` + Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` + Street *string `protobuf:"bytes,3,opt,name=street" json:"street,omitempty"` + Pobox *string `protobuf:"bytes,4,opt,name=pobox" json:"pobox,omitempty"` + Neighborhood *string `protobuf:"bytes,5,opt,name=neighborhood" json:"neighborhood,omitempty"` + City *string `protobuf:"bytes,6,opt,name=city" json:"city,omitempty"` + Region *string `protobuf:"bytes,7,opt,name=region" json:"region,omitempty"` + Postcode *string `protobuf:"bytes,8,opt,name=postcode" json:"postcode,omitempty"` + Country *string `protobuf:"bytes,9,opt,name=country" json:"country,omitempty"` unknownFields protoimpl.UnknownFields - - Type *DataMessage_Contact_PostalAddress_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.DataMessage_Contact_PostalAddress_Type" json:"type,omitempty"` - Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` - Street *string `protobuf:"bytes,3,opt,name=street" json:"street,omitempty"` - Pobox *string `protobuf:"bytes,4,opt,name=pobox" json:"pobox,omitempty"` - Neighborhood *string `protobuf:"bytes,5,opt,name=neighborhood" json:"neighborhood,omitempty"` - City *string `protobuf:"bytes,6,opt,name=city" json:"city,omitempty"` - Region *string `protobuf:"bytes,7,opt,name=region" json:"region,omitempty"` - Postcode *string `protobuf:"bytes,8,opt,name=postcode" json:"postcode,omitempty"` - Country *string `protobuf:"bytes,9,opt,name=country" json:"country,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Contact_PostalAddress) Reset() { @@ -5214,12 +5194,11 @@ func (x *DataMessage_Contact_PostalAddress) GetCountry() string { } type DataMessage_Contact_Avatar struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Avatar *AttachmentPointer `protobuf:"bytes,1,opt,name=avatar" json:"avatar,omitempty"` + IsProfile *bool `protobuf:"varint,2,opt,name=isProfile" json:"isProfile,omitempty"` unknownFields protoimpl.UnknownFields - - Avatar *AttachmentPointer `protobuf:"bytes,1,opt,name=avatar" json:"avatar,omitempty"` - IsProfile *bool `protobuf:"varint,2,opt,name=isProfile" json:"isProfile,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Contact_Avatar) Reset() { @@ -5267,14 +5246,13 @@ func (x *DataMessage_Contact_Avatar) GetIsProfile() bool { } type DataMessage_Payment_Amount struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Amount: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Amount: // // *DataMessage_Payment_Amount_MobileCoin_ - Amount isDataMessage_Payment_Amount_Amount `protobuf_oneof:"Amount"` + Amount isDataMessage_Payment_Amount_Amount `protobuf_oneof:"Amount"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Payment_Amount) Reset() { @@ -5307,16 +5285,18 @@ func (*DataMessage_Payment_Amount) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 0} } -func (m *DataMessage_Payment_Amount) GetAmount() isDataMessage_Payment_Amount_Amount { - if m != nil { - return m.Amount +func (x *DataMessage_Payment_Amount) GetAmount() isDataMessage_Payment_Amount_Amount { + if x != nil { + return x.Amount } return nil } func (x *DataMessage_Payment_Amount) GetMobileCoin() *DataMessage_Payment_Amount_MobileCoin { - if x, ok := x.GetAmount().(*DataMessage_Payment_Amount_MobileCoin_); ok { - return x.MobileCoin + if x != nil { + if x, ok := x.Amount.(*DataMessage_Payment_Amount_MobileCoin_); ok { + return x.MobileCoin + } } return nil } @@ -5332,15 +5312,14 @@ type DataMessage_Payment_Amount_MobileCoin_ struct { func (*DataMessage_Payment_Amount_MobileCoin_) isDataMessage_Payment_Amount_Amount() {} type DataMessage_Payment_Notification struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Transaction: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Transaction: // // *DataMessage_Payment_Notification_MobileCoin_ - Transaction isDataMessage_Payment_Notification_Transaction `protobuf_oneof:"Transaction"` - Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` + Transaction isDataMessage_Payment_Notification_Transaction `protobuf_oneof:"Transaction"` + Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Payment_Notification) Reset() { @@ -5373,16 +5352,18 @@ func (*DataMessage_Payment_Notification) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 1} } -func (m *DataMessage_Payment_Notification) GetTransaction() isDataMessage_Payment_Notification_Transaction { - if m != nil { - return m.Transaction +func (x *DataMessage_Payment_Notification) GetTransaction() isDataMessage_Payment_Notification_Transaction { + if x != nil { + return x.Transaction } return nil } func (x *DataMessage_Payment_Notification) GetMobileCoin() *DataMessage_Payment_Notification_MobileCoin { - if x, ok := x.GetTransaction().(*DataMessage_Payment_Notification_MobileCoin_); ok { - return x.MobileCoin + if x != nil { + if x, ok := x.Transaction.(*DataMessage_Payment_Notification_MobileCoin_); ok { + return x.MobileCoin + } } return nil } @@ -5406,11 +5387,10 @@ func (*DataMessage_Payment_Notification_MobileCoin_) isDataMessage_Payment_Notif } type DataMessage_Payment_Activation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *DataMessage_Payment_Activation_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.DataMessage_Payment_Activation_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Type *DataMessage_Payment_Activation_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.DataMessage_Payment_Activation_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Payment_Activation) Reset() { @@ -5451,11 +5431,10 @@ func (x *DataMessage_Payment_Activation) GetType() DataMessage_Payment_Activatio } type DataMessage_Payment_Amount_MobileCoin struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PicoMob *uint64 `protobuf:"varint,1,opt,name=picoMob" json:"picoMob,omitempty"` unknownFields protoimpl.UnknownFields - - PicoMob *uint64 `protobuf:"varint,1,opt,name=picoMob" json:"picoMob,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { @@ -5496,11 +5475,10 @@ func (x *DataMessage_Payment_Amount_MobileCoin) GetPicoMob() uint64 { } type DataMessage_Payment_Notification_MobileCoin struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Receipt []byte `protobuf:"bytes,1,opt,name=receipt" json:"receipt,omitempty"` unknownFields protoimpl.UnknownFields - - Receipt []byte `protobuf:"bytes,1,opt,name=receipt" json:"receipt,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { @@ -5541,15 +5519,14 @@ func (x *DataMessage_Payment_Notification_MobileCoin) GetReceipt() []byte { } type TextAttachment_Gradient struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + StartColor *uint32 `protobuf:"varint,1,opt,name=startColor" json:"startColor,omitempty"` // deprecated: this field will be removed in a future release. + EndColor *uint32 `protobuf:"varint,2,opt,name=endColor" json:"endColor,omitempty"` // deprecated: this field will be removed in a future release. + Angle *uint32 `protobuf:"varint,3,opt,name=angle" json:"angle,omitempty"` // degrees + Colors []uint32 `protobuf:"varint,4,rep,name=colors" json:"colors,omitempty"` + Positions []float32 `protobuf:"fixed32,5,rep,name=positions" json:"positions,omitempty"` // percent from 0 to 1 unknownFields protoimpl.UnknownFields - - StartColor *uint32 `protobuf:"varint,1,opt,name=startColor" json:"startColor,omitempty"` // deprecated: this field will be removed in a future release. - EndColor *uint32 `protobuf:"varint,2,opt,name=endColor" json:"endColor,omitempty"` // deprecated: this field will be removed in a future release. - Angle *uint32 `protobuf:"varint,3,opt,name=angle" json:"angle,omitempty"` // degrees - Colors []uint32 `protobuf:"varint,4,rep,name=colors" json:"colors,omitempty"` - Positions []float32 `protobuf:"fixed32,5,rep,name=positions" json:"positions,omitempty"` // percent from 0 to 1 + sizeCache protoimpl.SizeCache } func (x *TextAttachment_Gradient) Reset() { @@ -5618,10 +5595,7 @@ func (x *TextAttachment_Gradient) GetPositions() []float32 { } type SyncMessage_Sent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` DestinationE164 *string `protobuf:"bytes,1,opt,name=destinationE164" json:"destinationE164,omitempty"` DestinationServiceId *string `protobuf:"bytes,7,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` @@ -5632,6 +5606,8 @@ type SyncMessage_Sent struct { StoryMessage *StoryMessage `protobuf:"bytes,8,opt,name=storyMessage" json:"storyMessage,omitempty"` StoryMessageRecipients []*SyncMessage_Sent_StoryMessageRecipient `protobuf:"bytes,9,rep,name=storyMessageRecipients" json:"storyMessageRecipients,omitempty"` EditMessage *EditMessage `protobuf:"bytes,10,opt,name=editMessage" json:"editMessage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } // Default values for SyncMessage_Sent fields. @@ -5740,12 +5716,11 @@ func (x *SyncMessage_Sent) GetEditMessage() *EditMessage { } type SyncMessage_Contacts struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Blob *AttachmentPointer `protobuf:"bytes,1,opt,name=blob" json:"blob,omitempty"` + Complete *bool `protobuf:"varint,2,opt,name=complete,def=0" json:"complete,omitempty"` unknownFields protoimpl.UnknownFields - - Blob *AttachmentPointer `protobuf:"bytes,1,opt,name=blob" json:"blob,omitempty"` - Complete *bool `protobuf:"varint,2,opt,name=complete,def=0" json:"complete,omitempty"` + sizeCache protoimpl.SizeCache } // Default values for SyncMessage_Contacts fields. @@ -5798,13 +5773,12 @@ func (x *SyncMessage_Contacts) GetComplete() bool { } type SyncMessage_Blocked struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Numbers []string `protobuf:"bytes,1,rep,name=numbers" json:"numbers,omitempty"` + Acis []string `protobuf:"bytes,3,rep,name=acis" json:"acis,omitempty"` + GroupIds [][]byte `protobuf:"bytes,2,rep,name=groupIds" json:"groupIds,omitempty"` unknownFields protoimpl.UnknownFields - - Numbers []string `protobuf:"bytes,1,rep,name=numbers" json:"numbers,omitempty"` - Acis []string `protobuf:"bytes,3,rep,name=acis" json:"acis,omitempty"` - GroupIds [][]byte `protobuf:"bytes,2,rep,name=groupIds" json:"groupIds,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Blocked) Reset() { @@ -5859,11 +5833,10 @@ func (x *SyncMessage_Blocked) GetGroupIds() [][]byte { } type SyncMessage_Request struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *SyncMessage_Request_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_Request_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Type *SyncMessage_Request_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_Request_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Request) Reset() { @@ -5904,12 +5877,11 @@ func (x *SyncMessage_Request) GetType() SyncMessage_Request_Type { } type SyncMessage_Read struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Read) Reset() { @@ -5957,12 +5929,11 @@ func (x *SyncMessage_Read) GetTimestamp() uint64 { } type SyncMessage_Viewed struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Viewed) Reset() { @@ -6010,15 +5981,14 @@ func (x *SyncMessage_Viewed) GetTimestamp() uint64 { } type SyncMessage_Configuration struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ReadReceipts *bool `protobuf:"varint,1,opt,name=readReceipts" json:"readReceipts,omitempty"` - UnidentifiedDeliveryIndicators *bool `protobuf:"varint,2,opt,name=unidentifiedDeliveryIndicators" json:"unidentifiedDeliveryIndicators,omitempty"` - TypingIndicators *bool `protobuf:"varint,3,opt,name=typingIndicators" json:"typingIndicators,omitempty"` - ProvisioningVersion *uint32 `protobuf:"varint,5,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` - LinkPreviews *bool `protobuf:"varint,6,opt,name=linkPreviews" json:"linkPreviews,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ReadReceipts *bool `protobuf:"varint,1,opt,name=readReceipts" json:"readReceipts,omitempty"` + UnidentifiedDeliveryIndicators *bool `protobuf:"varint,2,opt,name=unidentifiedDeliveryIndicators" json:"unidentifiedDeliveryIndicators,omitempty"` + TypingIndicators *bool `protobuf:"varint,3,opt,name=typingIndicators" json:"typingIndicators,omitempty"` + ProvisioningVersion *uint32 `protobuf:"varint,5,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` + LinkPreviews *bool `protobuf:"varint,6,opt,name=linkPreviews" json:"linkPreviews,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Configuration) Reset() { @@ -6087,13 +6057,12 @@ func (x *SyncMessage_Configuration) GetLinkPreviews() bool { } type SyncMessage_StickerPackOperation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PackId []byte `protobuf:"bytes,1,opt,name=packId" json:"packId,omitempty"` + PackKey []byte `protobuf:"bytes,2,opt,name=packKey" json:"packKey,omitempty"` + Type *SyncMessage_StickerPackOperation_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_StickerPackOperation_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - PackId []byte `protobuf:"bytes,1,opt,name=packId" json:"packId,omitempty"` - PackKey []byte `protobuf:"bytes,2,opt,name=packKey" json:"packKey,omitempty"` - Type *SyncMessage_StickerPackOperation_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_StickerPackOperation_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_StickerPackOperation) Reset() { @@ -6148,12 +6117,11 @@ func (x *SyncMessage_StickerPackOperation) GetType() SyncMessage_StickerPackOper } type SyncMessage_ViewOnceOpen struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` unknownFields protoimpl.UnknownFields - - SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_ViewOnceOpen) Reset() { @@ -6201,11 +6169,10 @@ func (x *SyncMessage_ViewOnceOpen) GetTimestamp() uint64 { } type SyncMessage_FetchLatest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *SyncMessage_FetchLatest_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_FetchLatest_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Type *SyncMessage_FetchLatest_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_FetchLatest_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_FetchLatest) Reset() { @@ -6246,16 +6213,15 @@ func (x *SyncMessage_FetchLatest) GetType() SyncMessage_FetchLatest_Type { } type SyncMessage_Keys struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // @deprecated StorageService []byte `protobuf:"bytes,1,opt,name=storageService" json:"storageService,omitempty"` // @deprecated Master []byte `protobuf:"bytes,2,opt,name=master" json:"master,omitempty"` AccountEntropyPool *string `protobuf:"bytes,3,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` MediaRootBackupKey []byte `protobuf:"bytes,4,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Keys) Reset() { @@ -6317,13 +6283,12 @@ func (x *SyncMessage_Keys) GetMediaRootBackupKey() []byte { } type SyncMessage_MessageRequestResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ThreadAci *string `protobuf:"bytes,2,opt,name=threadAci" json:"threadAci,omitempty"` + GroupId []byte `protobuf:"bytes,3,opt,name=groupId" json:"groupId,omitempty"` + Type *SyncMessage_MessageRequestResponse_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_MessageRequestResponse_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - ThreadAci *string `protobuf:"bytes,2,opt,name=threadAci" json:"threadAci,omitempty"` - GroupId []byte `protobuf:"bytes,3,opt,name=groupId" json:"groupId,omitempty"` - Type *SyncMessage_MessageRequestResponse_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_MessageRequestResponse_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_MessageRequestResponse) Reset() { @@ -6378,16 +6343,15 @@ func (x *SyncMessage_MessageRequestResponse) GetType() SyncMessage_MessageReques } type SyncMessage_OutgoingPayment struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RecipientServiceId *string `protobuf:"bytes,1,opt,name=recipientServiceId" json:"recipientServiceId,omitempty"` - Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` - // Types that are assignable to PaymentDetail: + state protoimpl.MessageState `protogen:"open.v1"` + RecipientServiceId *string `protobuf:"bytes,1,opt,name=recipientServiceId" json:"recipientServiceId,omitempty"` + Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` + // Types that are valid to be assigned to PaymentDetail: // // *SyncMessage_OutgoingPayment_MobileCoin_ PaymentDetail isSyncMessage_OutgoingPayment_PaymentDetail `protobuf_oneof:"paymentDetail"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_OutgoingPayment) Reset() { @@ -6434,16 +6398,18 @@ func (x *SyncMessage_OutgoingPayment) GetNote() string { return "" } -func (m *SyncMessage_OutgoingPayment) GetPaymentDetail() isSyncMessage_OutgoingPayment_PaymentDetail { - if m != nil { - return m.PaymentDetail +func (x *SyncMessage_OutgoingPayment) GetPaymentDetail() isSyncMessage_OutgoingPayment_PaymentDetail { + if x != nil { + return x.PaymentDetail } return nil } func (x *SyncMessage_OutgoingPayment) GetMobileCoin() *SyncMessage_OutgoingPayment_MobileCoin { - if x, ok := x.GetPaymentDetail().(*SyncMessage_OutgoingPayment_MobileCoin_); ok { - return x.MobileCoin + if x != nil { + if x, ok := x.PaymentDetail.(*SyncMessage_OutgoingPayment_MobileCoin_); ok { + return x.MobileCoin + } } return nil } @@ -6459,15 +6425,14 @@ type SyncMessage_OutgoingPayment_MobileCoin_ struct { func (*SyncMessage_OutgoingPayment_MobileCoin_) isSyncMessage_OutgoingPayment_PaymentDetail() {} type SyncMessage_PniChangeNumber struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IdentityKeyPair []byte `protobuf:"bytes,1,opt,name=identityKeyPair" json:"identityKeyPair,omitempty"` // Serialized libsignal-client IdentityKeyPair - SignedPreKey []byte `protobuf:"bytes,2,opt,name=signedPreKey" json:"signedPreKey,omitempty"` // Serialized libsignal-client SignedPreKeyRecord - LastResortKyberPreKey []byte `protobuf:"bytes,5,opt,name=lastResortKyberPreKey" json:"lastResortKyberPreKey,omitempty"` // Serialized libsignal-client KyberPreKeyRecord - RegistrationId *uint32 `protobuf:"varint,3,opt,name=registrationId" json:"registrationId,omitempty"` - NewE164 *string `protobuf:"bytes,4,opt,name=newE164" json:"newE164,omitempty"` // The e164 we have changed our number to + state protoimpl.MessageState `protogen:"open.v1"` + IdentityKeyPair []byte `protobuf:"bytes,1,opt,name=identityKeyPair" json:"identityKeyPair,omitempty"` // Serialized libsignal-client IdentityKeyPair + SignedPreKey []byte `protobuf:"bytes,2,opt,name=signedPreKey" json:"signedPreKey,omitempty"` // Serialized libsignal-client SignedPreKeyRecord + LastResortKyberPreKey []byte `protobuf:"bytes,5,opt,name=lastResortKyberPreKey" json:"lastResortKyberPreKey,omitempty"` // Serialized libsignal-client KyberPreKeyRecord + RegistrationId *uint32 `protobuf:"varint,3,opt,name=registrationId" json:"registrationId,omitempty"` + NewE164 *string `protobuf:"bytes,4,opt,name=newE164" json:"newE164,omitempty"` // The e164 we have changed our number to + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_PniChangeNumber) Reset() { @@ -6536,16 +6501,15 @@ func (x *SyncMessage_PniChangeNumber) GetNewE164() string { } type SyncMessage_CallEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` ConversationId []byte `protobuf:"bytes,1,opt,name=conversationId" json:"conversationId,omitempty"` Id *uint64 `protobuf:"varint,2,opt,name=id" json:"id,omitempty"` Timestamp *uint64 `protobuf:"varint,3,opt,name=timestamp" json:"timestamp,omitempty"` Type *SyncMessage_CallEvent_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_CallEvent_Type" json:"type,omitempty"` Direction *SyncMessage_CallEvent_Direction `protobuf:"varint,5,opt,name=direction,enum=signalservice.SyncMessage_CallEvent_Direction" json:"direction,omitempty"` Event *SyncMessage_CallEvent_Event `protobuf:"varint,6,opt,name=event,enum=signalservice.SyncMessage_CallEvent_Event" json:"event,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_CallEvent) Reset() { @@ -6621,13 +6585,12 @@ func (x *SyncMessage_CallEvent) GetEvent() SyncMessage_CallEvent_Event { } type SyncMessage_CallLinkUpdate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` + AdminPassKey []byte `protobuf:"bytes,2,opt,name=adminPassKey" json:"adminPassKey,omitempty"` + Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` - AdminPassKey []byte `protobuf:"bytes,2,opt,name=adminPassKey" json:"adminPassKey,omitempty"` - Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_CallLinkUpdate) Reset() { @@ -6682,10 +6645,7 @@ func (x *SyncMessage_CallLinkUpdate) GetType() SyncMessage_CallLinkUpdate_Type { } type SyncMessage_CallLogEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Type *SyncMessage_CallLogEvent_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_CallLogEvent_Type" json:"type,omitempty"` Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` // Data identifying a conversation. The service ID for 1:1, the group ID for @@ -6694,7 +6654,9 @@ type SyncMessage_CallLogEvent struct { ConversationId []byte `protobuf:"bytes,3,opt,name=conversationId" json:"conversationId,omitempty"` // An identifier for a call. Generated directly for 1:1, or derived from // the era ID for group and ad-hoc calls. See also `CallEvent/callId`. - CallId *uint64 `protobuf:"varint,4,opt,name=callId" json:"callId,omitempty"` + CallId *uint64 `protobuf:"varint,4,opt,name=callId" json:"callId,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_CallLogEvent) Reset() { @@ -6756,14 +6718,13 @@ func (x *SyncMessage_CallLogEvent) GetCallId() uint64 { } type SyncMessage_DeleteForMe struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` MessageDeletes []*SyncMessage_DeleteForMe_MessageDeletes `protobuf:"bytes,1,rep,name=messageDeletes" json:"messageDeletes,omitempty"` ConversationDeletes []*SyncMessage_DeleteForMe_ConversationDelete `protobuf:"bytes,2,rep,name=conversationDeletes" json:"conversationDeletes,omitempty"` LocalOnlyConversationDeletes []*SyncMessage_DeleteForMe_LocalOnlyConversationDelete `protobuf:"bytes,3,rep,name=localOnlyConversationDeletes" json:"localOnlyConversationDeletes,omitempty"` AttachmentDeletes []*SyncMessage_DeleteForMe_AttachmentDelete `protobuf:"bytes,4,rep,name=attachmentDeletes" json:"attachmentDeletes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe) Reset() { @@ -6825,11 +6786,10 @@ func (x *SyncMessage_DeleteForMe) GetAttachmentDeletes() []*SyncMessage_DeleteFo } type SyncMessage_DeviceNameChange struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DeviceId *uint32 `protobuf:"varint,2,opt,name=deviceId" json:"deviceId,omitempty"` unknownFields protoimpl.UnknownFields - - DeviceId *uint32 `protobuf:"varint,2,opt,name=deviceId" json:"deviceId,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeviceNameChange) Reset() { @@ -6870,13 +6830,12 @@ func (x *SyncMessage_DeviceNameChange) GetDeviceId() uint32 { } type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` - DestinationIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationIdentityKey" json:"destinationIdentityKey,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` + DestinationIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationIdentityKey" json:"destinationIdentityKey,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { @@ -6931,13 +6890,12 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationIdentityKey( } type SyncMessage_Sent_StoryMessageRecipient struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - DestinationServiceId *string `protobuf:"bytes,1,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - DistributionListIds []string `protobuf:"bytes,2,rep,name=distributionListIds" json:"distributionListIds,omitempty"` - IsAllowedToReply *bool `protobuf:"varint,3,opt,name=isAllowedToReply" json:"isAllowedToReply,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + DestinationServiceId *string `protobuf:"bytes,1,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + DistributionListIds []string `protobuf:"bytes,2,rep,name=distributionListIds" json:"distributionListIds,omitempty"` + IsAllowedToReply *bool `protobuf:"varint,3,opt,name=isAllowedToReply" json:"isAllowedToReply,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { @@ -6992,11 +6950,8 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) GetIsAllowedToReply() bool { } type SyncMessage_OutgoingPayment_MobileCoin struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RecipientAddress []byte `protobuf:"bytes,1,opt,name=recipientAddress" json:"recipientAddress,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + RecipientAddress []byte `protobuf:"bytes,1,opt,name=recipientAddress" json:"recipientAddress,omitempty"` // @required AmountPicoMob *uint64 `protobuf:"varint,2,opt,name=amountPicoMob" json:"amountPicoMob,omitempty"` // @required @@ -7007,6 +6962,8 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { LedgerBlockIndex *uint64 `protobuf:"varint,6,opt,name=ledgerBlockIndex" json:"ledgerBlockIndex,omitempty"` SpentKeyImages [][]byte `protobuf:"bytes,7,rep,name=spentKeyImages" json:"spentKeyImages,omitempty"` OutputPublicKeys [][]byte `protobuf:"bytes,8,rep,name=outputPublicKeys" json:"outputPublicKeys,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { @@ -7096,16 +7053,15 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) GetOutputPublicKeys() [][]byte } type SyncMessage_DeleteForMe_ConversationIdentifier struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Identifier: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Identifier: // // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 - Identifier isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier `protobuf_oneof:"identifier"` + Identifier isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier `protobuf_oneof:"identifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_ConversationIdentifier) Reset() { @@ -7138,30 +7094,36 @@ func (*SyncMessage_DeleteForMe_ConversationIdentifier) Descriptor() ([]byte, []i return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 0} } -func (m *SyncMessage_DeleteForMe_ConversationIdentifier) GetIdentifier() isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier { - if m != nil { - return m.Identifier +func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetIdentifier() isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier { + if x != nil { + return x.Identifier } return nil } func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadServiceId() string { - if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId); ok { - return x.ThreadServiceId + if x != nil { + if x, ok := x.Identifier.(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId); ok { + return x.ThreadServiceId + } } return "" } func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadGroupId() []byte { - if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId); ok { - return x.ThreadGroupId + if x != nil { + if x, ok := x.Identifier.(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId); ok { + return x.ThreadGroupId + } } return nil } func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadE164() string { - if x, ok := x.GetIdentifier().(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164); ok { - return x.ThreadE164 + if x != nil { + if x, ok := x.Identifier.(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164); ok { + return x.ThreadE164 + } } return "" } @@ -7192,16 +7154,15 @@ func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164) isSyncMessage_ } type SyncMessage_DeleteForMe_AddressableMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Author: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Author: // // *SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId // *SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 Author isSyncMessage_DeleteForMe_AddressableMessage_Author `protobuf_oneof:"author"` SentTimestamp *uint64 `protobuf:"varint,3,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_AddressableMessage) Reset() { @@ -7234,23 +7195,27 @@ func (*SyncMessage_DeleteForMe_AddressableMessage) Descriptor() ([]byte, []int) return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 1} } -func (m *SyncMessage_DeleteForMe_AddressableMessage) GetAuthor() isSyncMessage_DeleteForMe_AddressableMessage_Author { - if m != nil { - return m.Author +func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthor() isSyncMessage_DeleteForMe_AddressableMessage_Author { + if x != nil { + return x.Author } return nil } func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorServiceId() string { - if x, ok := x.GetAuthor().(*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId); ok { - return x.AuthorServiceId + if x != nil { + if x, ok := x.Author.(*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId); ok { + return x.AuthorServiceId + } } return "" } func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorE164() string { - if x, ok := x.GetAuthor().(*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164); ok { - return x.AuthorE164 + if x != nil { + if x, ok := x.Author.(*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164); ok { + return x.AuthorE164 + } } return "" } @@ -7281,12 +7246,11 @@ func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164) isSyncMessage_Dele } type SyncMessage_DeleteForMe_MessageDeletes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + Messages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=messages" json:"messages,omitempty"` unknownFields protoimpl.UnknownFields - - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` - Messages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=messages" json:"messages,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { @@ -7334,15 +7298,14 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) GetMessages() []*SyncMessage_De } type SyncMessage_DeleteForMe_AttachmentDelete struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` TargetMessage *SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,opt,name=targetMessage" json:"targetMessage,omitempty"` Uuid []byte `protobuf:"bytes,3,opt,name=uuid" json:"uuid,omitempty"` // The `uuid` from the `Attachment`. FallbackDigest []byte `protobuf:"bytes,4,opt,name=fallbackDigest" json:"fallbackDigest,omitempty"` FallbackPlaintextHash []byte `protobuf:"bytes,5,opt,name=fallbackPlaintextHash" json:"fallbackPlaintextHash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { @@ -7411,14 +7374,13 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetFallbackPlaintextHash() [] } type SyncMessage_DeleteForMe_ConversationDelete struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` MostRecentMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=mostRecentMessages" json:"mostRecentMessages,omitempty"` MostRecentNonExpiringMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,4,rep,name=mostRecentNonExpiringMessages" json:"mostRecentNonExpiringMessages,omitempty"` IsFullDelete *bool `protobuf:"varint,3,opt,name=isFullDelete" json:"isFullDelete,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { @@ -7480,11 +7442,10 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) GetIsFullDelete() bool { } type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` unknownFields protoimpl.UnknownFields - - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { @@ -7525,11 +7486,10 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) GetConversation() } type GroupContext_Member struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + E164 *string `protobuf:"bytes,2,opt,name=e164" json:"e164,omitempty"` unknownFields protoimpl.UnknownFields - - E164 *string `protobuf:"bytes,2,opt,name=e164" json:"e164,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupContext_Member) Reset() { @@ -7570,12 +7530,11 @@ func (x *GroupContext_Member) GetE164() string { } type ContactDetails_Avatar struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` unknownFields protoimpl.UnknownFields - - ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ContactDetails_Avatar) Reset() { @@ -7623,12 +7582,11 @@ func (x *ContactDetails_Avatar) GetLength() uint32 { } type GroupDetails_Avatar struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` unknownFields protoimpl.UnknownFields - - ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupDetails_Avatar) Reset() { @@ -7676,11 +7634,10 @@ func (x *GroupDetails_Avatar) GetLength() uint32 { } type GroupDetails_Member struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + E164 *string `protobuf:"bytes,2,opt,name=e164" json:"e164,omitempty"` unknownFields protoimpl.UnknownFields - - E164 *string `protobuf:"bytes,2,opt,name=e164" json:"e164,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GroupDetails_Member) Reset() { @@ -7721,12 +7678,11 @@ func (x *GroupDetails_Member) GetE164() string { } type PaymentAddress_MobileCoinAddress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` unknownFields protoimpl.UnknownFields - - Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PaymentAddress_MobileCoinAddress) Reset() { diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index d49db13..c194ebc 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: StickerResources.proto @@ -28,14 +28,13 @@ const ( ) type Pack struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Title *string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` + Author *string `protobuf:"bytes,2,opt,name=author" json:"author,omitempty"` + Cover *Pack_Sticker `protobuf:"bytes,3,opt,name=cover" json:"cover,omitempty"` + Stickers []*Pack_Sticker `protobuf:"bytes,4,rep,name=stickers" json:"stickers,omitempty"` unknownFields protoimpl.UnknownFields - - Title *string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` - Author *string `protobuf:"bytes,2,opt,name=author" json:"author,omitempty"` - Cover *Pack_Sticker `protobuf:"bytes,3,opt,name=cover" json:"cover,omitempty"` - Stickers []*Pack_Sticker `protobuf:"bytes,4,rep,name=stickers" json:"stickers,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Pack) Reset() { @@ -97,13 +96,12 @@ func (x *Pack) GetStickers() []*Pack_Sticker { } type Pack_Sticker struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Emoji *string `protobuf:"bytes,2,opt,name=emoji" json:"emoji,omitempty"` + ContentType *string `protobuf:"bytes,3,opt,name=contentType" json:"contentType,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Emoji *string `protobuf:"bytes,2,opt,name=emoji" json:"emoji,omitempty"` - ContentType *string `protobuf:"bytes,3,opt,name=contentType" json:"contentType,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Pack_Sticker) Reset() { diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index d37c1e2..ee6fbef 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: StorageService.proto @@ -352,12 +352,11 @@ func (AccountRecord_UsernameLink_Color) EnumDescriptor() ([]byte, []int) { } type StorageManifest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields - - Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageManifest) Reset() { @@ -405,12 +404,11 @@ func (x *StorageManifest) GetValue() []byte { } type StorageItem struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields - - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageItem) Reset() { @@ -458,11 +456,10 @@ func (x *StorageItem) GetValue() []byte { } type StorageItems struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Items []*StorageItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` unknownFields protoimpl.UnknownFields - - Items []*StorageItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StorageItems) Reset() { @@ -503,11 +500,10 @@ func (x *StorageItems) GetItems() []*StorageItem { } type ReadOperation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ReadKey [][]byte `protobuf:"bytes,1,rep,name=readKey,proto3" json:"readKey,omitempty"` unknownFields protoimpl.UnknownFields - - ReadKey [][]byte `protobuf:"bytes,1,rep,name=readKey,proto3" json:"readKey,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ReadOperation) Reset() { @@ -548,14 +544,13 @@ func (x *ReadOperation) GetReadKey() [][]byte { } type WriteOperation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Manifest *StorageManifest `protobuf:"bytes,1,opt,name=manifest,proto3" json:"manifest,omitempty"` + InsertItem []*StorageItem `protobuf:"bytes,2,rep,name=insertItem,proto3" json:"insertItem,omitempty"` + DeleteKey [][]byte `protobuf:"bytes,3,rep,name=deleteKey,proto3" json:"deleteKey,omitempty"` + ClearAll bool `protobuf:"varint,4,opt,name=clearAll,proto3" json:"clearAll,omitempty"` unknownFields protoimpl.UnknownFields - - Manifest *StorageManifest `protobuf:"bytes,1,opt,name=manifest,proto3" json:"manifest,omitempty"` - InsertItem []*StorageItem `protobuf:"bytes,2,rep,name=insertItem,proto3" json:"insertItem,omitempty"` - DeleteKey [][]byte `protobuf:"bytes,3,rep,name=deleteKey,proto3" json:"deleteKey,omitempty"` - ClearAll bool `protobuf:"varint,4,opt,name=clearAll,proto3" json:"clearAll,omitempty"` + sizeCache protoimpl.SizeCache } func (x *WriteOperation) Reset() { @@ -617,14 +612,13 @@ func (x *WriteOperation) GetClearAll() bool { } type ManifestRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + SourceDevice uint32 `protobuf:"varint,3,opt,name=sourceDevice,proto3" json:"sourceDevice,omitempty"` + Identifiers []*ManifestRecord_Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` + RecordIkm []byte `protobuf:"bytes,4,opt,name=recordIkm,proto3" json:"recordIkm,omitempty"` // Next ID: 5 unknownFields protoimpl.UnknownFields - - Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - SourceDevice uint32 `protobuf:"varint,3,opt,name=sourceDevice,proto3" json:"sourceDevice,omitempty"` - Identifiers []*ManifestRecord_Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` - RecordIkm []byte `protobuf:"bytes,4,opt,name=recordIkm,proto3" json:"recordIkm,omitempty"` // Next ID: 5 + sizeCache protoimpl.SizeCache } func (x *ManifestRecord) Reset() { @@ -686,11 +680,8 @@ func (x *ManifestRecord) GetRecordIkm() []byte { } type StorageRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Record: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Record: // // *StorageRecord_Contact // *StorageRecord_GroupV1 @@ -698,7 +689,9 @@ type StorageRecord struct { // *StorageRecord_Account // *StorageRecord_StoryDistributionList // *StorageRecord_CallLink - Record isStorageRecord_Record `protobuf_oneof:"record"` + Record isStorageRecord_Record `protobuf_oneof:"record"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StorageRecord) Reset() { @@ -731,51 +724,63 @@ func (*StorageRecord) Descriptor() ([]byte, []int) { return file_StorageService_proto_rawDescGZIP(), []int{6} } -func (m *StorageRecord) GetRecord() isStorageRecord_Record { - if m != nil { - return m.Record +func (x *StorageRecord) GetRecord() isStorageRecord_Record { + if x != nil { + return x.Record } return nil } func (x *StorageRecord) GetContact() *ContactRecord { - if x, ok := x.GetRecord().(*StorageRecord_Contact); ok { - return x.Contact + if x != nil { + if x, ok := x.Record.(*StorageRecord_Contact); ok { + return x.Contact + } } return nil } func (x *StorageRecord) GetGroupV1() *GroupV1Record { - if x, ok := x.GetRecord().(*StorageRecord_GroupV1); ok { - return x.GroupV1 + if x != nil { + if x, ok := x.Record.(*StorageRecord_GroupV1); ok { + return x.GroupV1 + } } return nil } func (x *StorageRecord) GetGroupV2() *GroupV2Record { - if x, ok := x.GetRecord().(*StorageRecord_GroupV2); ok { - return x.GroupV2 + if x != nil { + if x, ok := x.Record.(*StorageRecord_GroupV2); ok { + return x.GroupV2 + } } return nil } func (x *StorageRecord) GetAccount() *AccountRecord { - if x, ok := x.GetRecord().(*StorageRecord_Account); ok { - return x.Account + if x != nil { + if x, ok := x.Record.(*StorageRecord_Account); ok { + return x.Account + } } return nil } func (x *StorageRecord) GetStoryDistributionList() *StoryDistributionListRecord { - if x, ok := x.GetRecord().(*StorageRecord_StoryDistributionList); ok { - return x.StoryDistributionList + if x != nil { + if x, ok := x.Record.(*StorageRecord_StoryDistributionList); ok { + return x.StoryDistributionList + } } return nil } func (x *StorageRecord) GetCallLink() *CallLinkRecord { - if x, ok := x.GetRecord().(*StorageRecord_CallLink); ok { - return x.CallLink + if x != nil { + if x, ok := x.Record.(*StorageRecord_CallLink); ok { + return x.CallLink + } } return nil } @@ -821,10 +826,7 @@ func (*StorageRecord_StoryDistributionList) isStorageRecord_Record() {} func (*StorageRecord_CallLink) isStorageRecord_Record() {} type ContactRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Aci string `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` Pni string `protobuf:"bytes,15,opt,name=pni,proto3" json:"pni,omitempty"` @@ -848,6 +850,8 @@ type ContactRecord struct { PniSignatureVerified bool `protobuf:"varint,21,opt,name=pniSignatureVerified,proto3" json:"pniSignatureVerified,omitempty"` Nickname *ContactRecord_Name `protobuf:"bytes,22,opt,name=nickname,proto3" json:"nickname,omitempty"` Note string `protobuf:"bytes,23,opt,name=note,proto3" json:"note,omitempty"` // NEXT ID: 24 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ContactRecord) Reset() { @@ -1042,16 +1046,15 @@ func (x *ContactRecord) GetNote() string { } type GroupV1Record struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Blocked bool `protobuf:"varint,2,opt,name=blocked,proto3" json:"blocked,omitempty"` - Whitelisted bool `protobuf:"varint,3,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` - Archived bool `protobuf:"varint,4,opt,name=archived,proto3" json:"archived,omitempty"` - MarkedUnread bool `protobuf:"varint,5,opt,name=markedUnread,proto3" json:"markedUnread,omitempty"` - MutedUntilTimestamp uint64 `protobuf:"varint,6,opt,name=mutedUntilTimestamp,proto3" json:"mutedUntilTimestamp,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Blocked bool `protobuf:"varint,2,opt,name=blocked,proto3" json:"blocked,omitempty"` + Whitelisted bool `protobuf:"varint,3,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` + Archived bool `protobuf:"varint,4,opt,name=archived,proto3" json:"archived,omitempty"` + MarkedUnread bool `protobuf:"varint,5,opt,name=markedUnread,proto3" json:"markedUnread,omitempty"` + MutedUntilTimestamp uint64 `protobuf:"varint,6,opt,name=mutedUntilTimestamp,proto3" json:"mutedUntilTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupV1Record) Reset() { @@ -1127,10 +1130,7 @@ func (x *GroupV1Record) GetMutedUntilTimestamp() uint64 { } type GroupV2Record struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` MasterKey []byte `protobuf:"bytes,1,opt,name=masterKey,proto3" json:"masterKey,omitempty"` Blocked bool `protobuf:"varint,2,opt,name=blocked,proto3" json:"blocked,omitempty"` Whitelisted bool `protobuf:"varint,3,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` @@ -1140,6 +1140,8 @@ type GroupV2Record struct { DontNotifyForMentionsIfMuted bool `protobuf:"varint,7,opt,name=dontNotifyForMentionsIfMuted,proto3" json:"dontNotifyForMentionsIfMuted,omitempty"` HideStory bool `protobuf:"varint,8,opt,name=hideStory,proto3" json:"hideStory,omitempty"` StorySendMode GroupV2Record_StorySendMode `protobuf:"varint,10,opt,name=storySendMode,proto3,enum=signalservice.GroupV2Record_StorySendMode" json:"storySendMode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupV2Record) Reset() { @@ -1236,12 +1238,11 @@ func (x *GroupV2Record) GetStorySendMode() GroupV2Record_StorySendMode { } type Payments struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + Entropy []byte `protobuf:"bytes,2,opt,name=entropy,proto3" json:"entropy,omitempty"` unknownFields protoimpl.UnknownFields - - Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` - Entropy []byte `protobuf:"bytes,2,opt,name=entropy,proto3" json:"entropy,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Payments) Reset() { @@ -1289,10 +1290,7 @@ func (x *Payments) GetEntropy() []byte { } type AccountRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` GivenName string `protobuf:"bytes,2,opt,name=givenName,proto3" json:"givenName,omitempty"` FamilyName string `protobuf:"bytes,3,opt,name=familyName,proto3" json:"familyName,omitempty"` @@ -1327,6 +1325,8 @@ type AccountRecord struct { UsernameLink *AccountRecord_UsernameLink `protobuf:"bytes,35,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` BackupsSubscriberId []byte `protobuf:"bytes,36,opt,name=backupsSubscriberId,proto3" json:"backupsSubscriberId,omitempty"` BackupsSubscriberCurrencyCode string `protobuf:"bytes,37,opt,name=backupsSubscriberCurrencyCode,proto3" json:"backupsSubscriberCurrencyCode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountRecord) Reset() { @@ -1598,16 +1598,15 @@ func (x *AccountRecord) GetBackupsSubscriberCurrencyCode() string { } type StoryDistributionListRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - RecipientServiceIds []string `protobuf:"bytes,3,rep,name=recipientServiceIds,proto3" json:"recipientServiceIds,omitempty"` - DeletedAtTimestamp uint64 `protobuf:"varint,4,opt,name=deletedAtTimestamp,proto3" json:"deletedAtTimestamp,omitempty"` - AllowsReplies bool `protobuf:"varint,5,opt,name=allowsReplies,proto3" json:"allowsReplies,omitempty"` - IsBlockList bool `protobuf:"varint,6,opt,name=isBlockList,proto3" json:"isBlockList,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + RecipientServiceIds []string `protobuf:"bytes,3,rep,name=recipientServiceIds,proto3" json:"recipientServiceIds,omitempty"` + DeletedAtTimestamp uint64 `protobuf:"varint,4,opt,name=deletedAtTimestamp,proto3" json:"deletedAtTimestamp,omitempty"` + AllowsReplies bool `protobuf:"varint,5,opt,name=allowsReplies,proto3" json:"allowsReplies,omitempty"` + IsBlockList bool `protobuf:"varint,6,opt,name=isBlockList,proto3" json:"isBlockList,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StoryDistributionListRecord) Reset() { @@ -1683,13 +1682,12 @@ func (x *StoryDistributionListRecord) GetIsBlockList() bool { } type CallLinkRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` - AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` - DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` + AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` + DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CallLinkRecord) Reset() { @@ -1744,12 +1742,11 @@ func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 { } type ManifestRecord_Identifier struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Raw []byte `protobuf:"bytes,1,opt,name=raw,proto3" json:"raw,omitempty"` + Type ManifestRecord_Identifier_Type `protobuf:"varint,2,opt,name=type,proto3,enum=signalservice.ManifestRecord_Identifier_Type" json:"type,omitempty"` unknownFields protoimpl.UnknownFields - - Raw []byte `protobuf:"bytes,1,opt,name=raw,proto3" json:"raw,omitempty"` - Type ManifestRecord_Identifier_Type `protobuf:"varint,2,opt,name=type,proto3,enum=signalservice.ManifestRecord_Identifier_Type" json:"type,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ManifestRecord_Identifier) Reset() { @@ -1797,12 +1794,11 @@ func (x *ManifestRecord_Identifier) GetType() ManifestRecord_Identifier_Type { } type ContactRecord_Name struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Given string `protobuf:"bytes,1,opt,name=given,proto3" json:"given,omitempty"` + Family string `protobuf:"bytes,2,opt,name=family,proto3" json:"family,omitempty"` unknownFields protoimpl.UnknownFields - - Given string `protobuf:"bytes,1,opt,name=given,proto3" json:"given,omitempty"` - Family string `protobuf:"bytes,2,opt,name=family,proto3" json:"family,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ContactRecord_Name) Reset() { @@ -1850,16 +1846,15 @@ func (x *ContactRecord_Name) GetFamily() string { } type AccountRecord_PinnedConversation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Identifier: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Identifier: // // *AccountRecord_PinnedConversation_Contact_ // *AccountRecord_PinnedConversation_LegacyGroupId // *AccountRecord_PinnedConversation_GroupMasterKey - Identifier isAccountRecord_PinnedConversation_Identifier `protobuf_oneof:"identifier"` + Identifier isAccountRecord_PinnedConversation_Identifier `protobuf_oneof:"identifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountRecord_PinnedConversation) Reset() { @@ -1892,30 +1887,36 @@ func (*AccountRecord_PinnedConversation) Descriptor() ([]byte, []int) { return file_StorageService_proto_rawDescGZIP(), []int{11, 0} } -func (m *AccountRecord_PinnedConversation) GetIdentifier() isAccountRecord_PinnedConversation_Identifier { - if m != nil { - return m.Identifier +func (x *AccountRecord_PinnedConversation) GetIdentifier() isAccountRecord_PinnedConversation_Identifier { + if x != nil { + return x.Identifier } return nil } func (x *AccountRecord_PinnedConversation) GetContact() *AccountRecord_PinnedConversation_Contact { - if x, ok := x.GetIdentifier().(*AccountRecord_PinnedConversation_Contact_); ok { - return x.Contact + if x != nil { + if x, ok := x.Identifier.(*AccountRecord_PinnedConversation_Contact_); ok { + return x.Contact + } } return nil } func (x *AccountRecord_PinnedConversation) GetLegacyGroupId() []byte { - if x, ok := x.GetIdentifier().(*AccountRecord_PinnedConversation_LegacyGroupId); ok { - return x.LegacyGroupId + if x != nil { + if x, ok := x.Identifier.(*AccountRecord_PinnedConversation_LegacyGroupId); ok { + return x.LegacyGroupId + } } return nil } func (x *AccountRecord_PinnedConversation) GetGroupMasterKey() []byte { - if x, ok := x.GetIdentifier().(*AccountRecord_PinnedConversation_GroupMasterKey); ok { - return x.GroupMasterKey + if x != nil { + if x, ok := x.Identifier.(*AccountRecord_PinnedConversation_GroupMasterKey); ok { + return x.GroupMasterKey + } } return nil } @@ -1945,13 +1946,12 @@ func (*AccountRecord_PinnedConversation_GroupMasterKey) isAccountRecord_PinnedCo } type AccountRecord_UsernameLink struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Entropy []byte `protobuf:"bytes,1,opt,name=entropy,proto3" json:"entropy,omitempty"` // 32 bytes of entropy used for encryption + ServerId []byte `protobuf:"bytes,2,opt,name=serverId,proto3" json:"serverId,omitempty"` // 16 bytes of encoded UUID provided by the server + Color AccountRecord_UsernameLink_Color `protobuf:"varint,3,opt,name=color,proto3,enum=signalservice.AccountRecord_UsernameLink_Color" json:"color,omitempty"` unknownFields protoimpl.UnknownFields - - Entropy []byte `protobuf:"bytes,1,opt,name=entropy,proto3" json:"entropy,omitempty"` // 32 bytes of entropy used for encryption - ServerId []byte `protobuf:"bytes,2,opt,name=serverId,proto3" json:"serverId,omitempty"` // 16 bytes of encoded UUID provided by the server - Color AccountRecord_UsernameLink_Color `protobuf:"varint,3,opt,name=color,proto3,enum=signalservice.AccountRecord_UsernameLink_Color" json:"color,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AccountRecord_UsernameLink) Reset() { @@ -2006,12 +2006,11 @@ func (x *AccountRecord_UsernameLink) GetColor() AccountRecord_UsernameLink_Color } type AccountRecord_PinnedConversation_Contact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` + E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` unknownFields protoimpl.UnknownFields - - ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` - E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` + sizeCache protoimpl.SizeCache } func (x *AccountRecord_PinnedConversation_Contact) Reset() { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index e4eda97..1d1da9b 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: UnidentifiedDelivery.proto @@ -150,12 +150,11 @@ func (UnidentifiedSenderMessage_Message_ContentHint) EnumDescriptor() ([]byte, [ } type ServerCertificate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + 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 - - Certificate []byte `protobuf:"bytes,1,opt,name=certificate" json:"certificate,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ServerCertificate) Reset() { @@ -203,12 +202,11 @@ func (x *ServerCertificate) GetSignature() []byte { } type SenderCertificate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + 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 - - Certificate []byte `protobuf:"bytes,1,opt,name=certificate" json:"certificate,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + sizeCache protoimpl.SizeCache } func (x *SenderCertificate) Reset() { @@ -256,13 +254,12 @@ func (x *SenderCertificate) GetSignature() []byte { } type UnidentifiedSenderMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - 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"` + 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() { @@ -317,12 +314,11 @@ func (x *UnidentifiedSenderMessage) GetEncryptedMessage() []byte { } type ServerCertificate_Certificate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + 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 - - Id *uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Key []byte `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ServerCertificate_Certificate) Reset() { @@ -370,16 +366,15 @@ func (x *ServerCertificate_Certificate) GetKey() []byte { } type SenderCertificate_Certificate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + 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 - - 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"` + sizeCache protoimpl.SizeCache } func (x *SenderCertificate_Certificate) Reset() { @@ -455,15 +450,14 @@ func (x *SenderCertificate_Certificate) GetSigner() *ServerCertificate { } type UnidentifiedSenderMessage_Message struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + 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() { diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index 157c802..45d5396 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.2 +// protoc-gen-go v1.36.1 // protoc v3.21.12 // source: WebSocketResources.proto @@ -87,15 +87,14 @@ func (WebSocketMessage_Type) EnumDescriptor() ([]byte, []int) { } type WebSocketRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Verb *string `protobuf:"bytes,1,opt,name=verb" json:"verb,omitempty"` + Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"` + Body []byte `protobuf:"bytes,3,opt,name=body" json:"body,omitempty"` + Headers []string `protobuf:"bytes,5,rep,name=headers" json:"headers,omitempty"` + Id *uint64 `protobuf:"varint,4,opt,name=id" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Verb *string `protobuf:"bytes,1,opt,name=verb" json:"verb,omitempty"` - Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"` - Body []byte `protobuf:"bytes,3,opt,name=body" json:"body,omitempty"` - Headers []string `protobuf:"bytes,5,rep,name=headers" json:"headers,omitempty"` - Id *uint64 `protobuf:"varint,4,opt,name=id" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *WebSocketRequestMessage) Reset() { @@ -164,15 +163,14 @@ func (x *WebSocketRequestMessage) GetId() uint64 { } type WebSocketResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Status *uint32 `protobuf:"varint,2,opt,name=status" json:"status,omitempty"` + Message *string `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + Headers []string `protobuf:"bytes,5,rep,name=headers" json:"headers,omitempty"` + Body []byte `protobuf:"bytes,4,opt,name=body" json:"body,omitempty"` unknownFields protoimpl.UnknownFields - - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - Status *uint32 `protobuf:"varint,2,opt,name=status" json:"status,omitempty"` - Message *string `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` - Headers []string `protobuf:"bytes,5,rep,name=headers" json:"headers,omitempty"` - Body []byte `protobuf:"bytes,4,opt,name=body" json:"body,omitempty"` + sizeCache protoimpl.SizeCache } func (x *WebSocketResponseMessage) Reset() { @@ -241,13 +239,12 @@ func (x *WebSocketResponseMessage) GetBody() []byte { } type WebSocketMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *WebSocketMessage_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.WebSocketMessage_Type" json:"type,omitempty"` + Request *WebSocketRequestMessage `protobuf:"bytes,2,opt,name=request" json:"request,omitempty"` + Response *WebSocketResponseMessage `protobuf:"bytes,3,opt,name=response" json:"response,omitempty"` unknownFields protoimpl.UnknownFields - - Type *WebSocketMessage_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.WebSocketMessage_Type" json:"type,omitempty"` - Request *WebSocketRequestMessage `protobuf:"bytes,2,opt,name=request" json:"request,omitempty"` - Response *WebSocketResponseMessage `protobuf:"bytes,3,opt,name=response" json:"response,omitempty"` + sizeCache protoimpl.SizeCache } func (x *WebSocketMessage) Reset() { From 44f363fa4b2e5d149130e0df48beeee3d8f9ab36 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 7 Jan 2025 19:08:27 +0200 Subject: [PATCH 383/718] signalmeow/websocket: don't disconnect on first ping timeout --- pkg/signalmeow/web/signalwebsocket.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 3b192fb..4774b9f 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -195,8 +195,8 @@ func (s *SignalWebsocket) connectLoop( log.Warn().Dur("backoff", backoff).Msg("Failed to connect, waiting to retry...") time.Sleep(backoff) backoff += backoffIncrement - } else if !isFirstConnect { - time.Sleep(1 * time.Second) + } else if !isFirstConnect && s.basicAuth != nil { + time.Sleep(initialBackoff) } if ctx.Err() != nil { log.Info().Msg("ctx done, stopping connection loop") @@ -300,6 +300,7 @@ func (s *SignalWebsocket) connectLoop( ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() + pingTimeoutCount := 0 for { select { case <-ticker.C: @@ -307,11 +308,20 @@ func (s *SignalWebsocket) connectLoop( err := ws.Ping(pingCtx) cancel() if err != nil { + pingTimeoutCount++ log.Err(err).Msg("Error pinging") - loopCancel(err) - return + if pingTimeoutCount >= 5 { + log.Warn().Msg("Ping timeout count exceeded, closing websocket") + err = ws.Close(websocket.StatusNormalClosure, "Ping timeout") + if err != nil { + log.Err(err).Msg("Error closing websocket after ping timeout") + } + return + } + } else { + pingTimeoutCount = 0 + log.Trace().Msg("Sent keepalive") } - log.Trace().Msg("Sent keepalive") case <-loopCtx.Done(): return } From f986c8ec633f92823a2da1d963cd4c5b76515d98 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Jan 2025 16:57:54 +0200 Subject: [PATCH 384/718] capabilities: update to new format --- go.mod | 4 +- go.sum | 8 +- pkg/connector/capabilities.go | 166 ++++++++++++++++++++++++++++++++++ pkg/connector/client.go | 50 ++++------ pkg/connector/connector.go | 9 -- pkg/msgconv/from-matrix.go | 2 +- 6 files changed, 189 insertions(+), 50 deletions(-) create mode 100644 pkg/connector/capabilities.go diff --git a/go.mod b/go.mod index 554048c..36be8a9 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.4-0.20250106152331-30b8c95e7d7a + go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957 golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/net v0.34.0 google.golang.org/protobuf v1.36.2 - maunium.net/go/mautrix v0.22.2-0.20250107114437-ceb9c7b866e1 + maunium.net/go/mautrix v0.22.2-0.20250110145518-285106586976 ) require ( diff --git a/go.sum b/go.sum index 4d10fa9..4427ab3 100644 --- a/go.sum +++ b/go.sum @@ -67,8 +67,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.4-0.20250106152331-30b8c95e7d7a h1:D9RCHBFjxah9F/YB7amvRJjT2IEOFWcz8jpcEY8dBV0= -go.mau.fi/util v0.8.4-0.20250106152331-30b8c95e7d7a/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= +go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957 h1:tsLt3t6ARc55niz+JMgJy6U4sL210Z0K/nyxF09xT0E= +go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= @@ -97,5 +97,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.22.2-0.20250107114437-ceb9c7b866e1 h1:ECwjKJLKKsTp/gnp0Qd5GojeZOK/MLVFF0Tf7C6gZDQ= -maunium.net/go/mautrix v0.22.2-0.20250107114437-ceb9c7b866e1/go.mod h1:FmwzK7RSzrd1OfGDgJzFWXl7nYmYm8/P0Y77sy/A1Uw= +maunium.net/go/mautrix v0.22.2-0.20250110145518-285106586976 h1:I06GGTFPiwWTMuLoZCtTg2y9Oc3Qi85MzvS+9fgyCtg= +maunium.net/go/mautrix v0.22.2-0.20250110145518-285106586976/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go new file mode 100644 index 0000000..8a57f13 --- /dev/null +++ b/pkg/connector/capabilities.go @@ -0,0 +1,166 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "time" + + "go.mau.fi/util/ffmpeg" + "go.mau.fi/util/jsontime" + "go.mau.fi/util/ptr" + + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" +) + +func supportedIfFFmpeg() event.CapabilitySupportLevel { + if ffmpeg.Supported() { + return event.CapLevelPartialSupport + } + return event.CapLevelRejected +} + +func capID() string { + base := "fi.mau.signal.capabilities.2025_01_10" + if ffmpeg.Supported() { + return base + "+ffmpeg" + } + return base +} + +const MaxFileSize = 100 * 1024 * 1024 + +var signalCaps = &event.RoomFeatures{ + ID: capID(), + + Formatting: map[event.FormattingFeature]event.CapabilitySupportLevel{ + // Features that Signal supports natively + event.FmtBold: event.CapLevelFullySupported, + event.FmtItalic: event.CapLevelFullySupported, + event.FmtStrikethrough: event.CapLevelFullySupported, + event.FmtSpoiler: event.CapLevelFullySupported, + event.FmtInlineCode: event.CapLevelFullySupported, + event.FmtCodeBlock: event.CapLevelFullySupported, + event.FmtUserLink: event.CapLevelFullySupported, + + // Features that aren't supported on Signal, but are converted into a markdown-like representation + event.FmtBlockquote: event.CapLevelPartialSupport, + event.FmtInlineLink: event.CapLevelPartialSupport, + event.FmtUnorderedList: event.CapLevelPartialSupport, + event.FmtOrderedList: event.CapLevelPartialSupport, + event.FmtListStart: event.CapLevelPartialSupport, + event.FmtHeaders: event.CapLevelPartialSupport, + }, + File: map[event.CapabilityMsgType]*event.FileFeatures{ + event.MsgImage: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "image/gif": event.CapLevelFullySupported, + "image/png": event.CapLevelFullySupported, + "image/jpeg": event.CapLevelFullySupported, + }, + MaxWidth: 4096, + MaxHeight: 4096, + MaxSize: MaxFileSize, + }, + event.MsgVideo: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "video/mp4": event.CapLevelFullySupported, + "video/ogg": event.CapLevelFullySupported, + "video/webm": event.CapLevelFullySupported, + }, + MaxSize: MaxFileSize, + }, + event.MsgAudio: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "audio/aac": event.CapLevelFullySupported, + "audio/mpeg": event.CapLevelFullySupported, + }, + MaxSize: MaxFileSize, + }, + event.MsgFile: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "*/*": event.CapLevelFullySupported, + }, + MaxSize: MaxFileSize, + }, + event.CapMsgSticker: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "image/webp": event.CapLevelFullySupported, + "image/png": event.CapLevelFullySupported, + "image/apng": event.CapLevelFullySupported, + "image/gif": supportedIfFFmpeg(), + }, + Caption: event.CapLevelDropped, + MaxSize: MaxFileSize, + }, + event.CapMsgVoice: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "audio/aac": event.CapLevelFullySupported, + "audio/ogg": supportedIfFFmpeg(), + }, + Caption: event.CapLevelDropped, + MaxSize: MaxFileSize, + MaxDuration: ptr.Ptr(jsontime.S(1 * time.Hour)), + }, + }, + LocationMessage: event.CapLevelPartialSupport, + Poll: event.CapLevelRejected, + 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)), + Reaction: event.CapLevelFullySupported, + ReactionCount: 1, + AllowedReactions: nil, + CustomEmojiReactions: false, + ReadReceipts: true, + TypingNotifications: true, +} + +var signalCapsNoteToSelf *event.RoomFeatures + +func init() { + signalCapsNoteToSelf = ptr.Clone(signalCaps) + signalCapsNoteToSelf.EditMaxAge = nil + signalCapsNoteToSelf.ID = capID() + "+note_to_self" +} + +func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { + if portal.Receiver == s.UserLogin.ID && portal.ID == networkid.PortalID(s.UserLogin.ID) { + return signalCapsNoteToSelf + } + return signalCaps +} + +var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ + DisappearingMessages: true, + AggressiveUpdateInfo: true, +} + +func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { + return signalGeneralCaps +} + +func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { + return 1, 1 +} diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 8a8d415..3b0be20 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -1,3 +1,19 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + package connector import ( @@ -6,7 +22,6 @@ import ( "time" "github.com/rs/zerolog" - "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" @@ -22,39 +37,6 @@ type SignalClient struct { Ghost *bridgev2.Ghost } -var signalCaps = &bridgev2.NetworkRoomCapabilities{ - FormattedText: true, - UserMentions: true, - LocationMessages: true, - Captions: true, - Replies: true, - Edits: true, - EditMaxCount: 10, - EditMaxAge: 24 * time.Hour, - Deletes: true, - DeleteMaxAge: 24 * time.Hour, - DefaultFileRestriction: &bridgev2.FileRestriction{ - MaxSize: 100 * 1024 * 1024, - }, - ReadReceipts: true, - Reactions: true, - ReactionCount: 1, -} - -var signalCapsNoteToSelf *bridgev2.NetworkRoomCapabilities - -func init() { - signalCapsNoteToSelf = ptr.Clone(signalCaps) - signalCapsNoteToSelf.EditMaxAge = 0 -} - -func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *bridgev2.NetworkRoomCapabilities { - if portal.Receiver == s.UserLogin.ID && portal.ID == networkid.PortalID(s.UserLogin.ID) { - return signalCapsNoteToSelf - } - return signalCaps -} - var ( _ bridgev2.NetworkAPI = (*SignalClient)(nil) _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 1072983..f4fc7ae 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -40,15 +40,6 @@ type SignalConnector struct { var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) -var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ - DisappearingMessages: true, - AggressiveUpdateInfo: true, -} - -func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { - return signalGeneralCaps -} - func (s *SignalConnector) GetName() bridgev2.BridgeName { return bridgev2.BridgeName{ DisplayName: "Signal", diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index cb938e7..b91dcda 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -160,7 +160,7 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. fileName = content.FileName } mime := content.GetInfo().MimeType - if content.MSC3245Voice != nil && ffmpeg.Supported() { + if content.MSC3245Voice != nil && mime != "audio/aac" && ffmpeg.Supported() { data, err = ffmpeg.ConvertBytes(ctx, data, ".aac", []string{}, []string{"-c:a", "aac"}, mime) if err != nil { return nil, err From d205154aeda533313de41c9a4a4414a0562549dd Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Jan 2025 17:20:36 +0200 Subject: [PATCH 385/718] signalmeow/websocket: add log when ping stops failing --- pkg/signalmeow/web/signalwebsocket.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 4774b9f..4f817c8 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -309,7 +309,7 @@ func (s *SignalWebsocket) connectLoop( cancel() if err != nil { pingTimeoutCount++ - log.Err(err).Msg("Error pinging") + log.Err(err).Msg("Failed to send ping") if pingTimeoutCount >= 5 { log.Warn().Msg("Ping timeout count exceeded, closing websocket") err = ws.Close(websocket.StatusNormalClosure, "Ping timeout") @@ -318,8 +318,10 @@ func (s *SignalWebsocket) connectLoop( } return } - } else { + } else if pingTimeoutCount > 0 { pingTimeoutCount = 0 + log.Debug().Msg("Recovered from ping error") + } else { log.Trace().Msg("Sent keepalive") } case <-loopCtx.Done(): From 305d8499da188036f5e12e241bd015b0227cc9f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Jan 2025 18:26:44 +0200 Subject: [PATCH 386/718] capabilities: add text length limit --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/capabilities.go | 22 +++++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 36be8a9..88432c1 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/net v0.34.0 google.golang.org/protobuf v1.36.2 - maunium.net/go/mautrix v0.22.2-0.20250110145518-285106586976 + maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268 ) require ( diff --git a/go.sum b/go.sum index 4427ab3..570b3f9 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.22.2-0.20250110145518-285106586976 h1:I06GGTFPiwWTMuLoZCtTg2y9Oc3Qi85MzvS+9fgyCtg= -maunium.net/go/mautrix v0.22.2-0.20250110145518-285106586976/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4= +maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268 h1:p+3TofdhqiVYIkLjgzidayg2XriGUEbj+nbWs3/UQbk= +maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 8a57f13..9350180 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -37,7 +37,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_01_10" + base := "fi.mau.signal.capabilities.2025_01_10-2" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -45,6 +45,7 @@ func capID() string { } const MaxFileSize = 100 * 1024 * 1024 +const MaxTextLength = 2000 var signalCaps = &event.RoomFeatures{ ID: capID(), @@ -74,9 +75,11 @@ var signalCaps = &event.RoomFeatures{ "image/png": event.CapLevelFullySupported, "image/jpeg": event.CapLevelFullySupported, }, - MaxWidth: 4096, - MaxHeight: 4096, - MaxSize: MaxFileSize, + MaxWidth: 4096, + MaxHeight: 4096, + MaxSize: MaxFileSize, + Caption: event.CapLevelFullySupported, + MaxCaptionLength: MaxTextLength, }, event.MsgVideo: { MimeTypes: map[string]event.CapabilitySupportLevel{ @@ -84,7 +87,9 @@ var signalCaps = &event.RoomFeatures{ "video/ogg": event.CapLevelFullySupported, "video/webm": event.CapLevelFullySupported, }, - MaxSize: MaxFileSize, + MaxSize: MaxFileSize, + Caption: event.CapLevelFullySupported, + MaxCaptionLength: MaxTextLength, }, event.MsgAudio: { MimeTypes: map[string]event.CapabilitySupportLevel{ @@ -97,7 +102,9 @@ var signalCaps = &event.RoomFeatures{ MimeTypes: map[string]event.CapabilitySupportLevel{ "*/*": event.CapLevelFullySupported, }, - MaxSize: MaxFileSize, + MaxSize: MaxFileSize, + Caption: event.CapLevelFullySupported, + MaxCaptionLength: MaxTextLength, }, event.CapMsgSticker: { MimeTypes: map[string]event.CapabilitySupportLevel{ @@ -119,6 +126,7 @@ var signalCaps = &event.RoomFeatures{ MaxDuration: ptr.Ptr(jsontime.S(1 * time.Hour)), }, }, + MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files LocationMessage: event.CapLevelPartialSupport, Poll: event.CapLevelRejected, Thread: event.CapLevelUnsupported, @@ -162,5 +170,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 1 + return 1, 2 } From e19843f3f381e8d11bb8e605be4e2ed56e5fd9ee Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 14 Jan 2025 14:09:43 +0200 Subject: [PATCH 387/718] msgconv: add support for mp4 gifs in both directions --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/capabilities.go | 10 +++++++++- pkg/msgconv/from-matrix.go | 3 +++ pkg/msgconv/from-signal.go | 20 ++++++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 88432c1..ef61db9 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/net v0.34.0 google.golang.org/protobuf v1.36.2 - maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268 + maunium.net/go/mautrix v0.22.2-0.20250113200949-53a56684d3d3 ) require ( diff --git a/go.sum b/go.sum index 570b3f9..e9bd1dd 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.22.2-0.20250110154103-bbcb1904e268 h1:p+3TofdhqiVYIkLjgzidayg2XriGUEbj+nbWs3/UQbk= -maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4= +maunium.net/go/mautrix v0.22.2-0.20250113200949-53a56684d3d3 h1:ouuSo9unoAHaEze2hOo7z7lQG+rTjxhvXlXngExQwqg= +maunium.net/go/mautrix v0.22.2-0.20250113200949-53a56684d3d3/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 9350180..986e46d 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -37,7 +37,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_01_10-2" + base := "fi.mau.signal.capabilities.2025_01_14" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -125,6 +125,14 @@ var signalCaps = &event.RoomFeatures{ MaxSize: MaxFileSize, MaxDuration: ptr.Ptr(jsontime.S(1 * time.Hour)), }, + event.CapMsgGIF: { + MimeTypes: map[string]event.CapabilitySupportLevel{ + "image/gif": event.CapLevelFullySupported, + "video/mp4": event.CapLevelFullySupported, + }, + Caption: event.CapLevelFullySupported, + MaxSize: MaxFileSize, + }, }, MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files LocationMessage: event.CapLevelPartialSupport, diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index b91dcda..8edf40f 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -193,6 +193,9 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. if content.MSC3245Voice != nil && mime == "audio/aac" { att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_VOICE_MESSAGE)) } + if content.Info.MauGIF { + att.Flags = proto.Uint32(uint32(compatFlagGIF)) + } att.ContentType = proto.String(mime) att.FileName = &fileName att.Height = maybeInt(uint32(content.Info.Height)) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 486bde1..a7ceb0d 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -70,6 +70,13 @@ func CanConvertSignal(dm *signalpb.DataMessage) bool { const ViewOnceDisappearTimer = 5 * time.Minute +// Why does signal have two different flags for gifs?? +// https://github.com/signalapp/Signal-Android/blob/v7.29.4/libsignal-service/src/main/protowire/SignalService.proto#L745 +// https://github.com/signalapp/Signal-Desktop/blob/v7.38.0-beta.1/protos/SignalService.proto#L740 +// https://github.com/signalapp/Signal-iOS/blob/7.42.0.545-beta/SignalServiceKit/protobuf/SignalService.proto#L756 +// Apparently the android one is a lie and doesn't work? +const compatFlagGIF = 8 + func (mc *MessageConverter) ToMatrix( ctx context.Context, client *signalmeow.Client, @@ -478,6 +485,18 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp default: content.MsgType = event.MsgFile } + var extra map[string]any + if att.GetFlags()&uint32(compatFlagGIF) != 0 { + content.Info.MauGIF = true + extra = map[string]any{ + "info": map[string]any{ + "fi.mau.loop": true, + "fi.mau.autoplay": true, + "fi.mau.hide_controls": true, + "fi.mau.no_audio": true, + }, + } + } content.Body = fileName content.Info.MimeType = mimeType if content.Body == "" { @@ -486,5 +505,6 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: content, + Extra: extra, }, nil } From 53ad7fa43f7a382788b9cd0753e993a84389d7ae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 14 Jan 2025 14:13:46 +0200 Subject: [PATCH 388/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/StorageService.pb.go | 155 +++++++++++++++--- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 5964 -> 6238 bytes pkg/signalmeow/protobuf/StorageService.proto | 89 +++++----- pkg/signalmeow/protobuf/build-protos.sh | 1 + pkg/signalmeow/protobuf/update-protos.sh | 4 +- 5 files changed, 187 insertions(+), 62 deletions(-) diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index ee6fbef..a371ea9 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -1323,8 +1323,9 @@ type AccountRecord struct { Username string `protobuf:"bytes,33,opt,name=username,proto3" json:"username,omitempty"` HasCompletedUsernameOnboarding bool `protobuf:"varint,34,opt,name=hasCompletedUsernameOnboarding,proto3" json:"hasCompletedUsernameOnboarding,omitempty"` UsernameLink *AccountRecord_UsernameLink `protobuf:"bytes,35,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` - BackupsSubscriberId []byte `protobuf:"bytes,36,opt,name=backupsSubscriberId,proto3" json:"backupsSubscriberId,omitempty"` - BackupsSubscriberCurrencyCode string `protobuf:"bytes,37,opt,name=backupsSubscriberCurrencyCode,proto3" json:"backupsSubscriberCurrencyCode,omitempty"` + HasBackup *bool `protobuf:"varint,39,opt,name=hasBackup,proto3,oneof" json:"hasBackup,omitempty"` // Set to true after backups are enabled and one is uploaded. + BackupTier *uint64 `protobuf:"varint,40,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` // See zkgroup for integer particular values + BackupSubscriberData *AccountRecord_IAPSubscriberData `protobuf:"bytes,41,opt,name=backupSubscriberData,proto3" json:"backupSubscriberData,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1583,18 +1584,25 @@ func (x *AccountRecord) GetUsernameLink() *AccountRecord_UsernameLink { return nil } -func (x *AccountRecord) GetBackupsSubscriberId() []byte { - if x != nil { - return x.BackupsSubscriberId +func (x *AccountRecord) GetHasBackup() bool { + if x != nil && x.HasBackup != nil { + return *x.HasBackup } - return nil + return false } -func (x *AccountRecord) GetBackupsSubscriberCurrencyCode() string { - if x != nil { - return x.BackupsSubscriberCurrencyCode +func (x *AccountRecord) GetBackupTier() uint64 { + if x != nil && x.BackupTier != nil { + return *x.BackupTier } - return "" + return 0 +} + +func (x *AccountRecord) GetBackupSubscriberData() *AccountRecord_IAPSubscriberData { + if x != nil { + return x.BackupSubscriberData + } + return nil } type StoryDistributionListRecord struct { @@ -2005,6 +2013,100 @@ func (x *AccountRecord_UsernameLink) GetColor() AccountRecord_UsernameLink_Color return AccountRecord_UsernameLink_UNKNOWN } +type AccountRecord_IAPSubscriberData struct { + state protoimpl.MessageState `protogen:"open.v1"` + SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` + // Types that are valid to be assigned to IapSubscriptionId: + // + // *AccountRecord_IAPSubscriberData_PurchaseToken + // *AccountRecord_IAPSubscriberData_OriginalTransactionId + IapSubscriptionId isAccountRecord_IAPSubscriberData_IapSubscriptionId `protobuf_oneof:"iapSubscriptionId"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountRecord_IAPSubscriberData) Reset() { + *x = AccountRecord_IAPSubscriberData{} + mi := &file_StorageService_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountRecord_IAPSubscriberData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord_IAPSubscriberData) ProtoMessage() {} + +func (x *AccountRecord_IAPSubscriberData) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[18] + 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 AccountRecord_IAPSubscriberData.ProtoReflect.Descriptor instead. +func (*AccountRecord_IAPSubscriberData) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 2} +} + +func (x *AccountRecord_IAPSubscriberData) GetSubscriberId() []byte { + if x != nil { + return x.SubscriberId + } + return nil +} + +func (x *AccountRecord_IAPSubscriberData) GetIapSubscriptionId() isAccountRecord_IAPSubscriberData_IapSubscriptionId { + if x != nil { + return x.IapSubscriptionId + } + return nil +} + +func (x *AccountRecord_IAPSubscriberData) GetPurchaseToken() string { + if x != nil { + if x, ok := x.IapSubscriptionId.(*AccountRecord_IAPSubscriberData_PurchaseToken); ok { + return x.PurchaseToken + } + } + return "" +} + +func (x *AccountRecord_IAPSubscriberData) GetOriginalTransactionId() uint64 { + if x != nil { + if x, ok := x.IapSubscriptionId.(*AccountRecord_IAPSubscriberData_OriginalTransactionId); ok { + return x.OriginalTransactionId + } + } + return 0 +} + +type isAccountRecord_IAPSubscriberData_IapSubscriptionId interface { + isAccountRecord_IAPSubscriberData_IapSubscriptionId() +} + +type AccountRecord_IAPSubscriberData_PurchaseToken struct { + // Identifies an Android Play Store IAP subscription. + PurchaseToken string `protobuf:"bytes,2,opt,name=purchaseToken,proto3,oneof"` +} + +type AccountRecord_IAPSubscriberData_OriginalTransactionId struct { + // Identifies an iOS App Store IAP subscription. + OriginalTransactionId uint64 `protobuf:"varint,3,opt,name=originalTransactionId,proto3,oneof"` +} + +func (*AccountRecord_IAPSubscriberData_PurchaseToken) isAccountRecord_IAPSubscriberData_IapSubscriptionId() { +} + +func (*AccountRecord_IAPSubscriberData_OriginalTransactionId) isAccountRecord_IAPSubscriberData_IapSubscriptionId() { +} + type AccountRecord_PinnedConversation_Contact struct { state protoimpl.MessageState `protogen:"open.v1"` ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` @@ -2015,7 +2117,7 @@ type AccountRecord_PinnedConversation_Contact struct { func (x *AccountRecord_PinnedConversation_Contact) Reset() { *x = AccountRecord_PinnedConversation_Contact{} - mi := &file_StorageService_proto_msgTypes[18] + mi := &file_StorageService_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2027,7 +2129,7 @@ func (x *AccountRecord_PinnedConversation_Contact) String() string { func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[18] + mi := &file_StorageService_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2075,7 +2177,7 @@ func file_StorageService_proto_rawDescGZIP() []byte { } var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 20) var file_StorageService_proto_goTypes = []any{ (OptionalBool)(0), // 0: signalservice.OptionalBool (ManifestRecord_Identifier_Type)(0), // 1: signalservice.ManifestRecord.Identifier.Type @@ -2101,7 +2203,8 @@ var file_StorageService_proto_goTypes = []any{ (*ContactRecord_Name)(nil), // 21: signalservice.ContactRecord.Name (*AccountRecord_PinnedConversation)(nil), // 22: signalservice.AccountRecord.PinnedConversation (*AccountRecord_UsernameLink)(nil), // 23: signalservice.AccountRecord.UsernameLink - (*AccountRecord_PinnedConversation_Contact)(nil), // 24: signalservice.AccountRecord.PinnedConversation.Contact + (*AccountRecord_IAPSubscriberData)(nil), // 24: signalservice.AccountRecord.IAPSubscriberData + (*AccountRecord_PinnedConversation_Contact)(nil), // 25: signalservice.AccountRecord.PinnedConversation.Contact } var file_StorageService_proto_depIdxs = []int32{ 7, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem @@ -2122,14 +2225,15 @@ var file_StorageService_proto_depIdxs = []int32{ 16, // 15: signalservice.AccountRecord.payments:type_name -> signalservice.Payments 0, // 16: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool 23, // 17: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink - 1, // 18: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type - 24, // 19: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact - 5, // 20: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color - 21, // [21:21] is the sub-list for method output_type - 21, // [21:21] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 24, // 18: signalservice.AccountRecord.backupSubscriberData:type_name -> signalservice.AccountRecord.IAPSubscriberData + 1, // 19: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type + 25, // 20: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact + 5, // 21: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color + 22, // [22:22] is the sub-list for method output_type + 22, // [22:22] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name } func init() { file_StorageService_proto_init() } @@ -2145,18 +2249,23 @@ func file_StorageService_proto_init() { (*StorageRecord_StoryDistributionList)(nil), (*StorageRecord_CallLink)(nil), } + file_StorageService_proto_msgTypes[11].OneofWrappers = []any{} file_StorageService_proto_msgTypes[16].OneofWrappers = []any{ (*AccountRecord_PinnedConversation_Contact_)(nil), (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), } + file_StorageService_proto_msgTypes[18].OneofWrappers = []any{ + (*AccountRecord_IAPSubscriberData_PurchaseToken)(nil), + (*AccountRecord_IAPSubscriberData_OriginalTransactionId)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_StorageService_proto_rawDesc, NumEnums: 6, - NumMessages: 19, + NumMessages: 20, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw index 8f93e74982fe1059f03f61ad98f60995b00294e5..9c6689d9adaa8592bc569b23dfe69630c4881315 100644 GIT binary patch delta 428 zcmX@3ch6wMPHv_pqMLVfA7)Ee26QCyb zQUKAUx6=sUn~X SBvl2}fTWs$`et9z|BL_xoq!Ag delta 143 zcmca-a7J&#PHv`2!kc$ Date: Wed, 15 Jan 2025 23:40:50 +0200 Subject: [PATCH 389/718] signalmeow: update websocket auth --- pkg/signalmeow/client.go | 9 ++------- pkg/signalmeow/contactdiscovery.go | 2 +- pkg/signalmeow/provisioning.go | 12 ++++++++++-- pkg/signalmeow/web/signalwebsocket.go | 28 ++++++++++++--------------- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index fcb463a..8f44db0 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -84,12 +84,7 @@ func (cli *Client) ConnectAuthedWS(ctx context.Context, requestHandler web.Reque Str("username", username). Logger() ctx = log.WithContext(ctx) - username = url.QueryEscape(username) - password = url.QueryEscape(password) - path := web.WebsocketPath + - "?login=" + username + - "&password=" + password - authedWS := web.NewSignalWebsocket(path, &username, &password) + authedWS := web.NewSignalWebsocket(url.UserPassword(username, password)) statusChan := authedWS.Connect(ctx, &requestHandler) cli.AuthedWS = authedWS return statusChan, nil @@ -104,7 +99,7 @@ func (cli *Client) ConnectUnauthedWS(ctx context.Context) (chan web.SignalWebsoc Str("websocket_type", "unauthed"). Logger() ctx = log.WithContext(ctx) - unauthedWS := web.NewSignalWebsocket(web.WebsocketPath, nil, nil) + unauthedWS := web.NewSignalWebsocket(nil) statusChan := unauthedWS.Connect(ctx, nil) cli.UnauthedWS = unauthedWS return statusChan, nil diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index b732339..33b0ad3 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -111,7 +111,7 @@ func (cli *Client) doContactDiscovery(ctx context.Context, req *signalpb.CDSClie Path: path.Join("v1", ProdContactDiscoveryMrenclave, "discovery"), }).String() log.Trace().Msg("Connecting to contact discovery websocket") - ws, _, err := web.OpenWebsocketURL(ctx, addr) + ws, _, err := web.OpenWebsocket(ctx, addr) if err != nil { var closeErr websocket.CloseError if errors.As(err, &closeErr) && closeErr.Code == rateLimitCloseCode { diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 507f5d9..4aedc44 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -87,7 +87,11 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev timeoutCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() - ws, resp, err := web.OpenWebsocket(timeoutCtx, web.WebsocketProvisioningPath) + ws, resp, err := web.OpenWebsocket(timeoutCtx, (&url.URL{ + Scheme: "wss", + Host: web.APIHostname, + Path: web.WebsocketProvisioningPath, + }).String()) if err != nil { log.Err(err).Any("resp", resp).Msg("error opening provisioning websocket") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} @@ -388,7 +392,11 @@ func confirmDevice( return nil, fmt.Errorf("failed to encrypt device name: %w", err) } - ws, resp, err := web.OpenWebsocket(ctx, web.WebsocketPath) + ws, resp, err := web.OpenWebsocket(ctx, (&url.URL{ + Scheme: "wss", + Host: web.APIHostname, + Path: web.WebsocketPath, + }).String()) if err != nil { log.Err(err).Any("resp", resp).Msg("error opening websocket") return nil, err diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 4f817c8..c273c31 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "net/http" + "net/url" "strings" "sync" "time" @@ -43,20 +44,13 @@ type RequestHandlerFunc func(context.Context, *signalpb.WebSocketRequestMessage) type SignalWebsocket struct { ws *websocket.Conn - path string - basicAuth *string + basicAuth *url.Userinfo sendChannel chan SignalWebsocketSendMessage statusChannel chan SignalWebsocketConnectionStatus } -func NewSignalWebsocket(path string, username *string, password *string) *SignalWebsocket { - var basicAuth *string - if username != nil && password != nil { - b := base64.StdEncoding.EncodeToString([]byte(*username + ":" + *password)) - basicAuth = &b - } +func NewSignalWebsocket(basicAuth *url.Userinfo) *SignalWebsocket { return &SignalWebsocket{ - path: path, basicAuth: basicAuth, sendChannel: make(chan SignalWebsocketSendMessage), statusChannel: make(chan SignalWebsocketConnectionStatus), @@ -187,6 +181,12 @@ func (s *SignalWebsocket) connectLoop( retrying := false errorCount := 0 isFirstConnect := true + wsURL := (&url.URL{ + Scheme: "wss", + Host: APIHostname, + Path: WebsocketPath, + User: s.basicAuth, + }).String() for { if retrying { if backoff > maxBackoff { @@ -204,7 +204,7 @@ func (s *SignalWebsocket) connectLoop( } isFirstConnect = false - ws, resp, err := OpenWebsocket(ctx, s.path) + ws, resp, err := OpenWebsocket(ctx, wsURL) if resp != nil { if resp.StatusCode != 101 { // Server didn't want to open websocket @@ -555,7 +555,7 @@ func (s *SignalWebsocket) sendRequestInternal( retryCount int, ) (*signalpb.WebSocketResponseMessage, error) { if s.basicAuth != nil { - request.Headers = append(request.Headers, "authorization:Basic "+*s.basicAuth) + request.Headers = append(request.Headers, "authorization:Basic "+s.basicAuth.String()) } responseChannel := make(chan *signalpb.WebSocketResponseMessage, 1) if s.sendChannel == nil { @@ -590,11 +590,7 @@ func (s *SignalWebsocket) sendRequestInternal( return response, nil } -func OpenWebsocket(ctx context.Context, path string) (*websocket.Conn, *http.Response, error) { - return OpenWebsocketURL(ctx, "wss://"+APIHostname+path) -} - -func OpenWebsocketURL(ctx context.Context, url string) (*websocket.Conn, *http.Response, error) { +func OpenWebsocket(ctx context.Context, url string) (*websocket.Conn, *http.Response, error) { opt := &websocket.DialOptions{ HTTPClient: SignalHTTPClient, HTTPHeader: make(http.Header, 2), From 0083384814c820afe3bd7ddc6a593fece9265b30 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 16 Jan 2025 14:40:30 +0200 Subject: [PATCH 390/718] Bump version to v0.7.5 --- CHANGELOG.md | 8 ++++++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 12 ++++++------ go.sum | 21 ++++++++++++--------- pkg/connector/capabilities.go | 4 +++- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c2ef6c..da0850e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# v0.7.5 (2025-01-16) + +* Added support for bridging mp4 gifs in both directions. +* Added support for signaling supported features to clients using the + `com.beeper.room_features` state event. +* Updated Signal websocket authentication method. +* Fixed some cases where websocket would get stuck after a ping timeout. + # v0.7.4 (2024-12-16) * Fixed syncing server-side storage after Signal login. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 61d22dd..1cd74ce 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.4", + Version: "0.7.5", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index ef61db9..f4eaf6a 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957 + go.mau.fi/util v0.8.4 golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/net v0.34.0 - google.golang.org/protobuf v1.36.2 - maunium.net/go/mautrix v0.22.2-0.20250113200949-53a56684d3d3 + google.golang.org/protobuf v1.36.3 + maunium.net/go/mautrix v0.23.0 ) require ( @@ -28,8 +28,8 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // 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.24 // indirect github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -37,7 +37,7 @@ require ( github.com/rs/xid v1.6.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty 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.7.8 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect diff --git a/go.sum b/go.sum index e9bd1dd..1ee4934 100644 --- a/go.sum +++ b/go.sum @@ -29,11 +29,13 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-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.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= @@ -61,14 +63,15 @@ github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +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.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957 h1:tsLt3t6ARc55niz+JMgJy6U4sL210Z0K/nyxF09xT0E= -go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= +go.mau.fi/util v0.8.4 h1:mVKlJcXWfVo8ZW3f4vqtjGpqtZqJvX4ETekxawt2vnQ= +go.mau.fi/util v0.8.4/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= @@ -86,8 +89,8 @@ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= -google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -97,5 +100,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.22.2-0.20250113200949-53a56684d3d3 h1:ouuSo9unoAHaEze2hOo7z7lQG+rTjxhvXlXngExQwqg= -maunium.net/go/mautrix v0.22.2-0.20250113200949-53a56684d3d3/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4= +maunium.net/go/mautrix v0.23.0 h1:HNlR19eew5lvrNSL2muhExaGhYdaGk5FfEiA82QqUP4= +maunium.net/go/mautrix v0.23.0/go.mod h1:AGnnaz3ylGikUo1I1MJVn9QLsl2No1/ZNnGDyO0QD5s= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 986e46d..1be2d45 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -37,7 +37,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_01_14" + base := "fi.mau.signal.capabilities.2025_01_16" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -74,6 +74,8 @@ var signalCaps = &event.RoomFeatures{ "image/gif": event.CapLevelFullySupported, "image/png": event.CapLevelFullySupported, "image/jpeg": event.CapLevelFullySupported, + "image/webp": event.CapLevelFullySupported, + "image/bmp": event.CapLevelFullySupported, }, MaxWidth: 4096, MaxHeight: 4096, From aca0ee20e8793810b8ccce8a65819e306881c2b2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 16 Jan 2025 16:29:51 +0200 Subject: [PATCH 391/718] client: add support for connect-once background resync interface --- pkg/connector/client.go | 42 ++++++++++++++++++++++++++++++++ pkg/connector/connector.go | 3 +++ pkg/connector/handlesignal.go | 4 +++ pkg/signalmeow/client.go | 4 +-- pkg/signalmeow/events/message.go | 3 +++ pkg/signalmeow/receiving.go | 17 +++++++++++-- 6 files changed, 69 insertions(+), 4 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 3b0be20..2f2925c 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -22,12 +22,14 @@ import ( "time" "github.com/rs/zerolog" + "go.mau.fi/util/exsync" "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) type SignalClient struct { @@ -35,6 +37,8 @@ type SignalClient struct { UserLogin *bridgev2.UserLogin Client *signalmeow.Client Ghost *bridgev2.Ghost + + queueEmptyWaiter *exsync.Event } var ( @@ -51,6 +55,7 @@ var ( _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) ) var pushCfg = &bridgev2.PushConfig{ @@ -210,6 +215,43 @@ func (s *SignalClient) Connect(ctx context.Context) { s.tryConnect(ctx, 0) } +func (s *SignalClient) ConnectBackground(ctx context.Context) error { + s.queueEmptyWaiter.Clear() + ch, err := s.Client.StartAuthedWS(ctx) + if err != nil { + return err + } + defer s.Disconnect() + log := zerolog.Ctx(ctx) + queueEmpty := s.queueEmptyWaiter.GetChan() + for { + select { + case status := <-ch: + switch status.Event { + case web.SignalWebsocketConnectionEventConnected: + log.Info().Msg("Authed websocket connected") + case web.SignalWebsocketConnectionEventDisconnected: + log.Err(status.Err).Msg("Authed websocket disconnected") + return fmt.Errorf("authed websocket disconnected: %w", status.Err) + case web.SignalWebsocketConnectionEventLoggedOut: + log.Err(status.Err).Msg("Authed websocket logged out") + return fmt.Errorf("authed websocket logged out: %w", status.Err) + case web.SignalWebsocketConnectionEventError: + log.Err(status.Err).Msg("Authed websocket error") + return fmt.Errorf("authed websocket errored: %w", status.Err) + case web.SignalWebsocketConnectionEventCleanShutdown: + log.Info().Msg("Authed websocket clean shutdown") + } + case <-ctx.Done(): + log.Warn().Msg("Context finished before queue empty event") + return ctx.Err() + case <-queueEmpty: + log.Info().Msg("Received queue empty event") + return nil + } + } +} + func (s *SignalClient) Disconnect() { if s.Client == nil { return diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index f4fc7ae..229d4ea 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -23,6 +23,7 @@ import ( "github.com/google/uuid" "go.mau.fi/util/dbutil" + "go.mau.fi/util/exsync" "maunium.net/go/mautrix/bridgev2" "go.mau.fi/mautrix-signal/pkg/msgconv" @@ -89,6 +90,8 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use sc := &SignalClient{ Main: s, UserLogin: login, + + queueEmptyWaiter: exsync.NewEvent(), } if device != nil { sc.Client = &signalmeow.Client{ diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 1984862..d39f250 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -52,6 +52,10 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { s.handleSignalContactList(evt) case *events.ACIFound: s.handleSignalACIFound(evt) + case *events.QueueEmpty: + s.queueEmptyWaiter.Set() + default: + s.UserLogin.Log.Warn().Type("event_type", evt).Msg("Unrecognized signalmeow event type") } } diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 8f44db0..7ef1abb 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -73,7 +73,7 @@ func (cli *Client) IsConnected() bool { return cli.AuthedWS.IsConnected() && cli.UnauthedWS.IsConnected() } -func (cli *Client) ConnectAuthedWS(ctx context.Context, requestHandler web.RequestHandlerFunc) (chan web.SignalWebsocketConnectionStatus, error) { +func (cli *Client) connectAuthedWS(ctx context.Context, requestHandler web.RequestHandlerFunc) (chan web.SignalWebsocketConnectionStatus, error) { if cli.AuthedWS != nil { return nil, errors.New("authed websocket already connected") } @@ -90,7 +90,7 @@ func (cli *Client) ConnectAuthedWS(ctx context.Context, requestHandler web.Reque return statusChan, nil } -func (cli *Client) ConnectUnauthedWS(ctx context.Context) (chan web.SignalWebsocketConnectionStatus, error) { +func (cli *Client) connectUnauthedWS(ctx context.Context) (chan web.SignalWebsocketConnectionStatus, error) { if cli.UnauthedWS != nil { return nil, errors.New("unauthed websocket already connected") } diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 0038657..9b8e79d 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -35,6 +35,7 @@ func (*ReadSelf) isSignalEvent() {} func (*Call) isSignalEvent() {} func (*ContactList) isSignalEvent() {} func (*ACIFound) isSignalEvent() {} +func (*QueueEmpty) isSignalEvent() {} type MessageInfo struct { Sender uuid.UUID @@ -78,3 +79,5 @@ type ACIFound struct { PNI libsignalgo.ServiceID ACI libsignalgo.ServiceID } + +type QueueEmpty struct{} diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index b1dddea..4d913e2 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -68,17 +68,29 @@ type SignalConnectionStatus struct { Err error } +func (cli *Client) StartAuthedWS(ctx context.Context) (chan web.SignalWebsocketConnectionStatus, error) { + ctx, cancel := context.WithCancel(ctx) + cli.WSCancel = cancel + authChan, err := cli.connectAuthedWS(ctx, cli.incomingRequestHandler) + if err != nil { + cancel() + return nil, err + } + zerolog.Ctx(ctx).Info().Msg("Authed websocket connecting") + return authChan, nil +} + func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnectionStatus, error) { log := zerolog.Ctx(ctx).With().Str("action", "start receive loops").Logger() ctx, cancel := context.WithCancel(log.WithContext(ctx)) cli.WSCancel = cancel - authChan, err := cli.ConnectAuthedWS(ctx, cli.incomingRequestHandler) + authChan, err := cli.connectAuthedWS(ctx, cli.incomingRequestHandler) if err != nil { cancel() return nil, err } log.Info().Msg("Authed websocket connecting") - unauthChan, err := cli.ConnectUnauthedWS(ctx) + unauthChan, err := cli.connectUnauthedWS(ctx) if err != nil { cancel() return nil, err @@ -257,6 +269,7 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web return cli.incomingAPIMessageHandler(ctx, req) } else if *req.Verb == http.MethodPut && *req.Path == "/api/v1/queue/empty" { log.Trace().Msg("Received queue empty") + cli.handleEvent(&events.QueueEmpty{}) } else { log.Warn().Any("req", req).Msg("Unknown websocket request message") } From 33905f74ac051918e824d163aa0c78fc335c5148 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 17 Jan 2025 17:49:37 +0200 Subject: [PATCH 392/718] libsignal: update to v0.65.2 --- go.mod | 2 +- pkg/libsignalgo/address.go | 25 +- pkg/libsignalgo/aes256gcmsiv.go | 31 +- pkg/libsignalgo/authcredential.go | 5 +- pkg/libsignalgo/ciphertextmessage.go | 24 +- pkg/libsignalgo/decryptionerrormessage.go | 54 +- pkg/libsignalgo/fingerprint.go | 35 +- pkg/libsignalgo/groupcipher.go | 9 +- pkg/libsignalgo/groupsecretparams.go | 3 +- pkg/libsignalgo/hsmenclave.go | 29 +- pkg/libsignalgo/identitykey.go | 31 +- pkg/libsignalgo/identitykeystore.go | 7 +- pkg/libsignalgo/kyberprekey.go | 99 +- pkg/libsignalgo/kyberprekeystore.go | 7 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 1334 +++++++++++------ pkg/libsignalgo/message.go | 63 +- pkg/libsignalgo/plaintextcontent.go | 37 +- pkg/libsignalgo/prekey.go | 52 +- pkg/libsignalgo/prekeybundle.go | 39 +- pkg/libsignalgo/prekeymessage.go | 49 +- pkg/libsignalgo/prekeystore.go | 7 +- pkg/libsignalgo/privatekey.go | 37 +- pkg/libsignalgo/profilekey.go | 5 +- pkg/libsignalgo/protocol.go | 49 - pkg/libsignalgo/publickey.go | 34 +- pkg/libsignalgo/sealedsender.go | 51 +- pkg/libsignalgo/sendercertificate.go | 72 +- .../senderkeydistributionmessage.go | 31 +- pkg/libsignalgo/senderkeyrecord.go | 23 +- pkg/libsignalgo/senderkeystore.go | 7 +- pkg/libsignalgo/servercertificate.go | 46 +- pkg/libsignalgo/serverpublicparams.go | 12 +- pkg/libsignalgo/sessionrecord.go | 44 +- pkg/libsignalgo/sessionstore.go | 7 +- pkg/libsignalgo/sgxclient.go | 30 +- pkg/libsignalgo/signedprekey.go | 57 +- pkg/libsignalgo/signedprekeystore.go | 7 +- pkg/libsignalgo/version.go | 2 +- 39 files changed, 1626 insertions(+), 832 deletions(-) delete mode 100644 pkg/libsignalgo/protocol.go diff --git a/go.mod b/go.mod index f4eaf6a..040c374 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.22.0 -toolchain go1.23.4 +toolchain go1.23.5 require ( github.com/coder/websocket v1.8.12 diff --git a/pkg/libsignalgo/address.go b/pkg/libsignalgo/address.go index 9afacc0..95e4249 100644 --- a/pkg/libsignalgo/address.go +++ b/pkg/libsignalgo/address.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -45,27 +46,35 @@ func NewUUIDAddressFromString(uuidStr string, deviceID uint) (*Address, error) { } func newAddress(name string, deviceID uint) (*Address, error) { - var pa *C.SignalProtocolAddress + var pa C.SignalMutPointerProtocolAddress signalFfiError := C.signal_address_new(&pa, C.CString(name), C.uint(deviceID)) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapAddress(pa), nil + return wrapAddress(pa.raw), nil +} + +func (pa *Address) mutPtr() C.SignalMutPointerProtocolAddress { + return C.SignalMutPointerProtocolAddress{pa.ptr} +} + +func (pa *Address) constPtr() C.SignalConstPointerProtocolAddress { + return C.SignalConstPointerProtocolAddress{pa.ptr} } func (pa *Address) Clone() (*Address, error) { - var cloned *C.SignalProtocolAddress - signalFfiError := C.signal_address_clone(&cloned, pa.ptr) + var cloned C.SignalMutPointerProtocolAddress + signalFfiError := C.signal_address_clone(&cloned, pa.constPtr()) runtime.KeepAlive(pa) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapAddress(cloned), nil + return wrapAddress(cloned.raw), nil } func (pa *Address) Destroy() error { pa.CancelFinalizer() - return wrapError(C.signal_address_destroy(pa.ptr)) + return wrapError(C.signal_address_destroy(pa.mutPtr())) } func (pa *Address) CancelFinalizer() { @@ -74,7 +83,7 @@ func (pa *Address) CancelFinalizer() { func (pa *Address) Name() (string, error) { var name *C.char - signalFfiError := C.signal_address_get_name(&name, pa.ptr) + signalFfiError := C.signal_address_get_name(&name, pa.constPtr()) runtime.KeepAlive(pa) if signalFfiError != nil { return "", wrapError(signalFfiError) @@ -92,7 +101,7 @@ func (pa *Address) NameServiceID() (ServiceID, error) { func (pa *Address) DeviceID() (uint, error) { var deviceID C.uint - signalFfiError := C.signal_address_get_device_id(&deviceID, pa.ptr) + signalFfiError := C.signal_address_get_device_id(&deviceID, pa.constPtr()) runtime.KeepAlive(pa) if signalFfiError != nil { return 0, wrapError(signalFfiError) diff --git a/pkg/libsignalgo/aes256gcmsiv.go b/pkg/libsignalgo/aes256gcmsiv.go index f6fd2c8..b4d0924 100644 --- a/pkg/libsignalgo/aes256gcmsiv.go +++ b/pkg/libsignalgo/aes256gcmsiv.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -35,23 +36,37 @@ func wrapAES256_GCM_SIV(ptr *C.SignalAes256GcmSiv) *AES256_GCM_SIV { } func NewAES256_GCM_SIV(key []byte) (*AES256_GCM_SIV, error) { - var aes *C.SignalAes256GcmSiv + var aes C.SignalMutPointerAes256GcmSiv signalFfiError := C.signal_aes256_gcm_siv_new(&aes, BytesToBuffer(key)) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapAES256_GCM_SIV(aes), nil + return wrapAES256_GCM_SIV(aes.raw), nil +} + +func (aes *AES256_GCM_SIV) mutPtr() C.SignalMutPointerAes256GcmSiv { + return C.SignalMutPointerAes256GcmSiv{aes.ptr} +} + +func (aes *AES256_GCM_SIV) constPtr() C.SignalConstPointerAes256GcmSiv { + return C.SignalConstPointerAes256GcmSiv{aes.ptr} } func (aes *AES256_GCM_SIV) Destroy() error { runtime.SetFinalizer(aes, nil) - return wrapError(C.signal_aes256_gcm_siv_destroy(aes.ptr)) + return wrapError(C.signal_aes256_gcm_siv_destroy(C.SignalMutPointerAes256GcmSiv{raw: aes.ptr})) } func (aes *AES256_GCM_SIV) Encrypt(plaintext, nonce, associatedData []byte) ([]byte, error) { var encrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_aes256_gcm_siv_encrypt(&encrypted, aes.ptr, BytesToBuffer(plaintext), BytesToBuffer(nonce), BytesToBuffer(associatedData)) + signalFfiError := C.signal_aes256_gcm_siv_encrypt( + &encrypted, + C.SignalConstPointerAes256GcmSiv{raw: aes.ptr}, + BytesToBuffer(plaintext), + BytesToBuffer(nonce), + BytesToBuffer(associatedData), + ) runtime.KeepAlive(aes) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -61,7 +76,13 @@ func (aes *AES256_GCM_SIV) Encrypt(plaintext, nonce, associatedData []byte) ([]b func (aes *AES256_GCM_SIV) Decrypt(ciphertext, nonce, associatedData []byte) ([]byte, error) { var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_aes256_gcm_siv_decrypt(&decrypted, aes.ptr, BytesToBuffer(ciphertext), BytesToBuffer(nonce), BytesToBuffer(associatedData)) + signalFfiError := C.signal_aes256_gcm_siv_decrypt( + &decrypted, + C.SignalConstPointerAes256GcmSiv{raw: aes.ptr}, + BytesToBuffer(ciphertext), + BytesToBuffer(nonce), + BytesToBuffer(associatedData), + ) if signalFfiError != nil { return nil, wrapError(signalFfiError) } diff --git a/pkg/libsignalgo/authcredential.go b/pkg/libsignalgo/authcredential.go index 0c7354f..65b9a67 100644 --- a/pkg/libsignalgo/authcredential.go +++ b/pkg/libsignalgo/authcredential.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 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 @@ -50,7 +51,7 @@ func ReceiveAuthCredentialWithPni( signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_service_id( &c_result, - serverPublicParams, + C.SignalConstPointerServerPublicParams{serverPublicParams}, NewACIServiceID(aci).CFixedBytes(), NewPNIServiceID(pni).CFixedBytes(), C.uint64_t(redemptionTime), @@ -88,7 +89,7 @@ func CreateAuthCredentialWithPniPresentation( signalFfiError := C.signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic( &c_result, - serverPublicParams, + C.SignalConstPointerServerPublicParams{serverPublicParams}, c_randomness, c_groupSecretParams, BytesToBuffer(authCredWithPni[:]), diff --git a/pkg/libsignalgo/ciphertextmessage.go b/pkg/libsignalgo/ciphertextmessage.go index f783ad8..e1c1bdb 100644 --- a/pkg/libsignalgo/ciphertextmessage.go +++ b/pkg/libsignalgo/ciphertextmessage.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -44,17 +45,28 @@ func wrapCiphertextMessage(ptr *C.SignalCiphertextMessage) *CiphertextMessage { } func NewCiphertextMessage(plaintext *PlaintextContent) (*CiphertextMessage, error) { - var ciphertextMessage *C.SignalCiphertextMessage - signalFfiError := C.signal_ciphertext_message_from_plaintext_content(&ciphertextMessage, plaintext.ptr) + var ciphertextMessage C.SignalMutPointerCiphertextMessage + signalFfiError := C.signal_ciphertext_message_from_plaintext_content( + &ciphertextMessage, + plaintext.constPtr(), + ) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapCiphertextMessage(ciphertextMessage), nil + return wrapCiphertextMessage(ciphertextMessage.raw), nil +} + +func (c *CiphertextMessage) mutPtr() C.SignalMutPointerCiphertextMessage { + return C.SignalMutPointerCiphertextMessage{c.ptr} +} + +func (c *CiphertextMessage) constPtr() C.SignalConstPointerCiphertextMessage { + return C.SignalConstPointerCiphertextMessage{c.ptr} } func (c *CiphertextMessage) Destroy() error { c.CancelFinalizer() - return wrapError(C.signal_ciphertext_message_destroy(c.ptr)) + return wrapError(C.signal_ciphertext_message_destroy(c.mutPtr())) } func (c *CiphertextMessage) CancelFinalizer() { @@ -63,7 +75,7 @@ func (c *CiphertextMessage) CancelFinalizer() { func (c *CiphertextMessage) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_ciphertext_message_serialize(&serialized, c.ptr) + signalFfiError := C.signal_ciphertext_message_serialize(&serialized, c.constPtr()) runtime.KeepAlive(c) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -73,7 +85,7 @@ func (c *CiphertextMessage) Serialize() ([]byte, error) { func (c *CiphertextMessage) MessageType() (CiphertextMessageType, error) { var messageType C.uint8_t - signalFfiError := C.signal_ciphertext_message_type(&messageType, c.ptr) + signalFfiError := C.signal_ciphertext_message_type(&messageType, c.constPtr()) runtime.KeepAlive(c) if signalFfiError != nil { return 0, wrapError(signalFfiError) diff --git a/pkg/libsignalgo/decryptionerrormessage.go b/pkg/libsignalgo/decryptionerrormessage.go index c5d5f18..5e4e3b9 100644 --- a/pkg/libsignalgo/decryptionerrormessage.go +++ b/pkg/libsignalgo/decryptionerrormessage.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -38,47 +39,64 @@ func wrapDecryptionErrorMessage(ptr *C.SignalDecryptionErrorMessage) *Decryption } func DeserializeDecryptionErrorMessage(messageBytes []byte) (*DecryptionErrorMessage, error) { - var dem *C.SignalDecryptionErrorMessage - signalFfiError := C.signal_decryption_error_message_deserialize(&dem, BytesToBuffer(messageBytes)) + var dem C.SignalMutPointerDecryptionErrorMessage + signalFfiError := C.signal_decryption_error_message_deserialize( + &dem, + BytesToBuffer(messageBytes), + ) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapDecryptionErrorMessage(dem), nil + return wrapDecryptionErrorMessage(dem.raw), nil } func DecryptionErrorMessageForOriginalMessage(originalBytes []byte, originalType uint8, originalTs uint64, originalSenderDeviceID uint) (*DecryptionErrorMessage, error) { - var dem *C.SignalDecryptionErrorMessage - signalFfiError := C.signal_decryption_error_message_for_original_message(&dem, BytesToBuffer(originalBytes), C.uint8_t(originalType), C.uint64_t(originalTs), C.uint32_t(originalSenderDeviceID)) + var dem C.SignalMutPointerDecryptionErrorMessage + signalFfiError := C.signal_decryption_error_message_for_original_message( + &dem, + BytesToBuffer(originalBytes), + C.uint8_t(originalType), + C.uint64_t(originalTs), + C.uint32_t(originalSenderDeviceID), + ) runtime.KeepAlive(originalBytes) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapDecryptionErrorMessage(dem), nil + return wrapDecryptionErrorMessage(dem.raw), nil } func DecryptionErrorMessageFromSerializedContent(serialized []byte) (*DecryptionErrorMessage, error) { - var dem *C.SignalDecryptionErrorMessage + var dem C.SignalMutPointerDecryptionErrorMessage signalFfiError := C.signal_decryption_error_message_extract_from_serialized_content(&dem, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapDecryptionErrorMessage(dem), nil + return wrapDecryptionErrorMessage(dem.raw), nil +} + +func (dem *DecryptionErrorMessage) mutPtr() C.SignalMutPointerDecryptionErrorMessage { + return C.SignalMutPointerDecryptionErrorMessage{dem.ptr} +} + +func (dem *DecryptionErrorMessage) constPtr() C.SignalConstPointerDecryptionErrorMessage { + return C.SignalConstPointerDecryptionErrorMessage{dem.ptr} } func (dem *DecryptionErrorMessage) Clone() (*DecryptionErrorMessage, error) { - var cloned *C.SignalDecryptionErrorMessage - signalFfiError := C.signal_decryption_error_message_clone(&cloned, dem.ptr) + var cloned C.SignalMutPointerDecryptionErrorMessage + signalFfiError := C.signal_decryption_error_message_clone(&cloned, dem.constPtr()) runtime.KeepAlive(dem) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapDecryptionErrorMessage(cloned), nil + return wrapDecryptionErrorMessage(cloned.raw), nil } func (dem *DecryptionErrorMessage) Destroy() error { dem.CancelFinalizer() - return wrapError(C.signal_decryption_error_message_destroy(dem.ptr)) + return wrapError(C.signal_decryption_error_message_destroy(dem.mutPtr())) } func (dem *DecryptionErrorMessage) CancelFinalizer() { @@ -87,7 +105,7 @@ func (dem *DecryptionErrorMessage) CancelFinalizer() { func (dem *DecryptionErrorMessage) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_decryption_error_message_serialize(&serialized, dem.ptr) + signalFfiError := C.signal_decryption_error_message_serialize(&serialized, dem.constPtr()) runtime.KeepAlive(dem) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -97,7 +115,7 @@ func (dem *DecryptionErrorMessage) Serialize() ([]byte, error) { func (dem *DecryptionErrorMessage) GetTimestamp() (time.Time, error) { var ts C.uint64_t - signalFfiError := C.signal_decryption_error_message_get_timestamp(&ts, dem.ptr) + signalFfiError := C.signal_decryption_error_message_get_timestamp(&ts, dem.constPtr()) runtime.KeepAlive(dem) if signalFfiError != nil { return time.Time{}, wrapError(signalFfiError) @@ -107,7 +125,7 @@ func (dem *DecryptionErrorMessage) GetTimestamp() (time.Time, error) { func (dem *DecryptionErrorMessage) GetDeviceID() (uint32, error) { var deviceID C.uint32_t - signalFfiError := C.signal_decryption_error_message_get_device_id(&deviceID, dem.ptr) + signalFfiError := C.signal_decryption_error_message_get_device_id(&deviceID, dem.constPtr()) runtime.KeepAlive(dem) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -116,11 +134,11 @@ func (dem *DecryptionErrorMessage) GetDeviceID() (uint32, error) { } func (dem *DecryptionErrorMessage) GetRatchetKey() (*PublicKey, error) { - var pk *C.SignalPublicKey - signalFfiError := C.signal_decryption_error_message_get_ratchet_key(&pk, dem.ptr) + var pk C.SignalMutPointerPublicKey + signalFfiError := C.signal_decryption_error_message_get_ratchet_key(&pk, dem.constPtr()) runtime.KeepAlive(dem) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(pk), nil + return wrapPublicKey(pk.raw), nil } diff --git a/pkg/libsignalgo/fingerprint.go b/pkg/libsignalgo/fingerprint.go index 2636015..4bbf24c 100644 --- a/pkg/libsignalgo/fingerprint.go +++ b/pkg/libsignalgo/fingerprint.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -42,32 +43,48 @@ func wrapFingerprint(ptr *C.SignalFingerprint) *Fingerprint { } func NewFingerprint(iterations, version FingerprintVersion, localIdentifier []byte, localKey *PublicKey, remoteIdentifier []byte, remoteKey *PublicKey) (*Fingerprint, error) { - var pa *C.SignalFingerprint - signalFfiError := C.signal_fingerprint_new(&pa, C.uint32_t(iterations), C.uint32_t(version), BytesToBuffer(localIdentifier), localKey.ptr, BytesToBuffer(remoteIdentifier), remoteKey.ptr) + var pa C.SignalMutPointerFingerprint + signalFfiError := C.signal_fingerprint_new( + &pa, + C.uint32_t(iterations), + C.uint32_t(version), + BytesToBuffer(localIdentifier), + localKey.constPtr(), + BytesToBuffer(remoteIdentifier), + remoteKey.constPtr(), + ) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapFingerprint(pa), nil + return wrapFingerprint(pa.raw), nil +} + +func (f *Fingerprint) mutPtr() C.SignalMutPointerFingerprint { + return C.SignalMutPointerFingerprint{f.ptr} +} + +func (f *Fingerprint) constPtr() C.SignalConstPointerFingerprint { + return C.SignalConstPointerFingerprint{f.ptr} } func (f *Fingerprint) Clone() (*Fingerprint, error) { - var cloned *C.SignalFingerprint - signalFfiError := C.signal_fingerprint_clone(&cloned, f.ptr) + var cloned C.SignalMutPointerFingerprint + signalFfiError := C.signal_fingerprint_clone(&cloned, f.constPtr()) runtime.KeepAlive(f) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapFingerprint(cloned), nil + return wrapFingerprint(cloned.raw), nil } func (f *Fingerprint) Destroy() error { runtime.SetFinalizer(f, nil) - return wrapError(C.signal_fingerprint_destroy(f.ptr)) + return wrapError(C.signal_fingerprint_destroy(f.mutPtr())) } func (f *Fingerprint) ScannableEncoding() ([]byte, error) { var scannableEncoding C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_fingerprint_scannable_encoding(&scannableEncoding, f.ptr) + signalFfiError := C.signal_fingerprint_scannable_encoding(&scannableEncoding, f.constPtr()) runtime.KeepAlive(f) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -77,7 +94,7 @@ func (f *Fingerprint) ScannableEncoding() ([]byte, error) { func (f *Fingerprint) DisplayString() (string, error) { var displayString *C.char - signalFfiError := C.signal_fingerprint_display_string(&displayString, f.ptr) + signalFfiError := C.signal_fingerprint_display_string(&displayString, f.constPtr()) runtime.KeepAlive(f) if signalFfiError != nil { return "", wrapError(signalFfiError) diff --git a/pkg/libsignalgo/groupcipher.go b/pkg/libsignalgo/groupcipher.go index 7faaf90..33e18aa 100644 --- a/pkg/libsignalgo/groupcipher.go +++ b/pkg/libsignalgo/groupcipher.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -32,10 +33,10 @@ import ( func GroupEncrypt(ctx context.Context, ptext []byte, sender *Address, distributionID uuid.UUID, store SenderKeyStore) (*CiphertextMessage, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() - var ciphertextMessage *C.SignalCiphertextMessage + var ciphertextMessage C.SignalMutPointerCiphertextMessage signalFfiError := C.signal_group_encrypt_message( &ciphertextMessage, - sender.ptr, + sender.constPtr(), (*[C.SignalUUID_LEN]C.uchar)(unsafe.Pointer(&distributionID)), BytesToBuffer(ptext), callbackCtx.wrapSenderKeyStore(store)) @@ -44,7 +45,7 @@ func GroupEncrypt(ctx context.Context, ptext []byte, sender *Address, distributi if signalFfiError != nil { return nil, callbackCtx.wrapError(signalFfiError) } - return wrapCiphertextMessage(ciphertextMessage), nil + return wrapCiphertextMessage(ciphertextMessage.raw), nil } func GroupDecrypt(ctx context.Context, ctext []byte, sender *Address, store SenderKeyStore) ([]byte, error) { @@ -53,7 +54,7 @@ func GroupDecrypt(ctx context.Context, ctext []byte, sender *Address, store Send var resp C.SignalOwnedBuffer = C.SignalOwnedBuffer{} signalFfiError := C.signal_group_decrypt_message( &resp, - sender.ptr, + sender.constPtr(), BytesToBuffer(ctext), callbackCtx.wrapSenderKeyStore(store)) runtime.KeepAlive(ctext) diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 0df5ec8..943dfda 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -213,7 +214,7 @@ func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp randomness := GenerateRandomness() signalFfiError := C.signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic( &out, - spp, + 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)), diff --git a/pkg/libsignalgo/hsmenclave.go b/pkg/libsignalgo/hsmenclave.go index 51ca6f4..15a44fa 100644 --- a/pkg/libsignalgo/hsmenclave.go +++ b/pkg/libsignalgo/hsmenclave.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -35,22 +36,34 @@ func wrapHSMEnclaveClient(ptr *C.SignalHsmEnclaveClient) *HSMEnclaveClient { } func NewHSMEnclaveClient(trustedPublicKey, trustedCodeHashes []byte) (*HSMEnclaveClient, error) { - var cds *C.SignalHsmEnclaveClient - signalFfiError := C.signal_hsm_enclave_client_new(&cds, BytesToBuffer(trustedPublicKey), BytesToBuffer(trustedCodeHashes)) + var cds C.SignalMutPointerHsmEnclaveClient + signalFfiError := C.signal_hsm_enclave_client_new( + &cds, + BytesToBuffer(trustedPublicKey), + BytesToBuffer(trustedCodeHashes), + ) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapHSMEnclaveClient(cds), nil + return wrapHSMEnclaveClient(cds.raw), nil +} + +func (hsm *HSMEnclaveClient) mutPtr() C.SignalMutPointerHsmEnclaveClient { + return C.SignalMutPointerHsmEnclaveClient{hsm.ptr} +} + +func (hsm *HSMEnclaveClient) constPtr() C.SignalConstPointerHsmEnclaveClient { + return C.SignalConstPointerHsmEnclaveClient{hsm.ptr} } func (hsm *HSMEnclaveClient) Destroy() error { runtime.SetFinalizer(hsm, nil) - return wrapError(C.signal_hsm_enclave_client_destroy(hsm.ptr)) + return wrapError(C.signal_hsm_enclave_client_destroy(hsm.mutPtr())) } func (hsm *HSMEnclaveClient) InitialRequest() ([]byte, error) { var resp C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_hsm_enclave_client_initial_request(&resp, hsm.ptr) + signalFfiError := C.signal_hsm_enclave_client_initial_request(&resp, hsm.constPtr()) runtime.KeepAlive(hsm) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -59,7 +72,7 @@ func (hsm *HSMEnclaveClient) InitialRequest() ([]byte, error) { } func (hsm *HSMEnclaveClient) CompleteHandshake(handshakeReceived []byte) error { - signalFfiError := C.signal_hsm_enclave_client_complete_handshake(hsm.ptr, BytesToBuffer(handshakeReceived)) + signalFfiError := C.signal_hsm_enclave_client_complete_handshake(hsm.mutPtr(), BytesToBuffer(handshakeReceived)) runtime.KeepAlive(hsm) runtime.KeepAlive(handshakeReceived) return wrapError(signalFfiError) @@ -67,7 +80,7 @@ func (hsm *HSMEnclaveClient) CompleteHandshake(handshakeReceived []byte) error { func (hsm *HSMEnclaveClient) EstablishedSend(plaintext []byte) ([]byte, error) { var resp C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_hsm_enclave_client_established_send(&resp, hsm.ptr, BytesToBuffer(plaintext)) + signalFfiError := C.signal_hsm_enclave_client_established_send(&resp, hsm.mutPtr(), BytesToBuffer(plaintext)) runtime.KeepAlive(hsm) runtime.KeepAlive(plaintext) if signalFfiError != nil { @@ -78,7 +91,7 @@ func (hsm *HSMEnclaveClient) EstablishedSend(plaintext []byte) ([]byte, error) { func (hsm *HSMEnclaveClient) EstablishedReceive(ciphertext []byte) ([]byte, error) { var resp C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_hsm_enclave_client_established_recv(&resp, hsm.ptr, BytesToBuffer(ciphertext)) + signalFfiError := C.signal_hsm_enclave_client_established_recv(&resp, hsm.mutPtr(), BytesToBuffer(ciphertext)) runtime.KeepAlive(hsm) runtime.KeepAlive(ciphertext) if signalFfiError != nil { diff --git a/pkg/libsignalgo/identitykey.go b/pkg/libsignalgo/identitykey.go index 796e575..9cd8425 100644 --- a/pkg/libsignalgo/identitykey.go +++ b/pkg/libsignalgo/identitykey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -57,18 +58,23 @@ func (i *IdentityKey) Serialize() ([]byte, error) { } func DeserializeIdentityKey(bytes []byte) (*IdentityKey, error) { - var publicKey *C.SignalPublicKey + var publicKey C.SignalMutPointerPublicKey signalFfiError := C.signal_publickey_deserialize(&publicKey, BytesToBuffer(bytes)) runtime.KeepAlive(bytes) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return &IdentityKey{publicKey: wrapPublicKey(publicKey)}, nil + return &IdentityKey{publicKey: wrapPublicKey(publicKey.raw)}, nil } func (i *IdentityKey) VerifyAlternateIdentity(other *IdentityKey, signature []byte) (bool, error) { var verify C.bool - signalFfiError := C.signal_identitykey_verify_alternate_identity(&verify, i.publicKey.ptr, other.publicKey.ptr, BytesToBuffer(signature)) + signalFfiError := C.signal_identitykey_verify_alternate_identity( + &verify, + i.publicKey.constPtr(), + other.publicKey.constPtr(), + BytesToBuffer(signature), + ) runtime.KeepAlive(i) runtime.KeepAlive(other) runtime.KeepAlive(signature) @@ -109,14 +115,14 @@ func GenerateIdentityKeyPair() (*IdentityKeyPair, error) { } func DeserializeIdentityKeyPair(bytes []byte) (*IdentityKeyPair, error) { - var privateKey *C.SignalPrivateKey - var publicKey *C.SignalPublicKey + var privateKey C.SignalMutPointerPrivateKey + var publicKey C.SignalMutPointerPublicKey signalFfiError := C.signal_identitykeypair_deserialize(&privateKey, &publicKey, BytesToBuffer(bytes)) runtime.KeepAlive(bytes) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return &IdentityKeyPair{publicKey: wrapPublicKey(publicKey), privateKey: wrapPrivateKey(privateKey)}, nil + return &IdentityKeyPair{publicKey: wrapPublicKey(publicKey.raw), privateKey: wrapPrivateKey(privateKey.raw)}, nil } func NewIdentityKeyPair(publicKey *PublicKey, privateKey *PrivateKey) (*IdentityKeyPair, error) { @@ -125,7 +131,11 @@ func NewIdentityKeyPair(publicKey *PublicKey, privateKey *PrivateKey) (*Identity func (i *IdentityKeyPair) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_identitykeypair_serialize(&serialized, i.publicKey.ptr, i.privateKey.ptr) + signalFfiError := C.signal_identitykeypair_serialize( + &serialized, + i.publicKey.constPtr(), + i.privateKey.constPtr(), + ) runtime.KeepAlive(i) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -139,7 +149,12 @@ func (i *IdentityKeyPair) GetIdentityKey() *IdentityKey { func (i *IdentityKeyPair) SignAlternateIdentity(other *IdentityKey) ([]byte, error) { var signature C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_identitykeypair_sign_alternate_identity(&signature, i.publicKey.ptr, i.privateKey.ptr, other.publicKey.ptr) + signalFfiError := C.signal_identitykeypair_sign_alternate_identity( + &signature, + i.publicKey.constPtr(), + i.privateKey.constPtr(), + other.publicKey.constPtr(), + ) runtime.KeepAlive(i) runtime.KeepAlive(other) if signalFfiError != nil { diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index 19c6520..88e5eaa 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -148,13 +149,13 @@ func signal_is_trusted_identity_callback(storeCtx unsafe.Pointer, address *C.con }) } -func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) *C.SignalIdentityKeyStore { - return &C.SignalIdentityKeyStore{ +func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct { + return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{ ctx: wrapStore(ctx, store), get_identity_key_pair: C.SignalGetIdentityKeyPair(C.signal_get_identity_key_pair_callback), get_local_registration_id: C.SignalGetLocalRegistrationId(C.signal_get_local_registration_id_callback), save_identity: C.SignalSaveIdentityKey(C.signal_save_identity_key_callback), get_identity: C.SignalGetIdentityKey(C.signal_get_identity_key_callback), is_trusted_identity: C.SignalIsTrustedIdentity(C.signal_is_trusted_identity_callback), - } + }} } diff --git a/pkg/libsignalgo/kyberprekey.go b/pkg/libsignalgo/kyberprekey.go index d049d0a..7f9c7b4 100644 --- a/pkg/libsignalgo/kyberprekey.go +++ b/pkg/libsignalgo/kyberprekey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 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 @@ -52,9 +53,17 @@ func wrapKyberKeyPair(ptr *C.SignalKyberKeyPair) *KyberKeyPair { return kp } +func (kp *KyberKeyPair) mutPtr() C.SignalMutPointerKyberKeyPair { + return C.SignalMutPointerKyberKeyPair{kp.ptr} +} + +func (kp *KyberKeyPair) constPtr() C.SignalConstPointerKyberKeyPair { + return C.SignalConstPointerKyberKeyPair{kp.ptr} +} + func (kp *KyberKeyPair) Destroy() error { kp.CancelFinalizer() - return wrapError(C.signal_kyber_key_pair_destroy(kp.ptr)) + return wrapError(C.signal_kyber_key_pair_destroy(kp.mutPtr())) } func (kp *KyberKeyPair) CancelFinalizer() { @@ -67,9 +76,17 @@ func wrapKyberPublicKey(ptr *C.SignalKyberPublicKey) *KyberPublicKey { return publicKey } +func (k *KyberPublicKey) mutPtr() C.SignalMutPointerKyberPublicKey { + return C.SignalMutPointerKyberPublicKey{k.ptr} +} + +func (k *KyberPublicKey) constPtr() C.SignalConstPointerKyberPublicKey { + return C.SignalConstPointerKyberPublicKey{k.ptr} +} + func (k *KyberPublicKey) Destroy() error { k.CancelFinalizer() - return wrapError(C.signal_publickey_destroy(k.ptr)) + return wrapError(C.signal_kyber_public_key_destroy(k.mutPtr())) } func (k *KyberPublicKey) CancelFinalizer() { @@ -82,9 +99,17 @@ func wrapKyberSecretKey(ptr *C.SignalKyberSecretKey) *KyberSecretKey { return secretKey } +func (k *KyberSecretKey) mutPtr() C.SignalMutPointerKyberSecretKey { + return C.SignalMutPointerKyberSecretKey{k.ptr} +} + +func (k *KyberSecretKey) constPtr() C.SignalConstPointerKyberSecretKey { + return C.SignalConstPointerKyberSecretKey{k.ptr} +} + func (k *KyberSecretKey) Destroy() error { k.CancelFinalizer() - return wrapError(C.signal_kyber_secret_key_destroy(k.ptr)) + return wrapError(C.signal_kyber_secret_key_destroy(k.mutPtr())) } func (k *KyberSecretKey) CancelFinalizer() { @@ -98,18 +123,18 @@ func wrapKyberPreKeyRecord(ptr *C.SignalKyberPreKeyRecord) *KyberPreKeyRecord { } func (kp *KyberKeyPair) GetPublicKey() (*KyberPublicKey, error) { - var pub *C.SignalKyberPublicKey - signalFfiError := C.signal_kyber_key_pair_get_public_key(&pub, kp.ptr) + var pub C.SignalMutPointerKyberPublicKey + signalFfiError := C.signal_kyber_key_pair_get_public_key(&pub, kp.constPtr()) runtime.KeepAlive(kp) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberPublicKey(pub), nil + return wrapKyberPublicKey(pub.raw), nil } func (kp *KyberPublicKey) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_kyber_public_key_serialize(&serialized, kp.ptr) + signalFfiError := C.signal_kyber_public_key_serialize(&serialized, kp.constPtr()) runtime.KeepAlive(kp) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -118,49 +143,63 @@ func (kp *KyberPublicKey) Serialize() ([]byte, error) { } func DeserializeKyberPublicKey(serialized []byte) (*KyberPublicKey, error) { - var kyberPublicKey *C.SignalKyberPublicKey + var kyberPublicKey C.SignalMutPointerKyberPublicKey signalFfiError := C.signal_kyber_public_key_deserialize(&kyberPublicKey, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberPublicKey(kyberPublicKey), nil + return wrapKyberPublicKey(kyberPublicKey.raw), nil } func NewKyberPreKeyRecord(id uint32, timestamp time.Time, keyPair *KyberKeyPair, signature []byte) (*KyberPreKeyRecord, error) { - var kpkr *C.SignalKyberPreKeyRecord - signalFfiError := C.signal_kyber_pre_key_record_new(&kpkr, C.uint32_t(id), C.uint64_t(timestamp.UnixMilli()), keyPair.ptr, BytesToBuffer(signature)) + var kpkr C.SignalMutPointerKyberPreKeyRecord + signalFfiError := C.signal_kyber_pre_key_record_new( + &kpkr, + C.uint32_t(id), + C.uint64_t(timestamp.UnixMilli()), + keyPair.constPtr(), + BytesToBuffer(signature), + ) runtime.KeepAlive(keyPair) runtime.KeepAlive(signature) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberPreKeyRecord(kpkr), nil + return wrapKyberPreKeyRecord(kpkr.raw), nil } func DeserializeKyberPreKeyRecord(serialized []byte) (*KyberPreKeyRecord, error) { - var kpkr *C.SignalKyberPreKeyRecord + var kpkr C.SignalMutPointerKyberPreKeyRecord signalFfiError := C.signal_kyber_pre_key_record_deserialize(&kpkr, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberPreKeyRecord(kpkr), nil + return wrapKyberPreKeyRecord(kpkr.raw), nil +} + +func (kpkr *KyberPreKeyRecord) mutPtr() C.SignalMutPointerKyberPreKeyRecord { + return C.SignalMutPointerKyberPreKeyRecord{kpkr.ptr} +} + +func (kpkr *KyberPreKeyRecord) constPtr() C.SignalConstPointerKyberPreKeyRecord { + return C.SignalConstPointerKyberPreKeyRecord{kpkr.ptr} } func (kpkr *KyberPreKeyRecord) Clone() (*KyberPreKeyRecord, error) { - var cloned *C.SignalKyberPreKeyRecord - signalFfiError := C.signal_kyber_pre_key_record_clone(&cloned, kpkr.ptr) + var cloned C.SignalMutPointerKyberPreKeyRecord + signalFfiError := C.signal_kyber_pre_key_record_clone(&cloned, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberPreKeyRecord(cloned), nil + return wrapKyberPreKeyRecord(cloned.raw), nil } func (kpkr *KyberPreKeyRecord) Destroy() error { kpkr.CancelFinalizer() - return wrapError(C.signal_kyber_pre_key_record_destroy(kpkr.ptr)) + return wrapError(C.signal_kyber_pre_key_record_destroy(kpkr.mutPtr())) } func (kpkr *KyberPreKeyRecord) CancelFinalizer() { @@ -169,7 +208,7 @@ func (kpkr *KyberPreKeyRecord) CancelFinalizer() { func (kpkr *KyberPreKeyRecord) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_kyber_pre_key_record_serialize(&serialized, kpkr.ptr) + signalFfiError := C.signal_kyber_pre_key_record_serialize(&serialized, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -179,7 +218,7 @@ func (kpkr *KyberPreKeyRecord) Serialize() ([]byte, error) { func (kpkr *KyberPreKeyRecord) GetSignature() ([]byte, error) { var signature C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_kyber_pre_key_record_get_signature(&signature, kpkr.ptr) + signalFfiError := C.signal_kyber_pre_key_record_get_signature(&signature, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -189,7 +228,7 @@ func (kpkr *KyberPreKeyRecord) GetSignature() ([]byte, error) { func (kpkr *KyberPreKeyRecord) GetID() (uint32, error) { var id C.uint32_t - signalFfiError := C.signal_kyber_pre_key_record_get_id(&id, kpkr.ptr) + signalFfiError := C.signal_kyber_pre_key_record_get_id(&id, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -199,7 +238,7 @@ func (kpkr *KyberPreKeyRecord) GetID() (uint32, error) { func (kpkr *KyberPreKeyRecord) GetTimestamp() (time.Time, error) { var ts C.uint64_t - signalFfiError := C.signal_kyber_pre_key_record_get_timestamp(&ts, kpkr.ptr) + signalFfiError := C.signal_kyber_pre_key_record_get_timestamp(&ts, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return time.Time{}, wrapError(signalFfiError) @@ -208,30 +247,30 @@ func (kpkr *KyberPreKeyRecord) GetTimestamp() (time.Time, error) { } func (kpkr *KyberPreKeyRecord) GetPublicKey() (*KyberPublicKey, error) { - var pub *C.SignalKyberPublicKey - signalFfiError := C.signal_kyber_pre_key_record_get_public_key(&pub, kpkr.ptr) + var pub C.SignalMutPointerKyberPublicKey + signalFfiError := C.signal_kyber_pre_key_record_get_public_key(&pub, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberPublicKey(pub), nil + return wrapKyberPublicKey(pub.raw), nil } func (kpkr *KyberPreKeyRecord) GetSecretKey() (*KyberSecretKey, error) { - var sec *C.SignalKyberSecretKey - signalFfiError := C.signal_kyber_pre_key_record_get_secret_key(&sec, kpkr.ptr) + var sec C.SignalMutPointerKyberSecretKey + signalFfiError := C.signal_kyber_pre_key_record_get_secret_key(&sec, kpkr.constPtr()) runtime.KeepAlive(kpkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberSecretKey(sec), nil + return wrapKyberSecretKey(sec.raw), nil } func KyberKeyPairGenerate() (*KyberKeyPair, error) { - var kp *C.SignalKyberKeyPair + var kp C.SignalMutPointerKyberKeyPair signalFfiError := C.signal_kyber_key_pair_generate(&kp) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapKyberKeyPair(kp), nil + return wrapKyberKeyPair(kp.raw), nil } diff --git a/pkg/libsignalgo/kyberprekeystore.go b/pkg/libsignalgo/kyberprekeystore.go index a0204e5..39beed7 100644 --- a/pkg/libsignalgo/kyberprekeystore.go +++ b/pkg/libsignalgo/kyberprekeystore.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 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 @@ -70,11 +71,11 @@ func signal_mark_kyber_pre_key_used_callback(storeCtx unsafe.Pointer, id C.uint3 }) } -func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) *C.SignalKyberPreKeyStore { - return &C.SignalKyberPreKeyStore{ +func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) C.SignalConstPointerFfiKyberPreKeyStoreStruct { + return C.SignalConstPointerFfiKyberPreKeyStoreStruct{&C.SignalKyberPreKeyStore{ ctx: wrapStore(ctx, store), load_kyber_pre_key: C.SignalLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), store_kyber_pre_key: C.SignalStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), mark_kyber_pre_key_used: C.SignalMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), - } + }} } diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 4b78ebf..864a1a1 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 4b78ebfeeaec42e1f37c87ecb67b0e480b15f03a +Subproject commit 864a1a1a87d08b30516fdf5734ae426b0508f445 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index b16aca6..457d343 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -224,6 +224,8 @@ typedef struct SignalAes256GcmEncryption SignalAes256GcmEncryption; typedef struct SignalAes256GcmSiv SignalAes256GcmSiv; +typedef struct SignalAuthenticatedChatConnection SignalAuthenticatedChatConnection; + typedef struct SignalCdsiLookup SignalCdsiLookup; typedef struct SignalChatAuthChatService SignalChatAuthChatService; @@ -232,6 +234,11 @@ typedef struct SignalChatUnauthChatService SignalChatUnauthChatService; typedef struct SignalCiphertextMessage SignalCiphertextMessage; +/** + * Information about an established connection. + */ +typedef struct SignalConnectionInfo SignalConnectionInfo; + typedef struct SignalConnectionManager SignalConnectionManager; typedef struct SignalDecryptionErrorMessage SignalDecryptionErrorMessage; @@ -277,9 +284,7 @@ typedef struct SignalProtocolAddress SignalProtocolAddress; typedef struct SignalPublicKey SignalPublicKey; -#if defined(SIGNAL_MEDIA_SUPPORTED) typedef struct SignalSanitizedMetadata SignalSanitizedMetadata; -#endif typedef struct SignalSenderCertificate SignalSenderCertificate; @@ -292,7 +297,7 @@ typedef struct SignalSenderKeyRecord SignalSenderKeyRecord; typedef struct SignalServerCertificate SignalServerCertificate; /** - * Wraps a named type and a single-use guard around [`chat::server_requests::AckEnvelopeFuture`]. + * Wraps a named type and a single-use guard around [`chat::server_requests::ResponseEnvelopeSender`]. */ typedef struct SignalServerMessageAck SignalServerMessageAck; @@ -320,6 +325,8 @@ typedef struct SignalSignedPreKeyRecord SignalSignedPreKeyRecord; typedef struct SignalTokioAsyncContext SignalTokioAsyncContext; +typedef struct SignalUnauthenticatedChatConnection SignalUnauthenticatedChatConnection; + typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMessageContent; typedef struct SignalValidatingMac SignalValidatingMac; @@ -388,16 +395,44 @@ typedef struct { SignalOwnedBufferOfusize lengths; } SignalBytestringArray; +typedef struct { + SignalProtocolAddress *raw; +} SignalMutPointerProtocolAddress; + typedef SignalBytestringArray SignalStringArray; +typedef struct { + SignalPrivateKey *raw; +} SignalMutPointerPrivateKey; + +typedef struct { + SignalPublicKey *raw; +} SignalMutPointerPublicKey; + typedef struct { const unsigned char *base; size_t length; } SignalBorrowedBuffer; -typedef int (*SignalLoadSession)(void *store_ctx, SignalSessionRecord **recordp, const SignalProtocolAddress *address); +typedef struct { + const SignalPublicKey *raw; +} SignalConstPointerPublicKey; -typedef int (*SignalStoreSession)(void *store_ctx, const SignalProtocolAddress *address, const SignalSessionRecord *record); +typedef struct { + SignalSessionRecord *raw; +} SignalMutPointerSessionRecord; + +typedef struct { + const SignalProtocolAddress *raw; +} SignalConstPointerProtocolAddress; + +typedef int (*SignalLoadSession)(void *store_ctx, SignalMutPointerSessionRecord *recordp, SignalConstPointerProtocolAddress address); + +typedef struct { + const SignalSessionRecord *raw; +} SignalConstPointerSessionRecord; + +typedef int (*SignalStoreSession)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerSessionRecord record); typedef struct { void *ctx; @@ -405,15 +440,19 @@ typedef struct { SignalStoreSession store_session; } SignalSessionStore; -typedef int (*SignalGetIdentityKeyPair)(void *store_ctx, SignalPrivateKey **keyp); +typedef struct { + const SignalSessionStore *raw; +} SignalConstPointerFfiSessionStoreStruct; + +typedef int (*SignalGetIdentityKeyPair)(void *store_ctx, SignalMutPointerPrivateKey *keyp); typedef int (*SignalGetLocalRegistrationId)(void *store_ctx, uint32_t *idp); -typedef int (*SignalSaveIdentityKey)(void *store_ctx, const SignalProtocolAddress *address, const SignalPublicKey *public_key); +typedef int (*SignalSaveIdentityKey)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerPublicKey public_key); -typedef int (*SignalGetIdentityKey)(void *store_ctx, SignalPublicKey **public_keyp, const SignalProtocolAddress *address); +typedef int (*SignalGetIdentityKey)(void *store_ctx, SignalMutPointerPublicKey *public_keyp, SignalConstPointerProtocolAddress address); -typedef int (*SignalIsTrustedIdentity)(void *store_ctx, const SignalProtocolAddress *address, const SignalPublicKey *public_key, unsigned int direction); +typedef int (*SignalIsTrustedIdentity)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerPublicKey public_key, unsigned int direction); typedef struct { void *ctx; @@ -424,9 +463,21 @@ typedef struct { SignalIsTrustedIdentity is_trusted_identity; } SignalIdentityKeyStore; -typedef int (*SignalLoadPreKey)(void *store_ctx, SignalPreKeyRecord **recordp, uint32_t id); +typedef struct { + const SignalIdentityKeyStore *raw; +} SignalConstPointerFfiIdentityKeyStoreStruct; -typedef int (*SignalStorePreKey)(void *store_ctx, uint32_t id, const SignalPreKeyRecord *record); +typedef struct { + SignalPreKeyRecord *raw; +} SignalMutPointerPreKeyRecord; + +typedef int (*SignalLoadPreKey)(void *store_ctx, SignalMutPointerPreKeyRecord *recordp, uint32_t id); + +typedef struct { + const SignalPreKeyRecord *raw; +} SignalConstPointerPreKeyRecord; + +typedef int (*SignalStorePreKey)(void *store_ctx, uint32_t id, SignalConstPointerPreKeyRecord record); typedef int (*SignalRemovePreKey)(void *store_ctx, uint32_t id); @@ -437,9 +488,21 @@ typedef struct { SignalRemovePreKey remove_pre_key; } SignalPreKeyStore; -typedef int (*SignalLoadSignedPreKey)(void *store_ctx, SignalSignedPreKeyRecord **recordp, uint32_t id); +typedef struct { + const SignalPreKeyStore *raw; +} SignalConstPointerFfiPreKeyStoreStruct; -typedef int (*SignalStoreSignedPreKey)(void *store_ctx, uint32_t id, const SignalSignedPreKeyRecord *record); +typedef struct { + SignalSignedPreKeyRecord *raw; +} SignalMutPointerSignedPreKeyRecord; + +typedef int (*SignalLoadSignedPreKey)(void *store_ctx, SignalMutPointerSignedPreKeyRecord *recordp, uint32_t id); + +typedef struct { + const SignalSignedPreKeyRecord *raw; +} SignalConstPointerSignedPreKeyRecord; + +typedef int (*SignalStoreSignedPreKey)(void *store_ctx, uint32_t id, SignalConstPointerSignedPreKeyRecord record); typedef struct { void *ctx; @@ -447,6 +510,10 @@ typedef struct { SignalStoreSignedPreKey store_signed_pre_key; } SignalSignedPreKeyStore; +typedef struct { + const SignalSignedPreKeyStore *raw; +} SignalConstPointerFfiSignedPreKeyStoreStruct; + typedef void (*SignalLogCallback)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); typedef void (*SignalLogFlushCallback)(void *ctx); @@ -457,15 +524,159 @@ typedef struct { SignalLogFlushCallback flush; } SignalFfiLogger; +typedef struct { + SignalAes256GcmSiv *raw; +} SignalMutPointerAes256GcmSiv; + +typedef struct { + SignalAes256Ctr32 *raw; +} SignalMutPointerAes256Ctr32; + +typedef struct { + SignalAes256GcmEncryption *raw; +} SignalMutPointerAes256GcmEncryption; + +typedef struct { + SignalAes256GcmDecryption *raw; +} SignalMutPointerAes256GcmDecryption; + typedef struct { unsigned char *base; size_t length; } SignalBorrowedMutableBuffer; +typedef struct { + const SignalAes256GcmSiv *raw; +} SignalConstPointerAes256GcmSiv; + +typedef struct { + SignalCiphertextMessage *raw; +} SignalMutPointerCiphertextMessage; + +typedef struct { + SignalDecryptionErrorMessage *raw; +} SignalMutPointerDecryptionErrorMessage; + +typedef struct { + const SignalDecryptionErrorMessage *raw; +} SignalConstPointerDecryptionErrorMessage; + +typedef struct { + SignalFingerprint *raw; +} SignalMutPointerFingerprint; + +typedef struct { + const SignalFingerprint *raw; +} SignalConstPointerFingerprint; + +typedef struct { + SignalPlaintextContent *raw; +} SignalMutPointerPlaintextContent; + +typedef struct { + const SignalPlaintextContent *raw; +} SignalConstPointerPlaintextContent; + +typedef struct { + SignalPreKeyBundle *raw; +} SignalMutPointerPreKeyBundle; + +typedef struct { + const SignalPreKeyBundle *raw; +} SignalConstPointerPreKeyBundle; + +typedef struct { + SignalPreKeySignalMessage *raw; +} SignalMutPointerPreKeySignalMessage; + +typedef struct { + const SignalPreKeySignalMessage *raw; +} SignalConstPointerPreKeySignalMessage; + +typedef struct { + const SignalPrivateKey *raw; +} SignalConstPointerPrivateKey; + +typedef struct { + SignalSenderCertificate *raw; +} SignalMutPointerSenderCertificate; + +typedef struct { + const SignalSenderCertificate *raw; +} SignalConstPointerSenderCertificate; + +typedef struct { + SignalSenderKeyDistributionMessage *raw; +} SignalMutPointerSenderKeyDistributionMessage; + +typedef struct { + const SignalSenderKeyDistributionMessage *raw; +} SignalConstPointerSenderKeyDistributionMessage; + +typedef struct { + SignalSenderKeyMessage *raw; +} SignalMutPointerSenderKeyMessage; + +typedef struct { + const SignalSenderKeyMessage *raw; +} SignalConstPointerSenderKeyMessage; + +typedef struct { + SignalSenderKeyRecord *raw; +} SignalMutPointerSenderKeyRecord; + +typedef struct { + const SignalSenderKeyRecord *raw; +} SignalConstPointerSenderKeyRecord; + +typedef struct { + SignalServerCertificate *raw; +} SignalMutPointerServerCertificate; + +typedef struct { + const SignalServerCertificate *raw; +} SignalConstPointerServerCertificate; + +typedef struct { + SignalMessage *raw; +} SignalMutPointerSignalMessage; + +typedef struct { + const SignalMessage *raw; +} SignalConstPointerSignalMessage; + +typedef struct { + SignalKyberPreKeyRecord *raw; +} SignalMutPointerKyberPreKeyRecord; + +typedef struct { + const SignalKyberPreKeyRecord *raw; +} SignalConstPointerKyberPreKeyRecord; + +typedef struct { + SignalUnidentifiedSenderMessageContent *raw; +} SignalMutPointerUnidentifiedSenderMessageContent; + typedef SignalKeyPair SignalKyberKeyPair; +typedef struct { + SignalKyberKeyPair *raw; +} SignalMutPointerKyberKeyPair; + +typedef struct { + const SignalKyberKeyPair *raw; +} SignalConstPointerKyberKeyPair; + typedef SignalPublicKey SignalKyberPublicKey; +typedef struct { + SignalKyberPublicKey *raw; +} SignalMutPointerKyberPublicKey; + +typedef struct { + const SignalKyberPublicKey *raw; +} SignalConstPointerKyberPublicKey; + /** * A KEM secret key with the ability to decapsulate a shared secret. */ @@ -473,6 +684,14 @@ typedef SignalKeySecret SignalSecretKey; typedef SignalSecretKey SignalKyberSecretKey; +typedef struct { + SignalKyberSecretKey *raw; +} SignalMutPointerKyberSecretKey; + +typedef struct { + const SignalKyberSecretKey *raw; +} SignalConstPointerKyberSecretKey; + /** * The fixed-width binary representation of a ServiceId. * @@ -480,9 +699,17 @@ typedef SignalSecretKey SignalKyberSecretKey; */ typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; -typedef int (*SignalLoadKyberPreKey)(void *store_ctx, SignalKyberPreKeyRecord **recordp, uint32_t id); +typedef struct { + const SignalUnidentifiedSenderMessageContent *raw; +} SignalConstPointerUnidentifiedSenderMessageContent; -typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, const SignalKyberPreKeyRecord *record); +typedef struct { + const SignalCiphertextMessage *raw; +} SignalConstPointerCiphertextMessage; + +typedef int (*SignalLoadKyberPreKey)(void *store_ctx, SignalMutPointerKyberPreKeyRecord *recordp, uint32_t id); + +typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, SignalConstPointerKyberPreKeyRecord record); typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id); @@ -494,18 +721,22 @@ typedef struct { } SignalKyberPreKeyStore; typedef struct { - const SignalProtocolAddress *const *base; - size_t length; -} SignalBorrowedSliceOfProtocolAddress; + const SignalKyberPreKeyStore *raw; +} SignalConstPointerFfiKyberPreKeyStoreStruct; typedef struct { - const SignalSessionRecord *const *base; + const SignalConstPointerProtocolAddress *base; size_t length; -} SignalBorrowedSliceOfSessionRecord; +} SignalBorrowedSliceOfConstPointerProtocolAddress; -typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalSenderKeyRecord**, const SignalProtocolAddress*, const uint8_t (*distribution_id)[16]); +typedef struct { + const SignalConstPointerSessionRecord *base; + size_t length; +} SignalBorrowedSliceOfConstPointerSessionRecord; -typedef int (*SignalStoreSenderKey)(void *store_ctx, const SignalProtocolAddress*, const uint8_t (*distribution_id)[16], const SignalSenderKeyRecord*); +typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalMutPointerSenderKeyRecord*, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16]); + +typedef int (*SignalStoreSenderKey)(void *store_ctx, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16], SignalConstPointerSenderKeyRecord); typedef struct { void *ctx; @@ -513,11 +744,71 @@ typedef struct { SignalStoreSenderKey store_sender_key; } SignalSenderKeyStore; +typedef struct { + const SignalSenderKeyStore *raw; +} SignalConstPointerFfiSenderKeyStoreStruct; + +typedef struct { + SignalSgxClientState *raw; +} SignalMutPointerSgxClientState; + +typedef struct { + SignalHsmEnclaveClient *raw; +} SignalMutPointerHsmEnclaveClient; + +typedef struct { + const SignalHsmEnclaveClient *raw; +} SignalConstPointerHsmEnclaveClient; + +typedef struct { + const SignalSgxClientState *raw; +} SignalConstPointerSgxClientState; + +typedef struct { + SignalServerPublicParams *raw; +} SignalMutPointerServerPublicParams; + +typedef struct { + const SignalServerPublicParams *raw; +} SignalConstPointerServerPublicParams; + +typedef struct { + SignalServerSecretParams *raw; +} SignalMutPointerServerSecretParams; + +typedef struct { + const SignalServerSecretParams *raw; +} SignalConstPointerServerSecretParams; + typedef struct { const SignalBorrowedBuffer *base; size_t length; } SignalBorrowedSliceOfBuffers; +typedef struct { + SignalConnectionInfo *raw; +} SignalMutPointerConnectionInfo; + +typedef struct { + SignalConnectionManager *raw; +} SignalMutPointerConnectionManager; + +typedef struct { + const SignalConnectionManager *raw; +} SignalConstPointerConnectionManager; + +typedef struct { + SignalLookupRequest *raw; +} SignalMutPointerLookupRequest; + +typedef struct { + const SignalLookupRequest *raw; +} SignalConstPointerLookupRequest; + +typedef struct { + SignalCdsiLookup *raw; +} SignalMutPointerCdsiLookup; + typedef uint64_t SignalCancellationId; /** @@ -530,40 +821,18 @@ typedef uint64_t SignalCancellationId; * completed once. */ typedef struct { - void (*complete)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); + void (*complete)(SignalFfiError *error, const SignalMutPointerCdsiLookup *result, const void *context); const void *context; SignalCancellationId cancellation_id; -} SignalCPromiseOwnedBufferOfc_uchar; +} SignalCPromiseMutPointerCdsiLookup; -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ typedef struct { - void (*complete)(SignalFfiError *error, const bool *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromisebool; + const SignalTokioAsyncContext *raw; +} SignalConstPointerTokioAsyncContext; -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ typedef struct { - void (*complete)(SignalFfiError *error, SignalCdsiLookup *const *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseCdsiLookup; + const SignalCdsiLookup *raw; +} SignalConstPointerCdsiLookup; typedef struct { SignalOwnedBufferOfFfiCdsiLookupResponseEntry entries; @@ -587,13 +856,37 @@ typedef struct { typedef SignalChatAuthChatService SignalAuthChat; +typedef struct { + SignalAuthChat *raw; +} SignalMutPointerAuthChat; + typedef SignalChatUnauthChatService SignalUnauthChat; typedef struct { - uint8_t raw_ip_type; - double duration_secs; - const char *connection_info; -} SignalFfiChatServiceDebugInfo; + SignalUnauthChat *raw; +} SignalMutPointerUnauthChat; + +typedef struct { + SignalHttpRequest *raw; +} SignalMutPointerHttpRequest; + +typedef struct { + SignalUnauthenticatedChatConnection *raw; +} SignalMutPointerUnauthenticatedChatConnection; + +typedef struct { + SignalAuthenticatedChatConnection *raw; +} SignalMutPointerAuthenticatedChatConnection; + +typedef struct { + const SignalHttpRequest *raw; +} SignalConstPointerHttpRequest; + +typedef SignalConnectionInfo SignalChatConnectionInfo; + +typedef struct { + const SignalChatConnectionInfo *raw; +} SignalConstPointerChatConnectionInfo; /** * A C callback used to report the results of Rust futures. @@ -605,52 +898,14 @@ typedef struct { * completed once. */ typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiChatServiceDebugInfo *result, const void *context); + void (*complete)(SignalFfiError *error, const SignalMutPointerUnauthenticatedChatConnection *result, const void *context); const void *context; SignalCancellationId cancellation_id; -} SignalCPromiseFfiChatServiceDebugInfo; +} SignalCPromiseMutPointerUnauthenticatedChatConnection; typedef struct { - uint16_t status; - const char *message; - SignalOwnedBufferOfCStringPtr headers; - SignalOwnedBuffer body; -} SignalFfiChatResponse; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseFfiChatResponse; - -typedef struct { - SignalFfiChatResponse response; - SignalFfiChatServiceDebugInfo debug_info; -} SignalFfiResponseAndDebugInfo; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiResponseAndDebugInfo *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseFfiResponseAndDebugInfo; + const SignalUnauthenticatedChatConnection *raw; +} SignalConstPointerUnauthenticatedChatConnection; typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envelope, uint64_t timestamp_millis, SignalServerMessageAck *cleanup); @@ -683,6 +938,163 @@ typedef struct { SignalDestroyChatListener destroy; } SignalFfiChatListenerStruct; +typedef struct { + const SignalFfiChatListenerStruct *raw; +} SignalConstPointerFfiChatListenerStruct; + +typedef struct { + uint16_t status; + const char *message; + SignalOwnedBufferOfCStringPtr headers; + SignalOwnedBuffer body; +} SignalFfiChatResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiChatResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const bool *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromisebool; + +typedef struct { + SignalChatConnectionInfo *raw; +} SignalMutPointerChatConnectionInfo; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerAuthenticatedChatConnection *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerAuthenticatedChatConnection; + +typedef struct { + const SignalAuthenticatedChatConnection *raw; +} SignalConstPointerAuthenticatedChatConnection; + +typedef struct { + const SignalUnauthChat *raw; +} SignalConstPointerUnauthChat; + +typedef struct { + const SignalAuthChat *raw; +} SignalConstPointerAuthChat; + +typedef struct { + uint8_t raw_ip_type; + double duration_secs; + const char *connection_info; +} SignalFfiChatServiceDebugInfo; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiChatServiceDebugInfo *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiChatServiceDebugInfo; + +typedef struct { + SignalFfiChatResponse response; + SignalFfiChatServiceDebugInfo debug_info; +} SignalFfiResponseAndDebugInfo; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiResponseAndDebugInfo *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiResponseAndDebugInfo; + +typedef struct { + SignalServerMessageAck *raw; +} SignalMutPointerServerMessageAck; + +typedef struct { + const SignalServerMessageAck *raw; +} SignalConstPointerServerMessageAck; + +typedef struct { + SignalTokioAsyncContext *raw; +} SignalMutPointerTokioAsyncContext; + +typedef struct { + SignalPinHash *raw; +} SignalMutPointerPinHash; + +typedef struct { + const SignalPinHash *raw; +} SignalConstPointerPinHash; + +typedef struct { + SignalIncrementalMac *raw; +} SignalMutPointerIncrementalMac; + +typedef struct { + SignalValidatingMac *raw; +} SignalMutPointerValidatingMac; + +typedef struct { + SignalMessageBackupKey *raw; +} SignalMutPointerMessageBackupKey; + +typedef struct { + SignalMessageBackupValidationOutcome *raw; +} SignalMutPointerMessageBackupValidationOutcome; + +typedef struct { + const SignalMessageBackupKey *raw; +} SignalConstPointerMessageBackupKey; + +typedef struct { + const SignalMessageBackupValidationOutcome *raw; +} SignalConstPointerMessageBackupValidationOutcome; + typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); typedef int (*SignalSkip)(void *ctx, uint64_t amount); @@ -693,8 +1105,28 @@ typedef struct { SignalSkip skip; } SignalInputStream; +typedef struct { + const SignalInputStream *raw; +} SignalConstPointerFfiInputStreamStruct; + +typedef struct { + SignalOnlineBackupValidator *raw; +} SignalMutPointerOnlineBackupValidator; + +typedef struct { + SignalSanitizedMetadata *raw; +} SignalMutPointerSanitizedMetadata; + +typedef struct { + const SignalSanitizedMetadata *raw; +} SignalConstPointerSanitizedMetadata; + typedef SignalInputStream SignalSyncInputStream; +typedef struct { + const SignalSyncInputStream *raw; +} SignalConstPointerFfiSyncInputStreamStruct; + typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN]; void signal_print_ptr(const void *p); @@ -711,7 +1143,7 @@ void signal_free_bytestring_array(SignalBytestringArray array); SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); -SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalProtocolAddress **out); +SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalMutPointerProtocolAddress *out); SignalFfiError *signal_error_get_uuid(const SignalFfiError *err, uint8_t (*out)[16]); @@ -725,129 +1157,129 @@ SignalFfiError *signal_error_get_unknown_fields(const SignalFfiError *err, Signa void signal_error_free(SignalFfiError *err); -SignalFfiError *signal_identitykeypair_deserialize(SignalPrivateKey **private_key, SignalPublicKey **public_key, SignalBorrowedBuffer input); +SignalFfiError *signal_identitykeypair_deserialize(SignalMutPointerPrivateKey *private_key, SignalMutPointerPublicKey *public_key, SignalBorrowedBuffer input); -SignalFfiError *signal_sealed_session_cipher_decrypt(SignalOwnedBuffer *out, const char **sender_e164, const char **sender_uuid, uint32_t *sender_device_id, SignalBorrowedBuffer ctext, const SignalPublicKey *trust_root, uint64_t timestamp, const char *local_e164, const char *local_uuid, unsigned int local_device_id, const SignalSessionStore *session_store, const SignalIdentityKeyStore *identity_store, const SignalPreKeyStore *prekey_store, const SignalSignedPreKeyStore *signed_prekey_store); +SignalFfiError *signal_sealed_session_cipher_decrypt(SignalOwnedBuffer *out, const char **sender_e164, const char **sender_uuid, uint32_t *sender_device_id, SignalBorrowedBuffer ctext, SignalConstPointerPublicKey trust_root, uint64_t timestamp, const char *local_e164, const char *local_uuid, unsigned int local_device_id, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store); bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); -SignalFfiError *signal_aes256_gcm_siv_destroy(SignalAes256GcmSiv *p); +SignalFfiError *signal_aes256_gcm_siv_destroy(SignalMutPointerAes256GcmSiv p); -SignalFfiError *signal_aes256_ctr32_destroy(SignalAes256Ctr32 *p); +SignalFfiError *signal_aes256_ctr32_destroy(SignalMutPointerAes256Ctr32 p); -SignalFfiError *signal_aes256_gcm_encryption_destroy(SignalAes256GcmEncryption *p); +SignalFfiError *signal_aes256_gcm_encryption_destroy(SignalMutPointerAes256GcmEncryption p); -SignalFfiError *signal_aes256_gcm_decryption_destroy(SignalAes256GcmDecryption *p); +SignalFfiError *signal_aes256_gcm_decryption_destroy(SignalMutPointerAes256GcmDecryption p); -SignalFfiError *signal_aes256_ctr32_new(SignalAes256Ctr32 **out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, uint32_t initial_ctr); +SignalFfiError *signal_aes256_ctr32_new(SignalMutPointerAes256Ctr32 *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, uint32_t initial_ctr); -SignalFfiError *signal_aes256_ctr32_process(SignalAes256Ctr32 *ctr, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); +SignalFfiError *signal_aes256_ctr32_process(SignalMutPointerAes256Ctr32 ctr, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); -SignalFfiError *signal_aes256_gcm_encryption_new(SignalAes256GcmEncryption **out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); +SignalFfiError *signal_aes256_gcm_encryption_new(SignalMutPointerAes256GcmEncryption *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); -SignalFfiError *signal_aes256_gcm_encryption_update(SignalAes256GcmEncryption *gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); +SignalFfiError *signal_aes256_gcm_encryption_update(SignalMutPointerAes256GcmEncryption gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); -SignalFfiError *signal_aes256_gcm_encryption_compute_tag(SignalOwnedBuffer *out, SignalAes256GcmEncryption *gcm); +SignalFfiError *signal_aes256_gcm_encryption_compute_tag(SignalOwnedBuffer *out, SignalMutPointerAes256GcmEncryption gcm); -SignalFfiError *signal_aes256_gcm_decryption_new(SignalAes256GcmDecryption **out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); +SignalFfiError *signal_aes256_gcm_decryption_new(SignalMutPointerAes256GcmDecryption *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); -SignalFfiError *signal_aes256_gcm_decryption_update(SignalAes256GcmDecryption *gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); +SignalFfiError *signal_aes256_gcm_decryption_update(SignalMutPointerAes256GcmDecryption gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); -SignalFfiError *signal_aes256_gcm_decryption_verify_tag(bool *out, SignalAes256GcmDecryption *gcm, SignalBorrowedBuffer tag); +SignalFfiError *signal_aes256_gcm_decryption_verify_tag(bool *out, SignalMutPointerAes256GcmDecryption gcm, SignalBorrowedBuffer tag); -SignalFfiError *signal_aes256_gcm_siv_new(SignalAes256GcmSiv **out, SignalBorrowedBuffer key); +SignalFfiError *signal_aes256_gcm_siv_new(SignalMutPointerAes256GcmSiv *out, SignalBorrowedBuffer key); -SignalFfiError *signal_aes256_gcm_siv_encrypt(SignalOwnedBuffer *out, const SignalAes256GcmSiv *aes_gcm_siv_obj, SignalBorrowedBuffer ptext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); +SignalFfiError *signal_aes256_gcm_siv_encrypt(SignalOwnedBuffer *out, SignalConstPointerAes256GcmSiv aes_gcm_siv_obj, SignalBorrowedBuffer ptext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); -SignalFfiError *signal_aes256_gcm_siv_decrypt(SignalOwnedBuffer *out, const SignalAes256GcmSiv *aes_gcm_siv, SignalBorrowedBuffer ctext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); +SignalFfiError *signal_aes256_gcm_siv_decrypt(SignalOwnedBuffer *out, SignalConstPointerAes256GcmSiv aes_gcm_siv, SignalBorrowedBuffer ctext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); -SignalFfiError *signal_ciphertext_message_destroy(SignalCiphertextMessage *p); +SignalFfiError *signal_ciphertext_message_destroy(SignalMutPointerCiphertextMessage p); -SignalFfiError *signal_decryption_error_message_destroy(SignalDecryptionErrorMessage *p); +SignalFfiError *signal_decryption_error_message_destroy(SignalMutPointerDecryptionErrorMessage p); -SignalFfiError *signal_decryption_error_message_clone(SignalDecryptionErrorMessage **new_obj, const SignalDecryptionErrorMessage *obj); +SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); -SignalFfiError *signal_fingerprint_destroy(SignalFingerprint *p); +SignalFfiError *signal_fingerprint_destroy(SignalMutPointerFingerprint p); -SignalFfiError *signal_fingerprint_clone(SignalFingerprint **new_obj, const SignalFingerprint *obj); +SignalFfiError *signal_fingerprint_clone(SignalMutPointerFingerprint *new_obj, SignalConstPointerFingerprint obj); -SignalFfiError *signal_plaintext_content_destroy(SignalPlaintextContent *p); +SignalFfiError *signal_plaintext_content_destroy(SignalMutPointerPlaintextContent p); -SignalFfiError *signal_plaintext_content_clone(SignalPlaintextContent **new_obj, const SignalPlaintextContent *obj); +SignalFfiError *signal_plaintext_content_clone(SignalMutPointerPlaintextContent *new_obj, SignalConstPointerPlaintextContent obj); -SignalFfiError *signal_pre_key_bundle_destroy(SignalPreKeyBundle *p); +SignalFfiError *signal_pre_key_bundle_destroy(SignalMutPointerPreKeyBundle p); -SignalFfiError *signal_pre_key_bundle_clone(SignalPreKeyBundle **new_obj, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_clone(SignalMutPointerPreKeyBundle *new_obj, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_record_destroy(SignalPreKeyRecord *p); +SignalFfiError *signal_pre_key_record_destroy(SignalMutPointerPreKeyRecord p); -SignalFfiError *signal_pre_key_record_clone(SignalPreKeyRecord **new_obj, const SignalPreKeyRecord *obj); +SignalFfiError *signal_pre_key_record_clone(SignalMutPointerPreKeyRecord *new_obj, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_pre_key_signal_message_destroy(SignalPreKeySignalMessage *p); +SignalFfiError *signal_pre_key_signal_message_destroy(SignalMutPointerPreKeySignalMessage p); -SignalFfiError *signal_pre_key_signal_message_clone(SignalPreKeySignalMessage **new_obj, const SignalPreKeySignalMessage *obj); +SignalFfiError *signal_pre_key_signal_message_clone(SignalMutPointerPreKeySignalMessage *new_obj, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_privatekey_destroy(SignalPrivateKey *p); +SignalFfiError *signal_privatekey_destroy(SignalMutPointerPrivateKey p); -SignalFfiError *signal_privatekey_clone(SignalPrivateKey **new_obj, const SignalPrivateKey *obj); +SignalFfiError *signal_privatekey_clone(SignalMutPointerPrivateKey *new_obj, SignalConstPointerPrivateKey obj); -SignalFfiError *signal_address_destroy(SignalProtocolAddress *p); +SignalFfiError *signal_address_destroy(SignalMutPointerProtocolAddress p); -SignalFfiError *signal_address_clone(SignalProtocolAddress **new_obj, const SignalProtocolAddress *obj); +SignalFfiError *signal_address_clone(SignalMutPointerProtocolAddress *new_obj, SignalConstPointerProtocolAddress obj); -SignalFfiError *signal_publickey_destroy(SignalPublicKey *p); +SignalFfiError *signal_publickey_destroy(SignalMutPointerPublicKey p); -SignalFfiError *signal_publickey_clone(SignalPublicKey **new_obj, const SignalPublicKey *obj); +SignalFfiError *signal_publickey_clone(SignalMutPointerPublicKey *new_obj, SignalConstPointerPublicKey obj); -SignalFfiError *signal_sender_certificate_destroy(SignalSenderCertificate *p); +SignalFfiError *signal_sender_certificate_destroy(SignalMutPointerSenderCertificate p); -SignalFfiError *signal_sender_certificate_clone(SignalSenderCertificate **new_obj, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_clone(SignalMutPointerSenderCertificate *new_obj, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_key_distribution_message_destroy(SignalSenderKeyDistributionMessage *p); +SignalFfiError *signal_sender_key_distribution_message_destroy(SignalMutPointerSenderKeyDistributionMessage p); -SignalFfiError *signal_sender_key_distribution_message_clone(SignalSenderKeyDistributionMessage **new_obj, const SignalSenderKeyDistributionMessage *obj); +SignalFfiError *signal_sender_key_distribution_message_clone(SignalMutPointerSenderKeyDistributionMessage *new_obj, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_message_destroy(SignalSenderKeyMessage *p); +SignalFfiError *signal_sender_key_message_destroy(SignalMutPointerSenderKeyMessage p); -SignalFfiError *signal_sender_key_message_clone(SignalSenderKeyMessage **new_obj, const SignalSenderKeyMessage *obj); +SignalFfiError *signal_sender_key_message_clone(SignalMutPointerSenderKeyMessage *new_obj, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_record_destroy(SignalSenderKeyRecord *p); +SignalFfiError *signal_sender_key_record_destroy(SignalMutPointerSenderKeyRecord p); -SignalFfiError *signal_sender_key_record_clone(SignalSenderKeyRecord **new_obj, const SignalSenderKeyRecord *obj); +SignalFfiError *signal_sender_key_record_clone(SignalMutPointerSenderKeyRecord *new_obj, SignalConstPointerSenderKeyRecord obj); -SignalFfiError *signal_server_certificate_destroy(SignalServerCertificate *p); +SignalFfiError *signal_server_certificate_destroy(SignalMutPointerServerCertificate p); -SignalFfiError *signal_server_certificate_clone(SignalServerCertificate **new_obj, const SignalServerCertificate *obj); +SignalFfiError *signal_server_certificate_clone(SignalMutPointerServerCertificate *new_obj, SignalConstPointerServerCertificate obj); -SignalFfiError *signal_session_record_destroy(SignalSessionRecord *p); +SignalFfiError *signal_session_record_destroy(SignalMutPointerSessionRecord p); -SignalFfiError *signal_session_record_clone(SignalSessionRecord **new_obj, const SignalSessionRecord *obj); +SignalFfiError *signal_session_record_clone(SignalMutPointerSessionRecord *new_obj, SignalConstPointerSessionRecord obj); -SignalFfiError *signal_message_destroy(SignalMessage *p); +SignalFfiError *signal_message_destroy(SignalMutPointerSignalMessage p); -SignalFfiError *signal_message_clone(SignalMessage **new_obj, const SignalMessage *obj); +SignalFfiError *signal_message_clone(SignalMutPointerSignalMessage *new_obj, SignalConstPointerSignalMessage obj); -SignalFfiError *signal_signed_pre_key_record_destroy(SignalSignedPreKeyRecord *p); +SignalFfiError *signal_signed_pre_key_record_destroy(SignalMutPointerSignedPreKeyRecord p); -SignalFfiError *signal_signed_pre_key_record_clone(SignalSignedPreKeyRecord **new_obj, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_clone(SignalMutPointerSignedPreKeyRecord *new_obj, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_destroy(SignalKyberPreKeyRecord *p); +SignalFfiError *signal_kyber_pre_key_record_destroy(SignalMutPointerKyberPreKeyRecord p); -SignalFfiError *signal_kyber_pre_key_record_clone(SignalKyberPreKeyRecord **new_obj, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_clone(SignalMutPointerKyberPreKeyRecord *new_obj, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_unidentified_sender_message_content_destroy(SignalUnidentifiedSenderMessageContent *p); +SignalFfiError *signal_unidentified_sender_message_content_destroy(SignalMutPointerUnidentifiedSenderMessageContent p); -SignalFfiError *signal_kyber_key_pair_destroy(SignalKyberKeyPair *p); +SignalFfiError *signal_kyber_key_pair_destroy(SignalMutPointerKyberKeyPair p); -SignalFfiError *signal_kyber_key_pair_clone(SignalKyberKeyPair **new_obj, const SignalKyberKeyPair *obj); +SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj); -SignalFfiError *signal_kyber_public_key_destroy(SignalKyberPublicKey *p); +SignalFfiError *signal_kyber_public_key_destroy(SignalMutPointerKyberPublicKey p); -SignalFfiError *signal_kyber_public_key_clone(SignalKyberPublicKey **new_obj, const SignalKyberPublicKey *obj); +SignalFfiError *signal_kyber_public_key_clone(SignalMutPointerKyberPublicKey *new_obj, SignalConstPointerKyberPublicKey obj); -SignalFfiError *signal_kyber_secret_key_destroy(SignalKyberSecretKey *p); +SignalFfiError *signal_kyber_secret_key_destroy(SignalMutPointerKyberSecretKey p); -SignalFfiError *signal_kyber_secret_key_clone(SignalKyberSecretKey **new_obj, const SignalKyberSecretKey *obj); +SignalFfiError *signal_kyber_secret_key_clone(SignalMutPointerKyberSecretKey *new_obj, SignalConstPointerKyberSecretKey obj); SignalFfiError *signal_hkdf_derive(SignalBorrowedMutableBuffer output, SignalBorrowedBuffer ikm, SignalBorrowedBuffer label, SignalBorrowedBuffer salt); @@ -861,327 +1293,327 @@ SignalFfiError *signal_service_id_parse_from_service_id_binary(SignalServiceIdFi SignalFfiError *signal_service_id_parse_from_service_id_string(SignalServiceIdFixedWidthBinaryBytes *out, const char *input); -SignalFfiError *signal_address_new(SignalProtocolAddress **out, const char *name, uint32_t device_id); +SignalFfiError *signal_address_new(SignalMutPointerProtocolAddress *out, const char *name, uint32_t device_id); -SignalFfiError *signal_publickey_deserialize(SignalPublicKey **out, SignalBorrowedBuffer data); +SignalFfiError *signal_publickey_deserialize(SignalMutPointerPublicKey *out, SignalBorrowedBuffer data); -SignalFfiError *signal_publickey_serialize(SignalOwnedBuffer *out, const SignalPublicKey *obj); +SignalFfiError *signal_publickey_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); -SignalFfiError *signal_publickey_get_public_key_bytes(SignalOwnedBuffer *out, const SignalPublicKey *obj); +SignalFfiError *signal_publickey_get_public_key_bytes(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); -SignalFfiError *signal_address_get_device_id(uint32_t *out, const SignalProtocolAddress *obj); +SignalFfiError *signal_address_get_device_id(uint32_t *out, SignalConstPointerProtocolAddress obj); -SignalFfiError *signal_address_get_name(const char **out, const SignalProtocolAddress *obj); +SignalFfiError *signal_address_get_name(const char **out, SignalConstPointerProtocolAddress obj); -SignalFfiError *signal_publickey_equals(bool *out, const SignalPublicKey *lhs, const SignalPublicKey *rhs); +SignalFfiError *signal_publickey_equals(bool *out, SignalConstPointerPublicKey lhs, SignalConstPointerPublicKey rhs); -SignalFfiError *signal_publickey_compare(int32_t *out, const SignalPublicKey *key1, const SignalPublicKey *key2); +SignalFfiError *signal_publickey_compare(int32_t *out, SignalConstPointerPublicKey key1, SignalConstPointerPublicKey key2); -SignalFfiError *signal_publickey_verify(bool *out, const SignalPublicKey *key, SignalBorrowedBuffer message, SignalBorrowedBuffer signature); +SignalFfiError *signal_publickey_verify(bool *out, SignalConstPointerPublicKey key, SignalBorrowedBuffer message, SignalBorrowedBuffer signature); -SignalFfiError *signal_privatekey_deserialize(SignalPrivateKey **out, SignalBorrowedBuffer data); +SignalFfiError *signal_privatekey_deserialize(SignalMutPointerPrivateKey *out, SignalBorrowedBuffer data); -SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, const SignalPrivateKey *obj); +SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstPointerPrivateKey obj); -SignalFfiError *signal_privatekey_generate(SignalPrivateKey **out); +SignalFfiError *signal_privatekey_generate(SignalMutPointerPrivateKey *out); -SignalFfiError *signal_privatekey_get_public_key(SignalPublicKey **out, const SignalPrivateKey *k); +SignalFfiError *signal_privatekey_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPrivateKey k); -SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, const SignalPrivateKey *key, SignalBorrowedBuffer message); +SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); -SignalFfiError *signal_privatekey_agree(SignalOwnedBuffer *out, const SignalPrivateKey *private_key, const SignalPublicKey *public_key); +SignalFfiError *signal_privatekey_agree(SignalOwnedBuffer *out, SignalConstPointerPrivateKey private_key, SignalConstPointerPublicKey public_key); -SignalFfiError *signal_kyber_public_key_serialize(SignalOwnedBuffer *out, const SignalKyberPublicKey *obj); +SignalFfiError *signal_kyber_public_key_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberPublicKey obj); -SignalFfiError *signal_kyber_public_key_deserialize(SignalKyberPublicKey **out, SignalBorrowedBuffer data); +SignalFfiError *signal_kyber_public_key_deserialize(SignalMutPointerKyberPublicKey *out, SignalBorrowedBuffer data); -SignalFfiError *signal_kyber_secret_key_serialize(SignalOwnedBuffer *out, const SignalKyberSecretKey *obj); +SignalFfiError *signal_kyber_secret_key_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberSecretKey obj); -SignalFfiError *signal_kyber_secret_key_deserialize(SignalKyberSecretKey **out, SignalBorrowedBuffer data); +SignalFfiError *signal_kyber_secret_key_deserialize(SignalMutPointerKyberSecretKey *out, SignalBorrowedBuffer data); -SignalFfiError *signal_kyber_public_key_equals(bool *out, const SignalKyberPublicKey *lhs, const SignalKyberPublicKey *rhs); +SignalFfiError *signal_kyber_public_key_equals(bool *out, SignalConstPointerKyberPublicKey lhs, SignalConstPointerKyberPublicKey rhs); -SignalFfiError *signal_kyber_key_pair_generate(SignalKyberKeyPair **out); +SignalFfiError *signal_kyber_key_pair_generate(SignalMutPointerKyberKeyPair *out); -SignalFfiError *signal_kyber_key_pair_get_public_key(SignalKyberPublicKey **out, const SignalKyberKeyPair *key_pair); +SignalFfiError *signal_kyber_key_pair_get_public_key(SignalMutPointerKyberPublicKey *out, SignalConstPointerKyberKeyPair key_pair); -SignalFfiError *signal_kyber_key_pair_get_secret_key(SignalKyberSecretKey **out, const SignalKyberKeyPair *key_pair); +SignalFfiError *signal_kyber_key_pair_get_secret_key(SignalMutPointerKyberSecretKey *out, SignalConstPointerKyberKeyPair key_pair); -SignalFfiError *signal_identitykeypair_serialize(SignalOwnedBuffer *out, const SignalPublicKey *public_key, const SignalPrivateKey *private_key); +SignalFfiError *signal_identitykeypair_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key); -SignalFfiError *signal_identitykeypair_sign_alternate_identity(SignalOwnedBuffer *out, const SignalPublicKey *public_key, const SignalPrivateKey *private_key, const SignalPublicKey *other_identity); +SignalFfiError *signal_identitykeypair_sign_alternate_identity(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key, SignalConstPointerPublicKey other_identity); -SignalFfiError *signal_identitykey_verify_alternate_identity(bool *out, const SignalPublicKey *public_key, const SignalPublicKey *other_identity, SignalBorrowedBuffer signature); +SignalFfiError *signal_identitykey_verify_alternate_identity(bool *out, SignalConstPointerPublicKey public_key, SignalConstPointerPublicKey other_identity, SignalBorrowedBuffer signature); -SignalFfiError *signal_fingerprint_new(SignalFingerprint **out, uint32_t iterations, uint32_t version, SignalBorrowedBuffer local_identifier, const SignalPublicKey *local_key, SignalBorrowedBuffer remote_identifier, const SignalPublicKey *remote_key); +SignalFfiError *signal_fingerprint_new(SignalMutPointerFingerprint *out, uint32_t iterations, uint32_t version, SignalBorrowedBuffer local_identifier, SignalConstPointerPublicKey local_key, SignalBorrowedBuffer remote_identifier, SignalConstPointerPublicKey remote_key); -SignalFfiError *signal_fingerprint_scannable_encoding(SignalOwnedBuffer *out, const SignalFingerprint *obj); +SignalFfiError *signal_fingerprint_scannable_encoding(SignalOwnedBuffer *out, SignalConstPointerFingerprint obj); -SignalFfiError *signal_fingerprint_display_string(const char **out, const SignalFingerprint *obj); +SignalFfiError *signal_fingerprint_display_string(const char **out, SignalConstPointerFingerprint obj); SignalFfiError *signal_fingerprint_compare(bool *out, SignalBorrowedBuffer fprint1, SignalBorrowedBuffer fprint2); -SignalFfiError *signal_message_deserialize(SignalMessage **out, SignalBorrowedBuffer data); +SignalFfiError *signal_message_deserialize(SignalMutPointerSignalMessage *out, SignalBorrowedBuffer data); -SignalFfiError *signal_message_get_body(SignalOwnedBuffer *out, const SignalMessage *obj); +SignalFfiError *signal_message_get_body(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); -SignalFfiError *signal_message_get_serialized(SignalOwnedBuffer *out, const SignalMessage *obj); +SignalFfiError *signal_message_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); -SignalFfiError *signal_message_get_counter(uint32_t *out, const SignalMessage *obj); +SignalFfiError *signal_message_get_counter(uint32_t *out, SignalConstPointerSignalMessage obj); -SignalFfiError *signal_message_get_message_version(uint32_t *out, const SignalMessage *obj); +SignalFfiError *signal_message_get_message_version(uint32_t *out, SignalConstPointerSignalMessage obj); -SignalFfiError *signal_message_new(SignalMessage **out, uint8_t message_version, SignalBorrowedBuffer mac_key, const SignalPublicKey *sender_ratchet_key, uint32_t counter, uint32_t previous_counter, SignalBorrowedBuffer ciphertext, const SignalPublicKey *sender_identity_key, const SignalPublicKey *receiver_identity_key); +SignalFfiError *signal_message_new(SignalMutPointerSignalMessage *out, uint8_t message_version, SignalBorrowedBuffer mac_key, SignalConstPointerPublicKey sender_ratchet_key, uint32_t counter, uint32_t previous_counter, SignalBorrowedBuffer ciphertext, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key); -SignalFfiError *signal_message_verify_mac(bool *out, const SignalMessage *msg, const SignalPublicKey *sender_identity_key, const SignalPublicKey *receiver_identity_key, SignalBorrowedBuffer mac_key); +SignalFfiError *signal_message_verify_mac(bool *out, SignalConstPointerSignalMessage msg, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key, SignalBorrowedBuffer mac_key); -SignalFfiError *signal_message_get_sender_ratchet_key(SignalPublicKey **out, const SignalMessage *m); +SignalFfiError *signal_message_get_sender_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerSignalMessage m); -SignalFfiError *signal_pre_key_signal_message_new(SignalPreKeySignalMessage **out, uint8_t message_version, uint32_t registration_id, uint32_t pre_key_id, uint32_t signed_pre_key_id, const SignalPublicKey *base_key, const SignalPublicKey *identity_key, const SignalMessage *signal_message); +SignalFfiError *signal_pre_key_signal_message_new(SignalMutPointerPreKeySignalMessage *out, uint8_t message_version, uint32_t registration_id, uint32_t pre_key_id, uint32_t signed_pre_key_id, SignalConstPointerPublicKey base_key, SignalConstPointerPublicKey identity_key, SignalConstPointerSignalMessage signal_message); -SignalFfiError *signal_pre_key_signal_message_get_base_key(SignalPublicKey **out, const SignalPreKeySignalMessage *m); +SignalFfiError *signal_pre_key_signal_message_get_base_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeySignalMessage m); -SignalFfiError *signal_pre_key_signal_message_get_identity_key(SignalPublicKey **out, const SignalPreKeySignalMessage *m); +SignalFfiError *signal_pre_key_signal_message_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeySignalMessage m); -SignalFfiError *signal_pre_key_signal_message_get_signal_message(SignalMessage **out, const SignalPreKeySignalMessage *m); +SignalFfiError *signal_pre_key_signal_message_get_signal_message(SignalMutPointerSignalMessage *out, SignalConstPointerPreKeySignalMessage m); -SignalFfiError *signal_pre_key_signal_message_deserialize(SignalPreKeySignalMessage **out, SignalBorrowedBuffer data); +SignalFfiError *signal_pre_key_signal_message_deserialize(SignalMutPointerPreKeySignalMessage *out, SignalBorrowedBuffer data); -SignalFfiError *signal_pre_key_signal_message_serialize(SignalOwnedBuffer *out, const SignalPreKeySignalMessage *obj); +SignalFfiError *signal_pre_key_signal_message_serialize(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_pre_key_signal_message_get_registration_id(uint32_t *out, const SignalPreKeySignalMessage *obj); +SignalFfiError *signal_pre_key_signal_message_get_registration_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_pre_key_signal_message_get_signed_pre_key_id(uint32_t *out, const SignalPreKeySignalMessage *obj); +SignalFfiError *signal_pre_key_signal_message_get_signed_pre_key_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_pre_key_signal_message_get_pre_key_id(uint32_t *out, const SignalPreKeySignalMessage *obj); +SignalFfiError *signal_pre_key_signal_message_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_pre_key_signal_message_get_version(uint32_t *out, const SignalPreKeySignalMessage *obj); +SignalFfiError *signal_pre_key_signal_message_get_version(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_sender_key_message_deserialize(SignalSenderKeyMessage **out, SignalBorrowedBuffer data); +SignalFfiError *signal_sender_key_message_deserialize(SignalMutPointerSenderKeyMessage *out, SignalBorrowedBuffer data); -SignalFfiError *signal_sender_key_message_get_cipher_text(SignalOwnedBuffer *out, const SignalSenderKeyMessage *obj); +SignalFfiError *signal_sender_key_message_get_cipher_text(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_serialize(SignalOwnedBuffer *out, const SignalSenderKeyMessage *obj); +SignalFfiError *signal_sender_key_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_get_distribution_id(uint8_t (*out)[16], const SignalSenderKeyMessage *obj); +SignalFfiError *signal_sender_key_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_get_chain_id(uint32_t *out, const SignalSenderKeyMessage *obj); +SignalFfiError *signal_sender_key_message_get_chain_id(uint32_t *out, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_get_iteration(uint32_t *out, const SignalSenderKeyMessage *obj); +SignalFfiError *signal_sender_key_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_new(SignalSenderKeyMessage **out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer ciphertext, const SignalPrivateKey *pk); +SignalFfiError *signal_sender_key_message_new(SignalMutPointerSenderKeyMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer ciphertext, SignalConstPointerPrivateKey pk); -SignalFfiError *signal_sender_key_message_verify_signature(bool *out, const SignalSenderKeyMessage *skm, const SignalPublicKey *pubkey); +SignalFfiError *signal_sender_key_message_verify_signature(bool *out, SignalConstPointerSenderKeyMessage skm, SignalConstPointerPublicKey pubkey); -SignalFfiError *signal_sender_key_distribution_message_deserialize(SignalSenderKeyDistributionMessage **out, SignalBorrowedBuffer data); +SignalFfiError *signal_sender_key_distribution_message_deserialize(SignalMutPointerSenderKeyDistributionMessage *out, SignalBorrowedBuffer data); -SignalFfiError *signal_sender_key_distribution_message_get_chain_key(SignalOwnedBuffer *out, const SignalSenderKeyDistributionMessage *obj); +SignalFfiError *signal_sender_key_distribution_message_get_chain_key(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_serialize(SignalOwnedBuffer *out, const SignalSenderKeyDistributionMessage *obj); +SignalFfiError *signal_sender_key_distribution_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_get_distribution_id(uint8_t (*out)[16], const SignalSenderKeyDistributionMessage *obj); +SignalFfiError *signal_sender_key_distribution_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_get_chain_id(uint32_t *out, const SignalSenderKeyDistributionMessage *obj); +SignalFfiError *signal_sender_key_distribution_message_get_chain_id(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_get_iteration(uint32_t *out, const SignalSenderKeyDistributionMessage *obj); +SignalFfiError *signal_sender_key_distribution_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_new(SignalSenderKeyDistributionMessage **out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer chainkey, const SignalPublicKey *pk); +SignalFfiError *signal_sender_key_distribution_message_new(SignalMutPointerSenderKeyDistributionMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer chainkey, SignalConstPointerPublicKey pk); -SignalFfiError *signal_sender_key_distribution_message_get_signature_key(SignalPublicKey **out, const SignalSenderKeyDistributionMessage *m); +SignalFfiError *signal_sender_key_distribution_message_get_signature_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderKeyDistributionMessage m); -SignalFfiError *signal_decryption_error_message_deserialize(SignalDecryptionErrorMessage **out, SignalBorrowedBuffer data); +SignalFfiError *signal_decryption_error_message_deserialize(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer data); -SignalFfiError *signal_decryption_error_message_get_timestamp(uint64_t *out, const SignalDecryptionErrorMessage *obj); +SignalFfiError *signal_decryption_error_message_get_timestamp(uint64_t *out, SignalConstPointerDecryptionErrorMessage obj); -SignalFfiError *signal_decryption_error_message_get_device_id(uint32_t *out, const SignalDecryptionErrorMessage *obj); +SignalFfiError *signal_decryption_error_message_get_device_id(uint32_t *out, SignalConstPointerDecryptionErrorMessage obj); -SignalFfiError *signal_decryption_error_message_serialize(SignalOwnedBuffer *out, const SignalDecryptionErrorMessage *obj); +SignalFfiError *signal_decryption_error_message_serialize(SignalOwnedBuffer *out, SignalConstPointerDecryptionErrorMessage obj); -SignalFfiError *signal_decryption_error_message_get_ratchet_key(SignalPublicKey **out, const SignalDecryptionErrorMessage *m); +SignalFfiError *signal_decryption_error_message_get_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerDecryptionErrorMessage m); -SignalFfiError *signal_decryption_error_message_for_original_message(SignalDecryptionErrorMessage **out, SignalBorrowedBuffer original_bytes, uint8_t original_type, uint64_t original_timestamp, uint32_t original_sender_device_id); +SignalFfiError *signal_decryption_error_message_for_original_message(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer original_bytes, uint8_t original_type, uint64_t original_timestamp, uint32_t original_sender_device_id); -SignalFfiError *signal_decryption_error_message_extract_from_serialized_content(SignalDecryptionErrorMessage **out, SignalBorrowedBuffer bytes); +SignalFfiError *signal_decryption_error_message_extract_from_serialized_content(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer bytes); -SignalFfiError *signal_plaintext_content_deserialize(SignalPlaintextContent **out, SignalBorrowedBuffer data); +SignalFfiError *signal_plaintext_content_deserialize(SignalMutPointerPlaintextContent *out, SignalBorrowedBuffer data); -SignalFfiError *signal_plaintext_content_serialize(SignalOwnedBuffer *out, const SignalPlaintextContent *obj); +SignalFfiError *signal_plaintext_content_serialize(SignalOwnedBuffer *out, SignalConstPointerPlaintextContent obj); -SignalFfiError *signal_plaintext_content_get_body(SignalOwnedBuffer *out, const SignalPlaintextContent *obj); +SignalFfiError *signal_plaintext_content_get_body(SignalOwnedBuffer *out, SignalConstPointerPlaintextContent obj); -SignalFfiError *signal_plaintext_content_from_decryption_error_message(SignalPlaintextContent **out, const SignalDecryptionErrorMessage *m); +SignalFfiError *signal_plaintext_content_from_decryption_error_message(SignalMutPointerPlaintextContent *out, SignalConstPointerDecryptionErrorMessage m); -SignalFfiError *signal_pre_key_bundle_new(SignalPreKeyBundle **out, uint32_t registration_id, uint32_t device_id, uint32_t prekey_id, const SignalPublicKey *prekey, uint32_t signed_prekey_id, const SignalPublicKey *signed_prekey, SignalBorrowedBuffer signed_prekey_signature, const SignalPublicKey *identity_key, uint32_t kyber_prekey_id, const SignalKyberPublicKey *kyber_prekey, SignalBorrowedBuffer kyber_prekey_signature); +SignalFfiError *signal_pre_key_bundle_new(SignalMutPointerPreKeyBundle *out, uint32_t registration_id, uint32_t device_id, uint32_t prekey_id, SignalConstPointerPublicKey prekey, uint32_t signed_prekey_id, SignalConstPointerPublicKey signed_prekey, SignalBorrowedBuffer signed_prekey_signature, SignalConstPointerPublicKey identity_key, uint32_t kyber_prekey_id, SignalConstPointerKyberPublicKey kyber_prekey, SignalBorrowedBuffer kyber_prekey_signature); -SignalFfiError *signal_pre_key_bundle_get_identity_key(SignalPublicKey **out, const SignalPreKeyBundle *p); +SignalFfiError *signal_pre_key_bundle_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle p); -SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_signature(SignalOwnedBuffer *out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_registration_id(uint32_t *out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_registration_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_device_id(uint32_t *out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_device_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_id(uint32_t *out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_pre_key_id(uint32_t *out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_pre_key_public(SignalPublicKey **out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_pre_key_public(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_public(SignalPublicKey **out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_public(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, const SignalPreKeyBundle *obj); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalKyberPublicKey **out, const SignalPreKeyBundle *bundle); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalMutPointerKyberPublicKey *out, SignalConstPointerPreKeyBundle bundle); -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, const SignalPreKeyBundle *bundle); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle bundle); -SignalFfiError *signal_signed_pre_key_record_deserialize(SignalSignedPreKeyRecord **out, SignalBorrowedBuffer data); +SignalFfiError *signal_signed_pre_key_record_deserialize(SignalMutPointerSignedPreKeyRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_signed_pre_key_record_get_signature(SignalOwnedBuffer *out, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_get_signature(SignalOwnedBuffer *out, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_signed_pre_key_record_serialize(SignalOwnedBuffer *out, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_signed_pre_key_record_get_id(uint32_t *out, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_get_id(uint32_t *out, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_signed_pre_key_record_get_timestamp(uint64_t *out, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_get_timestamp(uint64_t *out, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_signed_pre_key_record_get_public_key(SignalPublicKey **out, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_signed_pre_key_record_get_private_key(SignalPrivateKey **out, const SignalSignedPreKeyRecord *obj); +SignalFfiError *signal_signed_pre_key_record_get_private_key(SignalMutPointerPrivateKey *out, SignalConstPointerSignedPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_deserialize(SignalKyberPreKeyRecord **out, SignalBorrowedBuffer data); +SignalFfiError *signal_kyber_pre_key_record_deserialize(SignalMutPointerKyberPreKeyRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_kyber_pre_key_record_get_signature(SignalOwnedBuffer *out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_get_signature(SignalOwnedBuffer *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_serialize(SignalOwnedBuffer *out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_get_id(uint32_t *out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_get_id(uint32_t *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_get_timestamp(uint64_t *out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_get_timestamp(uint64_t *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_get_public_key(SignalKyberPublicKey **out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_get_public_key(SignalMutPointerKyberPublicKey *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_get_secret_key(SignalKyberSecretKey **out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_get_secret_key(SignalMutPointerKyberSecretKey *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_kyber_pre_key_record_get_key_pair(SignalKyberKeyPair **out, const SignalKyberPreKeyRecord *obj); +SignalFfiError *signal_kyber_pre_key_record_get_key_pair(SignalMutPointerKyberKeyPair *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_signed_pre_key_record_new(SignalSignedPreKeyRecord **out, uint32_t id, uint64_t timestamp, const SignalPublicKey *pub_key, const SignalPrivateKey *priv_key, SignalBorrowedBuffer signature); +SignalFfiError *signal_signed_pre_key_record_new(SignalMutPointerSignedPreKeyRecord *out, uint32_t id, uint64_t timestamp, SignalConstPointerPublicKey pub_key, SignalConstPointerPrivateKey priv_key, SignalBorrowedBuffer signature); -SignalFfiError *signal_kyber_pre_key_record_new(SignalKyberPreKeyRecord **out, uint32_t id, uint64_t timestamp, const SignalKyberKeyPair *key_pair, SignalBorrowedBuffer signature); +SignalFfiError *signal_kyber_pre_key_record_new(SignalMutPointerKyberPreKeyRecord *out, uint32_t id, uint64_t timestamp, SignalConstPointerKyberKeyPair key_pair, SignalBorrowedBuffer signature); -SignalFfiError *signal_pre_key_record_deserialize(SignalPreKeyRecord **out, SignalBorrowedBuffer data); +SignalFfiError *signal_pre_key_record_deserialize(SignalMutPointerPreKeyRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_pre_key_record_serialize(SignalOwnedBuffer *out, const SignalPreKeyRecord *obj); +SignalFfiError *signal_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_pre_key_record_get_id(uint32_t *out, const SignalPreKeyRecord *obj); +SignalFfiError *signal_pre_key_record_get_id(uint32_t *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_pre_key_record_get_public_key(SignalPublicKey **out, const SignalPreKeyRecord *obj); +SignalFfiError *signal_pre_key_record_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_pre_key_record_get_private_key(SignalPrivateKey **out, const SignalPreKeyRecord *obj); +SignalFfiError *signal_pre_key_record_get_private_key(SignalMutPointerPrivateKey *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_pre_key_record_new(SignalPreKeyRecord **out, uint32_t id, const SignalPublicKey *pub_key, const SignalPrivateKey *priv_key); +SignalFfiError *signal_pre_key_record_new(SignalMutPointerPreKeyRecord *out, uint32_t id, SignalConstPointerPublicKey pub_key, SignalConstPointerPrivateKey priv_key); -SignalFfiError *signal_sender_key_record_deserialize(SignalSenderKeyRecord **out, SignalBorrowedBuffer data); +SignalFfiError *signal_sender_key_record_deserialize(SignalMutPointerSenderKeyRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_sender_key_record_serialize(SignalOwnedBuffer *out, const SignalSenderKeyRecord *obj); +SignalFfiError *signal_sender_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyRecord obj); -SignalFfiError *signal_server_certificate_deserialize(SignalServerCertificate **out, SignalBorrowedBuffer data); +SignalFfiError *signal_server_certificate_deserialize(SignalMutPointerServerCertificate *out, SignalBorrowedBuffer data); -SignalFfiError *signal_server_certificate_get_serialized(SignalOwnedBuffer *out, const SignalServerCertificate *obj); +SignalFfiError *signal_server_certificate_get_serialized(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); -SignalFfiError *signal_server_certificate_get_certificate(SignalOwnedBuffer *out, const SignalServerCertificate *obj); +SignalFfiError *signal_server_certificate_get_certificate(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); -SignalFfiError *signal_server_certificate_get_signature(SignalOwnedBuffer *out, const SignalServerCertificate *obj); +SignalFfiError *signal_server_certificate_get_signature(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); -SignalFfiError *signal_server_certificate_get_key_id(uint32_t *out, const SignalServerCertificate *obj); +SignalFfiError *signal_server_certificate_get_key_id(uint32_t *out, SignalConstPointerServerCertificate obj); -SignalFfiError *signal_server_certificate_get_key(SignalPublicKey **out, const SignalServerCertificate *obj); +SignalFfiError *signal_server_certificate_get_key(SignalMutPointerPublicKey *out, SignalConstPointerServerCertificate obj); -SignalFfiError *signal_server_certificate_new(SignalServerCertificate **out, uint32_t key_id, const SignalPublicKey *server_key, const SignalPrivateKey *trust_root); +SignalFfiError *signal_server_certificate_new(SignalMutPointerServerCertificate *out, uint32_t key_id, SignalConstPointerPublicKey server_key, SignalConstPointerPrivateKey trust_root); -SignalFfiError *signal_sender_certificate_deserialize(SignalSenderCertificate **out, SignalBorrowedBuffer data); +SignalFfiError *signal_sender_certificate_deserialize(SignalMutPointerSenderCertificate *out, SignalBorrowedBuffer data); -SignalFfiError *signal_sender_certificate_get_serialized(SignalOwnedBuffer *out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_certificate(SignalOwnedBuffer *out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_certificate(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_signature(SignalOwnedBuffer *out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_signature(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_sender_uuid(const char **out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_sender_uuid(const char **out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_sender_e164(const char **out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_sender_e164(const char **out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_expiration(uint64_t *out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_expiration(uint64_t *out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_device_id(uint32_t *out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_device_id(uint32_t *out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_get_key(SignalPublicKey **out, const SignalSenderCertificate *obj); +SignalFfiError *signal_sender_certificate_get_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderCertificate obj); -SignalFfiError *signal_sender_certificate_validate(bool *out, const SignalSenderCertificate *cert, const SignalPublicKey *key, uint64_t time); +SignalFfiError *signal_sender_certificate_validate(bool *out, SignalConstPointerSenderCertificate cert, SignalConstPointerPublicKey key, uint64_t time); -SignalFfiError *signal_sender_certificate_get_server_certificate(SignalServerCertificate **out, const SignalSenderCertificate *cert); +SignalFfiError *signal_sender_certificate_get_server_certificate(SignalMutPointerServerCertificate *out, SignalConstPointerSenderCertificate cert); -SignalFfiError *signal_sender_certificate_new(SignalSenderCertificate **out, const char *sender_uuid, const char *sender_e164, uint32_t sender_device_id, const SignalPublicKey *sender_key, uint64_t expiration, const SignalServerCertificate *signer_cert, const SignalPrivateKey *signer_key); +SignalFfiError *signal_sender_certificate_new(SignalMutPointerSenderCertificate *out, const char *sender_uuid, const char *sender_e164, uint32_t sender_device_id, SignalConstPointerPublicKey sender_key, uint64_t expiration, SignalConstPointerServerCertificate signer_cert, SignalConstPointerPrivateKey signer_key); -SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalUnidentifiedSenderMessageContent **out, SignalBorrowedBuffer data); +SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); -SignalFfiError *signal_unidentified_sender_message_content_serialize(SignalOwnedBuffer *out, const SignalUnidentifiedSenderMessageContent *obj); +SignalFfiError *signal_unidentified_sender_message_content_serialize(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent obj); -SignalFfiError *signal_unidentified_sender_message_content_get_contents(SignalOwnedBuffer *out, const SignalUnidentifiedSenderMessageContent *obj); +SignalFfiError *signal_unidentified_sender_message_content_get_contents(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent obj); -SignalFfiError *signal_unidentified_sender_message_content_get_group_id_or_empty(SignalOwnedBuffer *out, const SignalUnidentifiedSenderMessageContent *m); +SignalFfiError *signal_unidentified_sender_message_content_get_group_id_or_empty(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent m); -SignalFfiError *signal_unidentified_sender_message_content_get_sender_cert(SignalSenderCertificate **out, const SignalUnidentifiedSenderMessageContent *m); +SignalFfiError *signal_unidentified_sender_message_content_get_sender_cert(SignalMutPointerSenderCertificate *out, SignalConstPointerUnidentifiedSenderMessageContent m); -SignalFfiError *signal_unidentified_sender_message_content_get_msg_type(uint8_t *out, const SignalUnidentifiedSenderMessageContent *m); +SignalFfiError *signal_unidentified_sender_message_content_get_msg_type(uint8_t *out, SignalConstPointerUnidentifiedSenderMessageContent m); -SignalFfiError *signal_unidentified_sender_message_content_get_content_hint(uint32_t *out, const SignalUnidentifiedSenderMessageContent *m); +SignalFfiError *signal_unidentified_sender_message_content_get_content_hint(uint32_t *out, SignalConstPointerUnidentifiedSenderMessageContent m); -SignalFfiError *signal_unidentified_sender_message_content_new(SignalUnidentifiedSenderMessageContent **out, const SignalCiphertextMessage *message, const SignalSenderCertificate *sender, uint32_t content_hint, SignalBorrowedBuffer group_id); +SignalFfiError *signal_unidentified_sender_message_content_new(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalConstPointerCiphertextMessage message, SignalConstPointerSenderCertificate sender, uint32_t content_hint, SignalBorrowedBuffer group_id); -SignalFfiError *signal_ciphertext_message_type(uint8_t *out, const SignalCiphertextMessage *msg); +SignalFfiError *signal_ciphertext_message_type(uint8_t *out, SignalConstPointerCiphertextMessage msg); -SignalFfiError *signal_ciphertext_message_serialize(SignalOwnedBuffer *out, const SignalCiphertextMessage *obj); +SignalFfiError *signal_ciphertext_message_serialize(SignalOwnedBuffer *out, SignalConstPointerCiphertextMessage obj); -SignalFfiError *signal_ciphertext_message_from_plaintext_content(SignalCiphertextMessage **out, const SignalPlaintextContent *m); +SignalFfiError *signal_ciphertext_message_from_plaintext_content(SignalMutPointerCiphertextMessage *out, SignalConstPointerPlaintextContent m); -SignalFfiError *signal_session_record_archive_current_state(SignalSessionRecord *session_record); +SignalFfiError *signal_session_record_archive_current_state(SignalMutPointerSessionRecord session_record); -SignalFfiError *signal_session_record_has_usable_sender_chain(bool *out, const SignalSessionRecord *s, uint64_t now); +SignalFfiError *signal_session_record_has_usable_sender_chain(bool *out, SignalConstPointerSessionRecord s, uint64_t now); -SignalFfiError *signal_session_record_current_ratchet_key_matches(bool *out, const SignalSessionRecord *s, const SignalPublicKey *key); +SignalFfiError *signal_session_record_current_ratchet_key_matches(bool *out, SignalConstPointerSessionRecord s, SignalConstPointerPublicKey key); -SignalFfiError *signal_session_record_deserialize(SignalSessionRecord **out, SignalBorrowedBuffer data); +SignalFfiError *signal_session_record_deserialize(SignalMutPointerSessionRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_session_record_serialize(SignalOwnedBuffer *out, const SignalSessionRecord *obj); +SignalFfiError *signal_session_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSessionRecord obj); -SignalFfiError *signal_session_record_get_local_registration_id(uint32_t *out, const SignalSessionRecord *obj); +SignalFfiError *signal_session_record_get_local_registration_id(uint32_t *out, SignalConstPointerSessionRecord obj); -SignalFfiError *signal_session_record_get_remote_registration_id(uint32_t *out, const SignalSessionRecord *obj); +SignalFfiError *signal_session_record_get_remote_registration_id(uint32_t *out, SignalConstPointerSessionRecord obj); -SignalFfiError *signal_process_prekey_bundle(const SignalPreKeyBundle *bundle, const SignalProtocolAddress *protocol_address, const SignalSessionStore *session_store, const SignalIdentityKeyStore *identity_key_store, uint64_t now); +SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); -SignalFfiError *signal_encrypt_message(SignalCiphertextMessage **out, SignalBorrowedBuffer ptext, const SignalProtocolAddress *protocol_address, const SignalSessionStore *session_store, const SignalIdentityKeyStore *identity_key_store, uint64_t now); +SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); -SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, const SignalMessage *message, const SignalProtocolAddress *protocol_address, const SignalSessionStore *session_store, const SignalIdentityKeyStore *identity_key_store); +SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); -SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, const SignalPreKeySignalMessage *message, const SignalProtocolAddress *protocol_address, const SignalSessionStore *session_store, const SignalIdentityKeyStore *identity_key_store, const SignalPreKeyStore *prekey_store, const SignalSignedPreKeyStore *signed_prekey_store, const SignalKyberPreKeyStore *kyber_prekey_store); +SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); -SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, const SignalProtocolAddress *destination, const SignalUnidentifiedSenderMessageContent *content, const SignalIdentityKeyStore *identity_key_store); +SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress destination, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); -SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfProtocolAddress recipients, SignalBorrowedSliceOfSessionRecord recipient_sessions, SignalBorrowedBuffer excluded_recipients, const SignalUnidentifiedSenderMessageContent *content, const SignalIdentityKeyStore *identity_key_store); +SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfConstPointerProtocolAddress recipients, SignalBorrowedSliceOfConstPointerSessionRecord recipient_sessions, SignalBorrowedBuffer excluded_recipients, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); SignalFfiError *signal_sealed_sender_multi_recipient_message_for_single_recipient(SignalOwnedBuffer *out, SignalBorrowedBuffer encoded_multi_recipient_message); -SignalFfiError *signal_sealed_session_cipher_decrypt_to_usmc(SignalUnidentifiedSenderMessageContent **out, SignalBorrowedBuffer ctext, const SignalIdentityKeyStore *identity_store); +SignalFfiError *signal_sealed_session_cipher_decrypt_to_usmc(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer ctext, SignalConstPointerFfiIdentityKeyStoreStruct identity_store); -SignalFfiError *signal_sender_key_distribution_message_create(SignalSenderKeyDistributionMessage **out, const SignalProtocolAddress *sender, const uint8_t (*distribution_id)[16], const SignalSenderKeyStore *store); +SignalFfiError *signal_sender_key_distribution_message_create(SignalMutPointerSenderKeyDistributionMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalConstPointerFfiSenderKeyStoreStruct store); -SignalFfiError *signal_process_sender_key_distribution_message(const SignalProtocolAddress *sender, const SignalSenderKeyDistributionMessage *sender_key_distribution_message, const SignalSenderKeyStore *store); +SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); -SignalFfiError *signal_group_encrypt_message(SignalCiphertextMessage **out, const SignalProtocolAddress *sender, const uint8_t (*distribution_id)[16], SignalBorrowedBuffer message, const SignalSenderKeyStore *store); +SignalFfiError *signal_group_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); -SignalFfiError *signal_group_decrypt_message(SignalOwnedBuffer *out, const SignalProtocolAddress *sender, SignalBorrowedBuffer message, const SignalSenderKeyStore *store); +SignalFfiError *signal_group_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress sender, SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); SignalFfiError *signal_device_transfer_generate_private_key(SignalOwnedBuffer *out); @@ -1189,29 +1621,29 @@ SignalFfiError *signal_device_transfer_generate_private_key_with_format(SignalOw SignalFfiError *signal_device_transfer_generate_certificate(SignalOwnedBuffer *out, SignalBorrowedBuffer private_key, const char *name, uint32_t days_to_expire); -SignalFfiError *signal_cds2_client_state_new(SignalSgxClientState **out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); +SignalFfiError *signal_cds2_client_state_new(SignalMutPointerSgxClientState *out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); -SignalFfiError *signal_hsm_enclave_client_destroy(SignalHsmEnclaveClient *p); +SignalFfiError *signal_hsm_enclave_client_destroy(SignalMutPointerHsmEnclaveClient p); -SignalFfiError *signal_hsm_enclave_client_new(SignalHsmEnclaveClient **out, SignalBorrowedBuffer trusted_public_key, SignalBorrowedBuffer trusted_code_hashes); +SignalFfiError *signal_hsm_enclave_client_new(SignalMutPointerHsmEnclaveClient *out, SignalBorrowedBuffer trusted_public_key, SignalBorrowedBuffer trusted_code_hashes); -SignalFfiError *signal_hsm_enclave_client_complete_handshake(SignalHsmEnclaveClient *cli, SignalBorrowedBuffer handshake_received); +SignalFfiError *signal_hsm_enclave_client_complete_handshake(SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer handshake_received); -SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer plaintext_to_send); +SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *out, SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer plaintext_to_send); -SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalHsmEnclaveClient *cli, SignalBorrowedBuffer received_ciphertext); +SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer received_ciphertext); -SignalFfiError *signal_hsm_enclave_client_initial_request(SignalOwnedBuffer *out, const SignalHsmEnclaveClient *obj); +SignalFfiError *signal_hsm_enclave_client_initial_request(SignalOwnedBuffer *out, SignalConstPointerHsmEnclaveClient obj); -SignalFfiError *signal_sgx_client_state_destroy(SignalSgxClientState *p); +SignalFfiError *signal_sgx_client_state_destroy(SignalMutPointerSgxClientState p); -SignalFfiError *signal_sgx_client_state_initial_request(SignalOwnedBuffer *out, const SignalSgxClientState *obj); +SignalFfiError *signal_sgx_client_state_initial_request(SignalOwnedBuffer *out, SignalConstPointerSgxClientState obj); -SignalFfiError *signal_sgx_client_state_complete_handshake(SignalSgxClientState *cli, SignalBorrowedBuffer handshake_received); +SignalFfiError *signal_sgx_client_state_complete_handshake(SignalMutPointerSgxClientState cli, SignalBorrowedBuffer handshake_received); -SignalFfiError *signal_sgx_client_state_established_send(SignalOwnedBuffer *out, SignalSgxClientState *cli, SignalBorrowedBuffer plaintext_to_send); +SignalFfiError *signal_sgx_client_state_established_send(SignalOwnedBuffer *out, SignalMutPointerSgxClientState cli, SignalBorrowedBuffer plaintext_to_send); -SignalFfiError *signal_sgx_client_state_established_recv(SignalOwnedBuffer *out, SignalSgxClientState *cli, SignalBorrowedBuffer received_ciphertext); +SignalFfiError *signal_sgx_client_state_established_recv(SignalOwnedBuffer *out, SignalMutPointerSgxClientState cli, SignalBorrowedBuffer received_ciphertext); SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); @@ -1245,17 +1677,17 @@ SignalFfiError *signal_receipt_credential_response_check_valid_contents(SignalBo SignalFfiError *signal_uuid_ciphertext_check_valid_contents(SignalBorrowedBuffer buffer); -SignalFfiError *signal_server_public_params_destroy(SignalServerPublicParams *p); +SignalFfiError *signal_server_public_params_destroy(SignalMutPointerServerPublicParams p); -SignalFfiError *signal_server_public_params_deserialize(SignalServerPublicParams **out, SignalBorrowedBuffer buffer); +SignalFfiError *signal_server_public_params_deserialize(SignalMutPointerServerPublicParams *out, SignalBorrowedBuffer buffer); -SignalFfiError *signal_server_public_params_serialize(SignalOwnedBuffer *out, const SignalServerPublicParams *handle); +SignalFfiError *signal_server_public_params_serialize(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams handle); -SignalFfiError *signal_server_secret_params_destroy(SignalServerSecretParams *p); +SignalFfiError *signal_server_secret_params_destroy(SignalMutPointerServerSecretParams p); -SignalFfiError *signal_server_secret_params_deserialize(SignalServerSecretParams **out, SignalBorrowedBuffer buffer); +SignalFfiError *signal_server_secret_params_deserialize(SignalMutPointerServerSecretParams *out, SignalBorrowedBuffer buffer); -SignalFfiError *signal_server_secret_params_serialize(SignalOwnedBuffer *out, const SignalServerSecretParams *handle); +SignalFfiError *signal_server_secret_params_serialize(SignalOwnedBuffer *out, SignalConstPointerServerSecretParams handle); SignalFfiError *signal_profile_key_get_commitment(unsigned char (*out)[SignalPROFILE_KEY_COMMITMENT_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); @@ -1283,55 +1715,53 @@ SignalFfiError *signal_group_secret_params_encrypt_blob_with_padding_determinist SignalFfiError *signal_group_secret_params_decrypt_blob_with_padding(SignalOwnedBuffer *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer ciphertext); -SignalFfiError *signal_server_secret_params_generate_deterministic(SignalServerSecretParams **out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); +SignalFfiError *signal_server_secret_params_generate_deterministic(SignalMutPointerServerSecretParams *out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); -SignalFfiError *signal_server_secret_params_get_public_params(SignalServerPublicParams **out, const SignalServerSecretParams *params); +SignalFfiError *signal_server_secret_params_get_public_params(SignalMutPointerServerPublicParams *out, SignalConstPointerServerSecretParams params); -SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], const SignalServerSecretParams *params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); +SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], SignalConstPointerServerSecretParams params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); -SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, const SignalServerPublicParams *params, const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); +SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params, const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); -SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); +SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); -SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); +SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); -SignalFfiError *signal_server_public_params_receive_expiring_profile_key_credential(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN], const SignalServerPublicParams *server_public_params, const unsigned char (*request_context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], uint64_t current_time_in_seconds); +SignalFfiError *signal_server_public_params_receive_expiring_profile_key_credential(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN], SignalConstPointerServerPublicParams server_public_params, const unsigned char (*request_context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], uint64_t current_time_in_seconds); -SignalFfiError *signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(SignalOwnedBuffer *out, const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key_credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); +SignalFfiError *signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key_credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); -SignalFfiError *signal_server_public_params_create_receipt_credential_request_context_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const uint8_t (*receipt_serial)[SignalRECEIPT_SERIAL_LEN]); +SignalFfiError *signal_server_public_params_create_receipt_credential_request_context_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const uint8_t (*receipt_serial)[SignalRECEIPT_SERIAL_LEN]); -SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_LEN], const SignalServerPublicParams *server_public_params, const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN]); +SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_LEN], SignalConstPointerServerPublicParams server_public_params, const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN]); -SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], const SignalServerPublicParams *server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); +SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_as_service_id_deterministic(SignalOwnedBuffer *out, const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); - -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorrowedBuffer bytes); SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(const SignalServerSecretParams *server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); +SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); -SignalFfiError *signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*commitment)[SignalPROFILE_KEY_COMMITMENT_LEN], uint64_t expiration_in_seconds); +SignalFfiError *signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*commitment)[SignalPROFILE_KEY_COMMITMENT_LEN], uint64_t expiration_in_seconds); -SignalFfiError *signal_server_secret_params_verify_profile_key_credential_presentation(const SignalServerSecretParams *server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); +SignalFfiError *signal_server_secret_params_verify_profile_key_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); -SignalFfiError *signal_server_secret_params_issue_receipt_credential_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN], const SignalServerSecretParams *server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], uint64_t receipt_expiration_time, uint64_t receipt_level); +SignalFfiError *signal_server_secret_params_issue_receipt_credential_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN], SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], uint64_t receipt_expiration_time, uint64_t receipt_level); -SignalFfiError *signal_server_secret_params_verify_receipt_credential_presentation(const SignalServerSecretParams *server_secret_params, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); +SignalFfiError *signal_server_secret_params_verify_receipt_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); SignalFfiError *signal_group_public_params_get_group_identifier(uint8_t (*out)[SignalGROUP_IDENTIFIER_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN]); -SignalFfiError *signal_server_public_params_verify_signature(const SignalServerPublicParams *server_public_params, SignalBorrowedBuffer message, const uint8_t (*notary_signature)[SignalSIGNATURE_LEN]); +SignalFfiError *signal_server_public_params_verify_signature(SignalConstPointerServerPublicParams server_public_params, SignalBorrowedBuffer message, const uint8_t (*notary_signature)[SignalSIGNATURE_LEN]); SignalFfiError *signal_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); SignalFfiError *signal_auth_credential_presentation_get_uuid_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); -SignalFfiError *signal_auth_credential_presentation_get_pni_ciphertext_or_empty(SignalOwnedBuffer *out, SignalBorrowedBuffer presentation_bytes); +SignalFfiError *signal_auth_credential_presentation_get_pni_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); SignalFfiError *signal_auth_credential_presentation_get_redemption_time(uint64_t *out, SignalBorrowedBuffer presentation_bytes); @@ -1443,7 +1873,7 @@ SignalFfiError *signal_backup_auth_credential_presentation_verify(SignalBorrowed SignalFfiError *signal_group_send_derived_key_pair_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_group_send_derived_key_pair_for_expiration(SignalOwnedBuffer *out, uint64_t expiration, const SignalServerSecretParams *server_params); +SignalFfiError *signal_group_send_derived_key_pair_for_expiration(SignalOwnedBuffer *out, uint64_t expiration, SignalConstPointerServerSecretParams server_params); SignalFfiError *signal_group_send_endorsements_response_check_valid_contents(SignalBorrowedBuffer bytes); @@ -1451,9 +1881,9 @@ SignalFfiError *signal_group_send_endorsements_response_issue_deterministic(Sign SignalFfiError *signal_group_send_endorsements_response_get_expiration(uint64_t *out, SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], const SignalServerPublicParams *server_params); +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalConstPointerServerPublicParams server_params); -SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, const SignalServerPublicParams *server_params); +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, SignalConstPointerServerPublicParams server_params); SignalFfiError *signal_group_send_endorsement_check_valid_contents(SignalBorrowedBuffer bytes); @@ -1473,109 +1903,131 @@ SignalFfiError *signal_group_send_full_token_get_expiration(uint64_t *out, Signa SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalBorrowedBuffer user_ids, uint64_t now, SignalBorrowedBuffer key_pair); -SignalFfiError *signal_connection_manager_destroy(SignalConnectionManager *p); +SignalFfiError *signal_connection_info_destroy(SignalMutPointerConnectionInfo p); -SignalFfiError *signal_connection_manager_new(SignalConnectionManager **out, uint8_t environment, const char *user_agent); +SignalFfiError *signal_connection_manager_destroy(SignalMutPointerConnectionManager p); -SignalFfiError *signal_connection_manager_set_proxy(const SignalConnectionManager *connection_manager, const char *host, int32_t port); +SignalFfiError *signal_connection_manager_new(SignalMutPointerConnectionManager *out, uint8_t environment, const char *user_agent); -SignalFfiError *signal_connection_manager_clear_proxy(const SignalConnectionManager *connection_manager); +SignalFfiError *signal_connection_manager_set_proxy(SignalConstPointerConnectionManager connection_manager, const char *host, int32_t port); -SignalFfiError *signal_connection_manager_set_censorship_circumvention_enabled(const SignalConnectionManager *connection_manager, bool enabled); +SignalFfiError *signal_connection_manager_clear_proxy(SignalConstPointerConnectionManager connection_manager); -SignalFfiError *signal_connection_manager_on_network_change(const SignalConnectionManager *connection_manager); +SignalFfiError *signal_connection_manager_set_censorship_circumvention_enabled(SignalConstPointerConnectionManager connection_manager, bool enabled); + +SignalFfiError *signal_connection_manager_on_network_change(SignalConstPointerConnectionManager connection_manager); SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); -SignalFfiError *signal_svr3_backup(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); +SignalFfiError *signal_lookup_request_destroy(SignalMutPointerLookupRequest p); -SignalFfiError *signal_svr3_migrate(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer secret, const char *password, uint32_t max_tries, const char *username, const char *enclave_password); +SignalFfiError *signal_lookup_request_new(SignalMutPointerLookupRequest *out); -SignalFfiError *signal_svr3_restore(SignalCPromiseOwnedBufferOfc_uchar *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *password, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); +SignalFfiError *signal_lookup_request_add_e164(SignalConstPointerLookupRequest request, const char *e164); -SignalFfiError *signal_svr3_remove(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *enclave_password); +SignalFfiError *signal_lookup_request_add_previous_e164(SignalConstPointerLookupRequest request, const char *e164); -SignalFfiError *signal_svr3_rotate(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, SignalBorrowedBuffer share_set, const char *username, const char *enclave_password); +SignalFfiError *signal_lookup_request_set_token(SignalConstPointerLookupRequest request, SignalBorrowedBuffer token); -SignalFfiError *signal_lookup_request_destroy(SignalLookupRequest *p); +SignalFfiError *signal_lookup_request_add_aci_and_access_key(SignalConstPointerLookupRequest request, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer access_key); -SignalFfiError *signal_lookup_request_new(SignalLookupRequest **out); +SignalFfiError *signal_cdsi_lookup_destroy(SignalMutPointerCdsiLookup p); -SignalFfiError *signal_lookup_request_add_e164(const SignalLookupRequest *request, const char *e164); +SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseMutPointerCdsiLookup *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, SignalConstPointerLookupRequest request); -SignalFfiError *signal_lookup_request_add_previous_e164(const SignalLookupRequest *request, const char *e164); +SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, SignalConstPointerCdsiLookup lookup); -SignalFfiError *signal_lookup_request_set_token(const SignalLookupRequest *request, SignalBorrowedBuffer token); +SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerCdsiLookup lookup); -SignalFfiError *signal_lookup_request_add_aci_and_access_key(const SignalLookupRequest *request, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer access_key); +SignalFfiError *signal_auth_chat_destroy(SignalMutPointerAuthChat p); -SignalFfiError *signal_cdsi_lookup_destroy(SignalCdsiLookup *p); +SignalFfiError *signal_unauth_chat_destroy(SignalMutPointerUnauthChat p); -SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseCdsiLookup *promise, const SignalTokioAsyncContext *async_runtime, const SignalConnectionManager *connection_manager, const char *username, const char *password, const SignalLookupRequest *request); +SignalFfiError *signal_http_request_destroy(SignalMutPointerHttpRequest p); -SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, const SignalCdsiLookup *lookup); +SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); -SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalCdsiLookup *lookup); +SignalFfiError *signal_authenticated_chat_connection_destroy(SignalMutPointerAuthenticatedChatConnection p); -SignalFfiError *signal_auth_chat_destroy(SignalAuthChat *p); +SignalFfiError *signal_http_request_new_with_body(SignalMutPointerHttpRequest *out, const char *method, const char *path, SignalBorrowedBuffer body_as_slice); -SignalFfiError *signal_unauth_chat_destroy(SignalUnauthChat *p); +SignalFfiError *signal_http_request_new_without_body(SignalMutPointerHttpRequest *out, const char *method, const char *path); -SignalFfiError *signal_http_request_destroy(SignalHttpRequest *p); +SignalFfiError *signal_http_request_add_header(SignalConstPointerHttpRequest request, const char *name, const char *value); -SignalFfiError *signal_http_request_new_with_body(SignalHttpRequest **out, const char *method, const char *path, SignalBorrowedBuffer body_as_slice); +SignalFfiError *signal_chat_connection_info_local_port(uint16_t *out, SignalConstPointerChatConnectionInfo connection_info); -SignalFfiError *signal_http_request_new_without_body(SignalHttpRequest **out, const char *method, const char *path); +SignalFfiError *signal_chat_connection_info_ip_version(uint8_t *out, SignalConstPointerChatConnectionInfo connection_info); -SignalFfiError *signal_http_request_add_header(const SignalHttpRequest *request, const char *name, const char *value); +SignalFfiError *signal_chat_connection_info_description(const char **out, SignalConstPointerChatConnectionInfo connection_info); -SignalFfiError *signal_chat_service_new_unauth(SignalUnauthChat **out, const SignalConnectionManager *connection_manager); +SignalFfiError *signal_chat_service_new_unauth(SignalMutPointerUnauthChat *out, SignalConstPointerConnectionManager connection_manager); -SignalFfiError *signal_chat_service_new_auth(SignalAuthChat **out, const SignalConnectionManager *connection_manager, const char *username, const char *password, bool receive_stories); +SignalFfiError *signal_chat_service_new_auth(SignalMutPointerAuthChat *out, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); -SignalFfiError *signal_chat_service_disconnect_unauth(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat); +SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); -SignalFfiError *signal_chat_service_disconnect_auth(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat); +SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); -SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat); +SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat); +SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat); -SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); -SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalUnauthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_authenticated_chat_connection_connect(SignalCPromiseMutPointerAuthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); -SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); -SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, const SignalTokioAsyncContext *async_runtime, const SignalAuthChat *chat, const SignalHttpRequest *http_request, uint32_t timeout_millis); +SignalFfiError *signal_authenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncContext *runtime, const SignalAuthChat *chat, const SignalFfiChatListenerStruct *listener); +SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat); -SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalUnauthChat *chat, const SignalFfiChatListenerStruct *listener); +SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat); -SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p); +SignalFfiError *signal_chat_service_disconnect_unauth(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat); -SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalServerMessageAck *ack); +SignalFfiError *signal_chat_service_disconnect_auth(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat); -SignalFfiError *signal_tokio_async_context_destroy(SignalTokioAsyncContext *p); +SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat); -SignalFfiError *signal_tokio_async_context_new(SignalTokioAsyncContext **out); +SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat); -SignalFfiError *signal_tokio_async_context_cancel(const SignalTokioAsyncContext *context, uint64_t raw_cancellation_id); +SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_pin_hash_destroy(SignalPinHash *p); +SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_pin_hash_clone(SignalPinHash **new_obj, const SignalPinHash *obj); +SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_pin_hash_encryption_key(uint8_t (*out)[32], const SignalPinHash *ph); +SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_pin_hash_access_key(uint8_t (*out)[32], const SignalPinHash *ph); +SignalFfiError *signal_chat_service_set_listener_auth(SignalConstPointerTokioAsyncContext runtime, SignalConstPointerAuthChat chat, SignalConstPointerFfiChatListenerStruct listener); -SignalFfiError *signal_pin_hash_from_salt(SignalPinHash **out, SignalBorrowedBuffer pin, const uint8_t (*salt)[32]); +SignalFfiError *signal_chat_service_set_listener_unauth(SignalConstPointerTokioAsyncContext runtime, SignalConstPointerUnauthChat chat, SignalConstPointerFfiChatListenerStruct listener); -SignalFfiError *signal_pin_hash_from_username_mrenclave(SignalPinHash **out, SignalBorrowedBuffer pin, const char *username, SignalBorrowedBuffer mrenclave); +SignalFfiError *signal_server_message_ack_destroy(SignalMutPointerServerMessageAck p); + +SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerServerMessageAck ack); + +SignalFfiError *signal_tokio_async_context_destroy(SignalMutPointerTokioAsyncContext p); + +SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext *out); + +SignalFfiError *signal_tokio_async_context_cancel(SignalConstPointerTokioAsyncContext context, uint64_t raw_cancellation_id); + +SignalFfiError *signal_pin_hash_destroy(SignalMutPointerPinHash p); + +SignalFfiError *signal_pin_hash_clone(SignalMutPointerPinHash *new_obj, SignalConstPointerPinHash obj); + +SignalFfiError *signal_pin_hash_encryption_key(uint8_t (*out)[32], SignalConstPointerPinHash ph); + +SignalFfiError *signal_pin_hash_access_key(uint8_t (*out)[32], SignalConstPointerPinHash ph); + +SignalFfiError *signal_pin_hash_from_salt(SignalMutPointerPinHash *out, SignalBorrowedBuffer pin, const uint8_t (*salt)[32]); + +SignalFfiError *signal_pin_hash_from_username_mrenclave(SignalMutPointerPinHash *out, SignalBorrowedBuffer pin, const char *username, SignalBorrowedBuffer mrenclave); SignalFfiError *signal_pin_local_hash(const char **out, SignalBorrowedBuffer pin); @@ -1583,13 +2035,15 @@ SignalFfiError *signal_pin_verify_local_hash(bool *out, const char *encoded_hash SignalFfiError *signal_account_entropy_pool_generate(const char **out); +SignalFfiError *signal_account_entropy_pool_is_valid(bool *out, const char *account_entropy); + SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy); SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy); SignalFfiError *signal_backup_key_derive_backup_id(uint8_t (*out)[16], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); -SignalFfiError *signal_backup_key_derive_ec_key(SignalPrivateKey **out, const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_backup_key_derive_ec_key(SignalMutPointerPrivateKey *out, const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); SignalFfiError *signal_backup_key_derive_local_backup_metadata_key(uint8_t (*out)[SignalLOCAL_BACKUP_METADATA_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN]); @@ -1599,53 +2053,53 @@ SignalFfiError *signal_backup_key_derive_media_encryption_key(uint8_t (*out)[Sig SignalFfiError *signal_backup_key_derive_thumbnail_transit_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); -SignalFfiError *signal_svr2_client_new(SignalSgxClientState **out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); +SignalFfiError *signal_svr2_client_new(SignalMutPointerSgxClientState *out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); -SignalFfiError *signal_incremental_mac_destroy(SignalIncrementalMac *p); +SignalFfiError *signal_incremental_mac_destroy(SignalMutPointerIncrementalMac p); SignalFfiError *signal_incremental_mac_calculate_chunk_size(uint32_t *out, uint32_t data_size); -SignalFfiError *signal_incremental_mac_initialize(SignalIncrementalMac **out, SignalBorrowedBuffer key, uint32_t chunk_size); +SignalFfiError *signal_incremental_mac_initialize(SignalMutPointerIncrementalMac *out, SignalBorrowedBuffer key, uint32_t chunk_size); -SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalIncrementalMac *mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); +SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); -SignalFfiError *signal_incremental_mac_finalize(SignalOwnedBuffer *out, SignalIncrementalMac *mac); +SignalFfiError *signal_incremental_mac_finalize(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac); -SignalFfiError *signal_validating_mac_destroy(SignalValidatingMac *p); +SignalFfiError *signal_validating_mac_destroy(SignalMutPointerValidatingMac p); -SignalFfiError *signal_validating_mac_initialize(SignalValidatingMac **out, SignalBorrowedBuffer key, uint32_t chunk_size, SignalBorrowedBuffer digests); +SignalFfiError *signal_validating_mac_initialize(SignalMutPointerValidatingMac *out, SignalBorrowedBuffer key, uint32_t chunk_size, SignalBorrowedBuffer digests); -SignalFfiError *signal_validating_mac_update(int32_t *out, SignalValidatingMac *mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); +SignalFfiError *signal_validating_mac_update(int32_t *out, SignalMutPointerValidatingMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); -SignalFfiError *signal_validating_mac_finalize(int32_t *out, SignalValidatingMac *mac); +SignalFfiError *signal_validating_mac_finalize(int32_t *out, SignalMutPointerValidatingMac mac); -SignalFfiError *signal_message_backup_key_destroy(SignalMessageBackupKey *p); +SignalFfiError *signal_message_backup_key_destroy(SignalMutPointerMessageBackupKey p); -SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMessageBackupValidationOutcome *p); +SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMutPointerMessageBackupValidationOutcome p); -SignalFfiError *signal_message_backup_key_from_master_key(SignalMessageBackupKey **out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_message_backup_key_from_master_key(SignalMutPointerMessageBackupKey *out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); -SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMessageBackupKey **out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMutPointerMessageBackupKey *out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci); -SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMessageBackupKey **out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16]); +SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMutPointerMessageBackupKey *out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16]); -SignalFfiError *signal_message_backup_key_get_hmac_key(uint8_t (*out)[32], const SignalMessageBackupKey *key); +SignalFfiError *signal_message_backup_key_get_hmac_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); -SignalFfiError *signal_message_backup_key_get_aes_key(uint8_t (*out)[32], const SignalMessageBackupKey *key); +SignalFfiError *signal_message_backup_key_get_aes_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); -SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, const SignalMessageBackupValidationOutcome *outcome); +SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, SignalConstPointerMessageBackupValidationOutcome outcome); -SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, const SignalMessageBackupValidationOutcome *outcome); +SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, SignalConstPointerMessageBackupValidationOutcome outcome); -SignalFfiError *signal_message_backup_validator_validate(SignalMessageBackupValidationOutcome **out, const SignalMessageBackupKey *key, const SignalInputStream *first_stream, const SignalInputStream *second_stream, uint64_t len, uint8_t purpose); +SignalFfiError *signal_message_backup_validator_validate(SignalMutPointerMessageBackupValidationOutcome *out, SignalConstPointerMessageBackupKey key, SignalConstPointerFfiInputStreamStruct first_stream, SignalConstPointerFfiInputStreamStruct second_stream, uint64_t len, uint8_t purpose); -SignalFfiError *signal_online_backup_validator_destroy(SignalOnlineBackupValidator *p); +SignalFfiError *signal_online_backup_validator_destroy(SignalMutPointerOnlineBackupValidator p); -SignalFfiError *signal_online_backup_validator_new(SignalOnlineBackupValidator **out, SignalBorrowedBuffer backup_info_frame, uint8_t purpose); +SignalFfiError *signal_online_backup_validator_new(SignalMutPointerOnlineBackupValidator *out, SignalBorrowedBuffer backup_info_frame, uint8_t purpose); -SignalFfiError *signal_online_backup_validator_add_frame(SignalOnlineBackupValidator *backup, SignalBorrowedBuffer frame); +SignalFfiError *signal_online_backup_validator_add_frame(SignalMutPointerOnlineBackupValidator backup, SignalBorrowedBuffer frame); -SignalFfiError *signal_online_backup_validator_finalize(SignalOnlineBackupValidator *backup); +SignalFfiError *signal_online_backup_validator_finalize(SignalMutPointerOnlineBackupValidator backup); SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); @@ -1662,11 +2116,11 @@ SignalFfiError *signal_username_link_create(SignalOwnedBuffer *out, const char * SignalFfiError *signal_username_link_decrypt_username(const char **out, SignalBorrowedBuffer entropy, SignalBorrowedBuffer encrypted_username); #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_destroy(SignalSanitizedMetadata *p); +SignalFfiError *signal_sanitized_metadata_destroy(SignalMutPointerSanitizedMetadata p); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_clone(SignalSanitizedMetadata **new_obj, const SignalSanitizedMetadata *obj); +SignalFfiError *signal_sanitized_metadata_clone(SignalMutPointerSanitizedMetadata *new_obj, SignalConstPointerSanitizedMetadata obj); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) @@ -1674,23 +2128,23 @@ SignalFfiError *signal_signal_media_check_available(void); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_mp4_sanitizer_sanitize(SignalSanitizedMetadata **out, const SignalInputStream *input, uint64_t len); +SignalFfiError *signal_mp4_sanitizer_sanitize(SignalMutPointerSanitizedMetadata *out, SignalConstPointerFfiInputStreamStruct input, uint64_t len); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_webp_sanitizer_sanitize(const SignalSyncInputStream *input); +SignalFfiError *signal_webp_sanitizer_sanitize(SignalConstPointerFfiSyncInputStreamStruct input); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_get_metadata(SignalOwnedBuffer *out, const SignalSanitizedMetadata *sanitized); +SignalFfiError *signal_sanitized_metadata_get_metadata(SignalOwnedBuffer *out, SignalConstPointerSanitizedMetadata sanitized); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_get_data_offset(uint64_t *out, const SignalSanitizedMetadata *sanitized); +SignalFfiError *signal_sanitized_metadata_get_data_offset(uint64_t *out, SignalConstPointerSanitizedMetadata sanitized); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, const SignalSanitizedMetadata *sanitized); +SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, SignalConstPointerSanitizedMetadata sanitized); #endif #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/message.go b/pkg/libsignalgo/message.go index 43a1a39..d512d6f 100644 --- a/pkg/libsignalgo/message.go +++ b/pkg/libsignalgo/message.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -24,16 +25,38 @@ import "C" import ( "context" "runtime" + "time" ) +func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, sessionStore SessionStore, identityKeyStore IdentityKeyStore) (*CiphertextMessage, error) { + var ciphertextMessage C.SignalMutPointerCiphertextMessage + var now C.uint64_t = C.uint64_t(time.Now().Unix()) + callbackCtx := NewCallbackContext(ctx) + defer callbackCtx.Unref() + signalFfiError := C.signal_encrypt_message( + &ciphertextMessage, + BytesToBuffer(plaintext), + forAddress.constPtr(), + callbackCtx.wrapSessionStore(sessionStore), + callbackCtx.wrapIdentityKeyStore(identityKeyStore), + now, + ) + runtime.KeepAlive(plaintext) + runtime.KeepAlive(forAddress) + if signalFfiError != nil { + return nil, callbackCtx.wrapError(signalFfiError) + } + return wrapCiphertextMessage(ciphertextMessage.raw), nil +} + func Decrypt(ctx context.Context, message *Message, fromAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} signalFfiError := C.signal_decrypt_message( &decrypted, - message.ptr, - fromAddress.ptr, + message.constPtr(), + fromAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), ) @@ -57,28 +80,36 @@ func wrapMessage(ptr *C.SignalMessage) *Message { } func DeserializeMessage(serialized []byte) (*Message, error) { - var m *C.SignalMessage + var m C.SignalMutPointerSignalMessage signalFfiError := C.signal_message_deserialize(&m, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapMessage(m), nil + return wrapMessage(m.raw), nil +} + +func (m *Message) mutPtr() C.SignalMutPointerSignalMessage { + return C.SignalMutPointerSignalMessage{m.ptr} +} + +func (m *Message) constPtr() C.SignalConstPointerSignalMessage { + return C.SignalConstPointerSignalMessage{m.ptr} } func (m *Message) Clone() (*Message, error) { - var cloned *C.SignalMessage - signalFfiError := C.signal_message_clone(&cloned, m.ptr) + var cloned C.SignalMutPointerSignalMessage + signalFfiError := C.signal_message_clone(&cloned, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapMessage(cloned), nil + return wrapMessage(cloned.raw), nil } func (m *Message) Destroy() error { m.CancelFinalizer() - return wrapError(C.signal_message_destroy(m.ptr)) + return wrapError(C.signal_message_destroy(m.mutPtr())) } func (m *Message) CancelFinalizer() { @@ -87,7 +118,7 @@ func (m *Message) CancelFinalizer() { func (m *Message) GetBody() ([]byte, error) { var body C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_message_get_body(&body, m.ptr) + signalFfiError := C.signal_message_get_body(&body, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -97,7 +128,7 @@ func (m *Message) GetBody() ([]byte, error) { func (m *Message) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_message_get_serialized(&serialized, m.ptr) + signalFfiError := C.signal_message_get_serialized(&serialized, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -107,7 +138,7 @@ func (m *Message) Serialize() ([]byte, error) { func (m *Message) GetMessageVersion() (uint32, error) { var messageVersion C.uint32_t - signalFfiError := C.signal_message_get_message_version(&messageVersion, m.ptr) + signalFfiError := C.signal_message_get_message_version(&messageVersion, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -117,7 +148,7 @@ func (m *Message) GetMessageVersion() (uint32, error) { func (m *Message) GetCounter() (uint32, error) { var counter C.uint32_t - signalFfiError := C.signal_message_get_counter(&counter, m.ptr) + signalFfiError := C.signal_message_get_counter(&counter, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -127,7 +158,13 @@ func (m *Message) GetCounter() (uint32, error) { func (m *Message) VerifyMAC(sender, receiver *PublicKey, macKey []byte) (bool, error) { var result C.bool - signalFfiError := C.signal_message_verify_mac(&result, m.ptr, sender.ptr, receiver.ptr, BytesToBuffer(macKey)) + signalFfiError := C.signal_message_verify_mac( + &result, + m.constPtr(), + sender.constPtr(), + receiver.constPtr(), + BytesToBuffer(macKey), + ) runtime.KeepAlive(m) runtime.KeepAlive(sender) runtime.KeepAlive(receiver) diff --git a/pkg/libsignalgo/plaintextcontent.go b/pkg/libsignalgo/plaintextcontent.go index 6503c5d..f395f0b 100644 --- a/pkg/libsignalgo/plaintextcontent.go +++ b/pkg/libsignalgo/plaintextcontent.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -35,38 +36,52 @@ func wrapPlaintextContent(ptr *C.SignalPlaintextContent) *PlaintextContent { } func PlaintextContentFromDecryptionErrorMessage(message *DecryptionErrorMessage) (*PlaintextContent, error) { - var pc *C.SignalPlaintextContent - signalFfiError := C.signal_plaintext_content_from_decryption_error_message(&pc, message.ptr) + var pc C.SignalMutPointerPlaintextContent + signalFfiError := C.signal_plaintext_content_from_decryption_error_message( + &pc, + message.constPtr(), + ) runtime.KeepAlive(message) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPlaintextContent(pc), nil + return wrapPlaintextContent(pc.raw), nil } func DeserializePlaintextContent(plaintextContentBytes []byte) (*PlaintextContent, error) { - var pc *C.SignalPlaintextContent + var pc C.SignalMutPointerPlaintextContent signalFfiError := C.signal_plaintext_content_deserialize(&pc, BytesToBuffer(plaintextContentBytes)) runtime.KeepAlive(plaintextContentBytes) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPlaintextContent(pc), nil + return wrapPlaintextContent(pc.raw), nil +} + +func (pc *PlaintextContent) mutPtr() C.SignalMutPointerPlaintextContent { + return C.SignalMutPointerPlaintextContent{pc.ptr} +} + +func (pc *PlaintextContent) constPtr() C.SignalConstPointerPlaintextContent { + return C.SignalConstPointerPlaintextContent{pc.ptr} } func (pc *PlaintextContent) Clone() (*PlaintextContent, error) { - var cloned *C.SignalPlaintextContent - signalFfiError := C.signal_plaintext_content_clone(&cloned, pc.ptr) + var cloned C.SignalMutPointerPlaintextContent + signalFfiError := C.signal_plaintext_content_clone( + &cloned, + pc.constPtr(), + ) runtime.KeepAlive(pc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPlaintextContent(cloned), nil + return wrapPlaintextContent(cloned.raw), nil } func (pc *PlaintextContent) Destroy() error { pc.CancelFinalizer() - return wrapError(C.signal_plaintext_content_destroy(pc.ptr)) + return wrapError(C.signal_plaintext_content_destroy(pc.mutPtr())) } func (pc *PlaintextContent) CancelFinalizer() { @@ -75,7 +90,7 @@ func (pc *PlaintextContent) CancelFinalizer() { func (pc *PlaintextContent) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_plaintext_content_serialize(&serialized, pc.ptr) + signalFfiError := C.signal_plaintext_content_serialize(&serialized, pc.constPtr()) runtime.KeepAlive(pc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -85,7 +100,7 @@ func (pc *PlaintextContent) Serialize() ([]byte, error) { func (pc *PlaintextContent) GetBody() ([]byte, error) { var body C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_plaintext_content_get_body(&body, pc.ptr) + signalFfiError := C.signal_plaintext_content_get_body(&body, pc.constPtr()) runtime.KeepAlive(pc) if signalFfiError != nil { return nil, wrapError(signalFfiError) diff --git a/pkg/libsignalgo/prekey.go b/pkg/libsignalgo/prekey.go index 82b2cd1..0c56c71 100644 --- a/pkg/libsignalgo/prekey.go +++ b/pkg/libsignalgo/prekey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -32,8 +33,8 @@ func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddres var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} signalFfiError := C.signal_decrypt_pre_key_message( &decrypted, - preKeyMessage.ptr, - fromAddress.ptr, + preKeyMessage.constPtr(), + fromAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), callbackCtx.wrapPreKeyStore(preKeyStore), @@ -60,14 +61,19 @@ func wrapPreKeyRecord(ptr *C.SignalPreKeyRecord) *PreKeyRecord { } func NewPreKeyRecord(id uint32, publicKey *PublicKey, privateKey *PrivateKey) (*PreKeyRecord, error) { - var pkr *C.SignalPreKeyRecord - signalFfiError := C.signal_pre_key_record_new(&pkr, C.uint32_t(id), publicKey.ptr, privateKey.ptr) + var pkr C.SignalMutPointerPreKeyRecord + signalFfiError := C.signal_pre_key_record_new( + &pkr, + C.uint32_t(id), + publicKey.constPtr(), + privateKey.constPtr(), + ) runtime.KeepAlive(publicKey) runtime.KeepAlive(privateKey) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPreKeyRecord(pkr), nil + return wrapPreKeyRecord(pkr.raw), nil } func NewPreKeyRecordFromPrivateKey(id uint32, privateKey *PrivateKey) (*PreKeyRecord, error) { @@ -79,28 +85,36 @@ func NewPreKeyRecordFromPrivateKey(id uint32, privateKey *PrivateKey) (*PreKeyRe } func DeserializePreKeyRecord(serialized []byte) (*PreKeyRecord, error) { - var pkr *C.SignalPreKeyRecord + var pkr C.SignalMutPointerPreKeyRecord signalFfiError := C.signal_pre_key_record_deserialize(&pkr, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPreKeyRecord(pkr), nil + return wrapPreKeyRecord(pkr.raw), nil +} + +func (pkr *PreKeyRecord) mutPtr() C.SignalMutPointerPreKeyRecord { + return C.SignalMutPointerPreKeyRecord{pkr.ptr} +} + +func (pkr *PreKeyRecord) constPtr() C.SignalConstPointerPreKeyRecord { + return C.SignalConstPointerPreKeyRecord{pkr.ptr} } func (pkr *PreKeyRecord) Clone() (*PreKeyRecord, error) { - var cloned *C.SignalPreKeyRecord - signalFfiError := C.signal_pre_key_record_clone(&cloned, pkr.ptr) + var cloned C.SignalMutPointerPreKeyRecord + signalFfiError := C.signal_pre_key_record_clone(&cloned, pkr.constPtr()) runtime.KeepAlive(pkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPreKeyRecord(cloned), nil + return wrapPreKeyRecord(cloned.raw), nil } func (pkr *PreKeyRecord) Destroy() error { pkr.CancelFinalizer() - return wrapError(C.signal_pre_key_record_destroy(pkr.ptr)) + return wrapError(C.signal_pre_key_record_destroy(pkr.mutPtr())) } func (pkr *PreKeyRecord) CancelFinalizer() { @@ -109,7 +123,7 @@ func (pkr *PreKeyRecord) CancelFinalizer() { func (pkr *PreKeyRecord) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_pre_key_record_serialize(&serialized, pkr.ptr) + signalFfiError := C.signal_pre_key_record_serialize(&serialized, pkr.constPtr()) runtime.KeepAlive(pkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -119,7 +133,7 @@ func (pkr *PreKeyRecord) Serialize() ([]byte, error) { func (pkr *PreKeyRecord) GetID() (uint32, error) { var id C.uint32_t - signalFfiError := C.signal_pre_key_record_get_id(&id, pkr.ptr) + signalFfiError := C.signal_pre_key_record_get_id(&id, pkr.constPtr()) runtime.KeepAlive(pkr) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -128,21 +142,21 @@ func (pkr *PreKeyRecord) GetID() (uint32, error) { } func (pkr *PreKeyRecord) GetPublicKey() (*PublicKey, error) { - var pub *C.SignalPublicKey - signalFfiError := C.signal_pre_key_record_get_public_key(&pub, pkr.ptr) + var pub C.SignalMutPointerPublicKey + signalFfiError := C.signal_pre_key_record_get_public_key(&pub, pkr.constPtr()) runtime.KeepAlive(pkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(pub), nil + return wrapPublicKey(pub.raw), nil } func (pkr *PreKeyRecord) GetPrivateKey() (*PrivateKey, error) { - var priv *C.SignalPrivateKey - signalFfiError := C.signal_pre_key_record_get_private_key(&priv, pkr.ptr) + var priv C.SignalMutPointerPrivateKey + signalFfiError := C.signal_pre_key_record_get_private_key(&priv, pkr.constPtr()) runtime.KeepAlive(pkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPrivateKey(priv), nil + return wrapPrivateKey(priv.raw), nil } diff --git a/pkg/libsignalgo/prekeybundle.go b/pkg/libsignalgo/prekeybundle.go index 905496c..7fd2e34 100644 --- a/pkg/libsignalgo/prekeybundle.go +++ b/pkg/libsignalgo/prekeybundle.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -32,8 +33,8 @@ func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress * defer callbackCtx.Unref() var now C.uint64_t = C.uint64_t(time.Now().Unix()) signalFfiError := C.signal_process_prekey_bundle( - bundle.ptr, - forAddress.ptr, + bundle.constPtr(), + forAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), now, @@ -67,7 +68,7 @@ func NewPreKeyBundle( kyberPreKeySignature []byte, identityKey *IdentityKey, ) (*PreKeyBundle, error) { - var pkb *C.SignalPreKeyBundle + var pkb C.SignalMutPointerPreKeyBundle var zero uint32 = 0 var kyberSignatureBuffer = EmptyBorrowedBuffer() if preKey == nil { @@ -85,13 +86,13 @@ func NewPreKeyBundle( C.uint32_t(registrationID), C.uint32_t(deviceID), C.uint32_t(preKeyID), - preKey.ptr, + preKey.constPtr(), C.uint32_t(signedPreKeyID), - signedPreKey.ptr, + signedPreKey.constPtr(), BytesToBuffer(signedPreKeySignature), - identityKey.publicKey.ptr, + identityKey.publicKey.constPtr(), C.uint32_t(kyberPreKeyID), - kyberPreKey.ptr, + kyberPreKey.constPtr(), kyberSignatureBuffer, ) runtime.KeepAlive(preKey) @@ -103,22 +104,30 @@ func NewPreKeyBundle( if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPreKeyBundle(pkb), nil + return wrapPreKeyBundle(pkb.raw), nil +} + +func (pkb *PreKeyBundle) mutPtr() C.SignalMutPointerPreKeyBundle { + return C.SignalMutPointerPreKeyBundle{pkb.ptr} +} + +func (pkb *PreKeyBundle) constPtr() C.SignalConstPointerPreKeyBundle { + return C.SignalConstPointerPreKeyBundle{pkb.ptr} } func (pkb *PreKeyBundle) Clone() (*PreKeyBundle, error) { - var cloned *C.SignalPreKeyBundle - signalFfiError := C.signal_pre_key_bundle_clone(&cloned, pkb.ptr) + var cloned C.SignalMutPointerPreKeyBundle + signalFfiError := C.signal_pre_key_bundle_clone(&cloned, pkb.constPtr()) if signalFfiError != nil { return nil, wrapError(signalFfiError) } runtime.KeepAlive(pkb) - return wrapPreKeyBundle(cloned), nil + return wrapPreKeyBundle(cloned.raw), nil } func (pkb *PreKeyBundle) Destroy() error { pkb.CancelFinalizer() - return wrapError(C.signal_pre_key_bundle_destroy(pkb.ptr)) + return wrapError(C.signal_pre_key_bundle_destroy(pkb.mutPtr())) } func (pkb *PreKeyBundle) CancelFinalizer() { @@ -126,11 +135,11 @@ func (pkb *PreKeyBundle) CancelFinalizer() { } func (pkb *PreKeyBundle) GetIdentityKey() (*IdentityKey, error) { - var pk *C.SignalPublicKey - signalFfiError := C.signal_pre_key_bundle_get_identity_key(&pk, pkb.ptr) + var pk C.SignalMutPointerPublicKey + signalFfiError := C.signal_pre_key_bundle_get_identity_key(&pk, pkb.constPtr()) if signalFfiError != nil { return nil, wrapError(signalFfiError) } runtime.KeepAlive(pkb) - return NewIdentityKeyFromPublicKey(wrapPublicKey(pk)) + return NewIdentityKeyFromPublicKey(wrapPublicKey(pk.raw)) } diff --git a/pkg/libsignalgo/prekeymessage.go b/pkg/libsignalgo/prekeymessage.go index 435cf5e..6bff0bb 100644 --- a/pkg/libsignalgo/prekeymessage.go +++ b/pkg/libsignalgo/prekeymessage.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -35,28 +36,36 @@ func wrapPreKeyMessage(ptr *C.SignalPreKeySignalMessage) *PreKeyMessage { } func DeserializePreKeyMessage(serialized []byte) (*PreKeyMessage, error) { - var m *C.SignalPreKeySignalMessage + var m C.SignalMutPointerPreKeySignalMessage signalFfiError := C.signal_pre_key_signal_message_deserialize(&m, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPreKeyMessage(m), nil + return wrapPreKeyMessage(m.raw), nil +} + +func (m *PreKeyMessage) mutPtr() C.SignalMutPointerPreKeySignalMessage { + return C.SignalMutPointerPreKeySignalMessage{m.ptr} +} + +func (m *PreKeyMessage) constPtr() C.SignalConstPointerPreKeySignalMessage { + return C.SignalConstPointerPreKeySignalMessage{m.ptr} } func (m *PreKeyMessage) Clone() (*PreKeyMessage, error) { - var cloned *C.SignalPreKeySignalMessage - signalFfiError := C.signal_pre_key_signal_message_clone(&cloned, m.ptr) + var cloned C.SignalMutPointerPreKeySignalMessage + signalFfiError := C.signal_pre_key_signal_message_clone(&cloned, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPreKeyMessage(cloned), nil + return wrapPreKeyMessage(cloned.raw), nil } func (m *PreKeyMessage) Destroy() error { m.CancelFinalizer() - return wrapError(C.signal_pre_key_signal_message_destroy(m.ptr)) + return wrapError(C.signal_pre_key_signal_message_destroy(m.mutPtr())) } func (m *PreKeyMessage) CancelFinalizer() { @@ -65,7 +74,7 @@ func (m *PreKeyMessage) CancelFinalizer() { func (m *PreKeyMessage) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_pre_key_signal_message_serialize(&serialized, m.ptr) + signalFfiError := C.signal_pre_key_signal_message_serialize(&serialized, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -75,7 +84,7 @@ func (m *PreKeyMessage) Serialize() ([]byte, error) { func (m *PreKeyMessage) GetVersion() (uint32, error) { var version C.uint - signalFfiError := C.signal_pre_key_signal_message_get_version(&version, m.ptr) + signalFfiError := C.signal_pre_key_signal_message_get_version(&version, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -85,7 +94,7 @@ func (m *PreKeyMessage) GetVersion() (uint32, error) { func (m *PreKeyMessage) GetRegistrationID() (uint32, error) { var registrationID C.uint - signalFfiError := C.signal_pre_key_signal_message_get_registration_id(®istrationID, m.ptr) + signalFfiError := C.signal_pre_key_signal_message_get_registration_id(®istrationID, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -95,7 +104,7 @@ func (m *PreKeyMessage) GetRegistrationID() (uint32, error) { func (m *PreKeyMessage) GetPreKeyID() (*uint32, error) { var preKeyID C.uint - signalFfiError := C.signal_pre_key_signal_message_get_pre_key_id(&preKeyID, m.ptr) + signalFfiError := C.signal_pre_key_signal_message_get_pre_key_id(&preKeyID, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -108,7 +117,7 @@ func (m *PreKeyMessage) GetPreKeyID() (*uint32, error) { func (m *PreKeyMessage) GetSignedPreKeyID() (uint32, error) { var signedPreKeyID C.uint - signalFfiError := C.signal_pre_key_signal_message_get_signed_pre_key_id(&signedPreKeyID, m.ptr) + signalFfiError := C.signal_pre_key_signal_message_get_signed_pre_key_id(&signedPreKeyID, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -117,31 +126,31 @@ func (m *PreKeyMessage) GetSignedPreKeyID() (uint32, error) { } func (m *PreKeyMessage) GetBaseKey() (*PublicKey, error) { - var publicKey *C.SignalPublicKey - signalFfiError := C.signal_pre_key_signal_message_get_base_key(&publicKey, m.ptr) + var publicKey C.SignalMutPointerPublicKey + signalFfiError := C.signal_pre_key_signal_message_get_base_key(&publicKey, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(publicKey), nil + return wrapPublicKey(publicKey.raw), nil } func (m *PreKeyMessage) GetIdentityKey() (*IdentityKey, error) { - var publicKey *C.SignalPublicKey - signalFfiError := C.signal_pre_key_signal_message_get_identity_key(&publicKey, m.ptr) + var publicKey C.SignalMutPointerPublicKey + signalFfiError := C.signal_pre_key_signal_message_get_identity_key(&publicKey, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return &IdentityKey{wrapPublicKey(publicKey)}, nil + return &IdentityKey{wrapPublicKey(publicKey.raw)}, nil } func (m *PreKeyMessage) GetSignalMessage() (*Message, error) { - var message *C.SignalMessage - signalFfiError := C.signal_pre_key_signal_message_get_signal_message(&message, m.ptr) + var message C.SignalMutPointerSignalMessage + signalFfiError := C.signal_pre_key_signal_message_get_signal_message(&message, m.constPtr()) runtime.KeepAlive(m) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapMessage(message), nil + return wrapMessage(message.raw), nil } diff --git a/pkg/libsignalgo/prekeystore.go b/pkg/libsignalgo/prekeystore.go index c678ade..c9b0469 100644 --- a/pkg/libsignalgo/prekeystore.go +++ b/pkg/libsignalgo/prekeystore.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -69,11 +70,11 @@ func signal_remove_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t) C.in }) } -func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) *C.SignalPreKeyStore { - return &C.SignalPreKeyStore{ +func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) C.SignalConstPointerFfiPreKeyStoreStruct { + return C.SignalConstPointerFfiPreKeyStoreStruct{&C.SignalPreKeyStore{ ctx: wrapStore(ctx, store), load_pre_key: C.SignalLoadPreKey(C.signal_load_pre_key_callback), store_pre_key: C.SignalStorePreKey(C.signal_store_pre_key_callback), remove_pre_key: C.SignalRemovePreKey(C.signal_remove_pre_key_callback), - } + }} } diff --git a/pkg/libsignalgo/privatekey.go b/pkg/libsignalgo/privatekey.go index fa78a77..3703727 100644 --- a/pkg/libsignalgo/privatekey.go +++ b/pkg/libsignalgo/privatekey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -35,37 +36,45 @@ func wrapPrivateKey(ptr *C.SignalPrivateKey) *PrivateKey { } func GeneratePrivateKey() (*PrivateKey, error) { - var pk *C.SignalPrivateKey + var pk C.SignalMutPointerPrivateKey signalFfiError := C.signal_privatekey_generate(&pk) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPrivateKey(pk), nil + return wrapPrivateKey(pk.raw), nil } func DeserializePrivateKey(keyData []byte) (*PrivateKey, error) { - var pk *C.SignalPrivateKey + var pk C.SignalMutPointerPrivateKey signalFfiError := C.signal_privatekey_deserialize(&pk, BytesToBuffer(keyData)) runtime.KeepAlive(keyData) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPrivateKey(pk), nil + return wrapPrivateKey(pk.raw), nil +} + +func (pk *PrivateKey) mutPtr() C.SignalMutPointerPrivateKey { + return C.SignalMutPointerPrivateKey{pk.ptr} +} + +func (pk *PrivateKey) constPtr() C.SignalConstPointerPrivateKey { + return C.SignalConstPointerPrivateKey{pk.ptr} } func (pk *PrivateKey) Clone() (*PrivateKey, error) { - var cloned *C.SignalPrivateKey - signalFfiError := C.signal_privatekey_clone(&cloned, pk.ptr) + var cloned C.SignalMutPointerPrivateKey + signalFfiError := C.signal_privatekey_clone(&cloned, pk.constPtr()) runtime.KeepAlive(pk) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPrivateKey(cloned), nil + return wrapPrivateKey(cloned.raw), nil } func (pk *PrivateKey) Destroy() error { pk.CancelFinalizer() - return wrapError(C.signal_privatekey_destroy(pk.ptr)) + return wrapError(C.signal_privatekey_destroy(pk.mutPtr())) } func (pk *PrivateKey) CancelFinalizer() { @@ -73,18 +82,18 @@ func (pk *PrivateKey) CancelFinalizer() { } func (pk *PrivateKey) GetPublicKey() (*PublicKey, error) { - var pub *C.SignalPublicKey - signalFfiError := C.signal_privatekey_get_public_key(&pub, pk.ptr) + var pub C.SignalMutPointerPublicKey + signalFfiError := C.signal_privatekey_get_public_key(&pub, pk.constPtr()) runtime.KeepAlive(pk) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(pub), nil + return wrapPublicKey(pub.raw), nil } func (pk *PrivateKey) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_privatekey_serialize(&serialized, pk.ptr) + signalFfiError := C.signal_privatekey_serialize(&serialized, pk.constPtr()) runtime.KeepAlive(pk) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -94,7 +103,7 @@ func (pk *PrivateKey) Serialize() ([]byte, error) { func (pk *PrivateKey) Sign(message []byte) ([]byte, error) { var signed C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_privatekey_sign(&signed, pk.ptr, BytesToBuffer(message)) + signalFfiError := C.signal_privatekey_sign(&signed, pk.constPtr(), BytesToBuffer(message)) runtime.KeepAlive(pk) runtime.KeepAlive(message) if signalFfiError != nil { @@ -105,7 +114,7 @@ func (pk *PrivateKey) Sign(message []byte) ([]byte, error) { func (pk *PrivateKey) Agree(publicKey *PublicKey) ([]byte, error) { var agreed C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_privatekey_agree(&agreed, pk.ptr, publicKey.ptr) + signalFfiError := C.signal_privatekey_agree(&agreed, pk.constPtr(), publicKey.constPtr()) runtime.KeepAlive(pk) runtime.KeepAlive(publicKey) if signalFfiError != nil { diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index 82e3036..c78c9d1 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 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 @@ -148,7 +149,7 @@ func CreateProfileKeyCredentialRequestContext(serverPublicParams *ServerPublicPa signalFfiError := C.signal_server_public_params_create_profile_key_credential_request_context_deterministic( &c_result, - serverPublicParams, + C.SignalConstPointerServerPublicParams{serverPublicParams}, c_random, c_uuid, c_profileKey, @@ -194,7 +195,7 @@ func ReceiveExpiringProfileKeyCredential(spp *ServerPublicParams, requestContext c_credential := [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]C.uchar{} signalFfiError := C.signal_server_public_params_receive_expiring_profile_key_credential( &c_credential, - spp, + 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)), (C.uint64_t)(currentTimeInSeconds), diff --git a/pkg/libsignalgo/protocol.go b/pkg/libsignalgo/protocol.go deleted file mode 100644 index 4d834fe..0000000 --- a/pkg/libsignalgo/protocol.go +++ /dev/null @@ -1,49 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2023 Sumner Evans -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package libsignalgo - -/* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm -#include "./libsignal-ffi.h" -*/ -import "C" -import ( - "context" - "runtime" - "time" -) - -func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, sessionStore SessionStore, identityKeyStore IdentityKeyStore) (*CiphertextMessage, error) { - var ciphertextMessage *C.SignalCiphertextMessage - var now C.uint64_t = C.uint64_t(time.Now().Unix()) - callbackCtx := NewCallbackContext(ctx) - defer callbackCtx.Unref() - signalFfiError := C.signal_encrypt_message( - &ciphertextMessage, - BytesToBuffer(plaintext), - forAddress.ptr, - callbackCtx.wrapSessionStore(sessionStore), - callbackCtx.wrapIdentityKeyStore(identityKeyStore), - now, - ) - runtime.KeepAlive(plaintext) - runtime.KeepAlive(forAddress) - if signalFfiError != nil { - return nil, callbackCtx.wrapError(signalFfiError) - } - return wrapCiphertextMessage(ciphertextMessage), nil -} diff --git a/pkg/libsignalgo/publickey.go b/pkg/libsignalgo/publickey.go index 5ce452d..8c4c98f 100644 --- a/pkg/libsignalgo/publickey.go +++ b/pkg/libsignalgo/publickey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -34,29 +35,37 @@ func wrapPublicKey(ptr *C.SignalPublicKey) *PublicKey { return publicKey } +func (pk *PublicKey) mutPtr() C.SignalMutPointerPublicKey { + return C.SignalMutPointerPublicKey{pk.ptr} +} + +func (pk *PublicKey) constPtr() C.SignalConstPointerPublicKey { + return C.SignalConstPointerPublicKey{pk.ptr} +} + func (pk *PublicKey) Clone() (*PublicKey, error) { - var cloned *C.SignalPublicKey - signalFfiError := C.signal_publickey_clone(&cloned, pk.ptr) + var cloned C.SignalMutPointerPublicKey + signalFfiError := C.signal_publickey_clone(&cloned, pk.constPtr()) runtime.KeepAlive(pk) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(cloned), nil + return wrapPublicKey(cloned.raw), nil } func DeserializePublicKey(keyData []byte) (*PublicKey, error) { - var pk *C.SignalPublicKey + var pk C.SignalMutPointerPublicKey signalFfiError := C.signal_publickey_deserialize(&pk, BytesToBuffer(keyData)) runtime.KeepAlive(keyData) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(pk), nil + return wrapPublicKey(pk.raw), nil } func (pk *PublicKey) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_publickey_serialize(&serialized, pk.ptr) + signalFfiError := C.signal_publickey_serialize(&serialized, pk.constPtr()) runtime.KeepAlive(pk) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -66,7 +75,7 @@ func (pk *PublicKey) Serialize() ([]byte, error) { func (k *PublicKey) Destroy() error { k.CancelFinalizer() - return wrapError(C.signal_publickey_destroy(k.ptr)) + return wrapError(C.signal_publickey_destroy(k.mutPtr())) } func (k *PublicKey) CancelFinalizer() { @@ -75,7 +84,7 @@ func (k *PublicKey) CancelFinalizer() { func (k *PublicKey) Compare(other *PublicKey) (int, error) { var comparison C.int - signalFfiError := C.signal_publickey_compare(&comparison, k.ptr, other.ptr) + signalFfiError := C.signal_publickey_compare(&comparison, k.constPtr(), other.constPtr()) runtime.KeepAlive(k) runtime.KeepAlive(other) if signalFfiError != nil { @@ -86,7 +95,7 @@ func (k *PublicKey) Compare(other *PublicKey) (int, error) { func (k *PublicKey) Bytes() ([]byte, error) { var pub C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_publickey_get_public_key_bytes(&pub, k.ptr) + signalFfiError := C.signal_publickey_get_public_key_bytes(&pub, k.constPtr()) runtime.KeepAlive(k) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -96,7 +105,12 @@ func (k *PublicKey) Bytes() ([]byte, error) { func (k *PublicKey) Verify(message, signature []byte) (bool, error) { var verify C.bool - signalFfiError := C.signal_publickey_verify(&verify, k.ptr, BytesToBuffer(message), BytesToBuffer(signature)) + signalFfiError := C.signal_publickey_verify( + &verify, + k.constPtr(), + BytesToBuffer(message), + BytesToBuffer(signature), + ) runtime.KeepAlive(k) runtime.KeepAlive(message) runtime.KeepAlive(signature) diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 0d12b74..4912977 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 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 @@ -66,8 +67,8 @@ func SealedSenderEncrypt(ctx context.Context, usmc *UnidentifiedSenderMessageCon defer callbackCtx.Unref() signalFfiError := C.signal_sealed_session_cipher_encrypt( &encrypted, - forRecipient.ptr, - usmc.ptr, + forRecipient.constPtr(), + usmc.constPtr(), callbackCtx.wrapIdentityKeyStore(identityStore), ) runtime.KeepAlive(usmc) @@ -94,7 +95,7 @@ func SealedSenderDecryptToUSMC( ) (*UnidentifiedSenderMessageContent, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() - var usmc *C.SignalUnidentifiedSenderMessageContent = nil + var usmc C.SignalMutPointerUnidentifiedSenderMessageContent signalFfiError := C.signal_sealed_session_cipher_decrypt_to_usmc( &usmc, BytesToBuffer(ciphertext), @@ -104,7 +105,7 @@ func SealedSenderDecryptToUSMC( if signalFfiError != nil { return nil, callbackCtx.wrapError(signalFfiError) } - return wrapUnidentifiedSenderMessageContent(usmc), nil + return wrapUnidentifiedSenderMessageContent(usmc.raw), nil } func SealedSenderDecrypt( @@ -132,7 +133,7 @@ func SealedSenderDecrypt( &senderUUID, &senderDeviceID, BytesToBuffer(ciphertext), - trustRoot.ptr, + trustRoot.constPtr(), C.uint64_t(timestamp), C.CString(localAddress.E164), C.CString(localAddress.UUID.String()), @@ -182,15 +183,21 @@ func wrapUnidentifiedSenderMessageContent(ptr *C.SignalUnidentifiedSenderMessage } func NewUnidentifiedSenderMessageContent(message *CiphertextMessage, senderCertificate *SenderCertificate, contentHint UnidentifiedSenderMessageContentHint, groupID []byte) (*UnidentifiedSenderMessageContent, error) { - var usmc *C.SignalUnidentifiedSenderMessageContent - signalFfiError := C.signal_unidentified_sender_message_content_new(&usmc, message.ptr, senderCertificate.ptr, C.uint32_t(contentHint), BytesToBuffer(groupID)) + var usmc C.SignalMutPointerUnidentifiedSenderMessageContent + signalFfiError := C.signal_unidentified_sender_message_content_new( + &usmc, + message.constPtr(), + senderCertificate.constPtr(), + C.uint32_t(contentHint), + BytesToBuffer(groupID), + ) runtime.KeepAlive(message) runtime.KeepAlive(senderCertificate) runtime.KeepAlive(groupID) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapUnidentifiedSenderMessageContent(usmc), nil + return wrapUnidentifiedSenderMessageContent(usmc.raw), nil } //func NewUnidentifiedSenderMessageContentFromMessage(sealedSenderMessage []byte, identityStore IdentityKeyStore, ctx *CallbackContext) (*UnidentifiedSenderMessageContent, error) { @@ -212,18 +219,26 @@ func NewUnidentifiedSenderMessageContent(message *CiphertextMessage, senderCerti //} func DeserializeUnidentifiedSenderMessageContent(serialized []byte) (*UnidentifiedSenderMessageContent, error) { - var usmc *C.SignalUnidentifiedSenderMessageContent + var usmc C.SignalMutPointerUnidentifiedSenderMessageContent signalFfiError := C.signal_unidentified_sender_message_content_deserialize(&usmc, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapUnidentifiedSenderMessageContent(usmc), nil + return wrapUnidentifiedSenderMessageContent(usmc.raw), nil +} + +func (usmc *UnidentifiedSenderMessageContent) mutPtr() C.SignalMutPointerUnidentifiedSenderMessageContent { + return C.SignalMutPointerUnidentifiedSenderMessageContent{usmc.ptr} +} + +func (usmc *UnidentifiedSenderMessageContent) constPtr() C.SignalConstPointerUnidentifiedSenderMessageContent { + return C.SignalConstPointerUnidentifiedSenderMessageContent{usmc.ptr} } func (usmc *UnidentifiedSenderMessageContent) Destroy() error { usmc.CancelFinalizer() - return wrapError(C.signal_unidentified_sender_message_content_destroy(usmc.ptr)) + return wrapError(C.signal_unidentified_sender_message_content_destroy(usmc.mutPtr())) } func (usmc *UnidentifiedSenderMessageContent) CancelFinalizer() { @@ -232,7 +247,7 @@ func (usmc *UnidentifiedSenderMessageContent) CancelFinalizer() { func (usmc *UnidentifiedSenderMessageContent) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_unidentified_sender_message_content_serialize(&serialized, usmc.ptr) + signalFfiError := C.signal_unidentified_sender_message_content_serialize(&serialized, usmc.constPtr()) runtime.KeepAlive(usmc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -242,7 +257,7 @@ func (usmc *UnidentifiedSenderMessageContent) Serialize() ([]byte, error) { func (usmc *UnidentifiedSenderMessageContent) GetContents() ([]byte, error) { var contents C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_unidentified_sender_message_content_get_contents(&contents, usmc.ptr) + signalFfiError := C.signal_unidentified_sender_message_content_get_contents(&contents, usmc.constPtr()) runtime.KeepAlive(usmc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -264,18 +279,18 @@ func (usmc *UnidentifiedSenderMessageContent) GetContents() ([]byte, error) { //} func (usmc *UnidentifiedSenderMessageContent) GetSenderCertificate() (*SenderCertificate, error) { - var senderCertificate *C.SignalSenderCertificate - signalFfiError := C.signal_unidentified_sender_message_content_get_sender_cert(&senderCertificate, usmc.ptr) + var senderCertificate C.SignalMutPointerSenderCertificate + signalFfiError := C.signal_unidentified_sender_message_content_get_sender_cert(&senderCertificate, usmc.constPtr()) runtime.KeepAlive(usmc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderCertificate(senderCertificate), nil + return wrapSenderCertificate(senderCertificate.raw), nil } func (usmc *UnidentifiedSenderMessageContent) GetMessageType() (CiphertextMessageType, error) { var messageType C.uint8_t - signalFfiError := C.signal_unidentified_sender_message_content_get_msg_type(&messageType, usmc.ptr) + signalFfiError := C.signal_unidentified_sender_message_content_get_msg_type(&messageType, usmc.constPtr()) runtime.KeepAlive(usmc) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -285,7 +300,7 @@ func (usmc *UnidentifiedSenderMessageContent) GetMessageType() (CiphertextMessag func (usmc *UnidentifiedSenderMessageContent) GetContentHint() (UnidentifiedSenderMessageContentHint, error) { var contentHint C.uint32_t - signalFfiError := C.signal_unidentified_sender_message_content_get_content_hint(&contentHint, usmc.ptr) + signalFfiError := C.signal_unidentified_sender_message_content_get_content_hint(&contentHint, usmc.constPtr()) runtime.KeepAlive(usmc) if signalFfiError != nil { return 0, wrapError(signalFfiError) diff --git a/pkg/libsignalgo/sendercertificate.go b/pkg/libsignalgo/sendercertificate.go index a5d3f6f..46caf1c 100644 --- a/pkg/libsignalgo/sendercertificate.go +++ b/pkg/libsignalgo/sendercertificate.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -42,8 +43,17 @@ func wrapSenderCertificate(ptr *C.SignalSenderCertificate) *SenderCertificate { // NewSenderCertificate should only be used for testing (at least according to // the Swift bindings). func NewSenderCertificate(sender *SealedSenderAddress, publicKey *PublicKey, expiration time.Time, signerCertificate *ServerCertificate, signerKey *PrivateKey) (*SenderCertificate, error) { - var sc *C.SignalSenderCertificate - signalFfiError := C.signal_sender_certificate_new(&sc, C.CString(sender.UUID.String()), C.CString(sender.E164), C.uint32_t(sender.DeviceID), publicKey.ptr, C.uint64_t(expiration.UnixMilli()), signerCertificate.ptr, signerKey.ptr) + var sc C.SignalMutPointerSenderCertificate + signalFfiError := C.signal_sender_certificate_new( + &sc, + C.CString(sender.UUID.String()), + C.CString(sender.E164), + C.uint32_t(sender.DeviceID), + publicKey.constPtr(), + C.uint64_t(expiration.UnixMilli()), + signerCertificate.constPtr(), + signerKey.constPtr(), + ) runtime.KeepAlive(sender) runtime.KeepAlive(publicKey) runtime.KeepAlive(signerCertificate) @@ -51,32 +61,43 @@ func NewSenderCertificate(sender *SealedSenderAddress, publicKey *PublicKey, exp if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderCertificate(sc), nil + return wrapSenderCertificate(sc.raw), nil } func DeserializeSenderCertificate(serialized []byte) (*SenderCertificate, error) { - var sc *C.SignalSenderCertificate + var sc C.SignalMutPointerSenderCertificate signalFfiError := C.signal_sender_certificate_deserialize(&sc, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderCertificate(sc), nil + return wrapSenderCertificate(sc.raw), nil } func (sc *SenderCertificate) Clone() (*SenderCertificate, error) { - var cloned *C.SignalSenderCertificate - signalFfiError := C.signal_sender_certificate_clone(&cloned, sc.ptr) + var cloned C.SignalMutPointerSenderCertificate + signalFfiError := C.signal_sender_certificate_clone( + &cloned, + sc.constPtr(), + ) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderCertificate(cloned), nil + return wrapSenderCertificate(cloned.raw), nil +} + +func (sc *SenderCertificate) mutPtr() C.SignalMutPointerSenderCertificate { + return C.SignalMutPointerSenderCertificate{sc.ptr} +} + +func (sc *SenderCertificate) constPtr() C.SignalConstPointerSenderCertificate { + return C.SignalConstPointerSenderCertificate{sc.ptr} } func (sc *SenderCertificate) Destroy() error { sc.CancelFinalizer() - return wrapError(C.signal_sender_certificate_destroy(sc.ptr)) + return wrapError(C.signal_sender_certificate_destroy(sc.mutPtr())) } func (sc *SenderCertificate) CancelFinalizer() { @@ -85,7 +106,7 @@ func (sc *SenderCertificate) CancelFinalizer() { func (sc *SenderCertificate) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_sender_certificate_get_serialized(&serialized, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_serialized(&serialized, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -95,7 +116,7 @@ func (sc *SenderCertificate) Serialize() ([]byte, error) { func (sc *SenderCertificate) GetCertificate() ([]byte, error) { var certificate C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_sender_certificate_get_certificate(&certificate, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_certificate(&certificate, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -105,7 +126,7 @@ func (sc *SenderCertificate) GetCertificate() ([]byte, error) { func (sc *SenderCertificate) GetSignature() ([]byte, error) { var signature C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_sender_certificate_get_signature(&signature, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_signature(&signature, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -115,7 +136,7 @@ func (sc *SenderCertificate) GetSignature() ([]byte, error) { func (sc *SenderCertificate) GetSenderUUID() (uuid.UUID, error) { var rawUUID *C.char - signalFfiError := C.signal_sender_certificate_get_sender_uuid(&rawUUID, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_sender_uuid(&rawUUID, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return uuid.UUID{}, wrapError(signalFfiError) @@ -125,7 +146,7 @@ func (sc *SenderCertificate) GetSenderUUID() (uuid.UUID, error) { func (sc *SenderCertificate) GetSenderE164() (string, error) { var e164 *C.char - signalFfiError := C.signal_sender_certificate_get_sender_e164(&e164, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_sender_e164(&e164, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return "", wrapError(signalFfiError) @@ -138,7 +159,7 @@ func (sc *SenderCertificate) GetSenderE164() (string, error) { func (sc *SenderCertificate) GetExpiration() (time.Time, error) { var expiration C.uint64_t - signalFfiError := C.signal_sender_certificate_get_expiration(&expiration, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_expiration(&expiration, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return time.Time{}, wrapError(signalFfiError) @@ -148,7 +169,7 @@ func (sc *SenderCertificate) GetExpiration() (time.Time, error) { func (sc *SenderCertificate) GetDeviceID() (uint32, error) { var deviceID C.uint32_t - signalFfiError := C.signal_sender_certificate_get_device_id(&deviceID, sc.ptr) + signalFfiError := C.signal_sender_certificate_get_device_id(&deviceID, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -157,18 +178,23 @@ func (sc *SenderCertificate) GetDeviceID() (uint32, error) { } func (sc *SenderCertificate) GetKey() (*PublicKey, error) { - var key *C.SignalPublicKey - signalFfiError := C.signal_sender_certificate_get_key(&key, sc.ptr) + var key C.SignalMutPointerPublicKey + signalFfiError := C.signal_sender_certificate_get_key(&key, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(key), nil + return wrapPublicKey(key.raw), nil } func (sc *SenderCertificate) Validate(trustRoot *PublicKey, ts time.Time) (bool, error) { var valid C.bool - signalFfiError := C.signal_sender_certificate_validate(&valid, sc.ptr, trustRoot.ptr, C.uint64_t(ts.UnixMilli())) + signalFfiError := C.signal_sender_certificate_validate( + &valid, + sc.constPtr(), + trustRoot.constPtr(), + C.uint64_t(ts.UnixMilli()), + ) runtime.KeepAlive(sc) runtime.KeepAlive(trustRoot) if signalFfiError != nil { @@ -178,11 +204,11 @@ func (sc *SenderCertificate) Validate(trustRoot *PublicKey, ts time.Time) (bool, } func (sc *SenderCertificate) GetServerCertificate() (*ServerCertificate, error) { - var serverCertificate *C.SignalServerCertificate - signalFfiError := C.signal_sender_certificate_get_server_certificate(&serverCertificate, sc.ptr) + var serverCertificate C.SignalMutPointerServerCertificate + signalFfiError := C.signal_sender_certificate_get_server_certificate(&serverCertificate, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapServerCertificate(serverCertificate), nil + return wrapServerCertificate(serverCertificate.raw), nil } diff --git a/pkg/libsignalgo/senderkeydistributionmessage.go b/pkg/libsignalgo/senderkeydistributionmessage.go index 60c5910..e772c58 100644 --- a/pkg/libsignalgo/senderkeydistributionmessage.go +++ b/pkg/libsignalgo/senderkeydistributionmessage.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -33,8 +34,8 @@ func ProcessSenderKeyDistributionMessage(ctx context.Context, message *SenderKey callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() signalFfiError := C.signal_process_sender_key_distribution_message( - fromSender.ptr, - message.ptr, + fromSender.constPtr(), + message.constPtr(), callbackCtx.wrapSenderKeyStore(store), ) runtime.KeepAlive(message) @@ -56,10 +57,10 @@ func wrapSenderKeyDistributionMessage(ptr *C.SignalSenderKeyDistributionMessage) func NewSenderKeyDistributionMessage(ctx context.Context, sender *Address, distributionID uuid.UUID, store SenderKeyStore) (*SenderKeyDistributionMessage, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() - var skdm *C.SignalSenderKeyDistributionMessage + var skdm C.SignalMutPointerSenderKeyDistributionMessage signalFfiError := C.signal_sender_key_distribution_message_create( &skdm, - sender.ptr, + sender.constPtr(), (*[C.SignalUUID_LEN]C.uchar)(unsafe.Pointer(&distributionID)), callbackCtx.wrapSenderKeyStore(store), ) @@ -68,22 +69,30 @@ func NewSenderKeyDistributionMessage(ctx context.Context, sender *Address, distr if signalFfiError != nil { return nil, callbackCtx.wrapError(signalFfiError) } - return wrapSenderKeyDistributionMessage(skdm), nil + return wrapSenderKeyDistributionMessage(skdm.raw), nil } func DeserializeSenderKeyDistributionMessage(serialized []byte) (*SenderKeyDistributionMessage, error) { - var skdm *C.SignalSenderKeyDistributionMessage + var skdm C.SignalMutPointerSenderKeyDistributionMessage signalFfiError := C.signal_sender_key_distribution_message_deserialize(&skdm, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderKeyDistributionMessage(skdm), nil + return wrapSenderKeyDistributionMessage(skdm.raw), nil +} + +func (sc *SenderKeyDistributionMessage) mutPtr() C.SignalMutPointerSenderKeyDistributionMessage { + return C.SignalMutPointerSenderKeyDistributionMessage{sc.ptr} +} + +func (sc *SenderKeyDistributionMessage) constPtr() C.SignalConstPointerSenderKeyDistributionMessage { + return C.SignalConstPointerSenderKeyDistributionMessage{sc.ptr} } func (sc *SenderKeyDistributionMessage) Destroy() error { sc.CancelFinalizer() - return wrapError(C.signal_sender_key_distribution_message_destroy(sc.ptr)) + return wrapError(C.signal_sender_key_distribution_message_destroy(sc.mutPtr())) } func (sc *SenderKeyDistributionMessage) CancelFinalizer() { @@ -92,7 +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.ptr) + signalFfiError := C.signal_sender_key_distribution_message_serialize(&serialized, sc.constPtr()) if signalFfiError != nil { return nil, wrapError(signalFfiError) } @@ -103,8 +112,8 @@ func (sc *SenderKeyDistributionMessage) Process(ctx context.Context, sender *Add callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() signalFfiError := C.signal_process_sender_key_distribution_message( - sender.ptr, - sc.ptr, + sender.constPtr(), + sc.constPtr(), callbackCtx.wrapSenderKeyStore(store), ) runtime.KeepAlive(sender) diff --git a/pkg/libsignalgo/senderkeyrecord.go b/pkg/libsignalgo/senderkeyrecord.go index cc487df..7299ae5 100644 --- a/pkg/libsignalgo/senderkeyrecord.go +++ b/pkg/libsignalgo/senderkeyrecord.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -37,18 +38,18 @@ func wrapSenderKeyRecord(ptr *C.SignalSenderKeyRecord) *SenderKeyRecord { } func DeserializeSenderKeyRecord(serialized []byte) (*SenderKeyRecord, error) { - var sc *C.SignalSenderKeyRecord + var sc C.SignalMutPointerSenderKeyRecord signalFfiError := C.signal_sender_key_record_deserialize(&sc, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderKeyRecord(sc), nil + return wrapSenderKeyRecord(sc.raw), nil } func (skr *SenderKeyRecord) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_sender_key_record_serialize(&serialized, skr.ptr) + signalFfiError := C.signal_sender_key_record_serialize(&serialized, skr.constPtr()) runtime.KeepAlive(skr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -56,19 +57,27 @@ func (skr *SenderKeyRecord) Serialize() ([]byte, error) { return CopySignalOwnedBufferToBytes(serialized), nil } +func (skr *SenderKeyRecord) mutPtr() C.SignalMutPointerSenderKeyRecord { + return C.SignalMutPointerSenderKeyRecord{skr.ptr} +} + +func (skr *SenderKeyRecord) constPtr() C.SignalConstPointerSenderKeyRecord { + return C.SignalConstPointerSenderKeyRecord{skr.ptr} +} + func (skr *SenderKeyRecord) Clone() (*SenderKeyRecord, error) { - var cloned *C.SignalSenderKeyRecord - signalFfiError := C.signal_sender_key_record_clone(&cloned, skr.ptr) + var cloned C.SignalMutPointerSenderKeyRecord + signalFfiError := C.signal_sender_key_record_clone(&cloned, skr.constPtr()) runtime.KeepAlive(skr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSenderKeyRecord(cloned), nil + return wrapSenderKeyRecord(cloned.raw), nil } func (skr *SenderKeyRecord) Destroy() error { skr.CancelFinalizer() - return wrapError(C.signal_sender_key_record_destroy(skr.ptr)) + return wrapError(C.signal_sender_key_record_destroy(skr.mutPtr())) } func (skr *SenderKeyRecord) CancelFinalizer() { diff --git a/pkg/libsignalgo/senderkeystore.go b/pkg/libsignalgo/senderkeystore.go index 3d05fc2..d3bda2f 100644 --- a/pkg/libsignalgo/senderkeystore.go +++ b/pkg/libsignalgo/senderkeystore.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -68,10 +69,10 @@ func signal_store_sender_key_callback(storeCtx unsafe.Pointer, address *C.const_ }) } -func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) *C.SignalSenderKeyStore { - return &C.SignalSenderKeyStore{ +func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) C.SignalConstPointerFfiSenderKeyStoreStruct { + return C.SignalConstPointerFfiSenderKeyStoreStruct{&C.SignalSenderKeyStore{ ctx: wrapStore(ctx, store), load_sender_key: C.SignalLoadSenderKey(C.signal_load_sender_key_callback), store_sender_key: C.SignalStoreSenderKey(C.signal_store_sender_key_callback), - } + }} } diff --git a/pkg/libsignalgo/servercertificate.go b/pkg/libsignalgo/servercertificate.go index 64ba57a..da56b0b 100644 --- a/pkg/libsignalgo/servercertificate.go +++ b/pkg/libsignalgo/servercertificate.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -37,39 +38,52 @@ func wrapServerCertificate(ptr *C.SignalServerCertificate) *ServerCertificate { // NewServerCertificate should only be used for testing (at least according to // the Swift bindings). func NewServerCertificate(keyID uint32, publicKey *PublicKey, trustRoot *PrivateKey) (*ServerCertificate, error) { - var serverCertificate *C.SignalServerCertificate - signalFfiError := C.signal_server_certificate_new(&serverCertificate, C.uint32_t(keyID), publicKey.ptr, trustRoot.ptr) + var serverCertificate C.SignalMutPointerServerCertificate + signalFfiError := C.signal_server_certificate_new( + &serverCertificate, + C.uint32_t(keyID), + publicKey.constPtr(), + trustRoot.constPtr(), + ) runtime.KeepAlive(publicKey) runtime.KeepAlive(trustRoot) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapServerCertificate(serverCertificate), nil + return wrapServerCertificate(serverCertificate.raw), nil } func DeserializeServerCertificate(serialized []byte) (*ServerCertificate, error) { - var serverCertificate *C.SignalServerCertificate + var serverCertificate C.SignalMutPointerServerCertificate signalFfiError := C.signal_server_certificate_deserialize(&serverCertificate, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapServerCertificate(serverCertificate), nil + return wrapServerCertificate(serverCertificate.raw), nil +} + +func (sc *ServerCertificate) mutPtr() C.SignalMutPointerServerCertificate { + return C.SignalMutPointerServerCertificate{sc.ptr} +} + +func (sc *ServerCertificate) constPtr() C.SignalConstPointerServerCertificate { + return C.SignalConstPointerServerCertificate{sc.ptr} } func (sc *ServerCertificate) Clone() (*ServerCertificate, error) { - var cloned *C.SignalServerCertificate - signalFfiError := C.signal_server_certificate_clone(&cloned, sc.ptr) + var cloned C.SignalMutPointerServerCertificate + signalFfiError := C.signal_server_certificate_clone(&cloned, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapServerCertificate(cloned), nil + return wrapServerCertificate(cloned.raw), nil } func (sc *ServerCertificate) Destroy() error { sc.CancelFinalizer() - return wrapError(C.signal_server_certificate_destroy(sc.ptr)) + return wrapError(C.signal_server_certificate_destroy(sc.mutPtr())) } func (sc *ServerCertificate) CancelFinalizer() { @@ -78,7 +92,7 @@ func (sc *ServerCertificate) CancelFinalizer() { func (sc *ServerCertificate) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_server_certificate_get_serialized(&serialized, sc.ptr) + signalFfiError := C.signal_server_certificate_get_serialized(&serialized, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -88,7 +102,7 @@ func (sc *ServerCertificate) Serialize() ([]byte, error) { func (sc *ServerCertificate) GetCertificate() ([]byte, error) { var certificate C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_server_certificate_get_certificate(&certificate, sc.ptr) + signalFfiError := C.signal_server_certificate_get_certificate(&certificate, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -98,7 +112,7 @@ func (sc *ServerCertificate) GetCertificate() ([]byte, error) { func (sc *ServerCertificate) GetSignature() ([]byte, error) { var signature C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_server_certificate_get_signature(&signature, sc.ptr) + signalFfiError := C.signal_server_certificate_get_signature(&signature, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -108,7 +122,7 @@ func (sc *ServerCertificate) GetSignature() ([]byte, error) { func (sc *ServerCertificate) GetKeyID() (uint32, error) { var keyID C.uint32_t - signalFfiError := C.signal_server_certificate_get_key_id(&keyID, sc.ptr) + signalFfiError := C.signal_server_certificate_get_key_id(&keyID, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -117,11 +131,11 @@ func (sc *ServerCertificate) GetKeyID() (uint32, error) { } func (sc *ServerCertificate) GetKey() (*PublicKey, error) { - var key *C.SignalPublicKey - signalFfiError := C.signal_server_certificate_get_key(&key, sc.ptr) + var key C.SignalMutPointerPublicKey + signalFfiError := C.signal_server_certificate_get_key(&key, sc.constPtr()) runtime.KeepAlive(sc) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(key), nil + return wrapPublicKey(key.raw), nil } diff --git a/pkg/libsignalgo/serverpublicparams.go b/pkg/libsignalgo/serverpublicparams.go index 6e99471..fc046c1 100644 --- a/pkg/libsignalgo/serverpublicparams.go +++ b/pkg/libsignalgo/serverpublicparams.go @@ -31,16 +31,16 @@ import ( type ServerPublicParams = C.SignalServerPublicParams type NotarySignature [C.SignalSIGNATURE_LEN]byte -func DeserializeServerPublicParams(params []byte) (out *ServerPublicParams, err error) { +func DeserializeServerPublicParams(params []byte) (*ServerPublicParams, error) { if len(params) != C.SignalSERVER_PUBLIC_PARAMS_LEN { - err = fmt.Errorf("invalid server public params length: %d (expected %d)", len(params), int(C.SignalSERVER_PUBLIC_PARAMS_LEN)) - return + return nil, fmt.Errorf("invalid server public params length: %d (expected %d)", len(params), int(C.SignalSERVER_PUBLIC_PARAMS_LEN)) } + var out C.SignalMutPointerServerPublicParams signalFfiError := C.signal_server_public_params_deserialize(&out, BytesToBuffer(params[:])) if signalFfiError != nil { - err = wrapError(signalFfiError) + return nil, wrapError(signalFfiError) } - return + return out.raw, nil } func ServerPublicParamsVerifySignature( @@ -50,7 +50,7 @@ func ServerPublicParamsVerifySignature( ) error { c_notarySignature := (*[C.SignalSIGNATURE_LEN]C.uint8_t)(unsafe.Pointer(&NotarySignature[0])) signalFfiError := C.signal_server_public_params_verify_signature( - serverPublicParams, + C.SignalConstPointerServerPublicParams{serverPublicParams}, BytesToBuffer(messageBytes), c_notarySignature, ) diff --git a/pkg/libsignalgo/sessionrecord.go b/pkg/libsignalgo/sessionrecord.go index f47e524..3523f62 100644 --- a/pkg/libsignalgo/sessionrecord.go +++ b/pkg/libsignalgo/sessionrecord.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -38,28 +39,39 @@ func wrapSessionRecord(ptr *C.SignalSessionRecord) *SessionRecord { } func DeserializeSessionRecord(serialized []byte) (*SessionRecord, error) { - var ptr *C.SignalSessionRecord + var ptr C.SignalMutPointerSessionRecord signalFfiError := C.signal_session_record_deserialize(&ptr, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSessionRecord(ptr), nil + return wrapSessionRecord(ptr.raw), nil +} + +func (sr *SessionRecord) mutPtr() C.SignalMutPointerSessionRecord { + return C.SignalMutPointerSessionRecord{sr.ptr} +} + +func (sr *SessionRecord) constPtr() C.SignalConstPointerSessionRecord { + return C.SignalConstPointerSessionRecord{sr.ptr} } func (sr *SessionRecord) Clone() (*SessionRecord, error) { - var clone *C.SignalSessionRecord - signalFfiError := C.signal_session_record_clone(&clone, sr.ptr) + var clone C.SignalMutPointerSessionRecord + signalFfiError := C.signal_session_record_clone( + &clone, + sr.constPtr(), + ) runtime.KeepAlive(sr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSessionRecord(clone), nil + return wrapSessionRecord(clone.raw), nil } func (sr *SessionRecord) Destroy() error { sr.CancelFinalizer() - return wrapError(C.signal_session_record_destroy(sr.ptr)) + return wrapError(C.signal_session_record_destroy(sr.mutPtr())) } func (sr *SessionRecord) CancelFinalizer() { @@ -68,12 +80,16 @@ func (sr *SessionRecord) CancelFinalizer() { func (sr *SessionRecord) ArchiveCurrentState() error { defer runtime.KeepAlive(sr) - return wrapError(C.signal_session_record_archive_current_state(sr.ptr)) + return wrapError(C.signal_session_record_archive_current_state(sr.mutPtr())) } func (sr *SessionRecord) CurrentRatchetKeyMatches(key *PublicKey) (bool, error) { var result C.bool - signalFfiError := C.signal_session_record_current_ratchet_key_matches(&result, sr.ptr, key.ptr) + signalFfiError := C.signal_session_record_current_ratchet_key_matches( + &result, + sr.constPtr(), + key.constPtr(), + ) runtime.KeepAlive(sr) runtime.KeepAlive(key) if signalFfiError != nil { @@ -84,7 +100,11 @@ func (sr *SessionRecord) CurrentRatchetKeyMatches(key *PublicKey) (bool, error) func (sr *SessionRecord) HasCurrentState() (bool, error) { var result C.bool - signalFfiError := C.signal_session_record_has_usable_sender_chain(&result, sr.ptr, C.uint64_t(time.Now().Unix())) + signalFfiError := C.signal_session_record_has_usable_sender_chain( + &result, + sr.constPtr(), + C.uint64_t(time.Now().Unix()), + ) runtime.KeepAlive(sr) if signalFfiError != nil { return false, wrapError(signalFfiError) @@ -94,7 +114,7 @@ func (sr *SessionRecord) HasCurrentState() (bool, error) { func (sr *SessionRecord) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_session_record_serialize(&serialized, sr.ptr) + signalFfiError := C.signal_session_record_serialize(&serialized, sr.constPtr()) runtime.KeepAlive(sr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -104,7 +124,7 @@ func (sr *SessionRecord) Serialize() ([]byte, error) { func (sr *SessionRecord) GetLocalRegistrationID() (uint32, error) { var result C.uint32_t - signalFfiError := C.signal_session_record_get_local_registration_id(&result, sr.ptr) + signalFfiError := C.signal_session_record_get_local_registration_id(&result, sr.constPtr()) runtime.KeepAlive(sr) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -114,7 +134,7 @@ func (sr *SessionRecord) GetLocalRegistrationID() (uint32, error) { func (sr *SessionRecord) GetRemoteRegistrationID() (uint32, error) { var result C.uint32_t - signalFfiError := C.signal_session_record_get_remote_registration_id(&result, sr.ptr) + signalFfiError := C.signal_session_record_get_remote_registration_id(&result, sr.constPtr()) runtime.KeepAlive(sr) if signalFfiError != nil { return 0, wrapError(signalFfiError) diff --git a/pkg/libsignalgo/sessionstore.go b/pkg/libsignalgo/sessionstore.go index c02aa58..ad88d62 100644 --- a/pkg/libsignalgo/sessionstore.go +++ b/pkg/libsignalgo/sessionstore.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -61,10 +62,10 @@ func signal_store_session_callback(storeCtx unsafe.Pointer, address *C.const_add }) } -func (ctx *CallbackContext) wrapSessionStore(store SessionStore) *C.SignalSessionStore { - return &C.SignalSessionStore{ +func (ctx *CallbackContext) wrapSessionStore(store SessionStore) C.SignalConstPointerFfiSessionStoreStruct { + return C.SignalConstPointerFfiSessionStoreStruct{&C.SignalSessionStore{ ctx: wrapStore(ctx, store), load_session: C.SignalLoadSession(C.signal_load_session_callback), store_session: C.SignalStoreSession(C.signal_store_session_callback), - } + }} } diff --git a/pkg/libsignalgo/sgxclient.go b/pkg/libsignalgo/sgxclient.go index c85f058..a2ba553 100644 --- a/pkg/libsignalgo/sgxclient.go +++ b/pkg/libsignalgo/sgxclient.go @@ -38,7 +38,7 @@ func wrapSGXClientState(ptr *C.SignalSgxClientState) *SGXClientState { } func NewCDS2ClientState(mrenclave, attestationMessage []byte, currentTime time.Time) (*SGXClientState, error) { - var cds *C.SignalSgxClientState + var cds C.SignalMutPointerSgxClientState signalFfiError := C.signal_cds2_client_state_new( &cds, BytesToBuffer(mrenclave), @@ -50,17 +50,25 @@ func NewCDS2ClientState(mrenclave, attestationMessage []byte, currentTime time.T if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSGXClientState(cds), nil + return wrapSGXClientState(cds.raw), nil +} + +func (cds *SGXClientState) mutPtr() C.SignalMutPointerSgxClientState { + return C.SignalMutPointerSgxClientState{cds.ptr} +} + +func (cds *SGXClientState) constPtr() C.SignalConstPointerSgxClientState { + return C.SignalConstPointerSgxClientState{cds.ptr} } func (cds *SGXClientState) Destroy() error { runtime.SetFinalizer(cds, nil) - return wrapError(C.signal_sgx_client_state_destroy(cds.ptr)) + return wrapError(C.signal_sgx_client_state_destroy(cds.mutPtr())) } func (cds *SGXClientState) InitialRequest() ([]byte, error) { var resp C.SignalOwnedBuffer - signalFfiError := C.signal_sgx_client_state_initial_request(&resp, cds.ptr) + signalFfiError := C.signal_sgx_client_state_initial_request(&resp, cds.constPtr()) runtime.KeepAlive(cds) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -69,7 +77,7 @@ func (cds *SGXClientState) InitialRequest() ([]byte, error) { } func (cds *SGXClientState) CompleteHandshake(handshakeReceived []byte) error { - signalFfiError := C.signal_sgx_client_state_complete_handshake(cds.ptr, BytesToBuffer(handshakeReceived)) + signalFfiError := C.signal_sgx_client_state_complete_handshake(cds.mutPtr(), BytesToBuffer(handshakeReceived)) runtime.KeepAlive(cds) runtime.KeepAlive(handshakeReceived) return wrapError(signalFfiError) @@ -77,7 +85,11 @@ func (cds *SGXClientState) CompleteHandshake(handshakeReceived []byte) error { func (cds *SGXClientState) EstablishedSend(plaintext []byte) ([]byte, error) { var resp C.SignalOwnedBuffer - signalFfiError := C.signal_sgx_client_state_established_send(&resp, cds.ptr, BytesToBuffer(plaintext)) + signalFfiError := C.signal_sgx_client_state_established_send( + &resp, + cds.mutPtr(), + BytesToBuffer(plaintext), + ) runtime.KeepAlive(cds) runtime.KeepAlive(plaintext) if signalFfiError != nil { @@ -88,7 +100,11 @@ func (cds *SGXClientState) EstablishedSend(plaintext []byte) ([]byte, error) { func (cds *SGXClientState) EstablishedReceive(ciphertext []byte) ([]byte, error) { var resp C.SignalOwnedBuffer - signalFfiError := C.signal_sgx_client_state_established_recv(&resp, cds.ptr, BytesToBuffer(ciphertext)) + signalFfiError := C.signal_sgx_client_state_established_recv( + &resp, + cds.mutPtr(), + BytesToBuffer(ciphertext), + ) runtime.KeepAlive(cds) runtime.KeepAlive(ciphertext) if signalFfiError != nil { diff --git a/pkg/libsignalgo/signedprekey.go b/pkg/libsignalgo/signedprekey.go index e3aa926..ca86ce3 100644 --- a/pkg/libsignalgo/signedprekey.go +++ b/pkg/libsignalgo/signedprekey.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -38,15 +39,22 @@ func wrapSignedPreKeyRecord(ptr *C.SignalSignedPreKeyRecord) *SignedPreKeyRecord } func NewSignedPreKeyRecord(id uint32, timestamp time.Time, publicKey *PublicKey, privateKey *PrivateKey, signature []byte) (*SignedPreKeyRecord, error) { - var spkr *C.SignalSignedPreKeyRecord - signalFfiError := C.signal_signed_pre_key_record_new(&spkr, C.uint32_t(id), C.uint64_t(timestamp.UnixMilli()), publicKey.ptr, privateKey.ptr, BytesToBuffer(signature)) + var spkr C.SignalMutPointerSignedPreKeyRecord + signalFfiError := C.signal_signed_pre_key_record_new( + &spkr, + C.uint32_t(id), + C.uint64_t(timestamp.UnixMilli()), + publicKey.constPtr(), + privateKey.constPtr(), + BytesToBuffer(signature), + ) runtime.KeepAlive(publicKey) runtime.KeepAlive(privateKey) runtime.KeepAlive(signature) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSignedPreKeyRecord(spkr), nil + return wrapSignedPreKeyRecord(spkr.raw), nil } func NewSignedPreKeyRecordFromPrivateKey(id uint32, timestamp time.Time, privateKey *PrivateKey, signature []byte) (*SignedPreKeyRecord, error) { @@ -58,28 +66,36 @@ func NewSignedPreKeyRecordFromPrivateKey(id uint32, timestamp time.Time, private } func DeserializeSignedPreKeyRecord(serialized []byte) (*SignedPreKeyRecord, error) { - var spkr *C.SignalSignedPreKeyRecord + var spkr C.SignalMutPointerSignedPreKeyRecord signalFfiError := C.signal_signed_pre_key_record_deserialize(&spkr, BytesToBuffer(serialized)) runtime.KeepAlive(serialized) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSignedPreKeyRecord(spkr), nil + return wrapSignedPreKeyRecord(spkr.raw), nil +} + +func (spkr *SignedPreKeyRecord) mutPtr() C.SignalMutPointerSignedPreKeyRecord { + return C.SignalMutPointerSignedPreKeyRecord{spkr.ptr} +} + +func (spkr *SignedPreKeyRecord) constPtr() C.SignalConstPointerSignedPreKeyRecord { + return C.SignalConstPointerSignedPreKeyRecord{spkr.ptr} } func (spkr *SignedPreKeyRecord) Clone() (*SignedPreKeyRecord, error) { - var cloned *C.SignalSignedPreKeyRecord - signalFfiError := C.signal_signed_pre_key_record_clone(&cloned, spkr.ptr) + var cloned C.SignalMutPointerSignedPreKeyRecord + signalFfiError := C.signal_signed_pre_key_record_clone(&cloned, spkr.constPtr()) runtime.KeepAlive(spkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapSignedPreKeyRecord(cloned), nil + return wrapSignedPreKeyRecord(cloned.raw), nil } func (spkr *SignedPreKeyRecord) Destroy() error { spkr.CancelFinalizer() - return wrapError(C.signal_signed_pre_key_record_destroy(spkr.ptr)) + return wrapError(C.signal_signed_pre_key_record_destroy(spkr.mutPtr())) } func (spkr *SignedPreKeyRecord) CancelFinalizer() { @@ -88,7 +104,7 @@ func (spkr *SignedPreKeyRecord) CancelFinalizer() { func (spkr *SignedPreKeyRecord) Serialize() ([]byte, error) { var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_signed_pre_key_record_serialize(&serialized, spkr.ptr) + signalFfiError := C.signal_signed_pre_key_record_serialize(&serialized, spkr.constPtr()) runtime.KeepAlive(spkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -98,7 +114,7 @@ func (spkr *SignedPreKeyRecord) Serialize() ([]byte, error) { func (spkr *SignedPreKeyRecord) GetSignature() ([]byte, error) { var signature C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - signalFfiError := C.signal_signed_pre_key_record_get_signature(&signature, spkr.ptr) + signalFfiError := C.signal_signed_pre_key_record_get_signature(&signature, spkr.constPtr()) runtime.KeepAlive(spkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) @@ -108,7 +124,7 @@ func (spkr *SignedPreKeyRecord) GetSignature() ([]byte, error) { func (spkr *SignedPreKeyRecord) GetID() (uint32, error) { var id C.uint32_t - signalFfiError := C.signal_signed_pre_key_record_get_id(&id, spkr.ptr) + signalFfiError := C.signal_signed_pre_key_record_get_id(&id, spkr.constPtr()) runtime.KeepAlive(spkr) if signalFfiError != nil { return 0, wrapError(signalFfiError) @@ -118,7 +134,7 @@ func (spkr *SignedPreKeyRecord) GetID() (uint32, error) { func (spkr *SignedPreKeyRecord) GetTimestamp() (time.Time, error) { var ts C.uint64_t - signalFfiError := C.signal_signed_pre_key_record_get_timestamp(&ts, spkr.ptr) + signalFfiError := C.signal_signed_pre_key_record_get_timestamp(&ts, spkr.constPtr()) runtime.KeepAlive(spkr) if signalFfiError != nil { return time.Time{}, wrapError(signalFfiError) @@ -127,21 +143,24 @@ func (spkr *SignedPreKeyRecord) GetTimestamp() (time.Time, error) { } func (spkr *SignedPreKeyRecord) GetPublicKey() (*PublicKey, error) { - var pub *C.SignalPublicKey - signalFfiError := C.signal_signed_pre_key_record_get_public_key(&pub, spkr.ptr) + var pub C.SignalMutPointerPublicKey + signalFfiError := C.signal_signed_pre_key_record_get_public_key( + &pub, + spkr.constPtr(), + ) runtime.KeepAlive(spkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPublicKey(pub), nil + return wrapPublicKey(pub.raw), nil } func (spkr *SignedPreKeyRecord) GetPrivateKey() (*PrivateKey, error) { - var priv *C.SignalPrivateKey - signalFfiError := C.signal_signed_pre_key_record_get_private_key(&priv, spkr.ptr) + var priv C.SignalMutPointerPrivateKey + signalFfiError := C.signal_signed_pre_key_record_get_private_key(&priv, spkr.constPtr()) runtime.KeepAlive(spkr) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return wrapPrivateKey(priv), nil + return wrapPrivateKey(priv.raw), nil } diff --git a/pkg/libsignalgo/signedprekeystore.go b/pkg/libsignalgo/signedprekeystore.go index cf3ecca..8ee8ef5 100644 --- a/pkg/libsignalgo/signedprekeystore.go +++ b/pkg/libsignalgo/signedprekeystore.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Sumner Evans +// Copyright (C) 2025 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 @@ -60,10 +61,10 @@ func signal_store_signed_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t }) } -func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) *C.SignalSignedPreKeyStore { - return &C.SignalSignedPreKeyStore{ +func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) C.SignalConstPointerFfiSignedPreKeyStoreStruct { + return C.SignalConstPointerFfiSignedPreKeyStoreStruct{&C.SignalSignedPreKeyStore{ ctx: wrapStore(ctx, store), load_signed_pre_key: C.SignalLoadSignedPreKey(C.signal_load_signed_pre_key_callback), store_signed_pre_key: C.SignalStoreSignedPreKey(C.signal_store_signed_pre_key_callback), - } + }} } diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 5bcef1b..528ebe6 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.64.1" +const Version = "v0.65.2" From 22a18a74184ca04cb4aa1a083ffcfc578f75be78 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 17 Jan 2025 20:05:42 +0200 Subject: [PATCH 393/718] libsignalgo: remove duplicate cflags --- pkg/libsignalgo/accountentropy.go | 1 - pkg/libsignalgo/address.go | 1 - pkg/libsignalgo/aes256gcmsiv.go | 1 - pkg/libsignalgo/authcredential.go | 1 - pkg/libsignalgo/buffer.go | 1 - pkg/libsignalgo/cflags.go | 6 ++++++ pkg/libsignalgo/ciphertextmessage.go | 1 - pkg/libsignalgo/conversions.go | 1 - pkg/libsignalgo/decryptionerrormessage.go | 1 - pkg/libsignalgo/devicetransfer.go | 1 - pkg/libsignalgo/error.go | 1 - pkg/libsignalgo/fingerprint.go | 1 - pkg/libsignalgo/groupcipher.go | 1 - pkg/libsignalgo/groupsecretparams.go | 1 - pkg/libsignalgo/hsmenclave.go | 1 - pkg/libsignalgo/identitykey.go | 1 - pkg/libsignalgo/identitykeystore.go | 1 - pkg/libsignalgo/kdf.go | 1 - pkg/libsignalgo/kyberprekey.go | 1 - pkg/libsignalgo/kyberprekeystore.go | 1 - pkg/libsignalgo/logging.go | 1 - pkg/libsignalgo/message.go | 1 - pkg/libsignalgo/plaintextcontent.go | 1 - pkg/libsignalgo/prekey.go | 1 - pkg/libsignalgo/prekeybundle.go | 1 - pkg/libsignalgo/prekeymessage.go | 1 - pkg/libsignalgo/prekeystore.go | 1 - pkg/libsignalgo/privatekey.go | 1 - pkg/libsignalgo/profilekey.go | 1 - pkg/libsignalgo/publickey.go | 1 - pkg/libsignalgo/sealedsender.go | 1 - pkg/libsignalgo/sendercertificate.go | 1 - pkg/libsignalgo/senderkeydistributionmessage.go | 1 - pkg/libsignalgo/senderkeyrecord.go | 1 - pkg/libsignalgo/senderkeystore.go | 1 - pkg/libsignalgo/servercertificate.go | 1 - pkg/libsignalgo/serverpublicparams.go | 1 - pkg/libsignalgo/serviceid.go | 1 - pkg/libsignalgo/serviceid_clang.go | 1 - pkg/libsignalgo/serviceid_gcc.go | 1 - pkg/libsignalgo/sessionrecord.go | 1 - pkg/libsignalgo/sessionstore.go | 1 - pkg/libsignalgo/sgxclient.go | 1 - pkg/libsignalgo/signedprekey.go | 1 - pkg/libsignalgo/signedprekeystore.go | 1 - pkg/libsignalgo/storeutil.go | 1 - 46 files changed, 6 insertions(+), 45 deletions(-) create mode 100644 pkg/libsignalgo/cflags.go diff --git a/pkg/libsignalgo/accountentropy.go b/pkg/libsignalgo/accountentropy.go index 3160d64..d1ffe35 100644 --- a/pkg/libsignalgo/accountentropy.go +++ b/pkg/libsignalgo/accountentropy.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/address.go b/pkg/libsignalgo/address.go index 95e4249..cfc6e58 100644 --- a/pkg/libsignalgo/address.go +++ b/pkg/libsignalgo/address.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/aes256gcmsiv.go b/pkg/libsignalgo/aes256gcmsiv.go index b4d0924..0fddea2 100644 --- a/pkg/libsignalgo/aes256gcmsiv.go +++ b/pkg/libsignalgo/aes256gcmsiv.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/authcredential.go b/pkg/libsignalgo/authcredential.go index 65b9a67..ab759b2 100644 --- a/pkg/libsignalgo/authcredential.go +++ b/pkg/libsignalgo/authcredential.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" #include */ diff --git a/pkg/libsignalgo/buffer.go b/pkg/libsignalgo/buffer.go index 2758590..e6aafdd 100644 --- a/pkg/libsignalgo/buffer.go +++ b/pkg/libsignalgo/buffer.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/cflags.go b/pkg/libsignalgo/cflags.go new file mode 100644 index 0000000..b86e973 --- /dev/null +++ b/pkg/libsignalgo/cflags.go @@ -0,0 +1,6 @@ +package libsignalgo + +/* +#cgo LDFLAGS: -lsignal_ffi -ldl -lm +*/ +import "C" diff --git a/pkg/libsignalgo/ciphertextmessage.go b/pkg/libsignalgo/ciphertextmessage.go index e1c1bdb..f74fcd5 100644 --- a/pkg/libsignalgo/ciphertextmessage.go +++ b/pkg/libsignalgo/ciphertextmessage.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/conversions.go b/pkg/libsignalgo/conversions.go index a2da098..d17fa28 100644 --- a/pkg/libsignalgo/conversions.go +++ b/pkg/libsignalgo/conversions.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/decryptionerrormessage.go b/pkg/libsignalgo/decryptionerrormessage.go index 5e4e3b9..105fffc 100644 --- a/pkg/libsignalgo/decryptionerrormessage.go +++ b/pkg/libsignalgo/decryptionerrormessage.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/devicetransfer.go b/pkg/libsignalgo/devicetransfer.go index fb50971..f994e51 100644 --- a/pkg/libsignalgo/devicetransfer.go +++ b/pkg/libsignalgo/devicetransfer.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/error.go b/pkg/libsignalgo/error.go index 9e2a872..8b83a48 100644 --- a/pkg/libsignalgo/error.go +++ b/pkg/libsignalgo/error.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/fingerprint.go b/pkg/libsignalgo/fingerprint.go index 4bbf24c..b2ef8ce 100644 --- a/pkg/libsignalgo/fingerprint.go +++ b/pkg/libsignalgo/fingerprint.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/groupcipher.go b/pkg/libsignalgo/groupcipher.go index 33e18aa..7b58207 100644 --- a/pkg/libsignalgo/groupcipher.go +++ b/pkg/libsignalgo/groupcipher.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 943dfda..8ad9b39 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/hsmenclave.go b/pkg/libsignalgo/hsmenclave.go index 15a44fa..2eb61cd 100644 --- a/pkg/libsignalgo/hsmenclave.go +++ b/pkg/libsignalgo/hsmenclave.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/identitykey.go b/pkg/libsignalgo/identitykey.go index 9cd8425..7877d22 100644 --- a/pkg/libsignalgo/identitykey.go +++ b/pkg/libsignalgo/identitykey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index 88e5eaa..c59b660 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" typedef const SignalProtocolAddress const_address; diff --git a/pkg/libsignalgo/kdf.go b/pkg/libsignalgo/kdf.go index d64e819..2f6a497 100644 --- a/pkg/libsignalgo/kdf.go +++ b/pkg/libsignalgo/kdf.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/kyberprekey.go b/pkg/libsignalgo/kyberprekey.go index 7f9c7b4..707db76 100644 --- a/pkg/libsignalgo/kyberprekey.go +++ b/pkg/libsignalgo/kyberprekey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/kyberprekeystore.go b/pkg/libsignalgo/kyberprekeystore.go index 39beed7..072db99 100644 --- a/pkg/libsignalgo/kyberprekeystore.go +++ b/pkg/libsignalgo/kyberprekeystore.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" typedef const SignalKyberPreKeyRecord const_kyber_pre_key_record; diff --git a/pkg/libsignalgo/logging.go b/pkg/libsignalgo/logging.go index e0a2351..9d21afa 100644 --- a/pkg/libsignalgo/logging.go +++ b/pkg/libsignalgo/logging.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include <./libsignal-ffi.h> extern void signal_log_callback(void *ctx, SignalLogLevel level, char *file, uint32_t line, char *message); diff --git a/pkg/libsignalgo/message.go b/pkg/libsignalgo/message.go index d512d6f..f016daa 100644 --- a/pkg/libsignalgo/message.go +++ b/pkg/libsignalgo/message.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/plaintextcontent.go b/pkg/libsignalgo/plaintextcontent.go index f395f0b..346f0c9 100644 --- a/pkg/libsignalgo/plaintextcontent.go +++ b/pkg/libsignalgo/plaintextcontent.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/prekey.go b/pkg/libsignalgo/prekey.go index 0c56c71..4d01f89 100644 --- a/pkg/libsignalgo/prekey.go +++ b/pkg/libsignalgo/prekey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/prekeybundle.go b/pkg/libsignalgo/prekeybundle.go index 7fd2e34..4cd5547 100644 --- a/pkg/libsignalgo/prekeybundle.go +++ b/pkg/libsignalgo/prekeybundle.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/prekeymessage.go b/pkg/libsignalgo/prekeymessage.go index 6bff0bb..7261933 100644 --- a/pkg/libsignalgo/prekeymessage.go +++ b/pkg/libsignalgo/prekeymessage.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/prekeystore.go b/pkg/libsignalgo/prekeystore.go index c9b0469..643e286 100644 --- a/pkg/libsignalgo/prekeystore.go +++ b/pkg/libsignalgo/prekeystore.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" typedef const SignalPreKeyRecord const_pre_key_record; diff --git a/pkg/libsignalgo/privatekey.go b/pkg/libsignalgo/privatekey.go index 3703727..829d3f0 100644 --- a/pkg/libsignalgo/privatekey.go +++ b/pkg/libsignalgo/privatekey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index c78c9d1..8d2ae04 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" #include */ diff --git a/pkg/libsignalgo/publickey.go b/pkg/libsignalgo/publickey.go index 8c4c98f..dcf9647 100644 --- a/pkg/libsignalgo/publickey.go +++ b/pkg/libsignalgo/publickey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 4912977..1e93410 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/sendercertificate.go b/pkg/libsignalgo/sendercertificate.go index 46caf1c..1d7422f 100644 --- a/pkg/libsignalgo/sendercertificate.go +++ b/pkg/libsignalgo/sendercertificate.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/senderkeydistributionmessage.go b/pkg/libsignalgo/senderkeydistributionmessage.go index e772c58..d07c558 100644 --- a/pkg/libsignalgo/senderkeydistributionmessage.go +++ b/pkg/libsignalgo/senderkeydistributionmessage.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/senderkeyrecord.go b/pkg/libsignalgo/senderkeyrecord.go index 7299ae5..b40c46f 100644 --- a/pkg/libsignalgo/senderkeyrecord.go +++ b/pkg/libsignalgo/senderkeyrecord.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/senderkeystore.go b/pkg/libsignalgo/senderkeystore.go index d3bda2f..30df4ad 100644 --- a/pkg/libsignalgo/senderkeystore.go +++ b/pkg/libsignalgo/senderkeystore.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" typedef const SignalProtocolAddress const_address; diff --git a/pkg/libsignalgo/servercertificate.go b/pkg/libsignalgo/servercertificate.go index da56b0b..bf46009 100644 --- a/pkg/libsignalgo/servercertificate.go +++ b/pkg/libsignalgo/servercertificate.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/serverpublicparams.go b/pkg/libsignalgo/serverpublicparams.go index fc046c1..c1de0cd 100644 --- a/pkg/libsignalgo/serverpublicparams.go +++ b/pkg/libsignalgo/serverpublicparams.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" #include */ diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index 5308af1..19513de 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" #include */ diff --git a/pkg/libsignalgo/serviceid_clang.go b/pkg/libsignalgo/serviceid_clang.go index 3e9ae17..72c9ed3 100644 --- a/pkg/libsignalgo/serviceid_clang.go +++ b/pkg/libsignalgo/serviceid_clang.go @@ -3,7 +3,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" #include */ diff --git a/pkg/libsignalgo/serviceid_gcc.go b/pkg/libsignalgo/serviceid_gcc.go index 9ff97bc..b8dbbee 100644 --- a/pkg/libsignalgo/serviceid_gcc.go +++ b/pkg/libsignalgo/serviceid_gcc.go @@ -3,7 +3,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" #include */ diff --git a/pkg/libsignalgo/sessionrecord.go b/pkg/libsignalgo/sessionrecord.go index 3523f62..a2ee9dd 100644 --- a/pkg/libsignalgo/sessionrecord.go +++ b/pkg/libsignalgo/sessionrecord.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/sessionstore.go b/pkg/libsignalgo/sessionstore.go index ad88d62..da430c1 100644 --- a/pkg/libsignalgo/sessionstore.go +++ b/pkg/libsignalgo/sessionstore.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" typedef const SignalSessionRecord const_session_record; diff --git a/pkg/libsignalgo/sgxclient.go b/pkg/libsignalgo/sgxclient.go index a2ba553..e2d817e 100644 --- a/pkg/libsignalgo/sgxclient.go +++ b/pkg/libsignalgo/sgxclient.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/signedprekey.go b/pkg/libsignalgo/signedprekey.go index ca86ce3..32afc37 100644 --- a/pkg/libsignalgo/signedprekey.go +++ b/pkg/libsignalgo/signedprekey.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" diff --git a/pkg/libsignalgo/signedprekeystore.go b/pkg/libsignalgo/signedprekeystore.go index 8ee8ef5..b595578 100644 --- a/pkg/libsignalgo/signedprekeystore.go +++ b/pkg/libsignalgo/signedprekeystore.go @@ -18,7 +18,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" typedef const SignalSignedPreKeyRecord const_signed_pre_key_record; diff --git a/pkg/libsignalgo/storeutil.go b/pkg/libsignalgo/storeutil.go index cc99ddf..4041c9b 100644 --- a/pkg/libsignalgo/storeutil.go +++ b/pkg/libsignalgo/storeutil.go @@ -17,7 +17,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm #include "./libsignal-ffi.h" */ import "C" From 853171f4fcda854236afa89103f4375cccf7c29a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 18 Jan 2025 01:01:05 +0200 Subject: [PATCH 394/718] signalmeow/storageservice: fix ssre2 implementation --- pkg/signalmeow/storageservice.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 1902c4b..ae003ae 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -182,13 +182,13 @@ func deriveStorageManifestKey(storageKey []byte, version uint64) []byte { const storageServiceItemKeyInfoPrefix = "20240801_SIGNAL_STORAGE_SERVICE_ITEM_" const storageServiceItemKeyLen = 32 -func deriveStorageItemKey(storageKey, recordIKM []byte, itemID string) []byte { +func deriveStorageItemKey(storageKey, recordIKM, rawItemID []byte, b64ItemID string) []byte { if recordIKM == nil { h := hmac.New(sha256.New, storageKey) - exerrors.Must(fmt.Fprintf(h, "Item_%s", itemID)) + exerrors.Must(fmt.Fprintf(h, "Item_%s", b64ItemID)) return h.Sum(nil) } else { - h := hkdf.New(sha256.New, recordIKM, []byte{}, append([]byte(storageServiceItemKeyInfoPrefix), itemID...)) + h := hkdf.New(sha256.New, recordIKM, []byte{}, append([]byte(storageServiceItemKeyInfoPrefix), rawItemID...)) out := make([]byte, storageServiceItemKeyLen) exerrors.Must(io.ReadFull(h, out)) return out @@ -278,7 +278,7 @@ func (cli *Client) fetchStorageRecords( log.Warn().Int("item_index", i).Str("item_key", base64Key).Msg("Received unexpected storage item") continue } - itemKey := deriveStorageItemKey(storageKey, recordIKM, base64Key) + itemKey := deriveStorageItemKey(storageKey, recordIKM, encryptedItem.GetKey(), base64Key) decryptedItemBytes, err := decryptBytes(itemKey, encryptedItem.GetValue()) if err != nil { log.Warn().Err(err). From 0a0e0d50d36722f2fbe34dbf808a633a7ecdce87 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 18 Jan 2025 02:58:43 +0200 Subject: [PATCH 395/718] signalmeow: add support for receiving history transfers --- pkg/connector/login.go | 2 +- pkg/libsignalgo/backupkey.go | 140 + pkg/libsignalgo/messagebackupkey.go | 103 + pkg/signalmeow/attachments.go | 20 +- pkg/signalmeow/attachments_stream.go | 178 + pkg/signalmeow/backup.go | 275 + pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 11548 ++++++++++++++++ .../protobuf/backuppb/Backup.pb.raw | Bin 0 -> 31334 bytes pkg/signalmeow/protobuf/backuppb/Backup.proto | 1260 ++ pkg/signalmeow/protobuf/build-protos.sh | 5 + pkg/signalmeow/protobuf/update-protos.sh | 18 +- pkg/signalmeow/provisioning.go | 26 +- pkg/signalmeow/store/container.go | 26 +- pkg/signalmeow/store/device.go | 3 + pkg/signalmeow/store/upgrades/00-latest.sql | 9 +- .../store/upgrades/18-store-backup-keys.sql | 4 + 16 files changed, 13585 insertions(+), 32 deletions(-) create mode 100644 pkg/libsignalgo/backupkey.go create mode 100644 pkg/libsignalgo/messagebackupkey.go create mode 100644 pkg/signalmeow/attachments_stream.go create mode 100644 pkg/signalmeow/backup.go create mode 100644 pkg/signalmeow/protobuf/backuppb/Backup.pb.go create mode 100644 pkg/signalmeow/protobuf/backuppb/Backup.pb.raw create mode 100644 pkg/signalmeow/protobuf/backuppb/Backup.proto create mode 100644 pkg/signalmeow/store/upgrades/18-store-backup-keys.sql diff --git a/pkg/connector/login.go b/pkg/connector/login.go index da1b66a..e2f2e98 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -79,7 +79,7 @@ func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { provCtx, cancel := context.WithCancel(log.WithContext(context.Background())) qr.cancelChan = cancel // Don't use the start context here: the channel will outlive the start request. - qr.ProvChan = signalmeow.PerformProvisioning(provCtx, qr.Main.Store, qr.Main.Config.DeviceName) + qr.ProvChan = signalmeow.PerformProvisioning(provCtx, qr.Main.Store, qr.Main.Config.DeviceName, false) var resp signalmeow.ProvisioningResponse select { case resp = <-qr.ProvChan: diff --git a/pkg/libsignalgo/backupkey.go b/pkg/libsignalgo/backupkey.go new file mode 100644 index 0000000..fd8a800 --- /dev/null +++ b/pkg/libsignalgo/backupkey.go @@ -0,0 +1,140 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#include "./libsignal-ffi.h" +*/ +import "C" +import ( + "runtime" + "unsafe" + + "go.mau.fi/util/random" +) + +type BackupKey [C.SignalBACKUP_KEY_LEN]byte + +func (bk *BackupKey) Slice() []byte { + if bk == nil { + return nil + } + return bk[:] +} + +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 + +func GenerateRandomBackupKey() *BackupKey { + return (*BackupKey)(random.Bytes(C.SignalBACKUP_KEY_LEN)) +} + +func BytesToBackupKey(bytes []byte) *BackupKey { + if len(bytes) != C.SignalBACKUP_KEY_LEN { + return nil + } + return (*BackupKey)(bytes) +} + +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(), + ) + runtime.KeepAlive(bk) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return &out, nil +} + +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(), + ) + runtime.KeepAlive(bk) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return wrapPrivateKey(out.raw), nil +} + +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)), + ) + runtime.KeepAlive(bk) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return &out, nil +} + +func (bk *BackupKey) DeriveMediaID(mediaName string) (*BackupMediaID, error) { + var out BackupMediaID + 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)), + C.CString(mediaName), + ) + runtime.KeepAlive(bk) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return &out, nil +} + +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)), + ) + runtime.KeepAlive(bk) + runtime.KeepAlive(mediaID) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return &out, nil +} + +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)), + ) + runtime.KeepAlive(bk) + runtime.KeepAlive(mediaID) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return &out, nil +} diff --git a/pkg/libsignalgo/messagebackupkey.go b/pkg/libsignalgo/messagebackupkey.go new file mode 100644 index 0000000..87f2b4f --- /dev/null +++ b/pkg/libsignalgo/messagebackupkey.go @@ -0,0 +1,103 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#include "./libsignal-ffi.h" +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type MessageBackupKey struct { + nc noCopy + ptr *C.SignalMessageBackupKey +} + +func wrapMessageBackupKey(ptr *C.SignalMessageBackupKey) *MessageBackupKey { + backupKey := &MessageBackupKey{ptr: ptr} + runtime.SetFinalizer(backupKey, (*MessageBackupKey).Destroy) + return backupKey +} + +func MessageBackupKeyFromAccountEntropyPool(aep AccountEntropyPool, aci ServiceID) (*MessageBackupKey, error) { + var bk C.SignalMutPointerMessageBackupKey + signalFfiError := C.signal_message_backup_key_from_account_entropy_pool( + &bk, + C.CString(string(aep)), + aci.CFixedBytes(), + ) + runtime.KeepAlive(aep) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return wrapMessageBackupKey(bk.raw), nil +} + +func MessageBackupKeyFromBackupKeyAndID(backupKey *BackupKey, backupID *BackupID) (*MessageBackupKey, error) { + 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)), + ) + runtime.KeepAlive(backupKey) + runtime.KeepAlive(backupID) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return wrapMessageBackupKey(bk.raw), nil +} + +func (bk *MessageBackupKey) mutPtr() C.SignalMutPointerMessageBackupKey { + return C.SignalMutPointerMessageBackupKey{bk.ptr} +} + +func (bk *MessageBackupKey) constPtr() C.SignalConstPointerMessageBackupKey { + return C.SignalConstPointerMessageBackupKey{bk.ptr} +} + +func (bk *MessageBackupKey) Destroy() error { + runtime.SetFinalizer(bk, nil) + return wrapError(C.signal_message_backup_key_destroy(bk.mutPtr())) +} + +func (bk *MessageBackupKey) GetHMACKey() ([32]byte, error) { + var out [32]byte + signalFfiError := C.signal_message_backup_key_get_hmac_key( + (*[32]C.uint8_t)(unsafe.Pointer(&out)), + bk.constPtr(), + ) + if signalFfiError != nil { + return out, wrapError(signalFfiError) + } + return out, nil +} + +func (bk *MessageBackupKey) GetAESKey() ([32]byte, error) { + var out [32]byte + signalFfiError := C.signal_message_backup_key_get_aes_key( + (*[32]C.uint8_t)(unsafe.Pointer(&out)), + bk.constPtr(), + ) + if signalFfiError != nil { + return out, wrapError(signalFfiError) + } + return out, nil +} diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index ca56634..4d5d6d6 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -47,11 +47,11 @@ const ( attachmentIDDownloadPath = "/attachments/%d" ) -func getAttachmentPath(id uint64, key string, cdnNumber uint32) (string, error) { +func getAttachmentPath(id uint64, key string) string { if id != 0 { - return fmt.Sprintf(attachmentIDDownloadPath, id), nil + return fmt.Sprintf(attachmentIDDownloadPath, id) } - return fmt.Sprintf(attachmentKeyDownloadPath, key), nil + return fmt.Sprintf(attachmentKeyDownloadPath, key) } // ErrInvalidMACForAttachment signals that the downloaded attachment has an invalid MAC. @@ -59,10 +59,7 @@ var ErrInvalidMACForAttachment = errors.New("invalid MAC for attachment") var ErrInvalidDigestForAttachment = errors.New("invalid digest for attachment") func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]byte, error) { - path, err := getAttachmentPath(a.GetCdnId(), a.GetCdnKey(), a.GetCdnNumber()) - if err != nil { - return nil, err - } + path := getAttachmentPath(a.GetCdnId(), a.GetCdnKey()) resp, err := web.GetAttachment(ctx, path, a.GetCdnNumber(), nil) if err != nil { return nil, err @@ -86,17 +83,20 @@ func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]b return decryptAttachment(body, a.Key, a.Digest, *a.Size) } +const MACLength = 32 +const IVLength = 16 + func decryptAttachment(body, key, digest []byte, size uint32) ([]byte, error) { hash := sha256.Sum256(body) if !hmac.Equal(hash[:], digest) { return nil, ErrInvalidDigestForAttachment } - l := len(body) - 32 - if !verifyMAC(key[32:], body[:l], body[l:]) { + l := len(body) - MACLength + if !verifyMAC(key[MACLength:], body[:l], body[l:]) { return nil, ErrInvalidMACForAttachment } - decrypted, err := aesDecrypt(key[:32], body[:l]) + decrypted, err := aesDecrypt(key[:MACLength], body[:l]) if err != nil { return nil, err } diff --git a/pkg/signalmeow/attachments_stream.go b/pkg/signalmeow/attachments_stream.go new file mode 100644 index 0000000..a410df0 --- /dev/null +++ b/pkg/signalmeow/attachments_stream.go @@ -0,0 +1,178 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "bufio" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "encoding/binary" + "errors" + "fmt" + "hash" + "io" + "os" + + "google.golang.org/protobuf/proto" +) + +func verifyMACStream(hmacKey [32]byte, input io.Reader, totalSize int64) (bool, error) { + if totalSize <= 0 { + file, ok := input.(*os.File) + if ok { + stat, err := file.Stat() + if err != nil { + return false, fmt.Errorf("failed to stat file: %w", err) + } + totalSize = stat.Size() + } else { + return false, fmt.Errorf("total size is unknown") + } + } + hasher := hmac.New(sha256.New, hmacKey[:]) + _, err := io.CopyN(hasher, input, totalSize-MACLength) + if err != nil { + return false, fmt.Errorf("failed to hash file: %w", err) + } + actualHash := hasher.Sum(nil) + expectedHash := make([]byte, MACLength) + _, err = io.ReadFull(input, expectedHash) + if err != nil { + return false, fmt.Errorf("failed to read hash: %w", err) + } + return hmac.Equal(expectedHash, actualHash), nil +} + +type decryptingReader struct { + input io.Reader + cipher cipher.BlockMode + hasher hash.Hash + aesKey *[32]byte + remainingSize int64 +} + +func (dr *decryptingReader) Read(p []byte) (int, error) { + if dr.remainingSize == 0 { + return 0, io.EOF + } else if len(p) < aes.BlockSize { + return 0, fmt.Errorf("buffer too small (must be at least %d bytes)", aes.BlockSize) + } + if dr.cipher == nil { + iv := make([]byte, IVLength) + _, err := io.ReadFull(dr.input, iv) + if err != nil { + return 0, fmt.Errorf("failed to read IV: %w", err) + } + block, err := aes.NewCipher(dr.aesKey[:]) + if err != nil { + return 0, fmt.Errorf("failed to create cipher: %w", err) + } + dr.cipher = cipher.NewCBCDecrypter(block, iv) + dr.hasher.Write(iv) + } + maxLen := int64(len(p) - len(p)%aes.BlockSize) + if maxLen > dr.remainingSize { + maxLen = dr.remainingSize + } + p = p[:maxLen] + _, err := io.ReadFull(dr.input, p) + if err != nil { + return 0, err + } + dr.remainingSize -= maxLen + dr.hasher.Write(p) + dr.cipher.CryptBlocks(p, p) + if dr.remainingSize == 0 { + p, err = UnpadPKCS7(p) + if err != nil { + return 0, fmt.Errorf("failed to unpad: %w", err) + } + expectedMAC := make([]byte, MACLength) + _, err = io.ReadFull(dr.input, expectedMAC) + if err != nil { + return 0, fmt.Errorf("failed to read MAC: %w", err) + } + actualMAC := dr.hasher.Sum(nil) + if !hmac.Equal(expectedMAC, actualMAC) { + return 0, fmt.Errorf("hmac mismatch") + } + } + return len(p), nil +} + +func (dr *decryptingReader) Close() error { + if dr.remainingSize != 0 { + return fmt.Errorf("unexpected remaining size %d", dr.remainingSize) + } + return nil +} + +func aesDecryptStream(aesKey, macKey [32]byte, input io.Reader, totalSize int64) io.ReadCloser { + return &decryptingReader{ + aesKey: &aesKey, + hasher: hmac.New(sha256.New, macKey[:]), + input: input, + remainingSize: totalSize - MACLength - IVLength, + } +} + +func splitChunksStream(input io.Reader, callback func([]byte) error) error { + byteReader, ok := input.(io.ByteReader) + if !ok { + bufInput := bufio.NewReader(input) + byteReader = bufInput + input = bufInput + } + var cachedBuf []byte + for { + msgLen, err := binary.ReadUvarint(byteReader) + if errors.Is(err, io.EOF) { + return nil + } else if err != nil { + return fmt.Errorf("failed to read chunk length: %w", err) + } + if msgLen == 0 { + continue + } + if msgLen > uint64(len(cachedBuf)) { + cachedBuf = make([]byte, min(msgLen, 8192)) + } + buf := cachedBuf[:msgLen] + _, err = io.ReadFull(input, buf) + if err != nil { + return fmt.Errorf("failed to read chunk: %w", err) + } + err = callback(buf) + if err != nil { + return err + } + } +} + +func splitProtoChunksStream[ChunkType proto.Message](input io.Reader, callback func(ChunkType) error) error { + protoReflect := (*new(ChunkType)).ProtoReflect() + return splitChunksStream(input, func(buf []byte) error { + msg := protoReflect.New().Interface().(ChunkType) + err := proto.Unmarshal(buf, msg) + if err != nil { + return fmt.Errorf("failed to unmarshal chunk: %w", err) + } + return callback(msg) + }) +} diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go new file mode 100644 index 0000000..536302d --- /dev/null +++ b/pkg/signalmeow/backup.go @@ -0,0 +1,275 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "bufio" + "compress/gzip" + "context" + "crypto/hmac" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" + "strconv" + "time" + + "github.com/rs/zerolog" + "google.golang.org/protobuf/proto" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +const transferArchiveFetchTimeout = 1 * time.Hour + +var ( + ErrTransferRelinkRequested = errors.New("relink requested") + ErrTransferContinueWithoutUpload = errors.New("continue without upload") + + ErrNoEphemeralBackupKey = errors.New("no ephemeral backup key") +) + +type TransferArchiveMetadata struct { + CDN uint32 `json:"cdn"` + Key string `json:"key"` + Error string `json:"error"` // RELINK_REQUESTED or CONTINUE_WITHOUT_UPLOAD +} + +func (cli *Client) FetchAndProcessTransfer(ctx context.Context, meta *TransferArchiveMetadata) error { + if meta.Error != "" { + switch meta.Error { + case "RELINK_REQUESTED": + return ErrTransferRelinkRequested + case "CONTINUE_WITHOUT_UPLOAD": + return ErrTransferContinueWithoutUpload + default: + return fmt.Errorf("transfer archive error: %s", meta.Error) + } + } + aesKey, hmacKey, err := cli.deriveTransferKeys() + if err != nil { + return fmt.Errorf("failed to derive transfer keys: %w", err) + } + file, err := os.CreateTemp("", "signalmeow-transfer-archive-*") + if err != nil { + return fmt.Errorf("failed to create temporary file: %w", err) + } + defer func() { + _ = file.Close() + _ = os.Remove(file.Name()) + }() + err = downloadTransferArchive(ctx, meta, file) + if err != nil { + return err + } + _, err = file.Seek(0, io.SeekStart) + if err != nil { + return fmt.Errorf("failed to seek to start of file: %w", err) + } + stat, err := file.Stat() + if err != nil { + return fmt.Errorf("failed to stat file: %w", err) + } + ok, err := verifyMACStream(hmacKey, file, stat.Size()) + if err != nil { + return fmt.Errorf("failed to verify MAC: %w", err) + } else if !ok { + return fmt.Errorf("checksum mismatch") + } + _, err = file.Seek(0, io.SeekStart) + if err != nil { + return fmt.Errorf("failed to seek to start of file: %w", err) + } + err = cli.processTransferArchive(ctx, aesKey, hmacKey, file, stat.Size()) + if err != nil { + return err + } + cli.Store.EphemeralBackupKey = nil + err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + if err != nil { + return fmt.Errorf("failed to save device data after clearing ephemeral backup key: %w", err) + } + return nil +} + +func (cli *Client) processTransferArchive(ctx context.Context, aesKey, hmacKey [32]byte, file io.Reader, size int64) error { + decrypter := aesDecryptStream(aesKey, hmacKey, file, size) + bufDecrypted := bufio.NewReader(decrypter) + decompressor, err := gzip.NewReader(bufDecrypted) + if err != nil { + return fmt.Errorf("failed to create gzip reader: %w", err) + } + // There's an unknown amount of zero padding after the gzip stream, + // so tell gzip not to try to read another stream after the first one. + decompressor.Multistream(false) + err = splitChunksStream(decompressor, (&archiveChunkProcessor{cli: cli, ctx: ctx}).processChunk) + if err != nil { + return err + } + err = decompressor.Close() + if err != nil { + return fmt.Errorf("failed to close gzip reader: %w", err) + } + zeroBuf := make([]byte, 256) + var n int + // Validate that the zero padding is really all zeroes. This will also finish the hmac checking. + for { + n, err = bufDecrypted.Read(zeroBuf) + if errors.Is(err, io.EOF) && n == 0 { + break + } else if err != nil { + return fmt.Errorf("failed to read zero buffer: %w", err) + } + for i := 0; i < n; i++ { + if zeroBuf[i] != 0 { + return fmt.Errorf("unexpected data after decompression") + } + } + } + err = decrypter.Close() + if err != nil { + return fmt.Errorf("failed to close decryption reader: %w", err) + } + return nil +} + +type archiveChunkProcessor struct { + cli *Client + ctx context.Context + info *backuppb.BackupInfo +} + +const BackupVersion = 1 + +func (acp *archiveChunkProcessor) processChunk(buf []byte) error { + if acp.ctx.Err() != nil { + return acp.ctx.Err() + } + if acp.info == nil { + acp.info = &backuppb.BackupInfo{} + err := proto.Unmarshal(buf, acp.info) + if err != nil { + return fmt.Errorf("failed to unmarshal backup info: %w", err) + } else if acp.info.GetVersion() != BackupVersion { + return fmt.Errorf("unsupported backup version: %d", acp.info.GetVersion()) + } else if !hmac.Equal(acp.info.GetMediaRootBackupKey(), acp.cli.Store.MediaRootBackupKey[:]) { + return fmt.Errorf("media root backup key mismatch") + } + zerolog.Ctx(acp.ctx).Info().Any("backup_info", acp.info).Msg("Received backup info") + return nil + } + var frame backuppb.Frame + err := proto.Unmarshal(buf, &frame) + if err != nil { + return fmt.Errorf("failed to unmarshal frame: %w", err) + } + return acp.processFrame(&frame) +} + +func (acp *archiveChunkProcessor) processFrame(frame *backuppb.Frame) error { + acp.cli.Log.Info().Any("backup_frame", frame).Msg("Received backup frame") + return nil +} + +func (cli *Client) deriveTransferKeys() (aesKey, hmacKey [32]byte, err error) { + var backupID *libsignalgo.BackupID + var mbk *libsignalgo.MessageBackupKey + if cli.Store.EphemeralBackupKey == nil { + err = ErrNoEphemeralBackupKey + } else if backupID, err = cli.Store.EphemeralBackupKey.DeriveBackupID(cli.Store.ACIServiceID()); err != nil { + err = fmt.Errorf("failed to derive backup ID: %w", err) + } else if mbk, err = libsignalgo.MessageBackupKeyFromBackupKeyAndID(cli.Store.EphemeralBackupKey, backupID); err != nil { + err = fmt.Errorf("failed to derive message backup key: %w", err) + } else if aesKey, err = mbk.GetAESKey(); err != nil { + err = fmt.Errorf("failed to get AES key: %w", err) + } else if hmacKey, err = mbk.GetHMACKey(); err != nil { + err = fmt.Errorf("failed to get HMAC key: %w", err) + } + return +} + +func downloadTransferArchive(ctx context.Context, meta *TransferArchiveMetadata, writeTo io.Writer) error { + resp, err := web.GetAttachment(ctx, getAttachmentPath(0, meta.Key), meta.CDN, nil) + if err != nil { + return fmt.Errorf("failed to download transfer archive: %w", err) + } + if writeToFile, ok := writeTo.(*os.File); ok { + fileInfo, err := writeToFile.Stat() + if err != nil { + return fmt.Errorf("failed to stat destination file: %w", err) + } + if size := fileInfo.Size(); size > 0 { + zerolog.Ctx(ctx).Debug().Int64("skip_count", size).Msg("Transfer archive already exists, skipping bytes") + _, err = io.CopyN(io.Discard, resp.Body, size) + if err != nil { + return fmt.Errorf("failed to skip existing bytes: %w", err) + } + } + } + _, err = io.Copy(writeTo, resp.Body) + if err != nil { + return fmt.Errorf("failed to write transfer archive to disk: %w", err) + } + return nil +} + +func (cli *Client) WaitForTransfer(ctx context.Context) (*TransferArchiveMetadata, error) { + if cli.Store.EphemeralBackupKey == nil { + return nil, ErrNoEphemeralBackupKey + } + timeout := time.Now().Add(transferArchiveFetchTimeout) + + for { + remainingTime := time.Until(timeout) + if remainingTime < 0 { + return nil, fmt.Errorf("timed out") + } + resp, err := cli.tryRequestTransferArchive(ctx, min(remainingTime, 5*time.Minute)) + if resp != nil || err != nil { + return resp, err + } + } +} + +func (cli *Client) tryRequestTransferArchive(ctx context.Context, timeout time.Duration) (respBody *TransferArchiveMetadata, err error) { + reqCtx, cancel := context.WithTimeout(ctx, timeout+15*time.Second) + defer cancel() + path := "/v1/devices/transfer_archive?timeout=" + strconv.Itoa(int(timeout.Seconds())) + username, password := cli.Store.BasicAuthCreds() + opts := &web.HTTPReqOpt{Username: &username, Password: &password} + resp, err := web.SendHTTPRequest(reqCtx, http.MethodGet, path, opts) + defer func() { + if resp != nil && resp.Body != nil { + _ = resp.Body.Close() + } + }() + if err != nil { + return nil, err + } else if resp.StatusCode == http.StatusNoContent { + return nil, nil + } else if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) + } else if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } else { + return respBody, nil + } +} diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go new file mode 100644 index 0000000..1df6d19 --- /dev/null +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -0,0 +1,11548 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.1 +// protoc v3.21.12 +// source: backuppb/Backup.proto + +package backuppb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +import _ "embed" + +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 GroupV2AccessLevel int32 + +const ( + GroupV2AccessLevel_UNKNOWN GroupV2AccessLevel = 0 + GroupV2AccessLevel_ANY GroupV2AccessLevel = 1 + GroupV2AccessLevel_MEMBER GroupV2AccessLevel = 2 + GroupV2AccessLevel_ADMINISTRATOR GroupV2AccessLevel = 3 + GroupV2AccessLevel_UNSATISFIABLE GroupV2AccessLevel = 4 +) + +// Enum value maps for GroupV2AccessLevel. +var ( + GroupV2AccessLevel_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ANY", + 2: "MEMBER", + 3: "ADMINISTRATOR", + 4: "UNSATISFIABLE", + } + GroupV2AccessLevel_value = map[string]int32{ + "UNKNOWN": 0, + "ANY": 1, + "MEMBER": 2, + "ADMINISTRATOR": 3, + "UNSATISFIABLE": 4, + } +) + +func (x GroupV2AccessLevel) Enum() *GroupV2AccessLevel { + p := new(GroupV2AccessLevel) + *p = x + return p +} + +func (x GroupV2AccessLevel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GroupV2AccessLevel) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[0].Descriptor() +} + +func (GroupV2AccessLevel) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[0] +} + +func (x GroupV2AccessLevel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GroupV2AccessLevel.Descriptor instead. +func (GroupV2AccessLevel) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{0} +} + +type AccountData_PhoneNumberSharingMode int32 + +const ( + AccountData_UNKNOWN AccountData_PhoneNumberSharingMode = 0 + AccountData_EVERYBODY AccountData_PhoneNumberSharingMode = 1 + AccountData_NOBODY AccountData_PhoneNumberSharingMode = 2 +) + +// Enum value maps for AccountData_PhoneNumberSharingMode. +var ( + AccountData_PhoneNumberSharingMode_name = map[int32]string{ + 0: "UNKNOWN", + 1: "EVERYBODY", + 2: "NOBODY", + } + AccountData_PhoneNumberSharingMode_value = map[string]int32{ + "UNKNOWN": 0, + "EVERYBODY": 1, + "NOBODY": 2, + } +) + +func (x AccountData_PhoneNumberSharingMode) Enum() *AccountData_PhoneNumberSharingMode { + p := new(AccountData_PhoneNumberSharingMode) + *p = x + return p +} + +func (x AccountData_PhoneNumberSharingMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_PhoneNumberSharingMode) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[1].Descriptor() +} + +func (AccountData_PhoneNumberSharingMode) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[1] +} + +func (x AccountData_PhoneNumberSharingMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_PhoneNumberSharingMode.Descriptor instead. +func (AccountData_PhoneNumberSharingMode) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 0} +} + +type AccountData_UsernameLink_Color int32 + +const ( + AccountData_UsernameLink_UNKNOWN AccountData_UsernameLink_Color = 0 + AccountData_UsernameLink_BLUE AccountData_UsernameLink_Color = 1 + AccountData_UsernameLink_WHITE AccountData_UsernameLink_Color = 2 + AccountData_UsernameLink_GREY AccountData_UsernameLink_Color = 3 + AccountData_UsernameLink_OLIVE AccountData_UsernameLink_Color = 4 + AccountData_UsernameLink_GREEN AccountData_UsernameLink_Color = 5 + AccountData_UsernameLink_ORANGE AccountData_UsernameLink_Color = 6 + AccountData_UsernameLink_PINK AccountData_UsernameLink_Color = 7 + AccountData_UsernameLink_PURPLE AccountData_UsernameLink_Color = 8 +) + +// Enum value maps for AccountData_UsernameLink_Color. +var ( + AccountData_UsernameLink_Color_name = map[int32]string{ + 0: "UNKNOWN", + 1: "BLUE", + 2: "WHITE", + 3: "GREY", + 4: "OLIVE", + 5: "GREEN", + 6: "ORANGE", + 7: "PINK", + 8: "PURPLE", + } + AccountData_UsernameLink_Color_value = map[string]int32{ + "UNKNOWN": 0, + "BLUE": 1, + "WHITE": 2, + "GREY": 3, + "OLIVE": 4, + "GREEN": 5, + "ORANGE": 6, + "PINK": 7, + "PURPLE": 8, + } +) + +func (x AccountData_UsernameLink_Color) Enum() *AccountData_UsernameLink_Color { + p := new(AccountData_UsernameLink_Color) + *p = x + return p +} + +func (x AccountData_UsernameLink_Color) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_UsernameLink_Color) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[2].Descriptor() +} + +func (AccountData_UsernameLink_Color) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[2] +} + +func (x AccountData_UsernameLink_Color) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_UsernameLink_Color.Descriptor instead. +func (AccountData_UsernameLink_Color) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 0, 0} +} + +type Contact_IdentityState int32 + +const ( + Contact_DEFAULT Contact_IdentityState = 0 + Contact_VERIFIED Contact_IdentityState = 1 + Contact_UNVERIFIED Contact_IdentityState = 2 +) + +// Enum value maps for Contact_IdentityState. +var ( + Contact_IdentityState_name = map[int32]string{ + 0: "DEFAULT", + 1: "VERIFIED", + 2: "UNVERIFIED", + } + Contact_IdentityState_value = map[string]int32{ + "DEFAULT": 0, + "VERIFIED": 1, + "UNVERIFIED": 2, + } +) + +func (x Contact_IdentityState) Enum() *Contact_IdentityState { + p := new(Contact_IdentityState) + *p = x + return p +} + +func (x Contact_IdentityState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Contact_IdentityState) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[3].Descriptor() +} + +func (Contact_IdentityState) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[3] +} + +func (x Contact_IdentityState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Contact_IdentityState.Descriptor instead. +func (Contact_IdentityState) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{4, 0} +} + +type Contact_Visibility int32 + +const ( + Contact_VISIBLE Contact_Visibility = 0 + Contact_HIDDEN Contact_Visibility = 1 + Contact_HIDDEN_MESSAGE_REQUEST Contact_Visibility = 2 +) + +// Enum value maps for Contact_Visibility. +var ( + Contact_Visibility_name = map[int32]string{ + 0: "VISIBLE", + 1: "HIDDEN", + 2: "HIDDEN_MESSAGE_REQUEST", + } + Contact_Visibility_value = map[string]int32{ + "VISIBLE": 0, + "HIDDEN": 1, + "HIDDEN_MESSAGE_REQUEST": 2, + } +) + +func (x Contact_Visibility) Enum() *Contact_Visibility { + p := new(Contact_Visibility) + *p = x + return p +} + +func (x Contact_Visibility) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Contact_Visibility) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[4].Descriptor() +} + +func (Contact_Visibility) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[4] +} + +func (x Contact_Visibility) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Contact_Visibility.Descriptor instead. +func (Contact_Visibility) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{4, 1} +} + +type Group_StorySendMode int32 + +const ( + Group_DEFAULT Group_StorySendMode = 0 + Group_DISABLED Group_StorySendMode = 1 + Group_ENABLED Group_StorySendMode = 2 +) + +// Enum value maps for Group_StorySendMode. +var ( + Group_StorySendMode_name = map[int32]string{ + 0: "DEFAULT", + 1: "DISABLED", + 2: "ENABLED", + } + Group_StorySendMode_value = map[string]int32{ + "DEFAULT": 0, + "DISABLED": 1, + "ENABLED": 2, + } +) + +func (x Group_StorySendMode) Enum() *Group_StorySendMode { + p := new(Group_StorySendMode) + *p = x + return p +} + +func (x Group_StorySendMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Group_StorySendMode) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[5].Descriptor() +} + +func (Group_StorySendMode) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[5] +} + +func (x Group_StorySendMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Group_StorySendMode.Descriptor instead. +func (Group_StorySendMode) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 0} +} + +type Group_Member_Role int32 + +const ( + Group_Member_UNKNOWN Group_Member_Role = 0 + Group_Member_DEFAULT Group_Member_Role = 1 + Group_Member_ADMINISTRATOR Group_Member_Role = 2 +) + +// Enum value maps for Group_Member_Role. +var ( + Group_Member_Role_name = map[int32]string{ + 0: "UNKNOWN", + 1: "DEFAULT", + 2: "ADMINISTRATOR", + } + Group_Member_Role_value = map[string]int32{ + "UNKNOWN": 0, + "DEFAULT": 1, + "ADMINISTRATOR": 2, + } +) + +func (x Group_Member_Role) Enum() *Group_Member_Role { + p := new(Group_Member_Role) + *p = x + return p +} + +func (x Group_Member_Role) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Group_Member_Role) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[6].Descriptor() +} + +func (Group_Member_Role) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[6] +} + +func (x Group_Member_Role) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Group_Member_Role.Descriptor instead. +func (Group_Member_Role) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 2, 0} +} + +type Group_AccessControl_AccessRequired int32 + +const ( + Group_AccessControl_UNKNOWN Group_AccessControl_AccessRequired = 0 + Group_AccessControl_ANY Group_AccessControl_AccessRequired = 1 + Group_AccessControl_MEMBER Group_AccessControl_AccessRequired = 2 + Group_AccessControl_ADMINISTRATOR Group_AccessControl_AccessRequired = 3 + Group_AccessControl_UNSATISFIABLE Group_AccessControl_AccessRequired = 4 +) + +// Enum value maps for Group_AccessControl_AccessRequired. +var ( + Group_AccessControl_AccessRequired_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ANY", + 2: "MEMBER", + 3: "ADMINISTRATOR", + 4: "UNSATISFIABLE", + } + Group_AccessControl_AccessRequired_value = map[string]int32{ + "UNKNOWN": 0, + "ANY": 1, + "MEMBER": 2, + "ADMINISTRATOR": 3, + "UNSATISFIABLE": 4, + } +) + +func (x Group_AccessControl_AccessRequired) Enum() *Group_AccessControl_AccessRequired { + p := new(Group_AccessControl_AccessRequired) + *p = x + return p +} + +func (x Group_AccessControl_AccessRequired) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Group_AccessControl_AccessRequired) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[7].Descriptor() +} + +func (Group_AccessControl_AccessRequired) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[7] +} + +func (x Group_AccessControl_AccessRequired) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Group_AccessControl_AccessRequired.Descriptor instead. +func (Group_AccessControl_AccessRequired) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 6, 0} +} + +type CallLink_Restrictions int32 + +const ( + CallLink_UNKNOWN CallLink_Restrictions = 0 + CallLink_NONE CallLink_Restrictions = 1 + CallLink_ADMIN_APPROVAL CallLink_Restrictions = 2 +) + +// Enum value maps for CallLink_Restrictions. +var ( + CallLink_Restrictions_name = map[int32]string{ + 0: "UNKNOWN", + 1: "NONE", + 2: "ADMIN_APPROVAL", + } + CallLink_Restrictions_value = map[string]int32{ + "UNKNOWN": 0, + "NONE": 1, + "ADMIN_APPROVAL": 2, + } +) + +func (x CallLink_Restrictions) Enum() *CallLink_Restrictions { + p := new(CallLink_Restrictions) + *p = x + return p +} + +func (x CallLink_Restrictions) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CallLink_Restrictions) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[8].Descriptor() +} + +func (CallLink_Restrictions) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[8] +} + +func (x CallLink_Restrictions) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CallLink_Restrictions.Descriptor instead. +func (CallLink_Restrictions) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{9, 0} +} + +type AdHocCall_State int32 + +const ( + AdHocCall_UNKNOWN_STATE AdHocCall_State = 0 + AdHocCall_GENERIC AdHocCall_State = 1 +) + +// Enum value maps for AdHocCall_State. +var ( + AdHocCall_State_name = map[int32]string{ + 0: "UNKNOWN_STATE", + 1: "GENERIC", + } + AdHocCall_State_value = map[string]int32{ + "UNKNOWN_STATE": 0, + "GENERIC": 1, + } +) + +func (x AdHocCall_State) Enum() *AdHocCall_State { + p := new(AdHocCall_State) + *p = x + return p +} + +func (x AdHocCall_State) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AdHocCall_State) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[9].Descriptor() +} + +func (AdHocCall_State) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[9] +} + +func (x AdHocCall_State) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AdHocCall_State.Descriptor instead. +func (AdHocCall_State) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{10, 0} +} + +type DistributionList_PrivacyMode int32 + +const ( + DistributionList_UNKNOWN DistributionList_PrivacyMode = 0 + DistributionList_ONLY_WITH DistributionList_PrivacyMode = 1 + DistributionList_ALL_EXCEPT DistributionList_PrivacyMode = 2 + DistributionList_ALL DistributionList_PrivacyMode = 3 +) + +// Enum value maps for DistributionList_PrivacyMode. +var ( + DistributionList_PrivacyMode_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ONLY_WITH", + 2: "ALL_EXCEPT", + 3: "ALL", + } + DistributionList_PrivacyMode_value = map[string]int32{ + "UNKNOWN": 0, + "ONLY_WITH": 1, + "ALL_EXCEPT": 2, + "ALL": 3, + } +) + +func (x DistributionList_PrivacyMode) Enum() *DistributionList_PrivacyMode { + p := new(DistributionList_PrivacyMode) + *p = x + return p +} + +func (x DistributionList_PrivacyMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DistributionList_PrivacyMode) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[10].Descriptor() +} + +func (DistributionList_PrivacyMode) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[10] +} + +func (x DistributionList_PrivacyMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DistributionList_PrivacyMode.Descriptor instead. +func (DistributionList_PrivacyMode) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{12, 0} +} + +type SendStatus_Failed_FailureReason int32 + +const ( + SendStatus_Failed_UNKNOWN SendStatus_Failed_FailureReason = 0 // A valid value -- could indicate a crash or lack of information + SendStatus_Failed_NETWORK SendStatus_Failed_FailureReason = 1 + SendStatus_Failed_IDENTITY_KEY_MISMATCH SendStatus_Failed_FailureReason = 2 +) + +// Enum value maps for SendStatus_Failed_FailureReason. +var ( + SendStatus_Failed_FailureReason_name = map[int32]string{ + 0: "UNKNOWN", + 1: "NETWORK", + 2: "IDENTITY_KEY_MISMATCH", + } + SendStatus_Failed_FailureReason_value = map[string]int32{ + "UNKNOWN": 0, + "NETWORK": 1, + "IDENTITY_KEY_MISMATCH": 2, + } +) + +func (x SendStatus_Failed_FailureReason) Enum() *SendStatus_Failed_FailureReason { + p := new(SendStatus_Failed_FailureReason) + *p = x + return p +} + +func (x SendStatus_Failed_FailureReason) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SendStatus_Failed_FailureReason) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[11].Descriptor() +} + +func (SendStatus_Failed_FailureReason) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[11] +} + +func (x SendStatus_Failed_FailureReason) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SendStatus_Failed_FailureReason.Descriptor instead. +func (SendStatus_Failed_FailureReason) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 6, 0} +} + +type PaymentNotification_TransactionDetails_FailedTransaction_FailureReason int32 + +const ( + PaymentNotification_TransactionDetails_FailedTransaction_GENERIC PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 0 + PaymentNotification_TransactionDetails_FailedTransaction_NETWORK PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 1 + PaymentNotification_TransactionDetails_FailedTransaction_INSUFFICIENT_FUNDS PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 2 +) + +// Enum value maps for PaymentNotification_TransactionDetails_FailedTransaction_FailureReason. +var ( + PaymentNotification_TransactionDetails_FailedTransaction_FailureReason_name = map[int32]string{ + 0: "GENERIC", + 1: "NETWORK", + 2: "INSUFFICIENT_FUNDS", + } + PaymentNotification_TransactionDetails_FailedTransaction_FailureReason_value = map[string]int32{ + "GENERIC": 0, + "NETWORK": 1, + "INSUFFICIENT_FUNDS": 2, + } +) + +func (x PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Enum() *PaymentNotification_TransactionDetails_FailedTransaction_FailureReason { + p := new(PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) + *p = x + return p +} + +func (x PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[12].Descriptor() +} + +func (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[12] +} + +func (x PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PaymentNotification_TransactionDetails_FailedTransaction_FailureReason.Descriptor instead. +func (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19, 0, 1, 0} +} + +type PaymentNotification_TransactionDetails_Transaction_Status int32 + +const ( + PaymentNotification_TransactionDetails_Transaction_INITIAL PaymentNotification_TransactionDetails_Transaction_Status = 0 + PaymentNotification_TransactionDetails_Transaction_SUBMITTED PaymentNotification_TransactionDetails_Transaction_Status = 1 + PaymentNotification_TransactionDetails_Transaction_SUCCESSFUL PaymentNotification_TransactionDetails_Transaction_Status = 2 +) + +// Enum value maps for PaymentNotification_TransactionDetails_Transaction_Status. +var ( + PaymentNotification_TransactionDetails_Transaction_Status_name = map[int32]string{ + 0: "INITIAL", + 1: "SUBMITTED", + 2: "SUCCESSFUL", + } + PaymentNotification_TransactionDetails_Transaction_Status_value = map[string]int32{ + "INITIAL": 0, + "SUBMITTED": 1, + "SUCCESSFUL": 2, + } +) + +func (x PaymentNotification_TransactionDetails_Transaction_Status) Enum() *PaymentNotification_TransactionDetails_Transaction_Status { + p := new(PaymentNotification_TransactionDetails_Transaction_Status) + *p = x + return p +} + +func (x PaymentNotification_TransactionDetails_Transaction_Status) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PaymentNotification_TransactionDetails_Transaction_Status) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[13].Descriptor() +} + +func (PaymentNotification_TransactionDetails_Transaction_Status) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[13] +} + +func (x PaymentNotification_TransactionDetails_Transaction_Status) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PaymentNotification_TransactionDetails_Transaction_Status.Descriptor instead. +func (PaymentNotification_TransactionDetails_Transaction_Status) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19, 0, 2, 0} +} + +type GiftBadge_State int32 + +const ( + GiftBadge_UNOPENED GiftBadge_State = 0 + GiftBadge_OPENED GiftBadge_State = 1 + GiftBadge_REDEEMED GiftBadge_State = 2 + GiftBadge_FAILED GiftBadge_State = 3 +) + +// Enum value maps for GiftBadge_State. +var ( + GiftBadge_State_name = map[int32]string{ + 0: "UNOPENED", + 1: "OPENED", + 2: "REDEEMED", + 3: "FAILED", + } + GiftBadge_State_value = map[string]int32{ + "UNOPENED": 0, + "OPENED": 1, + "REDEEMED": 2, + "FAILED": 3, + } +) + +func (x GiftBadge_State) Enum() *GiftBadge_State { + p := new(GiftBadge_State) + *p = x + return p +} + +func (x GiftBadge_State) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GiftBadge_State) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[14].Descriptor() +} + +func (GiftBadge_State) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[14] +} + +func (x GiftBadge_State) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GiftBadge_State.Descriptor instead. +func (GiftBadge_State) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{20, 0} +} + +type ContactAttachment_Phone_Type int32 + +const ( + ContactAttachment_Phone_UNKNOWN ContactAttachment_Phone_Type = 0 + ContactAttachment_Phone_HOME ContactAttachment_Phone_Type = 1 + ContactAttachment_Phone_MOBILE ContactAttachment_Phone_Type = 2 + ContactAttachment_Phone_WORK ContactAttachment_Phone_Type = 3 + ContactAttachment_Phone_CUSTOM ContactAttachment_Phone_Type = 4 +) + +// Enum value maps for ContactAttachment_Phone_Type. +var ( + ContactAttachment_Phone_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "HOME", + 2: "MOBILE", + 3: "WORK", + 4: "CUSTOM", + } + ContactAttachment_Phone_Type_value = map[string]int32{ + "UNKNOWN": 0, + "HOME": 1, + "MOBILE": 2, + "WORK": 3, + "CUSTOM": 4, + } +) + +func (x ContactAttachment_Phone_Type) Enum() *ContactAttachment_Phone_Type { + p := new(ContactAttachment_Phone_Type) + *p = x + return p +} + +func (x ContactAttachment_Phone_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContactAttachment_Phone_Type) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[15].Descriptor() +} + +func (ContactAttachment_Phone_Type) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[15] +} + +func (x ContactAttachment_Phone_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ContactAttachment_Phone_Type.Descriptor instead. +func (ContactAttachment_Phone_Type) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 1, 0} +} + +type ContactAttachment_Email_Type int32 + +const ( + ContactAttachment_Email_UNKNOWN ContactAttachment_Email_Type = 0 + ContactAttachment_Email_HOME ContactAttachment_Email_Type = 1 + ContactAttachment_Email_MOBILE ContactAttachment_Email_Type = 2 + ContactAttachment_Email_WORK ContactAttachment_Email_Type = 3 + ContactAttachment_Email_CUSTOM ContactAttachment_Email_Type = 4 +) + +// Enum value maps for ContactAttachment_Email_Type. +var ( + ContactAttachment_Email_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "HOME", + 2: "MOBILE", + 3: "WORK", + 4: "CUSTOM", + } + ContactAttachment_Email_Type_value = map[string]int32{ + "UNKNOWN": 0, + "HOME": 1, + "MOBILE": 2, + "WORK": 3, + "CUSTOM": 4, + } +) + +func (x ContactAttachment_Email_Type) Enum() *ContactAttachment_Email_Type { + p := new(ContactAttachment_Email_Type) + *p = x + return p +} + +func (x ContactAttachment_Email_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContactAttachment_Email_Type) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[16].Descriptor() +} + +func (ContactAttachment_Email_Type) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[16] +} + +func (x ContactAttachment_Email_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ContactAttachment_Email_Type.Descriptor instead. +func (ContactAttachment_Email_Type) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 2, 0} +} + +type ContactAttachment_PostalAddress_Type int32 + +const ( + ContactAttachment_PostalAddress_UNKNOWN ContactAttachment_PostalAddress_Type = 0 + ContactAttachment_PostalAddress_HOME ContactAttachment_PostalAddress_Type = 1 + ContactAttachment_PostalAddress_WORK ContactAttachment_PostalAddress_Type = 2 + ContactAttachment_PostalAddress_CUSTOM ContactAttachment_PostalAddress_Type = 3 +) + +// Enum value maps for ContactAttachment_PostalAddress_Type. +var ( + ContactAttachment_PostalAddress_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "HOME", + 2: "WORK", + 3: "CUSTOM", + } + ContactAttachment_PostalAddress_Type_value = map[string]int32{ + "UNKNOWN": 0, + "HOME": 1, + "WORK": 2, + "CUSTOM": 3, + } +) + +func (x ContactAttachment_PostalAddress_Type) Enum() *ContactAttachment_PostalAddress_Type { + p := new(ContactAttachment_PostalAddress_Type) + *p = x + return p +} + +func (x ContactAttachment_PostalAddress_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContactAttachment_PostalAddress_Type) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[17].Descriptor() +} + +func (ContactAttachment_PostalAddress_Type) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[17] +} + +func (x ContactAttachment_PostalAddress_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ContactAttachment_PostalAddress_Type.Descriptor instead. +func (ContactAttachment_PostalAddress_Type) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 3, 0} +} + +// Similar to SignalService.AttachmentPointer.Flags, +// but explicitly mutually exclusive. Note the different raw values +// (non-zero starting values are not supported in proto3.) +type MessageAttachment_Flag int32 + +const ( + MessageAttachment_NONE MessageAttachment_Flag = 0 + MessageAttachment_VOICE_MESSAGE MessageAttachment_Flag = 1 + MessageAttachment_BORDERLESS MessageAttachment_Flag = 2 + MessageAttachment_GIF MessageAttachment_Flag = 3 +) + +// Enum value maps for MessageAttachment_Flag. +var ( + MessageAttachment_Flag_name = map[int32]string{ + 0: "NONE", + 1: "VOICE_MESSAGE", + 2: "BORDERLESS", + 3: "GIF", + } + MessageAttachment_Flag_value = map[string]int32{ + "NONE": 0, + "VOICE_MESSAGE": 1, + "BORDERLESS": 2, + "GIF": 3, + } +) + +func (x MessageAttachment_Flag) Enum() *MessageAttachment_Flag { + p := new(MessageAttachment_Flag) + *p = x + return p +} + +func (x MessageAttachment_Flag) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (MessageAttachment_Flag) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[18].Descriptor() +} + +func (MessageAttachment_Flag) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[18] +} + +func (x MessageAttachment_Flag) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MessageAttachment_Flag.Descriptor instead. +func (MessageAttachment_Flag) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{27, 0} +} + +type Quote_Type int32 + +const ( + Quote_UNKNOWN Quote_Type = 0 + Quote_NORMAL Quote_Type = 1 + Quote_GIFT_BADGE Quote_Type = 2 + Quote_VIEW_ONCE Quote_Type = 3 +) + +// Enum value maps for Quote_Type. +var ( + Quote_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "NORMAL", + 2: "GIFT_BADGE", + 3: "VIEW_ONCE", + } + Quote_Type_value = map[string]int32{ + "UNKNOWN": 0, + "NORMAL": 1, + "GIFT_BADGE": 2, + "VIEW_ONCE": 3, + } +) + +func (x Quote_Type) Enum() *Quote_Type { + p := new(Quote_Type) + *p = x + return p +} + +func (x Quote_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Quote_Type) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[19].Descriptor() +} + +func (Quote_Type) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[19] +} + +func (x Quote_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Quote_Type.Descriptor instead. +func (Quote_Type) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{29, 0} +} + +type BodyRange_Style int32 + +const ( + BodyRange_NONE BodyRange_Style = 0 + BodyRange_BOLD BodyRange_Style = 1 + BodyRange_ITALIC BodyRange_Style = 2 + BodyRange_SPOILER BodyRange_Style = 3 + BodyRange_STRIKETHROUGH BodyRange_Style = 4 + BodyRange_MONOSPACE BodyRange_Style = 5 +) + +// Enum value maps for BodyRange_Style. +var ( + BodyRange_Style_name = map[int32]string{ + 0: "NONE", + 1: "BOLD", + 2: "ITALIC", + 3: "SPOILER", + 4: "STRIKETHROUGH", + 5: "MONOSPACE", + } + BodyRange_Style_value = map[string]int32{ + "NONE": 0, + "BOLD": 1, + "ITALIC": 2, + "SPOILER": 3, + "STRIKETHROUGH": 4, + "MONOSPACE": 5, + } +) + +func (x BodyRange_Style) Enum() *BodyRange_Style { + p := new(BodyRange_Style) + *p = x + return p +} + +func (x BodyRange_Style) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (BodyRange_Style) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[20].Descriptor() +} + +func (BodyRange_Style) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[20] +} + +func (x BodyRange_Style) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use BodyRange_Style.Descriptor instead. +func (BodyRange_Style) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{30, 0} +} + +type IndividualCall_Type int32 + +const ( + IndividualCall_UNKNOWN_TYPE IndividualCall_Type = 0 + IndividualCall_AUDIO_CALL IndividualCall_Type = 1 + IndividualCall_VIDEO_CALL IndividualCall_Type = 2 +) + +// Enum value maps for IndividualCall_Type. +var ( + IndividualCall_Type_name = map[int32]string{ + 0: "UNKNOWN_TYPE", + 1: "AUDIO_CALL", + 2: "VIDEO_CALL", + } + IndividualCall_Type_value = map[string]int32{ + "UNKNOWN_TYPE": 0, + "AUDIO_CALL": 1, + "VIDEO_CALL": 2, + } +) + +func (x IndividualCall_Type) Enum() *IndividualCall_Type { + p := new(IndividualCall_Type) + *p = x + return p +} + +func (x IndividualCall_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (IndividualCall_Type) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[21].Descriptor() +} + +func (IndividualCall_Type) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[21] +} + +func (x IndividualCall_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use IndividualCall_Type.Descriptor instead. +func (IndividualCall_Type) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{33, 0} +} + +type IndividualCall_Direction int32 + +const ( + IndividualCall_UNKNOWN_DIRECTION IndividualCall_Direction = 0 + IndividualCall_INCOMING IndividualCall_Direction = 1 + IndividualCall_OUTGOING IndividualCall_Direction = 2 +) + +// Enum value maps for IndividualCall_Direction. +var ( + IndividualCall_Direction_name = map[int32]string{ + 0: "UNKNOWN_DIRECTION", + 1: "INCOMING", + 2: "OUTGOING", + } + IndividualCall_Direction_value = map[string]int32{ + "UNKNOWN_DIRECTION": 0, + "INCOMING": 1, + "OUTGOING": 2, + } +) + +func (x IndividualCall_Direction) Enum() *IndividualCall_Direction { + p := new(IndividualCall_Direction) + *p = x + return p +} + +func (x IndividualCall_Direction) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (IndividualCall_Direction) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[22].Descriptor() +} + +func (IndividualCall_Direction) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[22] +} + +func (x IndividualCall_Direction) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use IndividualCall_Direction.Descriptor instead. +func (IndividualCall_Direction) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{33, 1} +} + +type IndividualCall_State int32 + +const ( + IndividualCall_UNKNOWN_STATE IndividualCall_State = 0 + IndividualCall_ACCEPTED IndividualCall_State = 1 + IndividualCall_NOT_ACCEPTED IndividualCall_State = 2 + // An incoming call that is no longer ongoing, which we neither accepted + // not actively declined. For example, it expired, was canceled by the + // sender, or was rejected due to being in another call. + IndividualCall_MISSED IndividualCall_State = 3 + // We auto-declined an incoming call due to a notification profile. + IndividualCall_MISSED_NOTIFICATION_PROFILE IndividualCall_State = 4 +) + +// Enum value maps for IndividualCall_State. +var ( + IndividualCall_State_name = map[int32]string{ + 0: "UNKNOWN_STATE", + 1: "ACCEPTED", + 2: "NOT_ACCEPTED", + 3: "MISSED", + 4: "MISSED_NOTIFICATION_PROFILE", + } + IndividualCall_State_value = map[string]int32{ + "UNKNOWN_STATE": 0, + "ACCEPTED": 1, + "NOT_ACCEPTED": 2, + "MISSED": 3, + "MISSED_NOTIFICATION_PROFILE": 4, + } +) + +func (x IndividualCall_State) Enum() *IndividualCall_State { + p := new(IndividualCall_State) + *p = x + return p +} + +func (x IndividualCall_State) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (IndividualCall_State) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[23].Descriptor() +} + +func (IndividualCall_State) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[23] +} + +func (x IndividualCall_State) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use IndividualCall_State.Descriptor instead. +func (IndividualCall_State) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{33, 2} +} + +type GroupCall_State int32 + +const ( + GroupCall_UNKNOWN_STATE GroupCall_State = 0 + // A group call was started without ringing. + GroupCall_GENERIC GroupCall_State = 1 + // We joined a group call that was started without ringing. + GroupCall_JOINED GroupCall_State = 2 + // An incoming group call is actively ringing. + GroupCall_RINGING GroupCall_State = 3 + // We accepted an incoming group ring. + GroupCall_ACCEPTED GroupCall_State = 4 + // We declined an incoming group ring. + GroupCall_DECLINED GroupCall_State = 5 + // We missed an incoming group ring, for example because it expired. + GroupCall_MISSED GroupCall_State = 6 + // We auto-declined an incoming group ring due to a notification profile. + GroupCall_MISSED_NOTIFICATION_PROFILE GroupCall_State = 7 + // An outgoing ring was started. We don't track any state for outgoing rings + // beyond that they started. + GroupCall_OUTGOING_RING GroupCall_State = 8 +) + +// Enum value maps for GroupCall_State. +var ( + GroupCall_State_name = map[int32]string{ + 0: "UNKNOWN_STATE", + 1: "GENERIC", + 2: "JOINED", + 3: "RINGING", + 4: "ACCEPTED", + 5: "DECLINED", + 6: "MISSED", + 7: "MISSED_NOTIFICATION_PROFILE", + 8: "OUTGOING_RING", + } + GroupCall_State_value = map[string]int32{ + "UNKNOWN_STATE": 0, + "GENERIC": 1, + "JOINED": 2, + "RINGING": 3, + "ACCEPTED": 4, + "DECLINED": 5, + "MISSED": 6, + "MISSED_NOTIFICATION_PROFILE": 7, + "OUTGOING_RING": 8, + } +) + +func (x GroupCall_State) Enum() *GroupCall_State { + p := new(GroupCall_State) + *p = x + return p +} + +func (x GroupCall_State) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GroupCall_State) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[24].Descriptor() +} + +func (GroupCall_State) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[24] +} + +func (x GroupCall_State) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GroupCall_State.Descriptor instead. +func (GroupCall_State) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 0} +} + +type SimpleChatUpdate_Type int32 + +const ( + SimpleChatUpdate_UNKNOWN SimpleChatUpdate_Type = 0 + SimpleChatUpdate_JOINED_SIGNAL SimpleChatUpdate_Type = 1 + SimpleChatUpdate_IDENTITY_UPDATE SimpleChatUpdate_Type = 2 + SimpleChatUpdate_IDENTITY_VERIFIED SimpleChatUpdate_Type = 3 + SimpleChatUpdate_IDENTITY_DEFAULT SimpleChatUpdate_Type = 4 // marking as unverified + SimpleChatUpdate_CHANGE_NUMBER SimpleChatUpdate_Type = 5 + SimpleChatUpdate_RELEASE_CHANNEL_DONATION_REQUEST SimpleChatUpdate_Type = 6 + SimpleChatUpdate_END_SESSION SimpleChatUpdate_Type = 7 + SimpleChatUpdate_CHAT_SESSION_REFRESH SimpleChatUpdate_Type = 8 + SimpleChatUpdate_BAD_DECRYPT SimpleChatUpdate_Type = 9 + SimpleChatUpdate_PAYMENTS_ACTIVATED SimpleChatUpdate_Type = 10 + SimpleChatUpdate_PAYMENT_ACTIVATION_REQUEST SimpleChatUpdate_Type = 11 + SimpleChatUpdate_UNSUPPORTED_PROTOCOL_MESSAGE SimpleChatUpdate_Type = 12 + SimpleChatUpdate_REPORTED_SPAM SimpleChatUpdate_Type = 13 + SimpleChatUpdate_BLOCKED SimpleChatUpdate_Type = 14 + SimpleChatUpdate_UNBLOCKED SimpleChatUpdate_Type = 15 + SimpleChatUpdate_MESSAGE_REQUEST_ACCEPTED SimpleChatUpdate_Type = 16 +) + +// Enum value maps for SimpleChatUpdate_Type. +var ( + SimpleChatUpdate_Type_name = map[int32]string{ + 0: "UNKNOWN", + 1: "JOINED_SIGNAL", + 2: "IDENTITY_UPDATE", + 3: "IDENTITY_VERIFIED", + 4: "IDENTITY_DEFAULT", + 5: "CHANGE_NUMBER", + 6: "RELEASE_CHANNEL_DONATION_REQUEST", + 7: "END_SESSION", + 8: "CHAT_SESSION_REFRESH", + 9: "BAD_DECRYPT", + 10: "PAYMENTS_ACTIVATED", + 11: "PAYMENT_ACTIVATION_REQUEST", + 12: "UNSUPPORTED_PROTOCOL_MESSAGE", + 13: "REPORTED_SPAM", + 14: "BLOCKED", + 15: "UNBLOCKED", + 16: "MESSAGE_REQUEST_ACCEPTED", + } + SimpleChatUpdate_Type_value = map[string]int32{ + "UNKNOWN": 0, + "JOINED_SIGNAL": 1, + "IDENTITY_UPDATE": 2, + "IDENTITY_VERIFIED": 3, + "IDENTITY_DEFAULT": 4, + "CHANGE_NUMBER": 5, + "RELEASE_CHANNEL_DONATION_REQUEST": 6, + "END_SESSION": 7, + "CHAT_SESSION_REFRESH": 8, + "BAD_DECRYPT": 9, + "PAYMENTS_ACTIVATED": 10, + "PAYMENT_ACTIVATION_REQUEST": 11, + "UNSUPPORTED_PROTOCOL_MESSAGE": 12, + "REPORTED_SPAM": 13, + "BLOCKED": 14, + "UNBLOCKED": 15, + "MESSAGE_REQUEST_ACCEPTED": 16, + } +) + +func (x SimpleChatUpdate_Type) Enum() *SimpleChatUpdate_Type { + p := new(SimpleChatUpdate_Type) + *p = x + return p +} + +func (x SimpleChatUpdate_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SimpleChatUpdate_Type) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[25].Descriptor() +} + +func (SimpleChatUpdate_Type) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[25] +} + +func (x SimpleChatUpdate_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SimpleChatUpdate_Type.Descriptor instead. +func (SimpleChatUpdate_Type) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 0} +} + +type ChatStyle_WallpaperPreset int32 + +const ( + ChatStyle_UNKNOWN_WALLPAPER_PRESET ChatStyle_WallpaperPreset = 0 + ChatStyle_SOLID_BLUSH ChatStyle_WallpaperPreset = 1 + ChatStyle_SOLID_COPPER ChatStyle_WallpaperPreset = 2 + ChatStyle_SOLID_DUST ChatStyle_WallpaperPreset = 3 + ChatStyle_SOLID_CELADON ChatStyle_WallpaperPreset = 4 + ChatStyle_SOLID_RAINFOREST ChatStyle_WallpaperPreset = 5 + ChatStyle_SOLID_PACIFIC ChatStyle_WallpaperPreset = 6 + ChatStyle_SOLID_FROST ChatStyle_WallpaperPreset = 7 + ChatStyle_SOLID_NAVY ChatStyle_WallpaperPreset = 8 + ChatStyle_SOLID_LILAC ChatStyle_WallpaperPreset = 9 + ChatStyle_SOLID_PINK ChatStyle_WallpaperPreset = 10 + ChatStyle_SOLID_EGGPLANT ChatStyle_WallpaperPreset = 11 + ChatStyle_SOLID_SILVER ChatStyle_WallpaperPreset = 12 + ChatStyle_GRADIENT_SUNSET ChatStyle_WallpaperPreset = 13 + ChatStyle_GRADIENT_NOIR ChatStyle_WallpaperPreset = 14 + ChatStyle_GRADIENT_HEATMAP ChatStyle_WallpaperPreset = 15 + ChatStyle_GRADIENT_AQUA ChatStyle_WallpaperPreset = 16 + ChatStyle_GRADIENT_IRIDESCENT ChatStyle_WallpaperPreset = 17 + ChatStyle_GRADIENT_MONSTERA ChatStyle_WallpaperPreset = 18 + ChatStyle_GRADIENT_BLISS ChatStyle_WallpaperPreset = 19 + ChatStyle_GRADIENT_SKY ChatStyle_WallpaperPreset = 20 + ChatStyle_GRADIENT_PEACH ChatStyle_WallpaperPreset = 21 +) + +// Enum value maps for ChatStyle_WallpaperPreset. +var ( + ChatStyle_WallpaperPreset_name = map[int32]string{ + 0: "UNKNOWN_WALLPAPER_PRESET", + 1: "SOLID_BLUSH", + 2: "SOLID_COPPER", + 3: "SOLID_DUST", + 4: "SOLID_CELADON", + 5: "SOLID_RAINFOREST", + 6: "SOLID_PACIFIC", + 7: "SOLID_FROST", + 8: "SOLID_NAVY", + 9: "SOLID_LILAC", + 10: "SOLID_PINK", + 11: "SOLID_EGGPLANT", + 12: "SOLID_SILVER", + 13: "GRADIENT_SUNSET", + 14: "GRADIENT_NOIR", + 15: "GRADIENT_HEATMAP", + 16: "GRADIENT_AQUA", + 17: "GRADIENT_IRIDESCENT", + 18: "GRADIENT_MONSTERA", + 19: "GRADIENT_BLISS", + 20: "GRADIENT_SKY", + 21: "GRADIENT_PEACH", + } + ChatStyle_WallpaperPreset_value = map[string]int32{ + "UNKNOWN_WALLPAPER_PRESET": 0, + "SOLID_BLUSH": 1, + "SOLID_COPPER": 2, + "SOLID_DUST": 3, + "SOLID_CELADON": 4, + "SOLID_RAINFOREST": 5, + "SOLID_PACIFIC": 6, + "SOLID_FROST": 7, + "SOLID_NAVY": 8, + "SOLID_LILAC": 9, + "SOLID_PINK": 10, + "SOLID_EGGPLANT": 11, + "SOLID_SILVER": 12, + "GRADIENT_SUNSET": 13, + "GRADIENT_NOIR": 14, + "GRADIENT_HEATMAP": 15, + "GRADIENT_AQUA": 16, + "GRADIENT_IRIDESCENT": 17, + "GRADIENT_MONSTERA": 18, + "GRADIENT_BLISS": 19, + "GRADIENT_SKY": 20, + "GRADIENT_PEACH": 21, + } +) + +func (x ChatStyle_WallpaperPreset) Enum() *ChatStyle_WallpaperPreset { + p := new(ChatStyle_WallpaperPreset) + *p = x + return p +} + +func (x ChatStyle_WallpaperPreset) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ChatStyle_WallpaperPreset) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[26].Descriptor() +} + +func (ChatStyle_WallpaperPreset) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[26] +} + +func (x ChatStyle_WallpaperPreset) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ChatStyle_WallpaperPreset.Descriptor instead. +func (ChatStyle_WallpaperPreset) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 0} +} + +type ChatStyle_BubbleColorPreset int32 + +const ( + ChatStyle_UNKNOWN_BUBBLE_COLOR_PRESET ChatStyle_BubbleColorPreset = 0 + ChatStyle_SOLID_ULTRAMARINE ChatStyle_BubbleColorPreset = 1 + ChatStyle_SOLID_CRIMSON ChatStyle_BubbleColorPreset = 2 + ChatStyle_SOLID_VERMILION ChatStyle_BubbleColorPreset = 3 + ChatStyle_SOLID_BURLAP ChatStyle_BubbleColorPreset = 4 + ChatStyle_SOLID_FOREST ChatStyle_BubbleColorPreset = 5 + ChatStyle_SOLID_WINTERGREEN ChatStyle_BubbleColorPreset = 6 + ChatStyle_SOLID_TEAL ChatStyle_BubbleColorPreset = 7 + ChatStyle_SOLID_BLUE ChatStyle_BubbleColorPreset = 8 + ChatStyle_SOLID_INDIGO ChatStyle_BubbleColorPreset = 9 + ChatStyle_SOLID_VIOLET ChatStyle_BubbleColorPreset = 10 + ChatStyle_SOLID_PLUM ChatStyle_BubbleColorPreset = 11 + ChatStyle_SOLID_TAUPE ChatStyle_BubbleColorPreset = 12 + ChatStyle_SOLID_STEEL ChatStyle_BubbleColorPreset = 13 + ChatStyle_GRADIENT_EMBER ChatStyle_BubbleColorPreset = 14 + ChatStyle_GRADIENT_MIDNIGHT ChatStyle_BubbleColorPreset = 15 + ChatStyle_GRADIENT_INFRARED ChatStyle_BubbleColorPreset = 16 + ChatStyle_GRADIENT_LAGOON ChatStyle_BubbleColorPreset = 17 + ChatStyle_GRADIENT_FLUORESCENT ChatStyle_BubbleColorPreset = 18 + ChatStyle_GRADIENT_BASIL ChatStyle_BubbleColorPreset = 19 + ChatStyle_GRADIENT_SUBLIME ChatStyle_BubbleColorPreset = 20 + ChatStyle_GRADIENT_SEA ChatStyle_BubbleColorPreset = 21 + ChatStyle_GRADIENT_TANGERINE ChatStyle_BubbleColorPreset = 22 +) + +// Enum value maps for ChatStyle_BubbleColorPreset. +var ( + ChatStyle_BubbleColorPreset_name = map[int32]string{ + 0: "UNKNOWN_BUBBLE_COLOR_PRESET", + 1: "SOLID_ULTRAMARINE", + 2: "SOLID_CRIMSON", + 3: "SOLID_VERMILION", + 4: "SOLID_BURLAP", + 5: "SOLID_FOREST", + 6: "SOLID_WINTERGREEN", + 7: "SOLID_TEAL", + 8: "SOLID_BLUE", + 9: "SOLID_INDIGO", + 10: "SOLID_VIOLET", + 11: "SOLID_PLUM", + 12: "SOLID_TAUPE", + 13: "SOLID_STEEL", + 14: "GRADIENT_EMBER", + 15: "GRADIENT_MIDNIGHT", + 16: "GRADIENT_INFRARED", + 17: "GRADIENT_LAGOON", + 18: "GRADIENT_FLUORESCENT", + 19: "GRADIENT_BASIL", + 20: "GRADIENT_SUBLIME", + 21: "GRADIENT_SEA", + 22: "GRADIENT_TANGERINE", + } + ChatStyle_BubbleColorPreset_value = map[string]int32{ + "UNKNOWN_BUBBLE_COLOR_PRESET": 0, + "SOLID_ULTRAMARINE": 1, + "SOLID_CRIMSON": 2, + "SOLID_VERMILION": 3, + "SOLID_BURLAP": 4, + "SOLID_FOREST": 5, + "SOLID_WINTERGREEN": 6, + "SOLID_TEAL": 7, + "SOLID_BLUE": 8, + "SOLID_INDIGO": 9, + "SOLID_VIOLET": 10, + "SOLID_PLUM": 11, + "SOLID_TAUPE": 12, + "SOLID_STEEL": 13, + "GRADIENT_EMBER": 14, + "GRADIENT_MIDNIGHT": 15, + "GRADIENT_INFRARED": 16, + "GRADIENT_LAGOON": 17, + "GRADIENT_FLUORESCENT": 18, + "GRADIENT_BASIL": 19, + "GRADIENT_SUBLIME": 20, + "GRADIENT_SEA": 21, + "GRADIENT_TANGERINE": 22, + } +) + +func (x ChatStyle_BubbleColorPreset) Enum() *ChatStyle_BubbleColorPreset { + p := new(ChatStyle_BubbleColorPreset) + *p = x + return p +} + +func (x ChatStyle_BubbleColorPreset) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ChatStyle_BubbleColorPreset) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[27].Descriptor() +} + +func (ChatStyle_BubbleColorPreset) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[27] +} + +func (x ChatStyle_BubbleColorPreset) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ChatStyle_BubbleColorPreset.Descriptor instead. +func (ChatStyle_BubbleColorPreset) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 1} +} + +type NotificationProfile_DayOfWeek int32 + +const ( + NotificationProfile_UNKNOWN NotificationProfile_DayOfWeek = 0 + NotificationProfile_MONDAY NotificationProfile_DayOfWeek = 1 + NotificationProfile_TUESDAY NotificationProfile_DayOfWeek = 2 + NotificationProfile_WEDNESDAY NotificationProfile_DayOfWeek = 3 + NotificationProfile_THURSDAY NotificationProfile_DayOfWeek = 4 + NotificationProfile_FRIDAY NotificationProfile_DayOfWeek = 5 + NotificationProfile_SATURDAY NotificationProfile_DayOfWeek = 6 + NotificationProfile_SUNDAY NotificationProfile_DayOfWeek = 7 +) + +// Enum value maps for NotificationProfile_DayOfWeek. +var ( + NotificationProfile_DayOfWeek_name = map[int32]string{ + 0: "UNKNOWN", + 1: "MONDAY", + 2: "TUESDAY", + 3: "WEDNESDAY", + 4: "THURSDAY", + 5: "FRIDAY", + 6: "SATURDAY", + 7: "SUNDAY", + } + NotificationProfile_DayOfWeek_value = map[string]int32{ + "UNKNOWN": 0, + "MONDAY": 1, + "TUESDAY": 2, + "WEDNESDAY": 3, + "THURSDAY": 4, + "FRIDAY": 5, + "SATURDAY": 6, + "SUNDAY": 7, + } +) + +func (x NotificationProfile_DayOfWeek) Enum() *NotificationProfile_DayOfWeek { + p := new(NotificationProfile_DayOfWeek) + *p = x + return p +} + +func (x NotificationProfile_DayOfWeek) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (NotificationProfile_DayOfWeek) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[28].Descriptor() +} + +func (NotificationProfile_DayOfWeek) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[28] +} + +func (x NotificationProfile_DayOfWeek) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use NotificationProfile_DayOfWeek.Descriptor instead. +func (NotificationProfile_DayOfWeek) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{78, 0} +} + +// Represents the default "All chats" folder record vs all other custom folders +type ChatFolder_FolderType int32 + +const ( + ChatFolder_UNKNOWN ChatFolder_FolderType = 0 + ChatFolder_ALL ChatFolder_FolderType = 1 + ChatFolder_CUSTOM ChatFolder_FolderType = 2 +) + +// Enum value maps for ChatFolder_FolderType. +var ( + ChatFolder_FolderType_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ALL", + 2: "CUSTOM", + } + ChatFolder_FolderType_value = map[string]int32{ + "UNKNOWN": 0, + "ALL": 1, + "CUSTOM": 2, + } +) + +func (x ChatFolder_FolderType) Enum() *ChatFolder_FolderType { + p := new(ChatFolder_FolderType) + *p = x + return p +} + +func (x ChatFolder_FolderType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ChatFolder_FolderType) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[29].Descriptor() +} + +func (ChatFolder_FolderType) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[29] +} + +func (x ChatFolder_FolderType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ChatFolder_FolderType.Descriptor instead. +func (ChatFolder_FolderType) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 0} +} + +type BackupInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + BackupTimeMs uint64 `protobuf:"varint,2,opt,name=backupTimeMs,proto3" json:"backupTimeMs,omitempty"` + MediaRootBackupKey []byte `protobuf:"bytes,3,opt,name=mediaRootBackupKey,proto3" json:"mediaRootBackupKey,omitempty"` // 32-byte random value generated when the backup is uploaded for the first time. + CurrentAppVersion string `protobuf:"bytes,4,opt,name=currentAppVersion,proto3" json:"currentAppVersion,omitempty"` + FirstAppVersion string `protobuf:"bytes,5,opt,name=firstAppVersion,proto3" json:"firstAppVersion,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BackupInfo) Reset() { + *x = BackupInfo{} + mi := &file_backuppb_Backup_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BackupInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BackupInfo) ProtoMessage() {} + +func (x *BackupInfo) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_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 BackupInfo.ProtoReflect.Descriptor instead. +func (*BackupInfo) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{0} +} + +func (x *BackupInfo) GetVersion() uint64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *BackupInfo) GetBackupTimeMs() uint64 { + if x != nil { + return x.BackupTimeMs + } + return 0 +} + +func (x *BackupInfo) GetMediaRootBackupKey() []byte { + if x != nil { + return x.MediaRootBackupKey + } + return nil +} + +func (x *BackupInfo) GetCurrentAppVersion() string { + if x != nil { + return x.CurrentAppVersion + } + return "" +} + +func (x *BackupInfo) GetFirstAppVersion() string { + if x != nil { + return x.FirstAppVersion + } + return "" +} + +// Frames must follow in the following ordering rules: +// +// 1. There is exactly one AccountData and it is the first frame. +// 2. A frame referenced by ID must come before the referencing frame. +// e.g. a Recipient must come before any Chat referencing it. +// 3. All ChatItems must appear in global Chat rendering order. +// (The order in which they were received by the client.) +// 4. ChatFolders must appear in render order (e.g., left to right for +// LTR locales), but can appear anywhere relative to other frames respecting +// rule 2 (after Recipients and Chats). +// +// Recipients, Chats, StickerPacks, AdHocCalls, and NotificationProfiles +// can be in any order. (But must respect rule 2.) +// +// For example, Chats may all be together at the beginning, +// or may each immediately precede its first ChatItem. +type Frame struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Item: + // + // *Frame_Account + // *Frame_Recipient + // *Frame_Chat + // *Frame_ChatItem + // *Frame_StickerPack + // *Frame_AdHocCall + // *Frame_NotificationProfile + // *Frame_ChatFolder + Item isFrame_Item `protobuf_oneof:"item"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Frame) Reset() { + *x = Frame{} + mi := &file_backuppb_Backup_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Frame) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Frame) ProtoMessage() {} + +func (x *Frame) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_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 Frame.ProtoReflect.Descriptor instead. +func (*Frame) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{1} +} + +func (x *Frame) GetItem() isFrame_Item { + if x != nil { + return x.Item + } + return nil +} + +func (x *Frame) GetAccount() *AccountData { + if x != nil { + if x, ok := x.Item.(*Frame_Account); ok { + return x.Account + } + } + return nil +} + +func (x *Frame) GetRecipient() *Recipient { + if x != nil { + if x, ok := x.Item.(*Frame_Recipient); ok { + return x.Recipient + } + } + return nil +} + +func (x *Frame) GetChat() *Chat { + if x != nil { + if x, ok := x.Item.(*Frame_Chat); ok { + return x.Chat + } + } + return nil +} + +func (x *Frame) GetChatItem() *ChatItem { + if x != nil { + if x, ok := x.Item.(*Frame_ChatItem); ok { + return x.ChatItem + } + } + return nil +} + +func (x *Frame) GetStickerPack() *StickerPack { + if x != nil { + if x, ok := x.Item.(*Frame_StickerPack); ok { + return x.StickerPack + } + } + return nil +} + +func (x *Frame) GetAdHocCall() *AdHocCall { + if x != nil { + if x, ok := x.Item.(*Frame_AdHocCall); ok { + return x.AdHocCall + } + } + return nil +} + +func (x *Frame) GetNotificationProfile() *NotificationProfile { + if x != nil { + if x, ok := x.Item.(*Frame_NotificationProfile); ok { + return x.NotificationProfile + } + } + return nil +} + +func (x *Frame) GetChatFolder() *ChatFolder { + if x != nil { + if x, ok := x.Item.(*Frame_ChatFolder); ok { + return x.ChatFolder + } + } + return nil +} + +type isFrame_Item interface { + isFrame_Item() +} + +type Frame_Account struct { + Account *AccountData `protobuf:"bytes,1,opt,name=account,proto3,oneof"` +} + +type Frame_Recipient struct { + Recipient *Recipient `protobuf:"bytes,2,opt,name=recipient,proto3,oneof"` +} + +type Frame_Chat struct { + Chat *Chat `protobuf:"bytes,3,opt,name=chat,proto3,oneof"` +} + +type Frame_ChatItem struct { + ChatItem *ChatItem `protobuf:"bytes,4,opt,name=chatItem,proto3,oneof"` +} + +type Frame_StickerPack struct { + StickerPack *StickerPack `protobuf:"bytes,5,opt,name=stickerPack,proto3,oneof"` +} + +type Frame_AdHocCall struct { + AdHocCall *AdHocCall `protobuf:"bytes,6,opt,name=adHocCall,proto3,oneof"` +} + +type Frame_NotificationProfile struct { + NotificationProfile *NotificationProfile `protobuf:"bytes,7,opt,name=notificationProfile,proto3,oneof"` +} + +type Frame_ChatFolder struct { + ChatFolder *ChatFolder `protobuf:"bytes,8,opt,name=chatFolder,proto3,oneof"` +} + +func (*Frame_Account) isFrame_Item() {} + +func (*Frame_Recipient) isFrame_Item() {} + +func (*Frame_Chat) isFrame_Item() {} + +func (*Frame_ChatItem) isFrame_Item() {} + +func (*Frame_StickerPack) isFrame_Item() {} + +func (*Frame_AdHocCall) isFrame_Item() {} + +func (*Frame_NotificationProfile) isFrame_Item() {} + +func (*Frame_ChatFolder) isFrame_Item() {} + +type AccountData struct { + state protoimpl.MessageState `protogen:"open.v1"` + ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + Username *string `protobuf:"bytes,2,opt,name=username,proto3,oneof" json:"username,omitempty"` + UsernameLink *AccountData_UsernameLink `protobuf:"bytes,3,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` + GivenName string `protobuf:"bytes,4,opt,name=givenName,proto3" json:"givenName,omitempty"` + FamilyName string `protobuf:"bytes,5,opt,name=familyName,proto3" json:"familyName,omitempty"` + AvatarUrlPath string `protobuf:"bytes,6,opt,name=avatarUrlPath,proto3" json:"avatarUrlPath,omitempty"` + DonationSubscriberData *AccountData_SubscriberData `protobuf:"bytes,7,opt,name=donationSubscriberData,proto3" json:"donationSubscriberData,omitempty"` + AccountSettings *AccountData_AccountSettings `protobuf:"bytes,9,opt,name=accountSettings,proto3" json:"accountSettings,omitempty"` + BackupsSubscriberData *AccountData_IAPSubscriberData `protobuf:"bytes,10,opt,name=backupsSubscriberData,proto3" json:"backupsSubscriberData,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData) Reset() { + *x = AccountData{} + mi := &file_backuppb_Backup_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData) ProtoMessage() {} + +func (x *AccountData) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_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 AccountData.ProtoReflect.Descriptor instead. +func (*AccountData) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2} +} + +func (x *AccountData) GetProfileKey() []byte { + if x != nil { + return x.ProfileKey + } + return nil +} + +func (x *AccountData) GetUsername() string { + if x != nil && x.Username != nil { + return *x.Username + } + return "" +} + +func (x *AccountData) GetUsernameLink() *AccountData_UsernameLink { + if x != nil { + return x.UsernameLink + } + return nil +} + +func (x *AccountData) GetGivenName() string { + if x != nil { + return x.GivenName + } + return "" +} + +func (x *AccountData) GetFamilyName() string { + if x != nil { + return x.FamilyName + } + return "" +} + +func (x *AccountData) GetAvatarUrlPath() string { + if x != nil { + return x.AvatarUrlPath + } + return "" +} + +func (x *AccountData) GetDonationSubscriberData() *AccountData_SubscriberData { + if x != nil { + return x.DonationSubscriberData + } + return nil +} + +func (x *AccountData) GetAccountSettings() *AccountData_AccountSettings { + if x != nil { + return x.AccountSettings + } + return nil +} + +func (x *AccountData) GetBackupsSubscriberData() *AccountData_IAPSubscriberData { + if x != nil { + return x.BackupsSubscriberData + } + return nil +} + +type Recipient struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // generated id for reference only within this file + // Types that are valid to be assigned to Destination: + // + // *Recipient_Contact + // *Recipient_Group + // *Recipient_DistributionList + // *Recipient_Self + // *Recipient_ReleaseNotes + // *Recipient_CallLink + Destination isRecipient_Destination `protobuf_oneof:"destination"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Recipient) Reset() { + *x = Recipient{} + mi := &file_backuppb_Backup_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Recipient) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Recipient) ProtoMessage() {} + +func (x *Recipient) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_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 Recipient.ProtoReflect.Descriptor instead. +func (*Recipient) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{3} +} + +func (x *Recipient) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Recipient) GetDestination() isRecipient_Destination { + if x != nil { + return x.Destination + } + return nil +} + +func (x *Recipient) GetContact() *Contact { + if x != nil { + if x, ok := x.Destination.(*Recipient_Contact); ok { + return x.Contact + } + } + return nil +} + +func (x *Recipient) GetGroup() *Group { + if x != nil { + if x, ok := x.Destination.(*Recipient_Group); ok { + return x.Group + } + } + return nil +} + +func (x *Recipient) GetDistributionList() *DistributionListItem { + if x != nil { + if x, ok := x.Destination.(*Recipient_DistributionList); ok { + return x.DistributionList + } + } + return nil +} + +func (x *Recipient) GetSelf() *Self { + if x != nil { + if x, ok := x.Destination.(*Recipient_Self); ok { + return x.Self + } + } + return nil +} + +func (x *Recipient) GetReleaseNotes() *ReleaseNotes { + if x != nil { + if x, ok := x.Destination.(*Recipient_ReleaseNotes); ok { + return x.ReleaseNotes + } + } + return nil +} + +func (x *Recipient) GetCallLink() *CallLink { + if x != nil { + if x, ok := x.Destination.(*Recipient_CallLink); ok { + return x.CallLink + } + } + return nil +} + +type isRecipient_Destination interface { + isRecipient_Destination() +} + +type Recipient_Contact struct { + Contact *Contact `protobuf:"bytes,2,opt,name=contact,proto3,oneof"` +} + +type Recipient_Group struct { + Group *Group `protobuf:"bytes,3,opt,name=group,proto3,oneof"` +} + +type Recipient_DistributionList struct { + DistributionList *DistributionListItem `protobuf:"bytes,4,opt,name=distributionList,proto3,oneof"` +} + +type Recipient_Self struct { + Self *Self `protobuf:"bytes,5,opt,name=self,proto3,oneof"` +} + +type Recipient_ReleaseNotes struct { + ReleaseNotes *ReleaseNotes `protobuf:"bytes,6,opt,name=releaseNotes,proto3,oneof"` +} + +type Recipient_CallLink struct { + CallLink *CallLink `protobuf:"bytes,7,opt,name=callLink,proto3,oneof"` +} + +func (*Recipient_Contact) isRecipient_Destination() {} + +func (*Recipient_Group) isRecipient_Destination() {} + +func (*Recipient_DistributionList) isRecipient_Destination() {} + +func (*Recipient_Self) isRecipient_Destination() {} + +func (*Recipient_ReleaseNotes) isRecipient_Destination() {} + +func (*Recipient_CallLink) isRecipient_Destination() {} + +type Contact struct { + state protoimpl.MessageState `protogen:"open.v1"` + Aci []byte `protobuf:"bytes,1,opt,name=aci,proto3,oneof" json:"aci,omitempty"` // should be 16 bytes + Pni []byte `protobuf:"bytes,2,opt,name=pni,proto3,oneof" json:"pni,omitempty"` // should be 16 bytes + Username *string `protobuf:"bytes,3,opt,name=username,proto3,oneof" json:"username,omitempty"` + E164 *uint64 `protobuf:"varint,4,opt,name=e164,proto3,oneof" json:"e164,omitempty"` + Blocked bool `protobuf:"varint,5,opt,name=blocked,proto3" json:"blocked,omitempty"` + Visibility Contact_Visibility `protobuf:"varint,6,opt,name=visibility,proto3,enum=signal.backup.Contact_Visibility" json:"visibility,omitempty"` + // Types that are valid to be assigned to Registration: + // + // *Contact_Registered_ + // *Contact_NotRegistered_ + Registration isContact_Registration `protobuf_oneof:"registration"` + ProfileKey []byte `protobuf:"bytes,9,opt,name=profileKey,proto3,oneof" json:"profileKey,omitempty"` + ProfileSharing bool `protobuf:"varint,10,opt,name=profileSharing,proto3" json:"profileSharing,omitempty"` + ProfileGivenName *string `protobuf:"bytes,11,opt,name=profileGivenName,proto3,oneof" json:"profileGivenName,omitempty"` + ProfileFamilyName *string `protobuf:"bytes,12,opt,name=profileFamilyName,proto3,oneof" json:"profileFamilyName,omitempty"` + HideStory bool `protobuf:"varint,13,opt,name=hideStory,proto3" json:"hideStory,omitempty"` + IdentityKey []byte `protobuf:"bytes,14,opt,name=identityKey,proto3,oneof" json:"identityKey,omitempty"` + IdentityState Contact_IdentityState `protobuf:"varint,15,opt,name=identityState,proto3,enum=signal.backup.Contact_IdentityState" json:"identityState,omitempty"` + Nickname *Contact_Name `protobuf:"bytes,16,opt,name=nickname,proto3" json:"nickname,omitempty"` // absent iff both `given` and `family` are empty + Note string `protobuf:"bytes,17,opt,name=note,proto3" json:"note,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Contact) Reset() { + *x = Contact{} + mi := &file_backuppb_Backup_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Contact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contact) ProtoMessage() {} + +func (x *Contact) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_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 Contact.ProtoReflect.Descriptor instead. +func (*Contact) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{4} +} + +func (x *Contact) GetAci() []byte { + if x != nil { + return x.Aci + } + return nil +} + +func (x *Contact) GetPni() []byte { + if x != nil { + return x.Pni + } + return nil +} + +func (x *Contact) GetUsername() string { + if x != nil && x.Username != nil { + return *x.Username + } + return "" +} + +func (x *Contact) GetE164() uint64 { + if x != nil && x.E164 != nil { + return *x.E164 + } + return 0 +} + +func (x *Contact) GetBlocked() bool { + if x != nil { + return x.Blocked + } + return false +} + +func (x *Contact) GetVisibility() Contact_Visibility { + if x != nil { + return x.Visibility + } + return Contact_VISIBLE +} + +func (x *Contact) GetRegistration() isContact_Registration { + if x != nil { + return x.Registration + } + return nil +} + +func (x *Contact) GetRegistered() *Contact_Registered { + if x != nil { + if x, ok := x.Registration.(*Contact_Registered_); ok { + return x.Registered + } + } + return nil +} + +func (x *Contact) GetNotRegistered() *Contact_NotRegistered { + if x != nil { + if x, ok := x.Registration.(*Contact_NotRegistered_); ok { + return x.NotRegistered + } + } + return nil +} + +func (x *Contact) GetProfileKey() []byte { + if x != nil { + return x.ProfileKey + } + return nil +} + +func (x *Contact) GetProfileSharing() bool { + if x != nil { + return x.ProfileSharing + } + return false +} + +func (x *Contact) GetProfileGivenName() string { + if x != nil && x.ProfileGivenName != nil { + return *x.ProfileGivenName + } + return "" +} + +func (x *Contact) GetProfileFamilyName() string { + if x != nil && x.ProfileFamilyName != nil { + return *x.ProfileFamilyName + } + return "" +} + +func (x *Contact) GetHideStory() bool { + if x != nil { + return x.HideStory + } + return false +} + +func (x *Contact) GetIdentityKey() []byte { + if x != nil { + return x.IdentityKey + } + return nil +} + +func (x *Contact) GetIdentityState() Contact_IdentityState { + if x != nil { + return x.IdentityState + } + return Contact_DEFAULT +} + +func (x *Contact) GetNickname() *Contact_Name { + if x != nil { + return x.Nickname + } + return nil +} + +func (x *Contact) GetNote() string { + if x != nil { + return x.Note + } + return "" +} + +type isContact_Registration interface { + isContact_Registration() +} + +type Contact_Registered_ struct { + Registered *Contact_Registered `protobuf:"bytes,7,opt,name=registered,proto3,oneof"` +} + +type Contact_NotRegistered_ struct { + NotRegistered *Contact_NotRegistered `protobuf:"bytes,8,opt,name=notRegistered,proto3,oneof"` +} + +func (*Contact_Registered_) isContact_Registration() {} + +func (*Contact_NotRegistered_) isContact_Registration() {} + +type Group struct { + state protoimpl.MessageState `protogen:"open.v1"` + MasterKey []byte `protobuf:"bytes,1,opt,name=masterKey,proto3" json:"masterKey,omitempty"` + Whitelisted bool `protobuf:"varint,2,opt,name=whitelisted,proto3" json:"whitelisted,omitempty"` + HideStory bool `protobuf:"varint,3,opt,name=hideStory,proto3" json:"hideStory,omitempty"` + StorySendMode Group_StorySendMode `protobuf:"varint,4,opt,name=storySendMode,proto3,enum=signal.backup.Group_StorySendMode" json:"storySendMode,omitempty"` + Snapshot *Group_GroupSnapshot `protobuf:"bytes,5,opt,name=snapshot,proto3" json:"snapshot,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group) Reset() { + *x = Group{} + mi := &file_backuppb_Backup_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group) ProtoMessage() {} + +func (x *Group) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_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 Group.ProtoReflect.Descriptor instead. +func (*Group) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5} +} + +func (x *Group) GetMasterKey() []byte { + if x != nil { + return x.MasterKey + } + return nil +} + +func (x *Group) GetWhitelisted() bool { + if x != nil { + return x.Whitelisted + } + return false +} + +func (x *Group) GetHideStory() bool { + if x != nil { + return x.HideStory + } + return false +} + +func (x *Group) GetStorySendMode() Group_StorySendMode { + if x != nil { + return x.StorySendMode + } + return Group_DEFAULT +} + +func (x *Group) GetSnapshot() *Group_GroupSnapshot { + if x != nil { + return x.Snapshot + } + return nil +} + +type Self struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Self) Reset() { + *x = Self{} + mi := &file_backuppb_Backup_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Self) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Self) ProtoMessage() {} + +func (x *Self) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[6] + 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 Self.ProtoReflect.Descriptor instead. +func (*Self) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{6} +} + +type ReleaseNotes struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReleaseNotes) Reset() { + *x = ReleaseNotes{} + mi := &file_backuppb_Backup_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReleaseNotes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReleaseNotes) ProtoMessage() {} + +func (x *ReleaseNotes) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[7] + 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 ReleaseNotes.ProtoReflect.Descriptor instead. +func (*ReleaseNotes) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{7} +} + +type Chat struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // generated id for reference only within this file + RecipientId uint64 `protobuf:"varint,2,opt,name=recipientId,proto3" json:"recipientId,omitempty"` + Archived bool `protobuf:"varint,3,opt,name=archived,proto3" json:"archived,omitempty"` + PinnedOrder *uint32 `protobuf:"varint,4,opt,name=pinnedOrder,proto3,oneof" json:"pinnedOrder,omitempty"` // will be displayed in ascending order + ExpirationTimerMs *uint64 `protobuf:"varint,5,opt,name=expirationTimerMs,proto3,oneof" json:"expirationTimerMs,omitempty"` + MuteUntilMs *uint64 `protobuf:"varint,6,opt,name=muteUntilMs,proto3,oneof" json:"muteUntilMs,omitempty"` // INT64_MAX (2^63 - 1) = "always muted". + MarkedUnread bool `protobuf:"varint,7,opt,name=markedUnread,proto3" json:"markedUnread,omitempty"` + DontNotifyForMentionsIfMuted bool `protobuf:"varint,8,opt,name=dontNotifyForMentionsIfMuted,proto3" json:"dontNotifyForMentionsIfMuted,omitempty"` + Style *ChatStyle `protobuf:"bytes,9,opt,name=style,proto3" json:"style,omitempty"` + ExpireTimerVersion uint32 `protobuf:"varint,10,opt,name=expireTimerVersion,proto3" json:"expireTimerVersion,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Chat) Reset() { + *x = Chat{} + mi := &file_backuppb_Backup_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Chat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Chat) ProtoMessage() {} + +func (x *Chat) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[8] + 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 Chat.ProtoReflect.Descriptor instead. +func (*Chat) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{8} +} + +func (x *Chat) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Chat) GetRecipientId() uint64 { + if x != nil { + return x.RecipientId + } + return 0 +} + +func (x *Chat) GetArchived() bool { + if x != nil { + return x.Archived + } + return false +} + +func (x *Chat) GetPinnedOrder() uint32 { + if x != nil && x.PinnedOrder != nil { + return *x.PinnedOrder + } + return 0 +} + +func (x *Chat) GetExpirationTimerMs() uint64 { + if x != nil && x.ExpirationTimerMs != nil { + return *x.ExpirationTimerMs + } + return 0 +} + +func (x *Chat) GetMuteUntilMs() uint64 { + if x != nil && x.MuteUntilMs != nil { + return *x.MuteUntilMs + } + return 0 +} + +func (x *Chat) GetMarkedUnread() bool { + if x != nil { + return x.MarkedUnread + } + return false +} + +func (x *Chat) GetDontNotifyForMentionsIfMuted() bool { + if x != nil { + return x.DontNotifyForMentionsIfMuted + } + return false +} + +func (x *Chat) GetStyle() *ChatStyle { + if x != nil { + return x.Style + } + return nil +} + +func (x *Chat) GetExpireTimerVersion() uint32 { + if x != nil { + return x.ExpireTimerVersion + } + return 0 +} + +// * +// Call Links have some associated data including a call, but unlike other recipients +// are not tied to threads because they do not have messages associated with them. +// +// note: +// - room id can be derived from the root key +// - the presence of an admin key means this user is a call admin +type CallLink struct { + state protoimpl.MessageState `protogen:"open.v1"` + RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` + AdminKey []byte `protobuf:"bytes,2,opt,name=adminKey,proto3,oneof" json:"adminKey,omitempty"` // Only present if the user is an admin + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Restrictions CallLink_Restrictions `protobuf:"varint,4,opt,name=restrictions,proto3,enum=signal.backup.CallLink_Restrictions" json:"restrictions,omitempty"` + ExpirationMs uint64 `protobuf:"varint,5,opt,name=expirationMs,proto3" json:"expirationMs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CallLink) Reset() { + *x = CallLink{} + mi := &file_backuppb_Backup_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CallLink) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallLink) ProtoMessage() {} + +func (x *CallLink) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[9] + 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 CallLink.ProtoReflect.Descriptor instead. +func (*CallLink) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{9} +} + +func (x *CallLink) GetRootKey() []byte { + if x != nil { + return x.RootKey + } + return nil +} + +func (x *CallLink) GetAdminKey() []byte { + if x != nil { + return x.AdminKey + } + return nil +} + +func (x *CallLink) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CallLink) GetRestrictions() CallLink_Restrictions { + if x != nil { + return x.Restrictions + } + return CallLink_UNKNOWN +} + +func (x *CallLink) GetExpirationMs() uint64 { + if x != nil { + return x.ExpirationMs + } + return 0 +} + +type AdHocCall struct { + state protoimpl.MessageState `protogen:"open.v1"` + CallId uint64 `protobuf:"varint,1,opt,name=callId,proto3" json:"callId,omitempty"` + // Refers to a `CallLink` recipient. + RecipientId uint64 `protobuf:"varint,2,opt,name=recipientId,proto3" json:"recipientId,omitempty"` + State AdHocCall_State `protobuf:"varint,3,opt,name=state,proto3,enum=signal.backup.AdHocCall_State" json:"state,omitempty"` + CallTimestamp uint64 `protobuf:"varint,4,opt,name=callTimestamp,proto3" json:"callTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdHocCall) Reset() { + *x = AdHocCall{} + mi := &file_backuppb_Backup_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdHocCall) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdHocCall) ProtoMessage() {} + +func (x *AdHocCall) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[10] + 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 AdHocCall.ProtoReflect.Descriptor instead. +func (*AdHocCall) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{10} +} + +func (x *AdHocCall) GetCallId() uint64 { + if x != nil { + return x.CallId + } + return 0 +} + +func (x *AdHocCall) GetRecipientId() uint64 { + if x != nil { + return x.RecipientId + } + return 0 +} + +func (x *AdHocCall) GetState() AdHocCall_State { + if x != nil { + return x.State + } + return AdHocCall_UNKNOWN_STATE +} + +func (x *AdHocCall) GetCallTimestamp() uint64 { + if x != nil { + return x.CallTimestamp + } + return 0 +} + +type DistributionListItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + // distribution ids are UUIDv4s. "My Story" is represented + // by an all-0 UUID (00000000-0000-0000-0000-000000000000). + DistributionId []byte `protobuf:"bytes,1,opt,name=distributionId,proto3" json:"distributionId,omitempty"` // distribution list ids are uuids + // Types that are valid to be assigned to Item: + // + // *DistributionListItem_DeletionTimestamp + // *DistributionListItem_DistributionList + Item isDistributionListItem_Item `protobuf_oneof:"item"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistributionListItem) Reset() { + *x = DistributionListItem{} + mi := &file_backuppb_Backup_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistributionListItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistributionListItem) ProtoMessage() {} + +func (x *DistributionListItem) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[11] + 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 DistributionListItem.ProtoReflect.Descriptor instead. +func (*DistributionListItem) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{11} +} + +func (x *DistributionListItem) GetDistributionId() []byte { + if x != nil { + return x.DistributionId + } + return nil +} + +func (x *DistributionListItem) GetItem() isDistributionListItem_Item { + if x != nil { + return x.Item + } + return nil +} + +func (x *DistributionListItem) GetDeletionTimestamp() uint64 { + if x != nil { + if x, ok := x.Item.(*DistributionListItem_DeletionTimestamp); ok { + return x.DeletionTimestamp + } + } + return 0 +} + +func (x *DistributionListItem) GetDistributionList() *DistributionList { + if x != nil { + if x, ok := x.Item.(*DistributionListItem_DistributionList); ok { + return x.DistributionList + } + } + return nil +} + +type isDistributionListItem_Item interface { + isDistributionListItem_Item() +} + +type DistributionListItem_DeletionTimestamp struct { + DeletionTimestamp uint64 `protobuf:"varint,2,opt,name=deletionTimestamp,proto3,oneof"` +} + +type DistributionListItem_DistributionList struct { + DistributionList *DistributionList `protobuf:"bytes,3,opt,name=distributionList,proto3,oneof"` +} + +func (*DistributionListItem_DeletionTimestamp) isDistributionListItem_Item() {} + +func (*DistributionListItem_DistributionList) isDistributionListItem_Item() {} + +type DistributionList struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + AllowReplies bool `protobuf:"varint,2,opt,name=allowReplies,proto3" json:"allowReplies,omitempty"` + PrivacyMode DistributionList_PrivacyMode `protobuf:"varint,3,opt,name=privacyMode,proto3,enum=signal.backup.DistributionList_PrivacyMode" json:"privacyMode,omitempty"` + MemberRecipientIds []uint64 `protobuf:"varint,4,rep,packed,name=memberRecipientIds,proto3" json:"memberRecipientIds,omitempty"` // generated recipient id + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DistributionList) Reset() { + *x = DistributionList{} + mi := &file_backuppb_Backup_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DistributionList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DistributionList) ProtoMessage() {} + +func (x *DistributionList) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[12] + 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 DistributionList.ProtoReflect.Descriptor instead. +func (*DistributionList) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{12} +} + +func (x *DistributionList) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DistributionList) GetAllowReplies() bool { + if x != nil { + return x.AllowReplies + } + return false +} + +func (x *DistributionList) GetPrivacyMode() DistributionList_PrivacyMode { + if x != nil { + return x.PrivacyMode + } + return DistributionList_UNKNOWN +} + +func (x *DistributionList) GetMemberRecipientIds() []uint64 { + if x != nil { + return x.MemberRecipientIds + } + return nil +} + +type ChatItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + ChatId uint64 `protobuf:"varint,1,opt,name=chatId,proto3" json:"chatId,omitempty"` // conversation id + AuthorId uint64 `protobuf:"varint,2,opt,name=authorId,proto3" json:"authorId,omitempty"` // recipient id + DateSent uint64 `protobuf:"varint,3,opt,name=dateSent,proto3" json:"dateSent,omitempty"` + ExpireStartDate *uint64 `protobuf:"varint,4,opt,name=expireStartDate,proto3,oneof" json:"expireStartDate,omitempty"` // timestamp of when expiration timer started ticking down + ExpiresInMs *uint64 `protobuf:"varint,5,opt,name=expiresInMs,proto3,oneof" json:"expiresInMs,omitempty"` // how long timer of message is (ms) + Revisions []*ChatItem `protobuf:"bytes,6,rep,name=revisions,proto3" json:"revisions,omitempty"` // ordered from oldest to newest + Sms bool `protobuf:"varint,7,opt,name=sms,proto3" json:"sms,omitempty"` + // Types that are valid to be assigned to DirectionalDetails: + // + // *ChatItem_Incoming + // *ChatItem_Outgoing + // *ChatItem_Directionless + DirectionalDetails isChatItem_DirectionalDetails `protobuf_oneof:"directionalDetails"` + // Types that are valid to be assigned to Item: + // + // *ChatItem_StandardMessage + // *ChatItem_ContactMessage + // *ChatItem_StickerMessage + // *ChatItem_RemoteDeletedMessage + // *ChatItem_UpdateMessage + // *ChatItem_PaymentNotification + // *ChatItem_GiftBadge + // *ChatItem_ViewOnceMessage + // *ChatItem_DirectStoryReplyMessage + Item isChatItem_Item `protobuf_oneof:"item"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatItem) Reset() { + *x = ChatItem{} + mi := &file_backuppb_Backup_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatItem) ProtoMessage() {} + +func (x *ChatItem) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[13] + 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 ChatItem.ProtoReflect.Descriptor instead. +func (*ChatItem) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{13} +} + +func (x *ChatItem) GetChatId() uint64 { + if x != nil { + return x.ChatId + } + return 0 +} + +func (x *ChatItem) GetAuthorId() uint64 { + if x != nil { + return x.AuthorId + } + return 0 +} + +func (x *ChatItem) GetDateSent() uint64 { + if x != nil { + return x.DateSent + } + return 0 +} + +func (x *ChatItem) GetExpireStartDate() uint64 { + if x != nil && x.ExpireStartDate != nil { + return *x.ExpireStartDate + } + return 0 +} + +func (x *ChatItem) GetExpiresInMs() uint64 { + if x != nil && x.ExpiresInMs != nil { + return *x.ExpiresInMs + } + return 0 +} + +func (x *ChatItem) GetRevisions() []*ChatItem { + if x != nil { + return x.Revisions + } + return nil +} + +func (x *ChatItem) GetSms() bool { + if x != nil { + return x.Sms + } + return false +} + +func (x *ChatItem) GetDirectionalDetails() isChatItem_DirectionalDetails { + if x != nil { + return x.DirectionalDetails + } + return nil +} + +func (x *ChatItem) GetIncoming() *ChatItem_IncomingMessageDetails { + if x != nil { + if x, ok := x.DirectionalDetails.(*ChatItem_Incoming); ok { + return x.Incoming + } + } + return nil +} + +func (x *ChatItem) GetOutgoing() *ChatItem_OutgoingMessageDetails { + if x != nil { + if x, ok := x.DirectionalDetails.(*ChatItem_Outgoing); ok { + return x.Outgoing + } + } + return nil +} + +func (x *ChatItem) GetDirectionless() *ChatItem_DirectionlessMessageDetails { + if x != nil { + if x, ok := x.DirectionalDetails.(*ChatItem_Directionless); ok { + return x.Directionless + } + } + return nil +} + +func (x *ChatItem) GetItem() isChatItem_Item { + if x != nil { + return x.Item + } + return nil +} + +func (x *ChatItem) GetStandardMessage() *StandardMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_StandardMessage); ok { + return x.StandardMessage + } + } + return nil +} + +func (x *ChatItem) GetContactMessage() *ContactMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_ContactMessage); ok { + return x.ContactMessage + } + } + return nil +} + +func (x *ChatItem) GetStickerMessage() *StickerMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_StickerMessage); ok { + return x.StickerMessage + } + } + return nil +} + +func (x *ChatItem) GetRemoteDeletedMessage() *RemoteDeletedMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_RemoteDeletedMessage); ok { + return x.RemoteDeletedMessage + } + } + return nil +} + +func (x *ChatItem) GetUpdateMessage() *ChatUpdateMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_UpdateMessage); ok { + return x.UpdateMessage + } + } + return nil +} + +func (x *ChatItem) GetPaymentNotification() *PaymentNotification { + if x != nil { + if x, ok := x.Item.(*ChatItem_PaymentNotification); ok { + return x.PaymentNotification + } + } + return nil +} + +func (x *ChatItem) GetGiftBadge() *GiftBadge { + if x != nil { + if x, ok := x.Item.(*ChatItem_GiftBadge); ok { + return x.GiftBadge + } + } + return nil +} + +func (x *ChatItem) GetViewOnceMessage() *ViewOnceMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_ViewOnceMessage); ok { + return x.ViewOnceMessage + } + } + return nil +} + +func (x *ChatItem) GetDirectStoryReplyMessage() *DirectStoryReplyMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_DirectStoryReplyMessage); ok { + return x.DirectStoryReplyMessage + } + } + return nil +} + +type isChatItem_DirectionalDetails interface { + isChatItem_DirectionalDetails() +} + +type ChatItem_Incoming struct { + Incoming *ChatItem_IncomingMessageDetails `protobuf:"bytes,8,opt,name=incoming,proto3,oneof"` +} + +type ChatItem_Outgoing struct { + Outgoing *ChatItem_OutgoingMessageDetails `protobuf:"bytes,9,opt,name=outgoing,proto3,oneof"` +} + +type ChatItem_Directionless struct { + Directionless *ChatItem_DirectionlessMessageDetails `protobuf:"bytes,10,opt,name=directionless,proto3,oneof"` +} + +func (*ChatItem_Incoming) isChatItem_DirectionalDetails() {} + +func (*ChatItem_Outgoing) isChatItem_DirectionalDetails() {} + +func (*ChatItem_Directionless) isChatItem_DirectionalDetails() {} + +type isChatItem_Item interface { + isChatItem_Item() +} + +type ChatItem_StandardMessage struct { + StandardMessage *StandardMessage `protobuf:"bytes,11,opt,name=standardMessage,proto3,oneof"` +} + +type ChatItem_ContactMessage struct { + ContactMessage *ContactMessage `protobuf:"bytes,12,opt,name=contactMessage,proto3,oneof"` +} + +type ChatItem_StickerMessage struct { + StickerMessage *StickerMessage `protobuf:"bytes,13,opt,name=stickerMessage,proto3,oneof"` +} + +type ChatItem_RemoteDeletedMessage struct { + RemoteDeletedMessage *RemoteDeletedMessage `protobuf:"bytes,14,opt,name=remoteDeletedMessage,proto3,oneof"` +} + +type ChatItem_UpdateMessage struct { + UpdateMessage *ChatUpdateMessage `protobuf:"bytes,15,opt,name=updateMessage,proto3,oneof"` +} + +type ChatItem_PaymentNotification struct { + PaymentNotification *PaymentNotification `protobuf:"bytes,16,opt,name=paymentNotification,proto3,oneof"` +} + +type ChatItem_GiftBadge struct { + GiftBadge *GiftBadge `protobuf:"bytes,17,opt,name=giftBadge,proto3,oneof"` +} + +type ChatItem_ViewOnceMessage struct { + ViewOnceMessage *ViewOnceMessage `protobuf:"bytes,18,opt,name=viewOnceMessage,proto3,oneof"` +} + +type ChatItem_DirectStoryReplyMessage struct { + DirectStoryReplyMessage *DirectStoryReplyMessage `protobuf:"bytes,19,opt,name=directStoryReplyMessage,proto3,oneof"` // group story reply messages are not backed up +} + +func (*ChatItem_StandardMessage) isChatItem_Item() {} + +func (*ChatItem_ContactMessage) isChatItem_Item() {} + +func (*ChatItem_StickerMessage) isChatItem_Item() {} + +func (*ChatItem_RemoteDeletedMessage) isChatItem_Item() {} + +func (*ChatItem_UpdateMessage) isChatItem_Item() {} + +func (*ChatItem_PaymentNotification) isChatItem_Item() {} + +func (*ChatItem_GiftBadge) isChatItem_Item() {} + +func (*ChatItem_ViewOnceMessage) isChatItem_Item() {} + +func (*ChatItem_DirectStoryReplyMessage) isChatItem_Item() {} + +type SendStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + RecipientId uint64 `protobuf:"varint,1,opt,name=recipientId,proto3" json:"recipientId,omitempty"` + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // the time the status was last updated -- if from a receipt, it should be the sentTime of the receipt + // Types that are valid to be assigned to DeliveryStatus: + // + // *SendStatus_Pending_ + // *SendStatus_Sent_ + // *SendStatus_Delivered_ + // *SendStatus_Read_ + // *SendStatus_Viewed_ + // *SendStatus_Skipped_ + // *SendStatus_Failed_ + DeliveryStatus isSendStatus_DeliveryStatus `protobuf_oneof:"deliveryStatus"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus) Reset() { + *x = SendStatus{} + mi := &file_backuppb_Backup_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus) ProtoMessage() {} + +func (x *SendStatus) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[14] + 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 SendStatus.ProtoReflect.Descriptor instead. +func (*SendStatus) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14} +} + +func (x *SendStatus) GetRecipientId() uint64 { + if x != nil { + return x.RecipientId + } + return 0 +} + +func (x *SendStatus) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *SendStatus) GetDeliveryStatus() isSendStatus_DeliveryStatus { + if x != nil { + return x.DeliveryStatus + } + return nil +} + +func (x *SendStatus) GetPending() *SendStatus_Pending { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Pending_); ok { + return x.Pending + } + } + return nil +} + +func (x *SendStatus) GetSent() *SendStatus_Sent { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Sent_); ok { + return x.Sent + } + } + return nil +} + +func (x *SendStatus) GetDelivered() *SendStatus_Delivered { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Delivered_); ok { + return x.Delivered + } + } + return nil +} + +func (x *SendStatus) GetRead() *SendStatus_Read { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Read_); ok { + return x.Read + } + } + return nil +} + +func (x *SendStatus) GetViewed() *SendStatus_Viewed { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Viewed_); ok { + return x.Viewed + } + } + return nil +} + +func (x *SendStatus) GetSkipped() *SendStatus_Skipped { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Skipped_); ok { + return x.Skipped + } + } + return nil +} + +func (x *SendStatus) GetFailed() *SendStatus_Failed { + if x != nil { + if x, ok := x.DeliveryStatus.(*SendStatus_Failed_); ok { + return x.Failed + } + } + return nil +} + +type isSendStatus_DeliveryStatus interface { + isSendStatus_DeliveryStatus() +} + +type SendStatus_Pending_ struct { + Pending *SendStatus_Pending `protobuf:"bytes,3,opt,name=pending,proto3,oneof"` +} + +type SendStatus_Sent_ struct { + Sent *SendStatus_Sent `protobuf:"bytes,4,opt,name=sent,proto3,oneof"` +} + +type SendStatus_Delivered_ struct { + Delivered *SendStatus_Delivered `protobuf:"bytes,5,opt,name=delivered,proto3,oneof"` +} + +type SendStatus_Read_ struct { + Read *SendStatus_Read `protobuf:"bytes,6,opt,name=read,proto3,oneof"` +} + +type SendStatus_Viewed_ struct { + Viewed *SendStatus_Viewed `protobuf:"bytes,7,opt,name=viewed,proto3,oneof"` +} + +type SendStatus_Skipped_ struct { + Skipped *SendStatus_Skipped `protobuf:"bytes,8,opt,name=skipped,proto3,oneof"` +} + +type SendStatus_Failed_ struct { + Failed *SendStatus_Failed `protobuf:"bytes,9,opt,name=failed,proto3,oneof"` +} + +func (*SendStatus_Pending_) isSendStatus_DeliveryStatus() {} + +func (*SendStatus_Sent_) isSendStatus_DeliveryStatus() {} + +func (*SendStatus_Delivered_) isSendStatus_DeliveryStatus() {} + +func (*SendStatus_Read_) isSendStatus_DeliveryStatus() {} + +func (*SendStatus_Viewed_) isSendStatus_DeliveryStatus() {} + +func (*SendStatus_Skipped_) isSendStatus_DeliveryStatus() {} + +func (*SendStatus_Failed_) isSendStatus_DeliveryStatus() {} + +type Text struct { + state protoimpl.MessageState `protogen:"open.v1"` + Body string `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + BodyRanges []*BodyRange `protobuf:"bytes,2,rep,name=bodyRanges,proto3" json:"bodyRanges,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Text) Reset() { + *x = Text{} + mi := &file_backuppb_Backup_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Text) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Text) ProtoMessage() {} + +func (x *Text) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[15] + 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 Text.ProtoReflect.Descriptor instead. +func (*Text) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{15} +} + +func (x *Text) GetBody() string { + if x != nil { + return x.Body + } + return "" +} + +func (x *Text) GetBodyRanges() []*BodyRange { + if x != nil { + return x.BodyRanges + } + return nil +} + +type StandardMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Quote *Quote `protobuf:"bytes,1,opt,name=quote,proto3,oneof" json:"quote,omitempty"` + Text *Text `protobuf:"bytes,2,opt,name=text,proto3,oneof" json:"text,omitempty"` + Attachments []*MessageAttachment `protobuf:"bytes,3,rep,name=attachments,proto3" json:"attachments,omitempty"` + LinkPreview []*LinkPreview `protobuf:"bytes,4,rep,name=linkPreview,proto3" json:"linkPreview,omitempty"` + LongText *FilePointer `protobuf:"bytes,5,opt,name=longText,proto3,oneof" json:"longText,omitempty"` + Reactions []*Reaction `protobuf:"bytes,6,rep,name=reactions,proto3" json:"reactions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StandardMessage) Reset() { + *x = StandardMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StandardMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StandardMessage) ProtoMessage() {} + +func (x *StandardMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[16] + 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 StandardMessage.ProtoReflect.Descriptor instead. +func (*StandardMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{16} +} + +func (x *StandardMessage) GetQuote() *Quote { + if x != nil { + return x.Quote + } + return nil +} + +func (x *StandardMessage) GetText() *Text { + if x != nil { + return x.Text + } + return nil +} + +func (x *StandardMessage) GetAttachments() []*MessageAttachment { + if x != nil { + return x.Attachments + } + return nil +} + +func (x *StandardMessage) GetLinkPreview() []*LinkPreview { + if x != nil { + return x.LinkPreview + } + return nil +} + +func (x *StandardMessage) GetLongText() *FilePointer { + if x != nil { + return x.LongText + } + return nil +} + +func (x *StandardMessage) GetReactions() []*Reaction { + if x != nil { + return x.Reactions + } + return nil +} + +type ContactMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Contact *ContactAttachment `protobuf:"bytes,1,opt,name=contact,proto3" json:"contact,omitempty"` + Reactions []*Reaction `protobuf:"bytes,2,rep,name=reactions,proto3" json:"reactions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContactMessage) Reset() { + *x = ContactMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContactMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactMessage) ProtoMessage() {} + +func (x *ContactMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[17] + 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 ContactMessage.ProtoReflect.Descriptor instead. +func (*ContactMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{17} +} + +func (x *ContactMessage) GetContact() *ContactAttachment { + if x != nil { + return x.Contact + } + return nil +} + +func (x *ContactMessage) GetReactions() []*Reaction { + if x != nil { + return x.Reactions + } + return nil +} + +type DirectStoryReplyMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Reply: + // + // *DirectStoryReplyMessage_TextReply_ + // *DirectStoryReplyMessage_Emoji + Reply isDirectStoryReplyMessage_Reply `protobuf_oneof:"reply"` + Reactions []*Reaction `protobuf:"bytes,3,rep,name=reactions,proto3" json:"reactions,omitempty"` + StorySentTimestamp *uint64 `protobuf:"varint,4,opt,name=storySentTimestamp,proto3,oneof" json:"storySentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectStoryReplyMessage) Reset() { + *x = DirectStoryReplyMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectStoryReplyMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectStoryReplyMessage) ProtoMessage() {} + +func (x *DirectStoryReplyMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[18] + 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 DirectStoryReplyMessage.ProtoReflect.Descriptor instead. +func (*DirectStoryReplyMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{18} +} + +func (x *DirectStoryReplyMessage) GetReply() isDirectStoryReplyMessage_Reply { + if x != nil { + return x.Reply + } + return nil +} + +func (x *DirectStoryReplyMessage) GetTextReply() *DirectStoryReplyMessage_TextReply { + if x != nil { + if x, ok := x.Reply.(*DirectStoryReplyMessage_TextReply_); ok { + return x.TextReply + } + } + return nil +} + +func (x *DirectStoryReplyMessage) GetEmoji() string { + if x != nil { + if x, ok := x.Reply.(*DirectStoryReplyMessage_Emoji); ok { + return x.Emoji + } + } + return "" +} + +func (x *DirectStoryReplyMessage) GetReactions() []*Reaction { + if x != nil { + return x.Reactions + } + return nil +} + +func (x *DirectStoryReplyMessage) GetStorySentTimestamp() uint64 { + if x != nil && x.StorySentTimestamp != nil { + return *x.StorySentTimestamp + } + return 0 +} + +type isDirectStoryReplyMessage_Reply interface { + isDirectStoryReplyMessage_Reply() +} + +type DirectStoryReplyMessage_TextReply_ struct { + TextReply *DirectStoryReplyMessage_TextReply `protobuf:"bytes,1,opt,name=textReply,proto3,oneof"` +} + +type DirectStoryReplyMessage_Emoji struct { + Emoji string `protobuf:"bytes,2,opt,name=emoji,proto3,oneof"` +} + +func (*DirectStoryReplyMessage_TextReply_) isDirectStoryReplyMessage_Reply() {} + +func (*DirectStoryReplyMessage_Emoji) isDirectStoryReplyMessage_Reply() {} + +type PaymentNotification struct { + state protoimpl.MessageState `protogen:"open.v1"` + AmountMob *string `protobuf:"bytes,1,opt,name=amountMob,proto3,oneof" json:"amountMob,omitempty"` // stored as a decimal string, e.g. 1.00001 + FeeMob *string `protobuf:"bytes,2,opt,name=feeMob,proto3,oneof" json:"feeMob,omitempty"` // stored as a decimal string, e.g. 1.00001 + Note *string `protobuf:"bytes,3,opt,name=note,proto3,oneof" json:"note,omitempty"` + TransactionDetails *PaymentNotification_TransactionDetails `protobuf:"bytes,4,opt,name=transactionDetails,proto3" json:"transactionDetails,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PaymentNotification) Reset() { + *x = PaymentNotification{} + mi := &file_backuppb_Backup_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PaymentNotification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentNotification) ProtoMessage() {} + +func (x *PaymentNotification) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[19] + 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 PaymentNotification.ProtoReflect.Descriptor instead. +func (*PaymentNotification) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19} +} + +func (x *PaymentNotification) GetAmountMob() string { + if x != nil && x.AmountMob != nil { + return *x.AmountMob + } + return "" +} + +func (x *PaymentNotification) GetFeeMob() string { + if x != nil && x.FeeMob != nil { + return *x.FeeMob + } + return "" +} + +func (x *PaymentNotification) GetNote() string { + if x != nil && x.Note != nil { + return *x.Note + } + return "" +} + +func (x *PaymentNotification) GetTransactionDetails() *PaymentNotification_TransactionDetails { + if x != nil { + return x.TransactionDetails + } + return nil +} + +type GiftBadge struct { + state protoimpl.MessageState `protogen:"open.v1"` + ReceiptCredentialPresentation []byte `protobuf:"bytes,1,opt,name=receiptCredentialPresentation,proto3" json:"receiptCredentialPresentation,omitempty"` + State GiftBadge_State `protobuf:"varint,2,opt,name=state,proto3,enum=signal.backup.GiftBadge_State" json:"state,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GiftBadge) Reset() { + *x = GiftBadge{} + mi := &file_backuppb_Backup_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GiftBadge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GiftBadge) ProtoMessage() {} + +func (x *GiftBadge) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[20] + 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 GiftBadge.ProtoReflect.Descriptor instead. +func (*GiftBadge) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{20} +} + +func (x *GiftBadge) GetReceiptCredentialPresentation() []byte { + if x != nil { + return x.ReceiptCredentialPresentation + } + return nil +} + +func (x *GiftBadge) GetState() GiftBadge_State { + if x != nil { + return x.State + } + return GiftBadge_UNOPENED +} + +type ViewOnceMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Will be null for viewed messages + Attachment *MessageAttachment `protobuf:"bytes,1,opt,name=attachment,proto3" json:"attachment,omitempty"` + Reactions []*Reaction `protobuf:"bytes,2,rep,name=reactions,proto3" json:"reactions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ViewOnceMessage) Reset() { + *x = ViewOnceMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ViewOnceMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ViewOnceMessage) ProtoMessage() {} + +func (x *ViewOnceMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[21] + 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 ViewOnceMessage.ProtoReflect.Descriptor instead. +func (*ViewOnceMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{21} +} + +func (x *ViewOnceMessage) GetAttachment() *MessageAttachment { + if x != nil { + return x.Attachment + } + return nil +} + +func (x *ViewOnceMessage) GetReactions() []*Reaction { + if x != nil { + return x.Reactions + } + return nil +} + +type ContactAttachment struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name *ContactAttachment_Name `protobuf:"bytes,1,opt,name=name,proto3,oneof" json:"name,omitempty"` + Number []*ContactAttachment_Phone `protobuf:"bytes,3,rep,name=number,proto3" json:"number,omitempty"` + Email []*ContactAttachment_Email `protobuf:"bytes,4,rep,name=email,proto3" json:"email,omitempty"` + Address []*ContactAttachment_PostalAddress `protobuf:"bytes,5,rep,name=address,proto3" json:"address,omitempty"` + Avatar *FilePointer `protobuf:"bytes,6,opt,name=avatar,proto3,oneof" json:"avatar,omitempty"` + Organization string `protobuf:"bytes,7,opt,name=organization,proto3" json:"organization,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContactAttachment) Reset() { + *x = ContactAttachment{} + mi := &file_backuppb_Backup_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContactAttachment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactAttachment) ProtoMessage() {} + +func (x *ContactAttachment) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[22] + 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 ContactAttachment.ProtoReflect.Descriptor instead. +func (*ContactAttachment) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22} +} + +func (x *ContactAttachment) GetName() *ContactAttachment_Name { + if x != nil { + return x.Name + } + return nil +} + +func (x *ContactAttachment) GetNumber() []*ContactAttachment_Phone { + if x != nil { + return x.Number + } + return nil +} + +func (x *ContactAttachment) GetEmail() []*ContactAttachment_Email { + if x != nil { + return x.Email + } + return nil +} + +func (x *ContactAttachment) GetAddress() []*ContactAttachment_PostalAddress { + if x != nil { + return x.Address + } + return nil +} + +func (x *ContactAttachment) GetAvatar() *FilePointer { + if x != nil { + return x.Avatar + } + return nil +} + +func (x *ContactAttachment) GetOrganization() string { + if x != nil { + return x.Organization + } + return "" +} + +type StickerMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Sticker *Sticker `protobuf:"bytes,1,opt,name=sticker,proto3" json:"sticker,omitempty"` + Reactions []*Reaction `protobuf:"bytes,2,rep,name=reactions,proto3" json:"reactions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StickerMessage) Reset() { + *x = StickerMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StickerMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StickerMessage) ProtoMessage() {} + +func (x *StickerMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[23] + 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 StickerMessage.ProtoReflect.Descriptor instead. +func (*StickerMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{23} +} + +func (x *StickerMessage) GetSticker() *Sticker { + if x != nil { + return x.Sticker + } + return nil +} + +func (x *StickerMessage) GetReactions() []*Reaction { + if x != nil { + return x.Reactions + } + return nil +} + +// Tombstone for remote delete +type RemoteDeletedMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RemoteDeletedMessage) Reset() { + *x = RemoteDeletedMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RemoteDeletedMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoteDeletedMessage) ProtoMessage() {} + +func (x *RemoteDeletedMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[24] + 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 RemoteDeletedMessage.ProtoReflect.Descriptor instead. +func (*RemoteDeletedMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{24} +} + +type Sticker struct { + state protoimpl.MessageState `protogen:"open.v1"` + PackId []byte `protobuf:"bytes,1,opt,name=packId,proto3" json:"packId,omitempty"` + PackKey []byte `protobuf:"bytes,2,opt,name=packKey,proto3" json:"packKey,omitempty"` + StickerId uint32 `protobuf:"varint,3,opt,name=stickerId,proto3" json:"stickerId,omitempty"` + Emoji *string `protobuf:"bytes,4,opt,name=emoji,proto3,oneof" json:"emoji,omitempty"` + // Stickers are uploaded to be sent as attachments; we also + // back them up as normal attachments when they are in messages. + // DO NOT treat this as the definitive source of a sticker in + // an installed StickerPack that shares the same packId. + Data *FilePointer `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Sticker) Reset() { + *x = Sticker{} + mi := &file_backuppb_Backup_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Sticker) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Sticker) ProtoMessage() {} + +func (x *Sticker) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[25] + 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 Sticker.ProtoReflect.Descriptor instead. +func (*Sticker) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{25} +} + +func (x *Sticker) GetPackId() []byte { + if x != nil { + return x.PackId + } + return nil +} + +func (x *Sticker) GetPackKey() []byte { + if x != nil { + return x.PackKey + } + return nil +} + +func (x *Sticker) GetStickerId() uint32 { + if x != nil { + return x.StickerId + } + return 0 +} + +func (x *Sticker) GetEmoji() string { + if x != nil && x.Emoji != nil { + return *x.Emoji + } + return "" +} + +func (x *Sticker) GetData() *FilePointer { + if x != nil { + return x.Data + } + return nil +} + +type LinkPreview struct { + state protoimpl.MessageState `protogen:"open.v1"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Title *string `protobuf:"bytes,2,opt,name=title,proto3,oneof" json:"title,omitempty"` + Image *FilePointer `protobuf:"bytes,3,opt,name=image,proto3,oneof" json:"image,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description,proto3,oneof" json:"description,omitempty"` + Date *uint64 `protobuf:"varint,5,opt,name=date,proto3,oneof" json:"date,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LinkPreview) Reset() { + *x = LinkPreview{} + mi := &file_backuppb_Backup_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LinkPreview) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LinkPreview) ProtoMessage() {} + +func (x *LinkPreview) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[26] + 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 LinkPreview.ProtoReflect.Descriptor instead. +func (*LinkPreview) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{26} +} + +func (x *LinkPreview) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *LinkPreview) GetTitle() string { + if x != nil && x.Title != nil { + return *x.Title + } + return "" +} + +func (x *LinkPreview) GetImage() *FilePointer { + if x != nil { + return x.Image + } + return nil +} + +func (x *LinkPreview) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +func (x *LinkPreview) GetDate() uint64 { + if x != nil && x.Date != nil { + return *x.Date + } + return 0 +} + +// A FilePointer on a message that has additional +// metadata that applies only to message attachments. +type MessageAttachment struct { + state protoimpl.MessageState `protogen:"open.v1"` + Pointer *FilePointer `protobuf:"bytes,1,opt,name=pointer,proto3" json:"pointer,omitempty"` + Flag MessageAttachment_Flag `protobuf:"varint,2,opt,name=flag,proto3,enum=signal.backup.MessageAttachment_Flag" json:"flag,omitempty"` + WasDownloaded bool `protobuf:"varint,3,opt,name=wasDownloaded,proto3" json:"wasDownloaded,omitempty"` + // Cross-client identifier for this attachment among all attachments on the + // owning message. See: SignalService.AttachmentPointer.clientUuid. + ClientUuid []byte `protobuf:"bytes,4,opt,name=clientUuid,proto3,oneof" json:"clientUuid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MessageAttachment) Reset() { + *x = MessageAttachment{} + mi := &file_backuppb_Backup_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MessageAttachment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageAttachment) ProtoMessage() {} + +func (x *MessageAttachment) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[27] + 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 MessageAttachment.ProtoReflect.Descriptor instead. +func (*MessageAttachment) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{27} +} + +func (x *MessageAttachment) GetPointer() *FilePointer { + if x != nil { + return x.Pointer + } + return nil +} + +func (x *MessageAttachment) GetFlag() MessageAttachment_Flag { + if x != nil { + return x.Flag + } + return MessageAttachment_NONE +} + +func (x *MessageAttachment) GetWasDownloaded() bool { + if x != nil { + return x.WasDownloaded + } + return false +} + +func (x *MessageAttachment) GetClientUuid() []byte { + if x != nil { + return x.ClientUuid + } + return nil +} + +type FilePointer struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Locator: + // + // *FilePointer_BackupLocator_ + // *FilePointer_AttachmentLocator_ + // *FilePointer_InvalidAttachmentLocator_ + Locator isFilePointer_Locator `protobuf_oneof:"locator"` + ContentType *string `protobuf:"bytes,4,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` + IncrementalMac []byte `protobuf:"bytes,5,opt,name=incrementalMac,proto3,oneof" json:"incrementalMac,omitempty"` + IncrementalMacChunkSize *uint32 `protobuf:"varint,6,opt,name=incrementalMacChunkSize,proto3,oneof" json:"incrementalMacChunkSize,omitempty"` + FileName *string `protobuf:"bytes,7,opt,name=fileName,proto3,oneof" json:"fileName,omitempty"` + Width *uint32 `protobuf:"varint,8,opt,name=width,proto3,oneof" json:"width,omitempty"` + Height *uint32 `protobuf:"varint,9,opt,name=height,proto3,oneof" json:"height,omitempty"` + Caption *string `protobuf:"bytes,10,opt,name=caption,proto3,oneof" json:"caption,omitempty"` + BlurHash *string `protobuf:"bytes,11,opt,name=blurHash,proto3,oneof" json:"blurHash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilePointer) Reset() { + *x = FilePointer{} + mi := &file_backuppb_Backup_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilePointer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilePointer) ProtoMessage() {} + +func (x *FilePointer) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[28] + 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 FilePointer.ProtoReflect.Descriptor instead. +func (*FilePointer) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28} +} + +func (x *FilePointer) GetLocator() isFilePointer_Locator { + if x != nil { + return x.Locator + } + return nil +} + +func (x *FilePointer) GetBackupLocator() *FilePointer_BackupLocator { + if x != nil { + if x, ok := x.Locator.(*FilePointer_BackupLocator_); ok { + return x.BackupLocator + } + } + return nil +} + +func (x *FilePointer) GetAttachmentLocator() *FilePointer_AttachmentLocator { + if x != nil { + if x, ok := x.Locator.(*FilePointer_AttachmentLocator_); ok { + return x.AttachmentLocator + } + } + return nil +} + +func (x *FilePointer) GetInvalidAttachmentLocator() *FilePointer_InvalidAttachmentLocator { + if x != nil { + if x, ok := x.Locator.(*FilePointer_InvalidAttachmentLocator_); ok { + return x.InvalidAttachmentLocator + } + } + return nil +} + +func (x *FilePointer) GetContentType() string { + if x != nil && x.ContentType != nil { + return *x.ContentType + } + return "" +} + +func (x *FilePointer) GetIncrementalMac() []byte { + if x != nil { + return x.IncrementalMac + } + return nil +} + +func (x *FilePointer) GetIncrementalMacChunkSize() uint32 { + if x != nil && x.IncrementalMacChunkSize != nil { + return *x.IncrementalMacChunkSize + } + return 0 +} + +func (x *FilePointer) GetFileName() string { + if x != nil && x.FileName != nil { + return *x.FileName + } + return "" +} + +func (x *FilePointer) GetWidth() uint32 { + if x != nil && x.Width != nil { + return *x.Width + } + return 0 +} + +func (x *FilePointer) GetHeight() uint32 { + if x != nil && x.Height != nil { + return *x.Height + } + return 0 +} + +func (x *FilePointer) GetCaption() string { + if x != nil && x.Caption != nil { + return *x.Caption + } + return "" +} + +func (x *FilePointer) GetBlurHash() string { + if x != nil && x.BlurHash != nil { + return *x.BlurHash + } + return "" +} + +type isFilePointer_Locator interface { + isFilePointer_Locator() +} + +type FilePointer_BackupLocator_ struct { + BackupLocator *FilePointer_BackupLocator `protobuf:"bytes,1,opt,name=backupLocator,proto3,oneof"` +} + +type FilePointer_AttachmentLocator_ struct { + AttachmentLocator *FilePointer_AttachmentLocator `protobuf:"bytes,2,opt,name=attachmentLocator,proto3,oneof"` +} + +type FilePointer_InvalidAttachmentLocator_ struct { + InvalidAttachmentLocator *FilePointer_InvalidAttachmentLocator `protobuf:"bytes,3,opt,name=invalidAttachmentLocator,proto3,oneof"` +} + +func (*FilePointer_BackupLocator_) isFilePointer_Locator() {} + +func (*FilePointer_AttachmentLocator_) isFilePointer_Locator() {} + +func (*FilePointer_InvalidAttachmentLocator_) isFilePointer_Locator() {} + +type Quote struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp,proto3,oneof" json:"targetSentTimestamp,omitempty"` // null if the target message could not be found at time of quote insert + AuthorId uint64 `protobuf:"varint,2,opt,name=authorId,proto3" json:"authorId,omitempty"` + Text *Text `protobuf:"bytes,3,opt,name=text,proto3,oneof" json:"text,omitempty"` + Attachments []*Quote_QuotedAttachment `protobuf:"bytes,4,rep,name=attachments,proto3" json:"attachments,omitempty"` + Type Quote_Type `protobuf:"varint,5,opt,name=type,proto3,enum=signal.backup.Quote_Type" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Quote) Reset() { + *x = Quote{} + mi := &file_backuppb_Backup_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Quote) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Quote) ProtoMessage() {} + +func (x *Quote) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[29] + 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 Quote.ProtoReflect.Descriptor instead. +func (*Quote) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{29} +} + +func (x *Quote) GetTargetSentTimestamp() uint64 { + if x != nil && x.TargetSentTimestamp != nil { + return *x.TargetSentTimestamp + } + return 0 +} + +func (x *Quote) GetAuthorId() uint64 { + if x != nil { + return x.AuthorId + } + return 0 +} + +func (x *Quote) GetText() *Text { + if x != nil { + return x.Text + } + return nil +} + +func (x *Quote) GetAttachments() []*Quote_QuotedAttachment { + if x != nil { + return x.Attachments + } + return nil +} + +func (x *Quote) GetType() Quote_Type { + if x != nil { + return x.Type + } + return Quote_UNKNOWN +} + +type BodyRange struct { + state protoimpl.MessageState `protogen:"open.v1"` + Start *uint32 `protobuf:"varint,1,opt,name=start,proto3,oneof" json:"start,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length,proto3,oneof" json:"length,omitempty"` + // Types that are valid to be assigned to AssociatedValue: + // + // *BodyRange_MentionAci + // *BodyRange_Style_ + AssociatedValue isBodyRange_AssociatedValue `protobuf_oneof:"associatedValue"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BodyRange) Reset() { + *x = BodyRange{} + mi := &file_backuppb_Backup_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BodyRange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BodyRange) ProtoMessage() {} + +func (x *BodyRange) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[30] + 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 BodyRange.ProtoReflect.Descriptor instead. +func (*BodyRange) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{30} +} + +func (x *BodyRange) GetStart() uint32 { + if x != nil && x.Start != nil { + return *x.Start + } + return 0 +} + +func (x *BodyRange) GetLength() uint32 { + if x != nil && x.Length != nil { + return *x.Length + } + return 0 +} + +func (x *BodyRange) GetAssociatedValue() isBodyRange_AssociatedValue { + if x != nil { + return x.AssociatedValue + } + return nil +} + +func (x *BodyRange) GetMentionAci() []byte { + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_MentionAci); ok { + return x.MentionAci + } + } + return nil +} + +func (x *BodyRange) GetStyle() BodyRange_Style { + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_Style_); ok { + return x.Style + } + } + return BodyRange_NONE +} + +type isBodyRange_AssociatedValue interface { + isBodyRange_AssociatedValue() +} + +type BodyRange_MentionAci struct { + MentionAci []byte `protobuf:"bytes,3,opt,name=mentionAci,proto3,oneof"` +} + +type BodyRange_Style_ struct { + Style BodyRange_Style `protobuf:"varint,4,opt,name=style,proto3,enum=signal.backup.BodyRange_Style,oneof"` +} + +func (*BodyRange_MentionAci) isBodyRange_AssociatedValue() {} + +func (*BodyRange_Style_) isBodyRange_AssociatedValue() {} + +type Reaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + Emoji string `protobuf:"bytes,1,opt,name=emoji,proto3" json:"emoji,omitempty"` + AuthorId uint64 `protobuf:"varint,2,opt,name=authorId,proto3" json:"authorId,omitempty"` + SentTimestamp uint64 `protobuf:"varint,3,opt,name=sentTimestamp,proto3" json:"sentTimestamp,omitempty"` + // A higher sort order means that a reaction is more recent. Some clients may export this as + // incrementing numbers (e.g. 1, 2, 3), others as timestamps. + SortOrder uint64 `protobuf:"varint,4,opt,name=sortOrder,proto3" json:"sortOrder,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Reaction) Reset() { + *x = Reaction{} + mi := &file_backuppb_Backup_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Reaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reaction) ProtoMessage() {} + +func (x *Reaction) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[31] + 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 Reaction.ProtoReflect.Descriptor instead. +func (*Reaction) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{31} +} + +func (x *Reaction) GetEmoji() string { + if x != nil { + return x.Emoji + } + return "" +} + +func (x *Reaction) GetAuthorId() uint64 { + if x != nil { + return x.AuthorId + } + return 0 +} + +func (x *Reaction) GetSentTimestamp() uint64 { + if x != nil { + return x.SentTimestamp + } + return 0 +} + +func (x *Reaction) GetSortOrder() uint64 { + if x != nil { + return x.SortOrder + } + return 0 +} + +type ChatUpdateMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Update: + // + // *ChatUpdateMessage_SimpleUpdate + // *ChatUpdateMessage_GroupChange + // *ChatUpdateMessage_ExpirationTimerChange + // *ChatUpdateMessage_ProfileChange + // *ChatUpdateMessage_ThreadMerge + // *ChatUpdateMessage_SessionSwitchover + // *ChatUpdateMessage_IndividualCall + // *ChatUpdateMessage_GroupCall + // *ChatUpdateMessage_LearnedProfileChange + Update isChatUpdateMessage_Update `protobuf_oneof:"update"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatUpdateMessage) Reset() { + *x = ChatUpdateMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatUpdateMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatUpdateMessage) ProtoMessage() {} + +func (x *ChatUpdateMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[32] + 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 ChatUpdateMessage.ProtoReflect.Descriptor instead. +func (*ChatUpdateMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{32} +} + +func (x *ChatUpdateMessage) GetUpdate() isChatUpdateMessage_Update { + if x != nil { + return x.Update + } + return nil +} + +func (x *ChatUpdateMessage) GetSimpleUpdate() *SimpleChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_SimpleUpdate); ok { + return x.SimpleUpdate + } + } + return nil +} + +func (x *ChatUpdateMessage) GetGroupChange() *GroupChangeChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_GroupChange); ok { + return x.GroupChange + } + } + return nil +} + +func (x *ChatUpdateMessage) GetExpirationTimerChange() *ExpirationTimerChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_ExpirationTimerChange); ok { + return x.ExpirationTimerChange + } + } + return nil +} + +func (x *ChatUpdateMessage) GetProfileChange() *ProfileChangeChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_ProfileChange); ok { + return x.ProfileChange + } + } + return nil +} + +func (x *ChatUpdateMessage) GetThreadMerge() *ThreadMergeChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_ThreadMerge); ok { + return x.ThreadMerge + } + } + return nil +} + +func (x *ChatUpdateMessage) GetSessionSwitchover() *SessionSwitchoverChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_SessionSwitchover); ok { + return x.SessionSwitchover + } + } + return nil +} + +func (x *ChatUpdateMessage) GetIndividualCall() *IndividualCall { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_IndividualCall); ok { + return x.IndividualCall + } + } + return nil +} + +func (x *ChatUpdateMessage) GetGroupCall() *GroupCall { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_GroupCall); ok { + return x.GroupCall + } + } + return nil +} + +func (x *ChatUpdateMessage) GetLearnedProfileChange() *LearnedProfileChatUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_LearnedProfileChange); ok { + return x.LearnedProfileChange + } + } + return nil +} + +type isChatUpdateMessage_Update interface { + isChatUpdateMessage_Update() +} + +type ChatUpdateMessage_SimpleUpdate struct { + SimpleUpdate *SimpleChatUpdate `protobuf:"bytes,1,opt,name=simpleUpdate,proto3,oneof"` +} + +type ChatUpdateMessage_GroupChange struct { + GroupChange *GroupChangeChatUpdate `protobuf:"bytes,2,opt,name=groupChange,proto3,oneof"` +} + +type ChatUpdateMessage_ExpirationTimerChange struct { + ExpirationTimerChange *ExpirationTimerChatUpdate `protobuf:"bytes,3,opt,name=expirationTimerChange,proto3,oneof"` +} + +type ChatUpdateMessage_ProfileChange struct { + ProfileChange *ProfileChangeChatUpdate `protobuf:"bytes,4,opt,name=profileChange,proto3,oneof"` +} + +type ChatUpdateMessage_ThreadMerge struct { + ThreadMerge *ThreadMergeChatUpdate `protobuf:"bytes,5,opt,name=threadMerge,proto3,oneof"` +} + +type ChatUpdateMessage_SessionSwitchover struct { + SessionSwitchover *SessionSwitchoverChatUpdate `protobuf:"bytes,6,opt,name=sessionSwitchover,proto3,oneof"` +} + +type ChatUpdateMessage_IndividualCall struct { + IndividualCall *IndividualCall `protobuf:"bytes,7,opt,name=individualCall,proto3,oneof"` +} + +type ChatUpdateMessage_GroupCall struct { + GroupCall *GroupCall `protobuf:"bytes,8,opt,name=groupCall,proto3,oneof"` +} + +type ChatUpdateMessage_LearnedProfileChange struct { + LearnedProfileChange *LearnedProfileChatUpdate `protobuf:"bytes,9,opt,name=learnedProfileChange,proto3,oneof"` +} + +func (*ChatUpdateMessage_SimpleUpdate) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_GroupChange) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_ExpirationTimerChange) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_ProfileChange) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_ThreadMerge) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_SessionSwitchover) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_IndividualCall) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_GroupCall) isChatUpdateMessage_Update() {} + +func (*ChatUpdateMessage_LearnedProfileChange) isChatUpdateMessage_Update() {} + +type IndividualCall struct { + state protoimpl.MessageState `protogen:"open.v1"` + CallId *uint64 `protobuf:"varint,1,opt,name=callId,proto3,oneof" json:"callId,omitempty"` + Type IndividualCall_Type `protobuf:"varint,2,opt,name=type,proto3,enum=signal.backup.IndividualCall_Type" json:"type,omitempty"` + Direction IndividualCall_Direction `protobuf:"varint,3,opt,name=direction,proto3,enum=signal.backup.IndividualCall_Direction" json:"direction,omitempty"` + State IndividualCall_State `protobuf:"varint,4,opt,name=state,proto3,enum=signal.backup.IndividualCall_State" json:"state,omitempty"` + StartedCallTimestamp uint64 `protobuf:"varint,5,opt,name=startedCallTimestamp,proto3" json:"startedCallTimestamp,omitempty"` + Read bool `protobuf:"varint,6,opt,name=read,proto3" json:"read,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IndividualCall) Reset() { + *x = IndividualCall{} + mi := &file_backuppb_Backup_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IndividualCall) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IndividualCall) ProtoMessage() {} + +func (x *IndividualCall) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[33] + 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 IndividualCall.ProtoReflect.Descriptor instead. +func (*IndividualCall) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{33} +} + +func (x *IndividualCall) GetCallId() uint64 { + if x != nil && x.CallId != nil { + return *x.CallId + } + return 0 +} + +func (x *IndividualCall) GetType() IndividualCall_Type { + if x != nil { + return x.Type + } + return IndividualCall_UNKNOWN_TYPE +} + +func (x *IndividualCall) GetDirection() IndividualCall_Direction { + if x != nil { + return x.Direction + } + return IndividualCall_UNKNOWN_DIRECTION +} + +func (x *IndividualCall) GetState() IndividualCall_State { + if x != nil { + return x.State + } + return IndividualCall_UNKNOWN_STATE +} + +func (x *IndividualCall) GetStartedCallTimestamp() uint64 { + if x != nil { + return x.StartedCallTimestamp + } + return 0 +} + +func (x *IndividualCall) GetRead() bool { + if x != nil { + return x.Read + } + return false +} + +type GroupCall struct { + state protoimpl.MessageState `protogen:"open.v1"` + CallId *uint64 `protobuf:"varint,1,opt,name=callId,proto3,oneof" json:"callId,omitempty"` + State GroupCall_State `protobuf:"varint,2,opt,name=state,proto3,enum=signal.backup.GroupCall_State" json:"state,omitempty"` + RingerRecipientId *uint64 `protobuf:"varint,3,opt,name=ringerRecipientId,proto3,oneof" json:"ringerRecipientId,omitempty"` + StartedCallRecipientId *uint64 `protobuf:"varint,4,opt,name=startedCallRecipientId,proto3,oneof" json:"startedCallRecipientId,omitempty"` + StartedCallTimestamp uint64 `protobuf:"varint,5,opt,name=startedCallTimestamp,proto3" json:"startedCallTimestamp,omitempty"` + EndedCallTimestamp *uint64 `protobuf:"varint,6,opt,name=endedCallTimestamp,proto3,oneof" json:"endedCallTimestamp,omitempty"` // The time the call ended. + Read bool `protobuf:"varint,7,opt,name=read,proto3" json:"read,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupCall) Reset() { + *x = GroupCall{} + mi := &file_backuppb_Backup_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupCall) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupCall) ProtoMessage() {} + +func (x *GroupCall) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[34] + 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 GroupCall.ProtoReflect.Descriptor instead. +func (*GroupCall) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34} +} + +func (x *GroupCall) GetCallId() uint64 { + if x != nil && x.CallId != nil { + return *x.CallId + } + return 0 +} + +func (x *GroupCall) GetState() GroupCall_State { + if x != nil { + return x.State + } + return GroupCall_UNKNOWN_STATE +} + +func (x *GroupCall) GetRingerRecipientId() uint64 { + if x != nil && x.RingerRecipientId != nil { + return *x.RingerRecipientId + } + return 0 +} + +func (x *GroupCall) GetStartedCallRecipientId() uint64 { + if x != nil && x.StartedCallRecipientId != nil { + return *x.StartedCallRecipientId + } + return 0 +} + +func (x *GroupCall) GetStartedCallTimestamp() uint64 { + if x != nil { + return x.StartedCallTimestamp + } + return 0 +} + +func (x *GroupCall) GetEndedCallTimestamp() uint64 { + if x != nil && x.EndedCallTimestamp != nil { + return *x.EndedCallTimestamp + } + return 0 +} + +func (x *GroupCall) GetRead() bool { + if x != nil { + return x.Read + } + return false +} + +type SimpleChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type SimpleChatUpdate_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signal.backup.SimpleChatUpdate_Type" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SimpleChatUpdate) Reset() { + *x = SimpleChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SimpleChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleChatUpdate) ProtoMessage() {} + +func (x *SimpleChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[35] + 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 SimpleChatUpdate.ProtoReflect.Descriptor instead. +func (*SimpleChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35} +} + +func (x *SimpleChatUpdate) GetType() SimpleChatUpdate_Type { + if x != nil { + return x.Type + } + return SimpleChatUpdate_UNKNOWN +} + +// For 1:1 chat updates only. +// For group thread updates use GroupExpirationTimerUpdate. +type ExpirationTimerChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + ExpiresInMs uint64 `protobuf:"varint,1,opt,name=expiresInMs,proto3" json:"expiresInMs,omitempty"` // 0 means the expiration timer was disabled + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExpirationTimerChatUpdate) Reset() { + *x = ExpirationTimerChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExpirationTimerChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExpirationTimerChatUpdate) ProtoMessage() {} + +func (x *ExpirationTimerChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[36] + 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 ExpirationTimerChatUpdate.ProtoReflect.Descriptor instead. +func (*ExpirationTimerChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{36} +} + +func (x *ExpirationTimerChatUpdate) GetExpiresInMs() uint64 { + if x != nil { + return x.ExpiresInMs + } + return 0 +} + +type ProfileChangeChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + PreviousName string `protobuf:"bytes,1,opt,name=previousName,proto3" json:"previousName,omitempty"` + NewName string `protobuf:"bytes,2,opt,name=newName,proto3" json:"newName,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProfileChangeChatUpdate) Reset() { + *x = ProfileChangeChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProfileChangeChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProfileChangeChatUpdate) ProtoMessage() {} + +func (x *ProfileChangeChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[37] + 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 ProfileChangeChatUpdate.ProtoReflect.Descriptor instead. +func (*ProfileChangeChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{37} +} + +func (x *ProfileChangeChatUpdate) GetPreviousName() string { + if x != nil { + return x.PreviousName + } + return "" +} + +func (x *ProfileChangeChatUpdate) GetNewName() string { + if x != nil { + return x.NewName + } + return "" +} + +type LearnedProfileChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to PreviousName: + // + // *LearnedProfileChatUpdate_E164 + // *LearnedProfileChatUpdate_Username + PreviousName isLearnedProfileChatUpdate_PreviousName `protobuf_oneof:"previousName"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LearnedProfileChatUpdate) Reset() { + *x = LearnedProfileChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LearnedProfileChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LearnedProfileChatUpdate) ProtoMessage() {} + +func (x *LearnedProfileChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LearnedProfileChatUpdate.ProtoReflect.Descriptor instead. +func (*LearnedProfileChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{38} +} + +func (x *LearnedProfileChatUpdate) GetPreviousName() isLearnedProfileChatUpdate_PreviousName { + if x != nil { + return x.PreviousName + } + return nil +} + +func (x *LearnedProfileChatUpdate) GetE164() uint64 { + if x != nil { + if x, ok := x.PreviousName.(*LearnedProfileChatUpdate_E164); ok { + return x.E164 + } + } + return 0 +} + +func (x *LearnedProfileChatUpdate) GetUsername() string { + if x != nil { + if x, ok := x.PreviousName.(*LearnedProfileChatUpdate_Username); ok { + return x.Username + } + } + return "" +} + +type isLearnedProfileChatUpdate_PreviousName interface { + isLearnedProfileChatUpdate_PreviousName() +} + +type LearnedProfileChatUpdate_E164 struct { + E164 uint64 `protobuf:"varint,1,opt,name=e164,proto3,oneof"` +} + +type LearnedProfileChatUpdate_Username struct { + Username string `protobuf:"bytes,2,opt,name=username,proto3,oneof"` +} + +func (*LearnedProfileChatUpdate_E164) isLearnedProfileChatUpdate_PreviousName() {} + +func (*LearnedProfileChatUpdate_Username) isLearnedProfileChatUpdate_PreviousName() {} + +type ThreadMergeChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + PreviousE164 uint64 `protobuf:"varint,1,opt,name=previousE164,proto3" json:"previousE164,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ThreadMergeChatUpdate) Reset() { + *x = ThreadMergeChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ThreadMergeChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ThreadMergeChatUpdate) ProtoMessage() {} + +func (x *ThreadMergeChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[39] + 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 ThreadMergeChatUpdate.ProtoReflect.Descriptor instead. +func (*ThreadMergeChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{39} +} + +func (x *ThreadMergeChatUpdate) GetPreviousE164() uint64 { + if x != nil { + return x.PreviousE164 + } + return 0 +} + +type SessionSwitchoverChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + E164 uint64 `protobuf:"varint,1,opt,name=e164,proto3" json:"e164,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SessionSwitchoverChatUpdate) Reset() { + *x = SessionSwitchoverChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SessionSwitchoverChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionSwitchoverChatUpdate) ProtoMessage() {} + +func (x *SessionSwitchoverChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[40] + 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 SessionSwitchoverChatUpdate.ProtoReflect.Descriptor instead. +func (*SessionSwitchoverChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{40} +} + +func (x *SessionSwitchoverChatUpdate) GetE164() uint64 { + if x != nil { + return x.E164 + } + return 0 +} + +type GroupChangeChatUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Must be one or more; all updates batched together came from + // a single batched group state update. + Updates []*GroupChangeChatUpdate_Update `protobuf:"bytes,1,rep,name=updates,proto3" json:"updates,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChangeChatUpdate) Reset() { + *x = GroupChangeChatUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChangeChatUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChangeChatUpdate) ProtoMessage() {} + +func (x *GroupChangeChatUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupChangeChatUpdate.ProtoReflect.Descriptor instead. +func (*GroupChangeChatUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{41} +} + +func (x *GroupChangeChatUpdate) GetUpdates() []*GroupChangeChatUpdate_Update { + if x != nil { + return x.Updates + } + return nil +} + +type GenericGroupUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenericGroupUpdate) Reset() { + *x = GenericGroupUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenericGroupUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenericGroupUpdate) ProtoMessage() {} + +func (x *GenericGroupUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[42] + 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 GenericGroupUpdate.ProtoReflect.Descriptor instead. +func (*GenericGroupUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{42} +} + +func (x *GenericGroupUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +type GroupCreationUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupCreationUpdate) Reset() { + *x = GroupCreationUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupCreationUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupCreationUpdate) ProtoMessage() {} + +func (x *GroupCreationUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[43] + 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 GroupCreationUpdate.ProtoReflect.Descriptor instead. +func (*GroupCreationUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{43} +} + +func (x *GroupCreationUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +type GroupNameUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + // Null value means the group name was removed. + NewGroupName *string `protobuf:"bytes,2,opt,name=newGroupName,proto3,oneof" json:"newGroupName,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupNameUpdate) Reset() { + *x = GroupNameUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupNameUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupNameUpdate) ProtoMessage() {} + +func (x *GroupNameUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[44] + 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 GroupNameUpdate.ProtoReflect.Descriptor instead. +func (*GroupNameUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{44} +} + +func (x *GroupNameUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupNameUpdate) GetNewGroupName() string { + if x != nil && x.NewGroupName != nil { + return *x.NewGroupName + } + return "" +} + +type GroupAvatarUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + WasRemoved bool `protobuf:"varint,2,opt,name=wasRemoved,proto3" json:"wasRemoved,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupAvatarUpdate) Reset() { + *x = GroupAvatarUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupAvatarUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupAvatarUpdate) ProtoMessage() {} + +func (x *GroupAvatarUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[45] + 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 GroupAvatarUpdate.ProtoReflect.Descriptor instead. +func (*GroupAvatarUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{45} +} + +func (x *GroupAvatarUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupAvatarUpdate) GetWasRemoved() bool { + if x != nil { + return x.WasRemoved + } + return false +} + +type GroupDescriptionUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + // Null value means the group description was removed. + NewDescription *string `protobuf:"bytes,2,opt,name=newDescription,proto3,oneof" json:"newDescription,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupDescriptionUpdate) Reset() { + *x = GroupDescriptionUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupDescriptionUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupDescriptionUpdate) ProtoMessage() {} + +func (x *GroupDescriptionUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[46] + 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 GroupDescriptionUpdate.ProtoReflect.Descriptor instead. +func (*GroupDescriptionUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{46} +} + +func (x *GroupDescriptionUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupDescriptionUpdate) GetNewDescription() string { + if x != nil && x.NewDescription != nil { + return *x.NewDescription + } + return "" +} + +type GroupMembershipAccessLevelChangeUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + AccessLevel GroupV2AccessLevel `protobuf:"varint,2,opt,name=accessLevel,proto3,enum=signal.backup.GroupV2AccessLevel" json:"accessLevel,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMembershipAccessLevelChangeUpdate) Reset() { + *x = GroupMembershipAccessLevelChangeUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMembershipAccessLevelChangeUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMembershipAccessLevelChangeUpdate) ProtoMessage() {} + +func (x *GroupMembershipAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[47] + 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 GroupMembershipAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. +func (*GroupMembershipAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{47} +} + +func (x *GroupMembershipAccessLevelChangeUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupMembershipAccessLevelChangeUpdate) GetAccessLevel() GroupV2AccessLevel { + if x != nil { + return x.AccessLevel + } + return GroupV2AccessLevel_UNKNOWN +} + +type GroupAttributesAccessLevelChangeUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + AccessLevel GroupV2AccessLevel `protobuf:"varint,2,opt,name=accessLevel,proto3,enum=signal.backup.GroupV2AccessLevel" json:"accessLevel,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupAttributesAccessLevelChangeUpdate) Reset() { + *x = GroupAttributesAccessLevelChangeUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupAttributesAccessLevelChangeUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupAttributesAccessLevelChangeUpdate) ProtoMessage() {} + +func (x *GroupAttributesAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[48] + 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 GroupAttributesAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. +func (*GroupAttributesAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{48} +} + +func (x *GroupAttributesAccessLevelChangeUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupAttributesAccessLevelChangeUpdate) GetAccessLevel() GroupV2AccessLevel { + if x != nil { + return x.AccessLevel + } + return GroupV2AccessLevel_UNKNOWN +} + +type GroupAnnouncementOnlyChangeUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + IsAnnouncementOnly bool `protobuf:"varint,2,opt,name=isAnnouncementOnly,proto3" json:"isAnnouncementOnly,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupAnnouncementOnlyChangeUpdate) Reset() { + *x = GroupAnnouncementOnlyChangeUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupAnnouncementOnlyChangeUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupAnnouncementOnlyChangeUpdate) ProtoMessage() {} + +func (x *GroupAnnouncementOnlyChangeUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[49] + 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 GroupAnnouncementOnlyChangeUpdate.ProtoReflect.Descriptor instead. +func (*GroupAnnouncementOnlyChangeUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{49} +} + +func (x *GroupAnnouncementOnlyChangeUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupAnnouncementOnlyChangeUpdate) GetIsAnnouncementOnly() bool { + if x != nil { + return x.IsAnnouncementOnly + } + return false +} + +type GroupAdminStatusUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + // The aci who had admin status granted or revoked. + MemberAci []byte `protobuf:"bytes,2,opt,name=memberAci,proto3" json:"memberAci,omitempty"` + WasAdminStatusGranted bool `protobuf:"varint,3,opt,name=wasAdminStatusGranted,proto3" json:"wasAdminStatusGranted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupAdminStatusUpdate) Reset() { + *x = GroupAdminStatusUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupAdminStatusUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupAdminStatusUpdate) ProtoMessage() {} + +func (x *GroupAdminStatusUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[50] + 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 GroupAdminStatusUpdate.ProtoReflect.Descriptor instead. +func (*GroupAdminStatusUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{50} +} + +func (x *GroupAdminStatusUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupAdminStatusUpdate) GetMemberAci() []byte { + if x != nil { + return x.MemberAci + } + return nil +} + +func (x *GroupAdminStatusUpdate) GetWasAdminStatusGranted() bool { + if x != nil { + return x.WasAdminStatusGranted + } + return false +} + +type GroupMemberLeftUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Aci []byte `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMemberLeftUpdate) Reset() { + *x = GroupMemberLeftUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMemberLeftUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberLeftUpdate) ProtoMessage() {} + +func (x *GroupMemberLeftUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[51] + 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 GroupMemberLeftUpdate.ProtoReflect.Descriptor instead. +func (*GroupMemberLeftUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{51} +} + +func (x *GroupMemberLeftUpdate) GetAci() []byte { + if x != nil { + return x.Aci + } + return nil +} + +type GroupMemberRemovedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + RemoverAci []byte `protobuf:"bytes,1,opt,name=removerAci,proto3,oneof" json:"removerAci,omitempty"` + RemovedAci []byte `protobuf:"bytes,2,opt,name=removedAci,proto3" json:"removedAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMemberRemovedUpdate) Reset() { + *x = GroupMemberRemovedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMemberRemovedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberRemovedUpdate) ProtoMessage() {} + +func (x *GroupMemberRemovedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[52] + 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 GroupMemberRemovedUpdate.ProtoReflect.Descriptor instead. +func (*GroupMemberRemovedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{52} +} + +func (x *GroupMemberRemovedUpdate) GetRemoverAci() []byte { + if x != nil { + return x.RemoverAci + } + return nil +} + +func (x *GroupMemberRemovedUpdate) GetRemovedAci() []byte { + if x != nil { + return x.RemovedAci + } + return nil +} + +type SelfInvitedToGroupUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + InviterAci []byte `protobuf:"bytes,1,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SelfInvitedToGroupUpdate) Reset() { + *x = SelfInvitedToGroupUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SelfInvitedToGroupUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelfInvitedToGroupUpdate) ProtoMessage() {} + +func (x *SelfInvitedToGroupUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[53] + 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 SelfInvitedToGroupUpdate.ProtoReflect.Descriptor instead. +func (*SelfInvitedToGroupUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{53} +} + +func (x *SelfInvitedToGroupUpdate) GetInviterAci() []byte { + if x != nil { + return x.InviterAci + } + return nil +} + +type SelfInvitedOtherUserToGroupUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // If no invitee id available, use GroupUnknownInviteeUpdate + InviteeServiceId []byte `protobuf:"bytes,1,opt,name=inviteeServiceId,proto3" json:"inviteeServiceId,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SelfInvitedOtherUserToGroupUpdate) Reset() { + *x = SelfInvitedOtherUserToGroupUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SelfInvitedOtherUserToGroupUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelfInvitedOtherUserToGroupUpdate) ProtoMessage() {} + +func (x *SelfInvitedOtherUserToGroupUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[54] + 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 SelfInvitedOtherUserToGroupUpdate.ProtoReflect.Descriptor instead. +func (*SelfInvitedOtherUserToGroupUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{54} +} + +func (x *SelfInvitedOtherUserToGroupUpdate) GetInviteeServiceId() []byte { + if x != nil { + return x.InviteeServiceId + } + return nil +} + +type GroupUnknownInviteeUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Can be the self user. + InviterAci []byte `protobuf:"bytes,1,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` + InviteeCount uint32 `protobuf:"varint,2,opt,name=inviteeCount,proto3" json:"inviteeCount,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupUnknownInviteeUpdate) Reset() { + *x = GroupUnknownInviteeUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupUnknownInviteeUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupUnknownInviteeUpdate) ProtoMessage() {} + +func (x *GroupUnknownInviteeUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[55] + 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 GroupUnknownInviteeUpdate.ProtoReflect.Descriptor instead. +func (*GroupUnknownInviteeUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{55} +} + +func (x *GroupUnknownInviteeUpdate) GetInviterAci() []byte { + if x != nil { + return x.InviterAci + } + return nil +} + +func (x *GroupUnknownInviteeUpdate) GetInviteeCount() uint32 { + if x != nil { + return x.InviteeCount + } + return 0 +} + +type GroupInvitationAcceptedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + InviterAci []byte `protobuf:"bytes,1,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` + NewMemberAci []byte `protobuf:"bytes,2,opt,name=newMemberAci,proto3" json:"newMemberAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInvitationAcceptedUpdate) Reset() { + *x = GroupInvitationAcceptedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInvitationAcceptedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInvitationAcceptedUpdate) ProtoMessage() {} + +func (x *GroupInvitationAcceptedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[56] + 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 GroupInvitationAcceptedUpdate.ProtoReflect.Descriptor instead. +func (*GroupInvitationAcceptedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{56} +} + +func (x *GroupInvitationAcceptedUpdate) GetInviterAci() []byte { + if x != nil { + return x.InviterAci + } + return nil +} + +func (x *GroupInvitationAcceptedUpdate) GetNewMemberAci() []byte { + if x != nil { + return x.NewMemberAci + } + return nil +} + +type GroupInvitationDeclinedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + InviterAci []byte `protobuf:"bytes,1,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` + // Note: if invited by pni, just set inviteeAci to nil. + InviteeAci []byte `protobuf:"bytes,2,opt,name=inviteeAci,proto3,oneof" json:"inviteeAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInvitationDeclinedUpdate) Reset() { + *x = GroupInvitationDeclinedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInvitationDeclinedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInvitationDeclinedUpdate) ProtoMessage() {} + +func (x *GroupInvitationDeclinedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[57] + 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 GroupInvitationDeclinedUpdate.ProtoReflect.Descriptor instead. +func (*GroupInvitationDeclinedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{57} +} + +func (x *GroupInvitationDeclinedUpdate) GetInviterAci() []byte { + if x != nil { + return x.InviterAci + } + return nil +} + +func (x *GroupInvitationDeclinedUpdate) GetInviteeAci() []byte { + if x != nil { + return x.InviteeAci + } + return nil +} + +type GroupMemberJoinedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + NewMemberAci []byte `protobuf:"bytes,1,opt,name=newMemberAci,proto3" json:"newMemberAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMemberJoinedUpdate) Reset() { + *x = GroupMemberJoinedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMemberJoinedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberJoinedUpdate) ProtoMessage() {} + +func (x *GroupMemberJoinedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[58] + 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 GroupMemberJoinedUpdate.ProtoReflect.Descriptor instead. +func (*GroupMemberJoinedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{58} +} + +func (x *GroupMemberJoinedUpdate) GetNewMemberAci() []byte { + if x != nil { + return x.NewMemberAci + } + return nil +} + +type GroupMemberAddedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + NewMemberAci []byte `protobuf:"bytes,2,opt,name=newMemberAci,proto3" json:"newMemberAci,omitempty"` + HadOpenInvitation bool `protobuf:"varint,3,opt,name=hadOpenInvitation,proto3" json:"hadOpenInvitation,omitempty"` + // If hadOpenInvitation is true, optionally include aci of the inviter. + InviterAci []byte `protobuf:"bytes,4,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMemberAddedUpdate) Reset() { + *x = GroupMemberAddedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMemberAddedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberAddedUpdate) ProtoMessage() {} + +func (x *GroupMemberAddedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[59] + 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 GroupMemberAddedUpdate.ProtoReflect.Descriptor instead. +func (*GroupMemberAddedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{59} +} + +func (x *GroupMemberAddedUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupMemberAddedUpdate) GetNewMemberAci() []byte { + if x != nil { + return x.NewMemberAci + } + return nil +} + +func (x *GroupMemberAddedUpdate) GetHadOpenInvitation() bool { + if x != nil { + return x.HadOpenInvitation + } + return false +} + +func (x *GroupMemberAddedUpdate) GetInviterAci() []byte { + if x != nil { + return x.InviterAci + } + return nil +} + +// An invitation to self was revoked. +type GroupSelfInvitationRevokedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + RevokerAci []byte `protobuf:"bytes,1,opt,name=revokerAci,proto3,oneof" json:"revokerAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupSelfInvitationRevokedUpdate) Reset() { + *x = GroupSelfInvitationRevokedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupSelfInvitationRevokedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupSelfInvitationRevokedUpdate) ProtoMessage() {} + +func (x *GroupSelfInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[60] + 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 GroupSelfInvitationRevokedUpdate.ProtoReflect.Descriptor instead. +func (*GroupSelfInvitationRevokedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{60} +} + +func (x *GroupSelfInvitationRevokedUpdate) GetRevokerAci() []byte { + if x != nil { + return x.RevokerAci + } + return nil +} + +// These invitees should never be the local user. +// Use GroupSelfInvitationRevokedUpdate in those cases. +// The inviter or updater can be the local user. +type GroupInvitationRevokedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The member that revoked the invite(s), not the inviter! + // Assumed to be an admin (at the time, may no longer be an + // admin or even a member). + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + Invitees []*GroupInvitationRevokedUpdate_Invitee `protobuf:"bytes,2,rep,name=invitees,proto3" json:"invitees,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInvitationRevokedUpdate) Reset() { + *x = GroupInvitationRevokedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInvitationRevokedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInvitationRevokedUpdate) ProtoMessage() {} + +func (x *GroupInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[61] + 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 GroupInvitationRevokedUpdate.ProtoReflect.Descriptor instead. +func (*GroupInvitationRevokedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{61} +} + +func (x *GroupInvitationRevokedUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupInvitationRevokedUpdate) GetInvitees() []*GroupInvitationRevokedUpdate_Invitee { + if x != nil { + return x.Invitees + } + return nil +} + +type GroupJoinRequestUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + RequestorAci []byte `protobuf:"bytes,1,opt,name=requestorAci,proto3" json:"requestorAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupJoinRequestUpdate) Reset() { + *x = GroupJoinRequestUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupJoinRequestUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupJoinRequestUpdate) ProtoMessage() {} + +func (x *GroupJoinRequestUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[62] + 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 GroupJoinRequestUpdate.ProtoReflect.Descriptor instead. +func (*GroupJoinRequestUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{62} +} + +func (x *GroupJoinRequestUpdate) GetRequestorAci() []byte { + if x != nil { + return x.RequestorAci + } + return nil +} + +type GroupJoinRequestApprovalUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + RequestorAci []byte `protobuf:"bytes,1,opt,name=requestorAci,proto3" json:"requestorAci,omitempty"` + // The aci that approved or rejected the request. + UpdaterAci []byte `protobuf:"bytes,2,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + WasApproved bool `protobuf:"varint,3,opt,name=wasApproved,proto3" json:"wasApproved,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupJoinRequestApprovalUpdate) Reset() { + *x = GroupJoinRequestApprovalUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupJoinRequestApprovalUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupJoinRequestApprovalUpdate) ProtoMessage() {} + +func (x *GroupJoinRequestApprovalUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[63] + 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 GroupJoinRequestApprovalUpdate.ProtoReflect.Descriptor instead. +func (*GroupJoinRequestApprovalUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{63} +} + +func (x *GroupJoinRequestApprovalUpdate) GetRequestorAci() []byte { + if x != nil { + return x.RequestorAci + } + return nil +} + +func (x *GroupJoinRequestApprovalUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupJoinRequestApprovalUpdate) GetWasApproved() bool { + if x != nil { + return x.WasApproved + } + return false +} + +type GroupJoinRequestCanceledUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + RequestorAci []byte `protobuf:"bytes,1,opt,name=requestorAci,proto3" json:"requestorAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupJoinRequestCanceledUpdate) Reset() { + *x = GroupJoinRequestCanceledUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupJoinRequestCanceledUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupJoinRequestCanceledUpdate) ProtoMessage() {} + +func (x *GroupJoinRequestCanceledUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[64] + 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 GroupJoinRequestCanceledUpdate.ProtoReflect.Descriptor instead. +func (*GroupJoinRequestCanceledUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{64} +} + +func (x *GroupJoinRequestCanceledUpdate) GetRequestorAci() []byte { + if x != nil { + return x.RequestorAci + } + return nil +} + +// A single requestor has requested to join and cancelled +// their request repeatedly with no other updates in between. +// The last action encompassed by this update is always a +// cancellation; if there was another open request immediately +// after, it will be a separate GroupJoinRequestUpdate, either +// in the same frame or in a subsequent frame. +type GroupSequenceOfRequestsAndCancelsUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + RequestorAci []byte `protobuf:"bytes,1,opt,name=requestorAci,proto3" json:"requestorAci,omitempty"` + Count uint32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupSequenceOfRequestsAndCancelsUpdate) Reset() { + *x = GroupSequenceOfRequestsAndCancelsUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupSequenceOfRequestsAndCancelsUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupSequenceOfRequestsAndCancelsUpdate) ProtoMessage() {} + +func (x *GroupSequenceOfRequestsAndCancelsUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[65] + 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 GroupSequenceOfRequestsAndCancelsUpdate.ProtoReflect.Descriptor instead. +func (*GroupSequenceOfRequestsAndCancelsUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{65} +} + +func (x *GroupSequenceOfRequestsAndCancelsUpdate) GetRequestorAci() []byte { + if x != nil { + return x.RequestorAci + } + return nil +} + +func (x *GroupSequenceOfRequestsAndCancelsUpdate) GetCount() uint32 { + if x != nil { + return x.Count + } + return 0 +} + +type GroupInviteLinkResetUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInviteLinkResetUpdate) Reset() { + *x = GroupInviteLinkResetUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInviteLinkResetUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInviteLinkResetUpdate) ProtoMessage() {} + +func (x *GroupInviteLinkResetUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[66] + 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 GroupInviteLinkResetUpdate.ProtoReflect.Descriptor instead. +func (*GroupInviteLinkResetUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{66} +} + +func (x *GroupInviteLinkResetUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +type GroupInviteLinkEnabledUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + LinkRequiresAdminApproval bool `protobuf:"varint,2,opt,name=linkRequiresAdminApproval,proto3" json:"linkRequiresAdminApproval,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInviteLinkEnabledUpdate) Reset() { + *x = GroupInviteLinkEnabledUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInviteLinkEnabledUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInviteLinkEnabledUpdate) ProtoMessage() {} + +func (x *GroupInviteLinkEnabledUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[67] + 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 GroupInviteLinkEnabledUpdate.ProtoReflect.Descriptor instead. +func (*GroupInviteLinkEnabledUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{67} +} + +func (x *GroupInviteLinkEnabledUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupInviteLinkEnabledUpdate) GetLinkRequiresAdminApproval() bool { + if x != nil { + return x.LinkRequiresAdminApproval + } + return false +} + +type GroupInviteLinkAdminApprovalUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + LinkRequiresAdminApproval bool `protobuf:"varint,2,opt,name=linkRequiresAdminApproval,proto3" json:"linkRequiresAdminApproval,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInviteLinkAdminApprovalUpdate) Reset() { + *x = GroupInviteLinkAdminApprovalUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInviteLinkAdminApprovalUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInviteLinkAdminApprovalUpdate) ProtoMessage() {} + +func (x *GroupInviteLinkAdminApprovalUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[68] + 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 GroupInviteLinkAdminApprovalUpdate.ProtoReflect.Descriptor instead. +func (*GroupInviteLinkAdminApprovalUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{68} +} + +func (x *GroupInviteLinkAdminApprovalUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupInviteLinkAdminApprovalUpdate) GetLinkRequiresAdminApproval() bool { + if x != nil { + return x.LinkRequiresAdminApproval + } + return false +} + +type GroupInviteLinkDisabledUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInviteLinkDisabledUpdate) Reset() { + *x = GroupInviteLinkDisabledUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInviteLinkDisabledUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInviteLinkDisabledUpdate) ProtoMessage() {} + +func (x *GroupInviteLinkDisabledUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[69] + 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 GroupInviteLinkDisabledUpdate.ProtoReflect.Descriptor instead. +func (*GroupInviteLinkDisabledUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{69} +} + +func (x *GroupInviteLinkDisabledUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +type GroupMemberJoinedByLinkUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + NewMemberAci []byte `protobuf:"bytes,1,opt,name=newMemberAci,proto3" json:"newMemberAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMemberJoinedByLinkUpdate) Reset() { + *x = GroupMemberJoinedByLinkUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMemberJoinedByLinkUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberJoinedByLinkUpdate) ProtoMessage() {} + +func (x *GroupMemberJoinedByLinkUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[70] + 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 GroupMemberJoinedByLinkUpdate.ProtoReflect.Descriptor instead. +func (*GroupMemberJoinedByLinkUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{70} +} + +func (x *GroupMemberJoinedByLinkUpdate) GetNewMemberAci() []byte { + if x != nil { + return x.NewMemberAci + } + return nil +} + +// A gv1->gv2 migration occurred. +type GroupV2MigrationUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupV2MigrationUpdate) Reset() { + *x = GroupV2MigrationUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupV2MigrationUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupV2MigrationUpdate) ProtoMessage() {} + +func (x *GroupV2MigrationUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[71] + 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 GroupV2MigrationUpdate.ProtoReflect.Descriptor instead. +func (*GroupV2MigrationUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{71} +} + +// Another user migrated gv1->gv2 but was unable to add +// the local user and invited them instead. +type GroupV2MigrationSelfInvitedUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupV2MigrationSelfInvitedUpdate) Reset() { + *x = GroupV2MigrationSelfInvitedUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupV2MigrationSelfInvitedUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupV2MigrationSelfInvitedUpdate) ProtoMessage() {} + +func (x *GroupV2MigrationSelfInvitedUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[72] + 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 GroupV2MigrationSelfInvitedUpdate.ProtoReflect.Descriptor instead. +func (*GroupV2MigrationSelfInvitedUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{72} +} + +// The local user migrated gv1->gv2 but was unable to +// add some members and invited them instead. +// (Happens if we don't have the invitee's profile key) +type GroupV2MigrationInvitedMembersUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + InvitedMembersCount uint32 `protobuf:"varint,1,opt,name=invitedMembersCount,proto3" json:"invitedMembersCount,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupV2MigrationInvitedMembersUpdate) Reset() { + *x = GroupV2MigrationInvitedMembersUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupV2MigrationInvitedMembersUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupV2MigrationInvitedMembersUpdate) ProtoMessage() {} + +func (x *GroupV2MigrationInvitedMembersUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[73] + 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 GroupV2MigrationInvitedMembersUpdate.ProtoReflect.Descriptor instead. +func (*GroupV2MigrationInvitedMembersUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{73} +} + +func (x *GroupV2MigrationInvitedMembersUpdate) GetInvitedMembersCount() uint32 { + if x != nil { + return x.InvitedMembersCount + } + return 0 +} + +// The local user migrated gv1->gv2 but was unable to +// add or invite some members and dropped them instead. +// (Happens for e164 members where we don't have an aci). +type GroupV2MigrationDroppedMembersUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + DroppedMembersCount uint32 `protobuf:"varint,1,opt,name=droppedMembersCount,proto3" json:"droppedMembersCount,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupV2MigrationDroppedMembersUpdate) Reset() { + *x = GroupV2MigrationDroppedMembersUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupV2MigrationDroppedMembersUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupV2MigrationDroppedMembersUpdate) ProtoMessage() {} + +func (x *GroupV2MigrationDroppedMembersUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[74] + 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 GroupV2MigrationDroppedMembersUpdate.ProtoReflect.Descriptor instead. +func (*GroupV2MigrationDroppedMembersUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{74} +} + +func (x *GroupV2MigrationDroppedMembersUpdate) GetDroppedMembersCount() uint32 { + if x != nil { + return x.DroppedMembersCount + } + return 0 +} + +// For 1:1 timer updates, use ExpirationTimerChatUpdate. +type GroupExpirationTimerUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + ExpiresInMs uint64 `protobuf:"varint,1,opt,name=expiresInMs,proto3" json:"expiresInMs,omitempty"` // 0 means the expiration timer was disabled + UpdaterAci []byte `protobuf:"bytes,2,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupExpirationTimerUpdate) Reset() { + *x = GroupExpirationTimerUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupExpirationTimerUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupExpirationTimerUpdate) ProtoMessage() {} + +func (x *GroupExpirationTimerUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[75] + 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 GroupExpirationTimerUpdate.ProtoReflect.Descriptor instead. +func (*GroupExpirationTimerUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{75} +} + +func (x *GroupExpirationTimerUpdate) GetExpiresInMs() uint64 { + if x != nil { + return x.ExpiresInMs + } + return 0 +} + +func (x *GroupExpirationTimerUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +type StickerPack struct { + state protoimpl.MessageState `protogen:"open.v1"` + PackId []byte `protobuf:"bytes,1,opt,name=packId,proto3" json:"packId,omitempty"` + PackKey []byte `protobuf:"bytes,2,opt,name=packKey,proto3" json:"packKey,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StickerPack) Reset() { + *x = StickerPack{} + mi := &file_backuppb_Backup_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StickerPack) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StickerPack) ProtoMessage() {} + +func (x *StickerPack) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[76] + 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 StickerPack.ProtoReflect.Descriptor instead. +func (*StickerPack) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{76} +} + +func (x *StickerPack) GetPackId() []byte { + if x != nil { + return x.PackId + } + return nil +} + +func (x *StickerPack) GetPackKey() []byte { + if x != nil { + return x.PackKey + } + return nil +} + +type ChatStyle struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Wallpaper: + // + // *ChatStyle_WallpaperPreset_ + // *ChatStyle_WallpaperPhoto + Wallpaper isChatStyle_Wallpaper `protobuf_oneof:"wallpaper"` + // Types that are valid to be assigned to BubbleColor: + // + // *ChatStyle_AutoBubbleColor + // *ChatStyle_BubbleColorPreset_ + // *ChatStyle_CustomColorId + BubbleColor isChatStyle_BubbleColor `protobuf_oneof:"bubbleColor"` + DimWallpaperInDarkMode bool `protobuf:"varint,7,opt,name=dimWallpaperInDarkMode,proto3" json:"dimWallpaperInDarkMode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatStyle) Reset() { + *x = ChatStyle{} + mi := &file_backuppb_Backup_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatStyle) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatStyle) ProtoMessage() {} + +func (x *ChatStyle) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[77] + 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 ChatStyle.ProtoReflect.Descriptor instead. +func (*ChatStyle) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77} +} + +func (x *ChatStyle) GetWallpaper() isChatStyle_Wallpaper { + if x != nil { + return x.Wallpaper + } + return nil +} + +func (x *ChatStyle) GetWallpaperPreset() ChatStyle_WallpaperPreset { + if x != nil { + if x, ok := x.Wallpaper.(*ChatStyle_WallpaperPreset_); ok { + return x.WallpaperPreset + } + } + return ChatStyle_UNKNOWN_WALLPAPER_PRESET +} + +func (x *ChatStyle) GetWallpaperPhoto() *FilePointer { + if x != nil { + if x, ok := x.Wallpaper.(*ChatStyle_WallpaperPhoto); ok { + return x.WallpaperPhoto + } + } + return nil +} + +func (x *ChatStyle) GetBubbleColor() isChatStyle_BubbleColor { + if x != nil { + return x.BubbleColor + } + return nil +} + +func (x *ChatStyle) GetAutoBubbleColor() *ChatStyle_AutomaticBubbleColor { + if x != nil { + if x, ok := x.BubbleColor.(*ChatStyle_AutoBubbleColor); ok { + return x.AutoBubbleColor + } + } + return nil +} + +func (x *ChatStyle) GetBubbleColorPreset() ChatStyle_BubbleColorPreset { + if x != nil { + if x, ok := x.BubbleColor.(*ChatStyle_BubbleColorPreset_); ok { + return x.BubbleColorPreset + } + } + return ChatStyle_UNKNOWN_BUBBLE_COLOR_PRESET +} + +func (x *ChatStyle) GetCustomColorId() uint64 { + if x != nil { + if x, ok := x.BubbleColor.(*ChatStyle_CustomColorId); ok { + return x.CustomColorId + } + } + return 0 +} + +func (x *ChatStyle) GetDimWallpaperInDarkMode() bool { + if x != nil { + return x.DimWallpaperInDarkMode + } + return false +} + +type isChatStyle_Wallpaper interface { + isChatStyle_Wallpaper() +} + +type ChatStyle_WallpaperPreset_ struct { + WallpaperPreset ChatStyle_WallpaperPreset `protobuf:"varint,1,opt,name=wallpaperPreset,proto3,enum=signal.backup.ChatStyle_WallpaperPreset,oneof"` +} + +type ChatStyle_WallpaperPhoto struct { + // This `FilePointer` is expected not to contain a `fileName`, `width`, + // `height`, or `caption`. + WallpaperPhoto *FilePointer `protobuf:"bytes,2,opt,name=wallpaperPhoto,proto3,oneof"` +} + +func (*ChatStyle_WallpaperPreset_) isChatStyle_Wallpaper() {} + +func (*ChatStyle_WallpaperPhoto) isChatStyle_Wallpaper() {} + +type isChatStyle_BubbleColor interface { + isChatStyle_BubbleColor() +} + +type ChatStyle_AutoBubbleColor struct { + // Bubble setting is automatically determined based on the wallpaper setting, + // or `SOLID_ULTRAMARINE` for `noWallpaper` + AutoBubbleColor *ChatStyle_AutomaticBubbleColor `protobuf:"bytes,3,opt,name=autoBubbleColor,proto3,oneof"` +} + +type ChatStyle_BubbleColorPreset_ struct { + BubbleColorPreset ChatStyle_BubbleColorPreset `protobuf:"varint,4,opt,name=bubbleColorPreset,proto3,enum=signal.backup.ChatStyle_BubbleColorPreset,oneof"` +} + +type ChatStyle_CustomColorId struct { + // See AccountSettings.customChatColors + CustomColorId uint64 `protobuf:"varint,5,opt,name=customColorId,proto3,oneof"` +} + +func (*ChatStyle_AutoBubbleColor) isChatStyle_BubbleColor() {} + +func (*ChatStyle_BubbleColorPreset_) isChatStyle_BubbleColor() {} + +func (*ChatStyle_CustomColorId) isChatStyle_BubbleColor() {} + +type NotificationProfile struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Emoji *string `protobuf:"bytes,2,opt,name=emoji,proto3,oneof" json:"emoji,omitempty"` + Color uint32 `protobuf:"fixed32,3,opt,name=color,proto3" json:"color,omitempty"` // 0xAARRGGBB + CreatedAtMs uint64 `protobuf:"varint,4,opt,name=createdAtMs,proto3" json:"createdAtMs,omitempty"` + AllowAllCalls bool `protobuf:"varint,5,opt,name=allowAllCalls,proto3" json:"allowAllCalls,omitempty"` + AllowAllMentions bool `protobuf:"varint,6,opt,name=allowAllMentions,proto3" json:"allowAllMentions,omitempty"` + AllowedMembers []uint64 `protobuf:"varint,7,rep,packed,name=allowedMembers,proto3" json:"allowedMembers,omitempty"` // generated recipient id for allowed groups and contacts + ScheduleEnabled bool `protobuf:"varint,8,opt,name=scheduleEnabled,proto3" json:"scheduleEnabled,omitempty"` + ScheduleStartTime uint32 `protobuf:"varint,9,opt,name=scheduleStartTime,proto3" json:"scheduleStartTime,omitempty"` // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + ScheduleEndTime uint32 `protobuf:"varint,10,opt,name=scheduleEndTime,proto3" json:"scheduleEndTime,omitempty"` // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + ScheduleDaysEnabled []NotificationProfile_DayOfWeek `protobuf:"varint,11,rep,packed,name=scheduleDaysEnabled,proto3,enum=signal.backup.NotificationProfile_DayOfWeek" json:"scheduleDaysEnabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NotificationProfile) Reset() { + *x = NotificationProfile{} + mi := &file_backuppb_Backup_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NotificationProfile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotificationProfile) ProtoMessage() {} + +func (x *NotificationProfile) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[78] + 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 NotificationProfile.ProtoReflect.Descriptor instead. +func (*NotificationProfile) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} +} + +func (x *NotificationProfile) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NotificationProfile) GetEmoji() string { + if x != nil && x.Emoji != nil { + return *x.Emoji + } + return "" +} + +func (x *NotificationProfile) GetColor() uint32 { + if x != nil { + return x.Color + } + return 0 +} + +func (x *NotificationProfile) GetCreatedAtMs() uint64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *NotificationProfile) GetAllowAllCalls() bool { + if x != nil { + return x.AllowAllCalls + } + return false +} + +func (x *NotificationProfile) GetAllowAllMentions() bool { + if x != nil { + return x.AllowAllMentions + } + return false +} + +func (x *NotificationProfile) GetAllowedMembers() []uint64 { + if x != nil { + return x.AllowedMembers + } + return nil +} + +func (x *NotificationProfile) GetScheduleEnabled() bool { + if x != nil { + return x.ScheduleEnabled + } + return false +} + +func (x *NotificationProfile) GetScheduleStartTime() uint32 { + if x != nil { + return x.ScheduleStartTime + } + return 0 +} + +func (x *NotificationProfile) GetScheduleEndTime() uint32 { + if x != nil { + return x.ScheduleEndTime + } + return 0 +} + +func (x *NotificationProfile) GetScheduleDaysEnabled() []NotificationProfile_DayOfWeek { + if x != nil { + return x.ScheduleDaysEnabled + } + return nil +} + +type ChatFolder struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + ShowOnlyUnread bool `protobuf:"varint,2,opt,name=showOnlyUnread,proto3" json:"showOnlyUnread,omitempty"` + ShowMutedChats bool `protobuf:"varint,3,opt,name=showMutedChats,proto3" json:"showMutedChats,omitempty"` + // Folder includes all 1:1 chats, unless excluded + IncludeAllIndividualChats bool `protobuf:"varint,4,opt,name=includeAllIndividualChats,proto3" json:"includeAllIndividualChats,omitempty"` + // Folder includes all group chats, unless excluded + IncludeAllGroupChats bool `protobuf:"varint,5,opt,name=includeAllGroupChats,proto3" json:"includeAllGroupChats,omitempty"` + FolderType ChatFolder_FolderType `protobuf:"varint,6,opt,name=folderType,proto3,enum=signal.backup.ChatFolder_FolderType" json:"folderType,omitempty"` + IncludedRecipientIds []uint64 `protobuf:"varint,7,rep,packed,name=includedRecipientIds,proto3" json:"includedRecipientIds,omitempty"` // generated recipient id of groups, contacts, and/or note to self + ExcludedRecipientIds []uint64 `protobuf:"varint,8,rep,packed,name=excludedRecipientIds,proto3" json:"excludedRecipientIds,omitempty"` // generated recipient id of groups, contacts, and/or note to self + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatFolder) Reset() { + *x = ChatFolder{} + mi := &file_backuppb_Backup_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatFolder) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatFolder) ProtoMessage() {} + +func (x *ChatFolder) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[79] + 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 ChatFolder.ProtoReflect.Descriptor instead. +func (*ChatFolder) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} +} + +func (x *ChatFolder) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ChatFolder) GetShowOnlyUnread() bool { + if x != nil { + return x.ShowOnlyUnread + } + return false +} + +func (x *ChatFolder) GetShowMutedChats() bool { + if x != nil { + return x.ShowMutedChats + } + return false +} + +func (x *ChatFolder) GetIncludeAllIndividualChats() bool { + if x != nil { + return x.IncludeAllIndividualChats + } + return false +} + +func (x *ChatFolder) GetIncludeAllGroupChats() bool { + if x != nil { + return x.IncludeAllGroupChats + } + return false +} + +func (x *ChatFolder) GetFolderType() ChatFolder_FolderType { + if x != nil { + return x.FolderType + } + return ChatFolder_UNKNOWN +} + +func (x *ChatFolder) GetIncludedRecipientIds() []uint64 { + if x != nil { + return x.IncludedRecipientIds + } + return nil +} + +func (x *ChatFolder) GetExcludedRecipientIds() []uint64 { + if x != nil { + return x.ExcludedRecipientIds + } + return nil +} + +type AccountData_UsernameLink struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entropy []byte `protobuf:"bytes,1,opt,name=entropy,proto3" json:"entropy,omitempty"` // 32 bytes of entropy used for encryption + ServerId []byte `protobuf:"bytes,2,opt,name=serverId,proto3" json:"serverId,omitempty"` // 16 bytes of encoded UUID provided by the server + Color AccountData_UsernameLink_Color `protobuf:"varint,3,opt,name=color,proto3,enum=signal.backup.AccountData_UsernameLink_Color" json:"color,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData_UsernameLink) Reset() { + *x = AccountData_UsernameLink{} + mi := &file_backuppb_Backup_proto_msgTypes[80] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData_UsernameLink) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData_UsernameLink) ProtoMessage() {} + +func (x *AccountData_UsernameLink) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[80] + 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 AccountData_UsernameLink.ProtoReflect.Descriptor instead. +func (*AccountData_UsernameLink) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *AccountData_UsernameLink) GetEntropy() []byte { + if x != nil { + return x.Entropy + } + return nil +} + +func (x *AccountData_UsernameLink) GetServerId() []byte { + if x != nil { + return x.ServerId + } + return nil +} + +func (x *AccountData_UsernameLink) GetColor() AccountData_UsernameLink_Color { + if x != nil { + return x.Color + } + return AccountData_UsernameLink_UNKNOWN +} + +type AccountData_AccountSettings struct { + state protoimpl.MessageState `protogen:"open.v1"` + ReadReceipts bool `protobuf:"varint,1,opt,name=readReceipts,proto3" json:"readReceipts,omitempty"` + SealedSenderIndicators bool `protobuf:"varint,2,opt,name=sealedSenderIndicators,proto3" json:"sealedSenderIndicators,omitempty"` + TypingIndicators bool `protobuf:"varint,3,opt,name=typingIndicators,proto3" json:"typingIndicators,omitempty"` + LinkPreviews bool `protobuf:"varint,4,opt,name=linkPreviews,proto3" json:"linkPreviews,omitempty"` + NotDiscoverableByPhoneNumber bool `protobuf:"varint,5,opt,name=notDiscoverableByPhoneNumber,proto3" json:"notDiscoverableByPhoneNumber,omitempty"` + PreferContactAvatars bool `protobuf:"varint,6,opt,name=preferContactAvatars,proto3" json:"preferContactAvatars,omitempty"` + UniversalExpireTimerSeconds uint32 `protobuf:"varint,7,opt,name=universalExpireTimerSeconds,proto3" json:"universalExpireTimerSeconds,omitempty"` // 0 means no universal expire timer. + PreferredReactionEmoji []string `protobuf:"bytes,8,rep,name=preferredReactionEmoji,proto3" json:"preferredReactionEmoji,omitempty"` + DisplayBadgesOnProfile bool `protobuf:"varint,9,opt,name=displayBadgesOnProfile,proto3" json:"displayBadgesOnProfile,omitempty"` + KeepMutedChatsArchived bool `protobuf:"varint,10,opt,name=keepMutedChatsArchived,proto3" json:"keepMutedChatsArchived,omitempty"` + HasSetMyStoriesPrivacy bool `protobuf:"varint,11,opt,name=hasSetMyStoriesPrivacy,proto3" json:"hasSetMyStoriesPrivacy,omitempty"` + HasViewedOnboardingStory bool `protobuf:"varint,12,opt,name=hasViewedOnboardingStory,proto3" json:"hasViewedOnboardingStory,omitempty"` + StoriesDisabled bool `protobuf:"varint,13,opt,name=storiesDisabled,proto3" json:"storiesDisabled,omitempty"` + StoryViewReceiptsEnabled *bool `protobuf:"varint,14,opt,name=storyViewReceiptsEnabled,proto3,oneof" json:"storyViewReceiptsEnabled,omitempty"` + HasSeenGroupStoryEducationSheet bool `protobuf:"varint,15,opt,name=hasSeenGroupStoryEducationSheet,proto3" json:"hasSeenGroupStoryEducationSheet,omitempty"` + HasCompletedUsernameOnboarding bool `protobuf:"varint,16,opt,name=hasCompletedUsernameOnboarding,proto3" json:"hasCompletedUsernameOnboarding,omitempty"` + PhoneNumberSharingMode AccountData_PhoneNumberSharingMode `protobuf:"varint,17,opt,name=phoneNumberSharingMode,proto3,enum=signal.backup.AccountData_PhoneNumberSharingMode" json:"phoneNumberSharingMode,omitempty"` + DefaultChatStyle *ChatStyle `protobuf:"bytes,18,opt,name=defaultChatStyle,proto3" json:"defaultChatStyle,omitempty"` + CustomChatColors []*ChatStyle_CustomChatColor `protobuf:"bytes,19,rep,name=customChatColors,proto3" json:"customChatColors,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData_AccountSettings) Reset() { + *x = AccountData_AccountSettings{} + mi := &file_backuppb_Backup_proto_msgTypes[81] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData_AccountSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData_AccountSettings) ProtoMessage() {} + +func (x *AccountData_AccountSettings) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[81] + 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 AccountData_AccountSettings.ProtoReflect.Descriptor instead. +func (*AccountData_AccountSettings) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *AccountData_AccountSettings) GetReadReceipts() bool { + if x != nil { + return x.ReadReceipts + } + return false +} + +func (x *AccountData_AccountSettings) GetSealedSenderIndicators() bool { + if x != nil { + return x.SealedSenderIndicators + } + return false +} + +func (x *AccountData_AccountSettings) GetTypingIndicators() bool { + if x != nil { + return x.TypingIndicators + } + return false +} + +func (x *AccountData_AccountSettings) GetLinkPreviews() bool { + if x != nil { + return x.LinkPreviews + } + return false +} + +func (x *AccountData_AccountSettings) GetNotDiscoverableByPhoneNumber() bool { + if x != nil { + return x.NotDiscoverableByPhoneNumber + } + return false +} + +func (x *AccountData_AccountSettings) GetPreferContactAvatars() bool { + if x != nil { + return x.PreferContactAvatars + } + return false +} + +func (x *AccountData_AccountSettings) GetUniversalExpireTimerSeconds() uint32 { + if x != nil { + return x.UniversalExpireTimerSeconds + } + return 0 +} + +func (x *AccountData_AccountSettings) GetPreferredReactionEmoji() []string { + if x != nil { + return x.PreferredReactionEmoji + } + return nil +} + +func (x *AccountData_AccountSettings) GetDisplayBadgesOnProfile() bool { + if x != nil { + return x.DisplayBadgesOnProfile + } + return false +} + +func (x *AccountData_AccountSettings) GetKeepMutedChatsArchived() bool { + if x != nil { + return x.KeepMutedChatsArchived + } + return false +} + +func (x *AccountData_AccountSettings) GetHasSetMyStoriesPrivacy() bool { + if x != nil { + return x.HasSetMyStoriesPrivacy + } + return false +} + +func (x *AccountData_AccountSettings) GetHasViewedOnboardingStory() bool { + if x != nil { + return x.HasViewedOnboardingStory + } + return false +} + +func (x *AccountData_AccountSettings) GetStoriesDisabled() bool { + if x != nil { + return x.StoriesDisabled + } + return false +} + +func (x *AccountData_AccountSettings) GetStoryViewReceiptsEnabled() bool { + if x != nil && x.StoryViewReceiptsEnabled != nil { + return *x.StoryViewReceiptsEnabled + } + return false +} + +func (x *AccountData_AccountSettings) GetHasSeenGroupStoryEducationSheet() bool { + if x != nil { + return x.HasSeenGroupStoryEducationSheet + } + return false +} + +func (x *AccountData_AccountSettings) GetHasCompletedUsernameOnboarding() bool { + if x != nil { + return x.HasCompletedUsernameOnboarding + } + return false +} + +func (x *AccountData_AccountSettings) GetPhoneNumberSharingMode() AccountData_PhoneNumberSharingMode { + if x != nil { + return x.PhoneNumberSharingMode + } + return AccountData_UNKNOWN +} + +func (x *AccountData_AccountSettings) GetDefaultChatStyle() *ChatStyle { + if x != nil { + return x.DefaultChatStyle + } + return nil +} + +func (x *AccountData_AccountSettings) GetCustomChatColors() []*ChatStyle_CustomChatColor { + if x != nil { + return x.CustomChatColors + } + return nil +} + +type AccountData_SubscriberData struct { + state protoimpl.MessageState `protogen:"open.v1"` + SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` + CurrencyCode string `protobuf:"bytes,2,opt,name=currencyCode,proto3" json:"currencyCode,omitempty"` + ManuallyCancelled bool `protobuf:"varint,3,opt,name=manuallyCancelled,proto3" json:"manuallyCancelled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData_SubscriberData) Reset() { + *x = AccountData_SubscriberData{} + mi := &file_backuppb_Backup_proto_msgTypes[82] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData_SubscriberData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData_SubscriberData) ProtoMessage() {} + +func (x *AccountData_SubscriberData) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[82] + 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 AccountData_SubscriberData.ProtoReflect.Descriptor instead. +func (*AccountData_SubscriberData) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 2} +} + +func (x *AccountData_SubscriberData) GetSubscriberId() []byte { + if x != nil { + return x.SubscriberId + } + return nil +} + +func (x *AccountData_SubscriberData) GetCurrencyCode() string { + if x != nil { + return x.CurrencyCode + } + return "" +} + +func (x *AccountData_SubscriberData) GetManuallyCancelled() bool { + if x != nil { + return x.ManuallyCancelled + } + return false +} + +type AccountData_IAPSubscriberData struct { + state protoimpl.MessageState `protogen:"open.v1"` + SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` + // Types that are valid to be assigned to IapSubscriptionId: + // + // *AccountData_IAPSubscriberData_PurchaseToken + // *AccountData_IAPSubscriberData_OriginalTransactionId + IapSubscriptionId isAccountData_IAPSubscriberData_IapSubscriptionId `protobuf_oneof:"iapSubscriptionId"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData_IAPSubscriberData) Reset() { + *x = AccountData_IAPSubscriberData{} + mi := &file_backuppb_Backup_proto_msgTypes[83] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData_IAPSubscriberData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData_IAPSubscriberData) ProtoMessage() {} + +func (x *AccountData_IAPSubscriberData) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[83] + 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 AccountData_IAPSubscriberData.ProtoReflect.Descriptor instead. +func (*AccountData_IAPSubscriberData) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 3} +} + +func (x *AccountData_IAPSubscriberData) GetSubscriberId() []byte { + if x != nil { + return x.SubscriberId + } + return nil +} + +func (x *AccountData_IAPSubscriberData) GetIapSubscriptionId() isAccountData_IAPSubscriberData_IapSubscriptionId { + if x != nil { + return x.IapSubscriptionId + } + return nil +} + +func (x *AccountData_IAPSubscriberData) GetPurchaseToken() string { + if x != nil { + if x, ok := x.IapSubscriptionId.(*AccountData_IAPSubscriberData_PurchaseToken); ok { + return x.PurchaseToken + } + } + return "" +} + +func (x *AccountData_IAPSubscriberData) GetOriginalTransactionId() uint64 { + if x != nil { + if x, ok := x.IapSubscriptionId.(*AccountData_IAPSubscriberData_OriginalTransactionId); ok { + return x.OriginalTransactionId + } + } + return 0 +} + +type isAccountData_IAPSubscriberData_IapSubscriptionId interface { + isAccountData_IAPSubscriberData_IapSubscriptionId() +} + +type AccountData_IAPSubscriberData_PurchaseToken struct { + // Identifies an Android Play Store IAP subscription. + PurchaseToken string `protobuf:"bytes,2,opt,name=purchaseToken,proto3,oneof"` +} + +type AccountData_IAPSubscriberData_OriginalTransactionId struct { + // Identifies an iOS App Store IAP subscription. + OriginalTransactionId uint64 `protobuf:"varint,3,opt,name=originalTransactionId,proto3,oneof"` +} + +func (*AccountData_IAPSubscriberData_PurchaseToken) isAccountData_IAPSubscriberData_IapSubscriptionId() { +} + +func (*AccountData_IAPSubscriberData_OriginalTransactionId) isAccountData_IAPSubscriberData_IapSubscriptionId() { +} + +type Contact_Registered struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Contact_Registered) Reset() { + *x = Contact_Registered{} + mi := &file_backuppb_Backup_proto_msgTypes[84] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Contact_Registered) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contact_Registered) ProtoMessage() {} + +func (x *Contact_Registered) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[84] + 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 Contact_Registered.ProtoReflect.Descriptor instead. +func (*Contact_Registered) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{4, 0} +} + +type Contact_NotRegistered struct { + state protoimpl.MessageState `protogen:"open.v1"` + UnregisteredTimestamp uint64 `protobuf:"varint,1,opt,name=unregisteredTimestamp,proto3" json:"unregisteredTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Contact_NotRegistered) Reset() { + *x = Contact_NotRegistered{} + mi := &file_backuppb_Backup_proto_msgTypes[85] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Contact_NotRegistered) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contact_NotRegistered) ProtoMessage() {} + +func (x *Contact_NotRegistered) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[85] + 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 Contact_NotRegistered.ProtoReflect.Descriptor instead. +func (*Contact_NotRegistered) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{4, 1} +} + +func (x *Contact_NotRegistered) GetUnregisteredTimestamp() uint64 { + if x != nil { + return x.UnregisteredTimestamp + } + return 0 +} + +type Contact_Name struct { + state protoimpl.MessageState `protogen:"open.v1"` + Given string `protobuf:"bytes,1,opt,name=given,proto3" json:"given,omitempty"` + Family string `protobuf:"bytes,2,opt,name=family,proto3" json:"family,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Contact_Name) Reset() { + *x = Contact_Name{} + mi := &file_backuppb_Backup_proto_msgTypes[86] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Contact_Name) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contact_Name) ProtoMessage() {} + +func (x *Contact_Name) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[86] + 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 Contact_Name.ProtoReflect.Descriptor instead. +func (*Contact_Name) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{4, 2} +} + +func (x *Contact_Name) GetGiven() string { + if x != nil { + return x.Given + } + return "" +} + +func (x *Contact_Name) GetFamily() string { + if x != nil { + return x.Family + } + return "" +} + +// These are simply plaintext copies of the groups proto from Groups.proto. +// They should be kept completely in-sync with Groups.proto. +// These exist to allow us to have the latest snapshot of a group during restoration without having to hit the network. +// We would use Groups.proto if we could, but we want a plaintext version to improve export readability. +// For documentation, defer to Groups.proto. The only name change is Group -> GroupSnapshot to avoid the naming conflict. +type Group_GroupSnapshot struct { + state protoimpl.MessageState `protogen:"open.v1"` + Title *Group_GroupAttributeBlob `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Description *Group_GroupAttributeBlob `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` + AvatarUrl string `protobuf:"bytes,3,opt,name=avatarUrl,proto3" json:"avatarUrl,omitempty"` + DisappearingMessagesTimer *Group_GroupAttributeBlob `protobuf:"bytes,4,opt,name=disappearingMessagesTimer,proto3" json:"disappearingMessagesTimer,omitempty"` + AccessControl *Group_AccessControl `protobuf:"bytes,5,opt,name=accessControl,proto3" json:"accessControl,omitempty"` + Version uint32 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` + Members []*Group_Member `protobuf:"bytes,7,rep,name=members,proto3" json:"members,omitempty"` + MembersPendingProfileKey []*Group_MemberPendingProfileKey `protobuf:"bytes,8,rep,name=membersPendingProfileKey,proto3" json:"membersPendingProfileKey,omitempty"` + MembersPendingAdminApproval []*Group_MemberPendingAdminApproval `protobuf:"bytes,9,rep,name=membersPendingAdminApproval,proto3" json:"membersPendingAdminApproval,omitempty"` + InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"` + MembersBanned []*Group_MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_GroupSnapshot) Reset() { + *x = Group_GroupSnapshot{} + mi := &file_backuppb_Backup_proto_msgTypes[87] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_GroupSnapshot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_GroupSnapshot) ProtoMessage() {} + +func (x *Group_GroupSnapshot) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[87] + 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 Group_GroupSnapshot.ProtoReflect.Descriptor instead. +func (*Group_GroupSnapshot) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *Group_GroupSnapshot) GetTitle() *Group_GroupAttributeBlob { + if x != nil { + return x.Title + } + return nil +} + +func (x *Group_GroupSnapshot) GetDescription() *Group_GroupAttributeBlob { + if x != nil { + return x.Description + } + return nil +} + +func (x *Group_GroupSnapshot) GetAvatarUrl() string { + if x != nil { + return x.AvatarUrl + } + return "" +} + +func (x *Group_GroupSnapshot) GetDisappearingMessagesTimer() *Group_GroupAttributeBlob { + if x != nil { + return x.DisappearingMessagesTimer + } + return nil +} + +func (x *Group_GroupSnapshot) GetAccessControl() *Group_AccessControl { + if x != nil { + return x.AccessControl + } + return nil +} + +func (x *Group_GroupSnapshot) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Group_GroupSnapshot) GetMembers() []*Group_Member { + if x != nil { + return x.Members + } + return nil +} + +func (x *Group_GroupSnapshot) GetMembersPendingProfileKey() []*Group_MemberPendingProfileKey { + if x != nil { + return x.MembersPendingProfileKey + } + return nil +} + +func (x *Group_GroupSnapshot) GetMembersPendingAdminApproval() []*Group_MemberPendingAdminApproval { + if x != nil { + return x.MembersPendingAdminApproval + } + return nil +} + +func (x *Group_GroupSnapshot) GetInviteLinkPassword() []byte { + if x != nil { + return x.InviteLinkPassword + } + return nil +} + +func (x *Group_GroupSnapshot) GetAnnouncementsOnly() bool { + if x != nil { + return x.AnnouncementsOnly + } + return false +} + +func (x *Group_GroupSnapshot) GetMembersBanned() []*Group_MemberBanned { + if x != nil { + return x.MembersBanned + } + return nil +} + +type Group_GroupAttributeBlob struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Content: + // + // *Group_GroupAttributeBlob_Title + // *Group_GroupAttributeBlob_Avatar + // *Group_GroupAttributeBlob_DisappearingMessagesDuration + // *Group_GroupAttributeBlob_DescriptionText + Content isGroup_GroupAttributeBlob_Content `protobuf_oneof:"content"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_GroupAttributeBlob) Reset() { + *x = Group_GroupAttributeBlob{} + mi := &file_backuppb_Backup_proto_msgTypes[88] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_GroupAttributeBlob) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_GroupAttributeBlob) ProtoMessage() {} + +func (x *Group_GroupAttributeBlob) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[88] + 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 Group_GroupAttributeBlob.ProtoReflect.Descriptor instead. +func (*Group_GroupAttributeBlob) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 1} +} + +func (x *Group_GroupAttributeBlob) GetContent() isGroup_GroupAttributeBlob_Content { + if x != nil { + return x.Content + } + return nil +} + +func (x *Group_GroupAttributeBlob) GetTitle() string { + if x != nil { + if x, ok := x.Content.(*Group_GroupAttributeBlob_Title); ok { + return x.Title + } + } + return "" +} + +func (x *Group_GroupAttributeBlob) GetAvatar() []byte { + if x != nil { + if x, ok := x.Content.(*Group_GroupAttributeBlob_Avatar); ok { + return x.Avatar + } + } + return nil +} + +func (x *Group_GroupAttributeBlob) GetDisappearingMessagesDuration() uint32 { + if x != nil { + if x, ok := x.Content.(*Group_GroupAttributeBlob_DisappearingMessagesDuration); ok { + return x.DisappearingMessagesDuration + } + } + return 0 +} + +func (x *Group_GroupAttributeBlob) GetDescriptionText() string { + if x != nil { + if x, ok := x.Content.(*Group_GroupAttributeBlob_DescriptionText); ok { + return x.DescriptionText + } + } + return "" +} + +type isGroup_GroupAttributeBlob_Content interface { + isGroup_GroupAttributeBlob_Content() +} + +type Group_GroupAttributeBlob_Title struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3,oneof"` +} + +type Group_GroupAttributeBlob_Avatar struct { + Avatar []byte `protobuf:"bytes,2,opt,name=avatar,proto3,oneof"` +} + +type Group_GroupAttributeBlob_DisappearingMessagesDuration struct { + DisappearingMessagesDuration uint32 `protobuf:"varint,3,opt,name=disappearingMessagesDuration,proto3,oneof"` +} + +type Group_GroupAttributeBlob_DescriptionText struct { + DescriptionText string `protobuf:"bytes,4,opt,name=descriptionText,proto3,oneof"` +} + +func (*Group_GroupAttributeBlob_Title) isGroup_GroupAttributeBlob_Content() {} + +func (*Group_GroupAttributeBlob_Avatar) isGroup_GroupAttributeBlob_Content() {} + +func (*Group_GroupAttributeBlob_DisappearingMessagesDuration) isGroup_GroupAttributeBlob_Content() {} + +func (*Group_GroupAttributeBlob_DescriptionText) isGroup_GroupAttributeBlob_Content() {} + +type Group_Member struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Role Group_Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=signal.backup.Group_Member_Role" json:"role,omitempty"` + JoinedAtVersion uint32 `protobuf:"varint,5,opt,name=joinedAtVersion,proto3" json:"joinedAtVersion,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_Member) Reset() { + *x = Group_Member{} + mi := &file_backuppb_Backup_proto_msgTypes[89] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_Member) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_Member) ProtoMessage() {} + +func (x *Group_Member) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[89] + 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 Group_Member.ProtoReflect.Descriptor instead. +func (*Group_Member) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 2} +} + +func (x *Group_Member) GetUserId() []byte { + if x != nil { + return x.UserId + } + return nil +} + +func (x *Group_Member) GetRole() Group_Member_Role { + if x != nil { + return x.Role + } + return Group_Member_UNKNOWN +} + +func (x *Group_Member) GetJoinedAtVersion() uint32 { + if x != nil { + return x.JoinedAtVersion + } + return 0 +} + +type Group_MemberPendingProfileKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + Member *Group_Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` + AddedByUserId []byte `protobuf:"bytes,2,opt,name=addedByUserId,proto3" json:"addedByUserId,omitempty"` + Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_MemberPendingProfileKey) Reset() { + *x = Group_MemberPendingProfileKey{} + mi := &file_backuppb_Backup_proto_msgTypes[90] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_MemberPendingProfileKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_MemberPendingProfileKey) ProtoMessage() {} + +func (x *Group_MemberPendingProfileKey) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[90] + 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 Group_MemberPendingProfileKey.ProtoReflect.Descriptor instead. +func (*Group_MemberPendingProfileKey) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 3} +} + +func (x *Group_MemberPendingProfileKey) GetMember() *Group_Member { + if x != nil { + return x.Member + } + return nil +} + +func (x *Group_MemberPendingProfileKey) GetAddedByUserId() []byte { + if x != nil { + return x.AddedByUserId + } + return nil +} + +func (x *Group_MemberPendingProfileKey) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +type Group_MemberPendingAdminApproval struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_MemberPendingAdminApproval) Reset() { + *x = Group_MemberPendingAdminApproval{} + mi := &file_backuppb_Backup_proto_msgTypes[91] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_MemberPendingAdminApproval) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_MemberPendingAdminApproval) ProtoMessage() {} + +func (x *Group_MemberPendingAdminApproval) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[91] + 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 Group_MemberPendingAdminApproval.ProtoReflect.Descriptor instead. +func (*Group_MemberPendingAdminApproval) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 4} +} + +func (x *Group_MemberPendingAdminApproval) GetUserId() []byte { + if x != nil { + return x.UserId + } + return nil +} + +func (x *Group_MemberPendingAdminApproval) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +type Group_MemberBanned struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_MemberBanned) Reset() { + *x = Group_MemberBanned{} + mi := &file_backuppb_Backup_proto_msgTypes[92] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_MemberBanned) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_MemberBanned) ProtoMessage() {} + +func (x *Group_MemberBanned) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[92] + 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 Group_MemberBanned.ProtoReflect.Descriptor instead. +func (*Group_MemberBanned) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 5} +} + +func (x *Group_MemberBanned) GetUserId() []byte { + if x != nil { + return x.UserId + } + return nil +} + +func (x *Group_MemberBanned) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +type Group_AccessControl struct { + state protoimpl.MessageState `protogen:"open.v1"` + Attributes Group_AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"attributes,omitempty"` + Members Group_AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"members,omitempty"` + AddFromInviteLink Group_AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Group_AccessControl) Reset() { + *x = Group_AccessControl{} + mi := &file_backuppb_Backup_proto_msgTypes[93] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Group_AccessControl) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Group_AccessControl) ProtoMessage() {} + +func (x *Group_AccessControl) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[93] + 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 Group_AccessControl.ProtoReflect.Descriptor instead. +func (*Group_AccessControl) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{5, 6} +} + +func (x *Group_AccessControl) GetAttributes() Group_AccessControl_AccessRequired { + if x != nil { + return x.Attributes + } + return Group_AccessControl_UNKNOWN +} + +func (x *Group_AccessControl) GetMembers() Group_AccessControl_AccessRequired { + if x != nil { + return x.Members + } + return Group_AccessControl_UNKNOWN +} + +func (x *Group_AccessControl) GetAddFromInviteLink() Group_AccessControl_AccessRequired { + if x != nil { + return x.AddFromInviteLink + } + return Group_AccessControl_UNKNOWN +} + +type ChatItem_IncomingMessageDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + DateReceived uint64 `protobuf:"varint,1,opt,name=dateReceived,proto3" json:"dateReceived,omitempty"` + DateServerSent *uint64 `protobuf:"varint,2,opt,name=dateServerSent,proto3,oneof" json:"dateServerSent,omitempty"` + Read bool `protobuf:"varint,3,opt,name=read,proto3" json:"read,omitempty"` + SealedSender bool `protobuf:"varint,4,opt,name=sealedSender,proto3" json:"sealedSender,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatItem_IncomingMessageDetails) Reset() { + *x = ChatItem_IncomingMessageDetails{} + mi := &file_backuppb_Backup_proto_msgTypes[94] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatItem_IncomingMessageDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatItem_IncomingMessageDetails) ProtoMessage() {} + +func (x *ChatItem_IncomingMessageDetails) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[94] + 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 ChatItem_IncomingMessageDetails.ProtoReflect.Descriptor instead. +func (*ChatItem_IncomingMessageDetails) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{13, 0} +} + +func (x *ChatItem_IncomingMessageDetails) GetDateReceived() uint64 { + if x != nil { + return x.DateReceived + } + return 0 +} + +func (x *ChatItem_IncomingMessageDetails) GetDateServerSent() uint64 { + if x != nil && x.DateServerSent != nil { + return *x.DateServerSent + } + return 0 +} + +func (x *ChatItem_IncomingMessageDetails) GetRead() bool { + if x != nil { + return x.Read + } + return false +} + +func (x *ChatItem_IncomingMessageDetails) GetSealedSender() bool { + if x != nil { + return x.SealedSender + } + return false +} + +type ChatItem_OutgoingMessageDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + SendStatus []*SendStatus `protobuf:"bytes,1,rep,name=sendStatus,proto3" json:"sendStatus,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatItem_OutgoingMessageDetails) Reset() { + *x = ChatItem_OutgoingMessageDetails{} + mi := &file_backuppb_Backup_proto_msgTypes[95] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatItem_OutgoingMessageDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatItem_OutgoingMessageDetails) ProtoMessage() {} + +func (x *ChatItem_OutgoingMessageDetails) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[95] + 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 ChatItem_OutgoingMessageDetails.ProtoReflect.Descriptor instead. +func (*ChatItem_OutgoingMessageDetails) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{13, 1} +} + +func (x *ChatItem_OutgoingMessageDetails) GetSendStatus() []*SendStatus { + if x != nil { + return x.SendStatus + } + return nil +} + +type ChatItem_DirectionlessMessageDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatItem_DirectionlessMessageDetails) Reset() { + *x = ChatItem_DirectionlessMessageDetails{} + mi := &file_backuppb_Backup_proto_msgTypes[96] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatItem_DirectionlessMessageDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatItem_DirectionlessMessageDetails) ProtoMessage() {} + +func (x *ChatItem_DirectionlessMessageDetails) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[96] + 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 ChatItem_DirectionlessMessageDetails.ProtoReflect.Descriptor instead. +func (*ChatItem_DirectionlessMessageDetails) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{13, 2} +} + +type SendStatus_Pending struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Pending) Reset() { + *x = SendStatus_Pending{} + mi := &file_backuppb_Backup_proto_msgTypes[97] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Pending) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Pending) ProtoMessage() {} + +func (x *SendStatus_Pending) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[97] + 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 SendStatus_Pending.ProtoReflect.Descriptor instead. +func (*SendStatus_Pending) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 0} +} + +type SendStatus_Sent struct { + state protoimpl.MessageState `protogen:"open.v1"` + SealedSender bool `protobuf:"varint,1,opt,name=sealedSender,proto3" json:"sealedSender,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Sent) Reset() { + *x = SendStatus_Sent{} + mi := &file_backuppb_Backup_proto_msgTypes[98] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Sent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Sent) ProtoMessage() {} + +func (x *SendStatus_Sent) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[98] + 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 SendStatus_Sent.ProtoReflect.Descriptor instead. +func (*SendStatus_Sent) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 1} +} + +func (x *SendStatus_Sent) GetSealedSender() bool { + if x != nil { + return x.SealedSender + } + return false +} + +type SendStatus_Delivered struct { + state protoimpl.MessageState `protogen:"open.v1"` + SealedSender bool `protobuf:"varint,1,opt,name=sealedSender,proto3" json:"sealedSender,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Delivered) Reset() { + *x = SendStatus_Delivered{} + mi := &file_backuppb_Backup_proto_msgTypes[99] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Delivered) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Delivered) ProtoMessage() {} + +func (x *SendStatus_Delivered) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[99] + 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 SendStatus_Delivered.ProtoReflect.Descriptor instead. +func (*SendStatus_Delivered) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 2} +} + +func (x *SendStatus_Delivered) GetSealedSender() bool { + if x != nil { + return x.SealedSender + } + return false +} + +type SendStatus_Read struct { + state protoimpl.MessageState `protogen:"open.v1"` + SealedSender bool `protobuf:"varint,1,opt,name=sealedSender,proto3" json:"sealedSender,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Read) Reset() { + *x = SendStatus_Read{} + mi := &file_backuppb_Backup_proto_msgTypes[100] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Read) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Read) ProtoMessage() {} + +func (x *SendStatus_Read) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[100] + 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 SendStatus_Read.ProtoReflect.Descriptor instead. +func (*SendStatus_Read) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 3} +} + +func (x *SendStatus_Read) GetSealedSender() bool { + if x != nil { + return x.SealedSender + } + return false +} + +type SendStatus_Viewed struct { + state protoimpl.MessageState `protogen:"open.v1"` + SealedSender bool `protobuf:"varint,1,opt,name=sealedSender,proto3" json:"sealedSender,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Viewed) Reset() { + *x = SendStatus_Viewed{} + mi := &file_backuppb_Backup_proto_msgTypes[101] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Viewed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Viewed) ProtoMessage() {} + +func (x *SendStatus_Viewed) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[101] + 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 SendStatus_Viewed.ProtoReflect.Descriptor instead. +func (*SendStatus_Viewed) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 4} +} + +func (x *SendStatus_Viewed) GetSealedSender() bool { + if x != nil { + return x.SealedSender + } + return false +} + +// e.g. user in group was blocked, so we skipped sending to them +type SendStatus_Skipped struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Skipped) Reset() { + *x = SendStatus_Skipped{} + mi := &file_backuppb_Backup_proto_msgTypes[102] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Skipped) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Skipped) ProtoMessage() {} + +func (x *SendStatus_Skipped) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[102] + 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 SendStatus_Skipped.ProtoReflect.Descriptor instead. +func (*SendStatus_Skipped) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 5} +} + +type SendStatus_Failed struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reason SendStatus_Failed_FailureReason `protobuf:"varint,1,opt,name=reason,proto3,enum=signal.backup.SendStatus_Failed_FailureReason" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendStatus_Failed) Reset() { + *x = SendStatus_Failed{} + mi := &file_backuppb_Backup_proto_msgTypes[103] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendStatus_Failed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendStatus_Failed) ProtoMessage() {} + +func (x *SendStatus_Failed) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[103] + 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 SendStatus_Failed.ProtoReflect.Descriptor instead. +func (*SendStatus_Failed) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{14, 6} +} + +func (x *SendStatus_Failed) GetReason() SendStatus_Failed_FailureReason { + if x != nil { + return x.Reason + } + return SendStatus_Failed_UNKNOWN +} + +type DirectStoryReplyMessage_TextReply struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text *Text `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + LongText *FilePointer `protobuf:"bytes,2,opt,name=longText,proto3" json:"longText,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DirectStoryReplyMessage_TextReply) Reset() { + *x = DirectStoryReplyMessage_TextReply{} + mi := &file_backuppb_Backup_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DirectStoryReplyMessage_TextReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DirectStoryReplyMessage_TextReply) ProtoMessage() {} + +func (x *DirectStoryReplyMessage_TextReply) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[104] + 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 DirectStoryReplyMessage_TextReply.ProtoReflect.Descriptor instead. +func (*DirectStoryReplyMessage_TextReply) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{18, 0} +} + +func (x *DirectStoryReplyMessage_TextReply) GetText() *Text { + if x != nil { + return x.Text + } + return nil +} + +func (x *DirectStoryReplyMessage_TextReply) GetLongText() *FilePointer { + if x != nil { + return x.LongText + } + return nil +} + +type PaymentNotification_TransactionDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Payment: + // + // *PaymentNotification_TransactionDetails_Transaction_ + // *PaymentNotification_TransactionDetails_FailedTransaction_ + Payment isPaymentNotification_TransactionDetails_Payment `protobuf_oneof:"payment"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PaymentNotification_TransactionDetails) Reset() { + *x = PaymentNotification_TransactionDetails{} + mi := &file_backuppb_Backup_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PaymentNotification_TransactionDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentNotification_TransactionDetails) ProtoMessage() {} + +func (x *PaymentNotification_TransactionDetails) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[105] + 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 PaymentNotification_TransactionDetails.ProtoReflect.Descriptor instead. +func (*PaymentNotification_TransactionDetails) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19, 0} +} + +func (x *PaymentNotification_TransactionDetails) GetPayment() isPaymentNotification_TransactionDetails_Payment { + if x != nil { + return x.Payment + } + return nil +} + +func (x *PaymentNotification_TransactionDetails) GetTransaction() *PaymentNotification_TransactionDetails_Transaction { + if x != nil { + if x, ok := x.Payment.(*PaymentNotification_TransactionDetails_Transaction_); ok { + return x.Transaction + } + } + return nil +} + +func (x *PaymentNotification_TransactionDetails) GetFailedTransaction() *PaymentNotification_TransactionDetails_FailedTransaction { + if x != nil { + if x, ok := x.Payment.(*PaymentNotification_TransactionDetails_FailedTransaction_); ok { + return x.FailedTransaction + } + } + return nil +} + +type isPaymentNotification_TransactionDetails_Payment interface { + isPaymentNotification_TransactionDetails_Payment() +} + +type PaymentNotification_TransactionDetails_Transaction_ struct { + Transaction *PaymentNotification_TransactionDetails_Transaction `protobuf:"bytes,1,opt,name=transaction,proto3,oneof"` +} + +type PaymentNotification_TransactionDetails_FailedTransaction_ struct { + FailedTransaction *PaymentNotification_TransactionDetails_FailedTransaction `protobuf:"bytes,2,opt,name=failedTransaction,proto3,oneof"` +} + +func (*PaymentNotification_TransactionDetails_Transaction_) isPaymentNotification_TransactionDetails_Payment() { +} + +func (*PaymentNotification_TransactionDetails_FailedTransaction_) isPaymentNotification_TransactionDetails_Payment() { +} + +type PaymentNotification_TransactionDetails_MobileCoinTxoIdentification struct { + state protoimpl.MessageState `protogen:"open.v1"` + PublicKey [][]byte `protobuf:"bytes,1,rep,name=publicKey,proto3" json:"publicKey,omitempty"` // for received transactions + KeyImages [][]byte `protobuf:"bytes,2,rep,name=keyImages,proto3" json:"keyImages,omitempty"` // for sent transactions + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Reset() { + *x = PaymentNotification_TransactionDetails_MobileCoinTxoIdentification{} + mi := &file_backuppb_Backup_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoMessage() {} + +func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[106] + 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 PaymentNotification_TransactionDetails_MobileCoinTxoIdentification.ProtoReflect.Descriptor instead. +func (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19, 0, 0} +} + +func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) GetPublicKey() [][]byte { + if x != nil { + return x.PublicKey + } + return nil +} + +func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) GetKeyImages() [][]byte { + if x != nil { + return x.KeyImages + } + return nil +} + +type PaymentNotification_TransactionDetails_FailedTransaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reason PaymentNotification_TransactionDetails_FailedTransaction_FailureReason `protobuf:"varint,1,opt,name=reason,proto3,enum=signal.backup.PaymentNotification_TransactionDetails_FailedTransaction_FailureReason" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PaymentNotification_TransactionDetails_FailedTransaction) Reset() { + *x = PaymentNotification_TransactionDetails_FailedTransaction{} + mi := &file_backuppb_Backup_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PaymentNotification_TransactionDetails_FailedTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentNotification_TransactionDetails_FailedTransaction) ProtoMessage() {} + +func (x *PaymentNotification_TransactionDetails_FailedTransaction) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[107] + 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 PaymentNotification_TransactionDetails_FailedTransaction.ProtoReflect.Descriptor instead. +func (*PaymentNotification_TransactionDetails_FailedTransaction) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19, 0, 1} +} + +func (x *PaymentNotification_TransactionDetails_FailedTransaction) GetReason() PaymentNotification_TransactionDetails_FailedTransaction_FailureReason { + if x != nil { + return x.Reason + } + return PaymentNotification_TransactionDetails_FailedTransaction_GENERIC +} + +type PaymentNotification_TransactionDetails_Transaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + Status PaymentNotification_TransactionDetails_Transaction_Status `protobuf:"varint,1,opt,name=status,proto3,enum=signal.backup.PaymentNotification_TransactionDetails_Transaction_Status" json:"status,omitempty"` + // This identification is used to map the payment table to the ledger + // and is likely required otherwise we may have issues reconciling with + // the ledger + MobileCoinIdentification *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification `protobuf:"bytes,2,opt,name=mobileCoinIdentification,proto3" json:"mobileCoinIdentification,omitempty"` + Timestamp *uint64 `protobuf:"varint,3,opt,name=timestamp,proto3,oneof" json:"timestamp,omitempty"` + BlockIndex *uint64 `protobuf:"varint,4,opt,name=blockIndex,proto3,oneof" json:"blockIndex,omitempty"` + BlockTimestamp *uint64 `protobuf:"varint,5,opt,name=blockTimestamp,proto3,oneof" json:"blockTimestamp,omitempty"` + Transaction []byte `protobuf:"bytes,6,opt,name=transaction,proto3,oneof" json:"transaction,omitempty"` // mobile coin blobs + Receipt []byte `protobuf:"bytes,7,opt,name=receipt,proto3,oneof" json:"receipt,omitempty"` // mobile coin blobs + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PaymentNotification_TransactionDetails_Transaction) Reset() { + *x = PaymentNotification_TransactionDetails_Transaction{} + mi := &file_backuppb_Backup_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PaymentNotification_TransactionDetails_Transaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PaymentNotification_TransactionDetails_Transaction) ProtoMessage() {} + +func (x *PaymentNotification_TransactionDetails_Transaction) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[108] + 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 PaymentNotification_TransactionDetails_Transaction.ProtoReflect.Descriptor instead. +func (*PaymentNotification_TransactionDetails_Transaction) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{19, 0, 2} +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetStatus() PaymentNotification_TransactionDetails_Transaction_Status { + if x != nil { + return x.Status + } + return PaymentNotification_TransactionDetails_Transaction_INITIAL +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetMobileCoinIdentification() *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification { + if x != nil { + return x.MobileCoinIdentification + } + return nil +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetTimestamp() uint64 { + if x != nil && x.Timestamp != nil { + return *x.Timestamp + } + return 0 +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetBlockIndex() uint64 { + if x != nil && x.BlockIndex != nil { + return *x.BlockIndex + } + return 0 +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetBlockTimestamp() uint64 { + if x != nil && x.BlockTimestamp != nil { + return *x.BlockTimestamp + } + return 0 +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetTransaction() []byte { + if x != nil { + return x.Transaction + } + return nil +} + +func (x *PaymentNotification_TransactionDetails_Transaction) GetReceipt() []byte { + if x != nil { + return x.Receipt + } + return nil +} + +type ContactAttachment_Name struct { + state protoimpl.MessageState `protogen:"open.v1"` + GivenName string `protobuf:"bytes,1,opt,name=givenName,proto3" json:"givenName,omitempty"` + FamilyName string `protobuf:"bytes,2,opt,name=familyName,proto3" json:"familyName,omitempty"` + Prefix string `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix,omitempty"` + Suffix string `protobuf:"bytes,4,opt,name=suffix,proto3" json:"suffix,omitempty"` + MiddleName string `protobuf:"bytes,5,opt,name=middleName,proto3" json:"middleName,omitempty"` + Nickname string `protobuf:"bytes,6,opt,name=nickname,proto3" json:"nickname,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContactAttachment_Name) Reset() { + *x = ContactAttachment_Name{} + mi := &file_backuppb_Backup_proto_msgTypes[109] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContactAttachment_Name) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactAttachment_Name) ProtoMessage() {} + +func (x *ContactAttachment_Name) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[109] + 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 ContactAttachment_Name.ProtoReflect.Descriptor instead. +func (*ContactAttachment_Name) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 0} +} + +func (x *ContactAttachment_Name) GetGivenName() string { + if x != nil { + return x.GivenName + } + return "" +} + +func (x *ContactAttachment_Name) GetFamilyName() string { + if x != nil { + return x.FamilyName + } + return "" +} + +func (x *ContactAttachment_Name) GetPrefix() string { + if x != nil { + return x.Prefix + } + return "" +} + +func (x *ContactAttachment_Name) GetSuffix() string { + if x != nil { + return x.Suffix + } + return "" +} + +func (x *ContactAttachment_Name) GetMiddleName() string { + if x != nil { + return x.MiddleName + } + return "" +} + +func (x *ContactAttachment_Name) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +type ContactAttachment_Phone struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Type ContactAttachment_Phone_Type `protobuf:"varint,2,opt,name=type,proto3,enum=signal.backup.ContactAttachment_Phone_Type" json:"type,omitempty"` + Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContactAttachment_Phone) Reset() { + *x = ContactAttachment_Phone{} + mi := &file_backuppb_Backup_proto_msgTypes[110] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContactAttachment_Phone) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactAttachment_Phone) ProtoMessage() {} + +func (x *ContactAttachment_Phone) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[110] + 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 ContactAttachment_Phone.ProtoReflect.Descriptor instead. +func (*ContactAttachment_Phone) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 1} +} + +func (x *ContactAttachment_Phone) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *ContactAttachment_Phone) GetType() ContactAttachment_Phone_Type { + if x != nil { + return x.Type + } + return ContactAttachment_Phone_UNKNOWN +} + +func (x *ContactAttachment_Phone) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +type ContactAttachment_Email struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Type ContactAttachment_Email_Type `protobuf:"varint,2,opt,name=type,proto3,enum=signal.backup.ContactAttachment_Email_Type" json:"type,omitempty"` + Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContactAttachment_Email) Reset() { + *x = ContactAttachment_Email{} + mi := &file_backuppb_Backup_proto_msgTypes[111] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContactAttachment_Email) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactAttachment_Email) ProtoMessage() {} + +func (x *ContactAttachment_Email) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[111] + 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 ContactAttachment_Email.ProtoReflect.Descriptor instead. +func (*ContactAttachment_Email) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 2} +} + +func (x *ContactAttachment_Email) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *ContactAttachment_Email) GetType() ContactAttachment_Email_Type { + if x != nil { + return x.Type + } + return ContactAttachment_Email_UNKNOWN +} + +func (x *ContactAttachment_Email) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +type ContactAttachment_PostalAddress struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type ContactAttachment_PostalAddress_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signal.backup.ContactAttachment_PostalAddress_Type" json:"type,omitempty"` + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` + Street string `protobuf:"bytes,3,opt,name=street,proto3" json:"street,omitempty"` + Pobox string `protobuf:"bytes,4,opt,name=pobox,proto3" json:"pobox,omitempty"` + Neighborhood string `protobuf:"bytes,5,opt,name=neighborhood,proto3" json:"neighborhood,omitempty"` + City string `protobuf:"bytes,6,opt,name=city,proto3" json:"city,omitempty"` + Region string `protobuf:"bytes,7,opt,name=region,proto3" json:"region,omitempty"` + Postcode string `protobuf:"bytes,8,opt,name=postcode,proto3" json:"postcode,omitempty"` + Country string `protobuf:"bytes,9,opt,name=country,proto3" json:"country,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ContactAttachment_PostalAddress) Reset() { + *x = ContactAttachment_PostalAddress{} + mi := &file_backuppb_Backup_proto_msgTypes[112] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ContactAttachment_PostalAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContactAttachment_PostalAddress) ProtoMessage() {} + +func (x *ContactAttachment_PostalAddress) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[112] + 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 ContactAttachment_PostalAddress.ProtoReflect.Descriptor instead. +func (*ContactAttachment_PostalAddress) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{22, 3} +} + +func (x *ContactAttachment_PostalAddress) GetType() ContactAttachment_PostalAddress_Type { + if x != nil { + return x.Type + } + return ContactAttachment_PostalAddress_UNKNOWN +} + +func (x *ContactAttachment_PostalAddress) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetStreet() string { + if x != nil { + return x.Street + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetPobox() string { + if x != nil { + return x.Pobox + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetNeighborhood() string { + if x != nil { + return x.Neighborhood + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetCity() string { + if x != nil { + return x.City + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetRegion() string { + if x != nil { + return x.Region + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetPostcode() string { + if x != nil { + return x.Postcode + } + return "" +} + +func (x *ContactAttachment_PostalAddress) GetCountry() string { + if x != nil { + return x.Country + } + return "" +} + +// References attachments in the backup (media) storage tier. +type FilePointer_BackupLocator struct { + state protoimpl.MessageState `protogen:"open.v1"` + MediaName string `protobuf:"bytes,1,opt,name=mediaName,proto3" json:"mediaName,omitempty"` + // If present, the cdn number of the succesful upload. + // If empty/0, may still have been uploaded, and clients + // can discover the cdn number via the list endpoint. + CdnNumber *uint32 `protobuf:"varint,2,opt,name=cdnNumber,proto3,oneof" json:"cdnNumber,omitempty"` + Key []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + Digest []byte `protobuf:"bytes,4,opt,name=digest,proto3" json:"digest,omitempty"` + Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` + // Fallback in case backup tier upload failed. + TransitCdnKey *string `protobuf:"bytes,6,opt,name=transitCdnKey,proto3,oneof" json:"transitCdnKey,omitempty"` + TransitCdnNumber *uint32 `protobuf:"varint,7,opt,name=transitCdnNumber,proto3,oneof" json:"transitCdnNumber,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilePointer_BackupLocator) Reset() { + *x = FilePointer_BackupLocator{} + mi := &file_backuppb_Backup_proto_msgTypes[113] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilePointer_BackupLocator) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilePointer_BackupLocator) ProtoMessage() {} + +func (x *FilePointer_BackupLocator) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[113] + 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 FilePointer_BackupLocator.ProtoReflect.Descriptor instead. +func (*FilePointer_BackupLocator) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 0} +} + +func (x *FilePointer_BackupLocator) GetMediaName() string { + if x != nil { + return x.MediaName + } + return "" +} + +func (x *FilePointer_BackupLocator) GetCdnNumber() uint32 { + if x != nil && x.CdnNumber != nil { + return *x.CdnNumber + } + return 0 +} + +func (x *FilePointer_BackupLocator) GetKey() []byte { + if x != nil { + return x.Key + } + return nil +} + +func (x *FilePointer_BackupLocator) GetDigest() []byte { + if x != nil { + return x.Digest + } + return nil +} + +func (x *FilePointer_BackupLocator) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *FilePointer_BackupLocator) GetTransitCdnKey() string { + if x != nil && x.TransitCdnKey != nil { + return *x.TransitCdnKey + } + return "" +} + +func (x *FilePointer_BackupLocator) GetTransitCdnNumber() uint32 { + if x != nil && x.TransitCdnNumber != nil { + return *x.TransitCdnNumber + } + return 0 +} + +// References attachments in the transit storage tier. +// May be downloaded or not when the backup is generated; +// primarily for free-tier users who cannot copy the +// attachments to the backup (media) storage tier. +type FilePointer_AttachmentLocator struct { + state protoimpl.MessageState `protogen:"open.v1"` + CdnKey string `protobuf:"bytes,1,opt,name=cdnKey,proto3" json:"cdnKey,omitempty"` + CdnNumber uint32 `protobuf:"varint,2,opt,name=cdnNumber,proto3" json:"cdnNumber,omitempty"` + UploadTimestamp *uint64 `protobuf:"varint,3,opt,name=uploadTimestamp,proto3,oneof" json:"uploadTimestamp,omitempty"` + Key []byte `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"` + Digest []byte `protobuf:"bytes,5,opt,name=digest,proto3" json:"digest,omitempty"` + Size uint32 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilePointer_AttachmentLocator) Reset() { + *x = FilePointer_AttachmentLocator{} + mi := &file_backuppb_Backup_proto_msgTypes[114] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilePointer_AttachmentLocator) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilePointer_AttachmentLocator) ProtoMessage() {} + +func (x *FilePointer_AttachmentLocator) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[114] + 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 FilePointer_AttachmentLocator.ProtoReflect.Descriptor instead. +func (*FilePointer_AttachmentLocator) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 1} +} + +func (x *FilePointer_AttachmentLocator) GetCdnKey() string { + if x != nil { + return x.CdnKey + } + return "" +} + +func (x *FilePointer_AttachmentLocator) GetCdnNumber() uint32 { + if x != nil { + return x.CdnNumber + } + return 0 +} + +func (x *FilePointer_AttachmentLocator) GetUploadTimestamp() uint64 { + if x != nil && x.UploadTimestamp != nil { + return *x.UploadTimestamp + } + return 0 +} + +func (x *FilePointer_AttachmentLocator) GetKey() []byte { + if x != nil { + return x.Key + } + return nil +} + +func (x *FilePointer_AttachmentLocator) GetDigest() []byte { + if x != nil { + return x.Digest + } + return nil +} + +func (x *FilePointer_AttachmentLocator) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +// References attachments that are invalid in such a way where download +// cannot be attempted. Could range from missing digests to missing +// CDN keys or anything else that makes download attempts impossible. +// This serves as a 'tombstone' so that the UX can show that an attachment +// did exist, but for whatever reason it's not retrievable. +type FilePointer_InvalidAttachmentLocator struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilePointer_InvalidAttachmentLocator) Reset() { + *x = FilePointer_InvalidAttachmentLocator{} + mi := &file_backuppb_Backup_proto_msgTypes[115] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilePointer_InvalidAttachmentLocator) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilePointer_InvalidAttachmentLocator) ProtoMessage() {} + +func (x *FilePointer_InvalidAttachmentLocator) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[115] + 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 FilePointer_InvalidAttachmentLocator.ProtoReflect.Descriptor instead. +func (*FilePointer_InvalidAttachmentLocator) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 2} +} + +type Quote_QuotedAttachment struct { + state protoimpl.MessageState `protogen:"open.v1"` + ContentType *string `protobuf:"bytes,1,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` + FileName *string `protobuf:"bytes,2,opt,name=fileName,proto3,oneof" json:"fileName,omitempty"` + Thumbnail *MessageAttachment `protobuf:"bytes,3,opt,name=thumbnail,proto3,oneof" json:"thumbnail,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Quote_QuotedAttachment) Reset() { + *x = Quote_QuotedAttachment{} + mi := &file_backuppb_Backup_proto_msgTypes[116] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Quote_QuotedAttachment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Quote_QuotedAttachment) ProtoMessage() {} + +func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[116] + 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 Quote_QuotedAttachment.ProtoReflect.Descriptor instead. +func (*Quote_QuotedAttachment) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{29, 0} +} + +func (x *Quote_QuotedAttachment) GetContentType() string { + if x != nil && x.ContentType != nil { + return *x.ContentType + } + return "" +} + +func (x *Quote_QuotedAttachment) GetFileName() string { + if x != nil && x.FileName != nil { + return *x.FileName + } + return "" +} + +func (x *Quote_QuotedAttachment) GetThumbnail() *MessageAttachment { + if x != nil { + return x.Thumbnail + } + return nil +} + +type GroupChangeChatUpdate_Update struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Update: + // + // *GroupChangeChatUpdate_Update_GenericGroupUpdate + // *GroupChangeChatUpdate_Update_GroupCreationUpdate + // *GroupChangeChatUpdate_Update_GroupNameUpdate + // *GroupChangeChatUpdate_Update_GroupAvatarUpdate + // *GroupChangeChatUpdate_Update_GroupDescriptionUpdate + // *GroupChangeChatUpdate_Update_GroupMembershipAccessLevelChangeUpdate + // *GroupChangeChatUpdate_Update_GroupAttributesAccessLevelChangeUpdate + // *GroupChangeChatUpdate_Update_GroupAnnouncementOnlyChangeUpdate + // *GroupChangeChatUpdate_Update_GroupAdminStatusUpdate + // *GroupChangeChatUpdate_Update_GroupMemberLeftUpdate + // *GroupChangeChatUpdate_Update_GroupMemberRemovedUpdate + // *GroupChangeChatUpdate_Update_SelfInvitedToGroupUpdate + // *GroupChangeChatUpdate_Update_SelfInvitedOtherUserToGroupUpdate + // *GroupChangeChatUpdate_Update_GroupUnknownInviteeUpdate + // *GroupChangeChatUpdate_Update_GroupInvitationAcceptedUpdate + // *GroupChangeChatUpdate_Update_GroupInvitationDeclinedUpdate + // *GroupChangeChatUpdate_Update_GroupMemberJoinedUpdate + // *GroupChangeChatUpdate_Update_GroupMemberAddedUpdate + // *GroupChangeChatUpdate_Update_GroupSelfInvitationRevokedUpdate + // *GroupChangeChatUpdate_Update_GroupInvitationRevokedUpdate + // *GroupChangeChatUpdate_Update_GroupJoinRequestUpdate + // *GroupChangeChatUpdate_Update_GroupJoinRequestApprovalUpdate + // *GroupChangeChatUpdate_Update_GroupJoinRequestCanceledUpdate + // *GroupChangeChatUpdate_Update_GroupInviteLinkResetUpdate + // *GroupChangeChatUpdate_Update_GroupInviteLinkEnabledUpdate + // *GroupChangeChatUpdate_Update_GroupInviteLinkAdminApprovalUpdate + // *GroupChangeChatUpdate_Update_GroupInviteLinkDisabledUpdate + // *GroupChangeChatUpdate_Update_GroupMemberJoinedByLinkUpdate + // *GroupChangeChatUpdate_Update_GroupV2MigrationUpdate + // *GroupChangeChatUpdate_Update_GroupV2MigrationSelfInvitedUpdate + // *GroupChangeChatUpdate_Update_GroupV2MigrationInvitedMembersUpdate + // *GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate + // *GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate + // *GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate + Update isGroupChangeChatUpdate_Update_Update `protobuf_oneof:"update"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChangeChatUpdate_Update) Reset() { + *x = GroupChangeChatUpdate_Update{} + mi := &file_backuppb_Backup_proto_msgTypes[117] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChangeChatUpdate_Update) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChangeChatUpdate_Update) ProtoMessage() {} + +func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[117] + 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 GroupChangeChatUpdate_Update.ProtoReflect.Descriptor instead. +func (*GroupChangeChatUpdate_Update) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{41, 0} +} + +func (x *GroupChangeChatUpdate_Update) GetUpdate() isGroupChangeChatUpdate_Update_Update { + if x != nil { + return x.Update + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGenericGroupUpdate() *GenericGroupUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GenericGroupUpdate); ok { + return x.GenericGroupUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupCreationUpdate() *GroupCreationUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupCreationUpdate); ok { + return x.GroupCreationUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupNameUpdate() *GroupNameUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupNameUpdate); ok { + return x.GroupNameUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupAvatarUpdate() *GroupAvatarUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupAvatarUpdate); ok { + return x.GroupAvatarUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupDescriptionUpdate() *GroupDescriptionUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupDescriptionUpdate); ok { + return x.GroupDescriptionUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupMembershipAccessLevelChangeUpdate() *GroupMembershipAccessLevelChangeUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMembershipAccessLevelChangeUpdate); ok { + return x.GroupMembershipAccessLevelChangeUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupAttributesAccessLevelChangeUpdate() *GroupAttributesAccessLevelChangeUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupAttributesAccessLevelChangeUpdate); ok { + return x.GroupAttributesAccessLevelChangeUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupAnnouncementOnlyChangeUpdate() *GroupAnnouncementOnlyChangeUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupAnnouncementOnlyChangeUpdate); ok { + return x.GroupAnnouncementOnlyChangeUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupAdminStatusUpdate() *GroupAdminStatusUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupAdminStatusUpdate); ok { + return x.GroupAdminStatusUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupMemberLeftUpdate() *GroupMemberLeftUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMemberLeftUpdate); ok { + return x.GroupMemberLeftUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupMemberRemovedUpdate() *GroupMemberRemovedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMemberRemovedUpdate); ok { + return x.GroupMemberRemovedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetSelfInvitedToGroupUpdate() *SelfInvitedToGroupUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_SelfInvitedToGroupUpdate); ok { + return x.SelfInvitedToGroupUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetSelfInvitedOtherUserToGroupUpdate() *SelfInvitedOtherUserToGroupUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_SelfInvitedOtherUserToGroupUpdate); ok { + return x.SelfInvitedOtherUserToGroupUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupUnknownInviteeUpdate() *GroupUnknownInviteeUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupUnknownInviteeUpdate); ok { + return x.GroupUnknownInviteeUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInvitationAcceptedUpdate() *GroupInvitationAcceptedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInvitationAcceptedUpdate); ok { + return x.GroupInvitationAcceptedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInvitationDeclinedUpdate() *GroupInvitationDeclinedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInvitationDeclinedUpdate); ok { + return x.GroupInvitationDeclinedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupMemberJoinedUpdate() *GroupMemberJoinedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMemberJoinedUpdate); ok { + return x.GroupMemberJoinedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupMemberAddedUpdate() *GroupMemberAddedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMemberAddedUpdate); ok { + return x.GroupMemberAddedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupSelfInvitationRevokedUpdate() *GroupSelfInvitationRevokedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupSelfInvitationRevokedUpdate); ok { + return x.GroupSelfInvitationRevokedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInvitationRevokedUpdate() *GroupInvitationRevokedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInvitationRevokedUpdate); ok { + return x.GroupInvitationRevokedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupJoinRequestUpdate() *GroupJoinRequestUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupJoinRequestUpdate); ok { + return x.GroupJoinRequestUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupJoinRequestApprovalUpdate() *GroupJoinRequestApprovalUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupJoinRequestApprovalUpdate); ok { + return x.GroupJoinRequestApprovalUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupJoinRequestCanceledUpdate() *GroupJoinRequestCanceledUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupJoinRequestCanceledUpdate); ok { + return x.GroupJoinRequestCanceledUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInviteLinkResetUpdate() *GroupInviteLinkResetUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInviteLinkResetUpdate); ok { + return x.GroupInviteLinkResetUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInviteLinkEnabledUpdate() *GroupInviteLinkEnabledUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInviteLinkEnabledUpdate); ok { + return x.GroupInviteLinkEnabledUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInviteLinkAdminApprovalUpdate() *GroupInviteLinkAdminApprovalUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInviteLinkAdminApprovalUpdate); ok { + return x.GroupInviteLinkAdminApprovalUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupInviteLinkDisabledUpdate() *GroupInviteLinkDisabledUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupInviteLinkDisabledUpdate); ok { + return x.GroupInviteLinkDisabledUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupMemberJoinedByLinkUpdate() *GroupMemberJoinedByLinkUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMemberJoinedByLinkUpdate); ok { + return x.GroupMemberJoinedByLinkUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupV2MigrationUpdate() *GroupV2MigrationUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupV2MigrationUpdate); ok { + return x.GroupV2MigrationUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupV2MigrationSelfInvitedUpdate() *GroupV2MigrationSelfInvitedUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupV2MigrationSelfInvitedUpdate); ok { + return x.GroupV2MigrationSelfInvitedUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupV2MigrationInvitedMembersUpdate() *GroupV2MigrationInvitedMembersUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupV2MigrationInvitedMembersUpdate); ok { + return x.GroupV2MigrationInvitedMembersUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupV2MigrationDroppedMembersUpdate() *GroupV2MigrationDroppedMembersUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate); ok { + return x.GroupV2MigrationDroppedMembersUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupSequenceOfRequestsAndCancelsUpdate() *GroupSequenceOfRequestsAndCancelsUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate); ok { + return x.GroupSequenceOfRequestsAndCancelsUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupExpirationTimerUpdate() *GroupExpirationTimerUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate); ok { + return x.GroupExpirationTimerUpdate + } + } + return nil +} + +type isGroupChangeChatUpdate_Update_Update interface { + isGroupChangeChatUpdate_Update_Update() +} + +type GroupChangeChatUpdate_Update_GenericGroupUpdate struct { + GenericGroupUpdate *GenericGroupUpdate `protobuf:"bytes,1,opt,name=genericGroupUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupCreationUpdate struct { + GroupCreationUpdate *GroupCreationUpdate `protobuf:"bytes,2,opt,name=groupCreationUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupNameUpdate struct { + GroupNameUpdate *GroupNameUpdate `protobuf:"bytes,3,opt,name=groupNameUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupAvatarUpdate struct { + GroupAvatarUpdate *GroupAvatarUpdate `protobuf:"bytes,4,opt,name=groupAvatarUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupDescriptionUpdate struct { + GroupDescriptionUpdate *GroupDescriptionUpdate `protobuf:"bytes,5,opt,name=groupDescriptionUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupMembershipAccessLevelChangeUpdate struct { + GroupMembershipAccessLevelChangeUpdate *GroupMembershipAccessLevelChangeUpdate `protobuf:"bytes,6,opt,name=groupMembershipAccessLevelChangeUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupAttributesAccessLevelChangeUpdate struct { + GroupAttributesAccessLevelChangeUpdate *GroupAttributesAccessLevelChangeUpdate `protobuf:"bytes,7,opt,name=groupAttributesAccessLevelChangeUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupAnnouncementOnlyChangeUpdate struct { + GroupAnnouncementOnlyChangeUpdate *GroupAnnouncementOnlyChangeUpdate `protobuf:"bytes,8,opt,name=groupAnnouncementOnlyChangeUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupAdminStatusUpdate struct { + GroupAdminStatusUpdate *GroupAdminStatusUpdate `protobuf:"bytes,9,opt,name=groupAdminStatusUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupMemberLeftUpdate struct { + GroupMemberLeftUpdate *GroupMemberLeftUpdate `protobuf:"bytes,10,opt,name=groupMemberLeftUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupMemberRemovedUpdate struct { + GroupMemberRemovedUpdate *GroupMemberRemovedUpdate `protobuf:"bytes,11,opt,name=groupMemberRemovedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_SelfInvitedToGroupUpdate struct { + SelfInvitedToGroupUpdate *SelfInvitedToGroupUpdate `protobuf:"bytes,12,opt,name=selfInvitedToGroupUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_SelfInvitedOtherUserToGroupUpdate struct { + SelfInvitedOtherUserToGroupUpdate *SelfInvitedOtherUserToGroupUpdate `protobuf:"bytes,13,opt,name=selfInvitedOtherUserToGroupUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupUnknownInviteeUpdate struct { + GroupUnknownInviteeUpdate *GroupUnknownInviteeUpdate `protobuf:"bytes,14,opt,name=groupUnknownInviteeUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInvitationAcceptedUpdate struct { + GroupInvitationAcceptedUpdate *GroupInvitationAcceptedUpdate `protobuf:"bytes,15,opt,name=groupInvitationAcceptedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInvitationDeclinedUpdate struct { + GroupInvitationDeclinedUpdate *GroupInvitationDeclinedUpdate `protobuf:"bytes,16,opt,name=groupInvitationDeclinedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupMemberJoinedUpdate struct { + GroupMemberJoinedUpdate *GroupMemberJoinedUpdate `protobuf:"bytes,17,opt,name=groupMemberJoinedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupMemberAddedUpdate struct { + GroupMemberAddedUpdate *GroupMemberAddedUpdate `protobuf:"bytes,18,opt,name=groupMemberAddedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupSelfInvitationRevokedUpdate struct { + GroupSelfInvitationRevokedUpdate *GroupSelfInvitationRevokedUpdate `protobuf:"bytes,19,opt,name=groupSelfInvitationRevokedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInvitationRevokedUpdate struct { + GroupInvitationRevokedUpdate *GroupInvitationRevokedUpdate `protobuf:"bytes,20,opt,name=groupInvitationRevokedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupJoinRequestUpdate struct { + GroupJoinRequestUpdate *GroupJoinRequestUpdate `protobuf:"bytes,21,opt,name=groupJoinRequestUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupJoinRequestApprovalUpdate struct { + GroupJoinRequestApprovalUpdate *GroupJoinRequestApprovalUpdate `protobuf:"bytes,22,opt,name=groupJoinRequestApprovalUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupJoinRequestCanceledUpdate struct { + GroupJoinRequestCanceledUpdate *GroupJoinRequestCanceledUpdate `protobuf:"bytes,23,opt,name=groupJoinRequestCanceledUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInviteLinkResetUpdate struct { + GroupInviteLinkResetUpdate *GroupInviteLinkResetUpdate `protobuf:"bytes,24,opt,name=groupInviteLinkResetUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInviteLinkEnabledUpdate struct { + GroupInviteLinkEnabledUpdate *GroupInviteLinkEnabledUpdate `protobuf:"bytes,25,opt,name=groupInviteLinkEnabledUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInviteLinkAdminApprovalUpdate struct { + GroupInviteLinkAdminApprovalUpdate *GroupInviteLinkAdminApprovalUpdate `protobuf:"bytes,26,opt,name=groupInviteLinkAdminApprovalUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupInviteLinkDisabledUpdate struct { + GroupInviteLinkDisabledUpdate *GroupInviteLinkDisabledUpdate `protobuf:"bytes,27,opt,name=groupInviteLinkDisabledUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupMemberJoinedByLinkUpdate struct { + GroupMemberJoinedByLinkUpdate *GroupMemberJoinedByLinkUpdate `protobuf:"bytes,28,opt,name=groupMemberJoinedByLinkUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupV2MigrationUpdate struct { + GroupV2MigrationUpdate *GroupV2MigrationUpdate `protobuf:"bytes,29,opt,name=groupV2MigrationUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupV2MigrationSelfInvitedUpdate struct { + GroupV2MigrationSelfInvitedUpdate *GroupV2MigrationSelfInvitedUpdate `protobuf:"bytes,30,opt,name=groupV2MigrationSelfInvitedUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupV2MigrationInvitedMembersUpdate struct { + GroupV2MigrationInvitedMembersUpdate *GroupV2MigrationInvitedMembersUpdate `protobuf:"bytes,31,opt,name=groupV2MigrationInvitedMembersUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate struct { + GroupV2MigrationDroppedMembersUpdate *GroupV2MigrationDroppedMembersUpdate `protobuf:"bytes,32,opt,name=groupV2MigrationDroppedMembersUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate struct { + GroupSequenceOfRequestsAndCancelsUpdate *GroupSequenceOfRequestsAndCancelsUpdate `protobuf:"bytes,33,opt,name=groupSequenceOfRequestsAndCancelsUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate struct { + GroupExpirationTimerUpdate *GroupExpirationTimerUpdate `protobuf:"bytes,34,opt,name=groupExpirationTimerUpdate,proto3,oneof"` +} + +func (*GroupChangeChatUpdate_Update_GenericGroupUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupCreationUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupNameUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupAvatarUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupDescriptionUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupMembershipAccessLevelChangeUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupAttributesAccessLevelChangeUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupAnnouncementOnlyChangeUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupAdminStatusUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupMemberLeftUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupMemberRemovedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_SelfInvitedToGroupUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_SelfInvitedOtherUserToGroupUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupUnknownInviteeUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInvitationAcceptedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInvitationDeclinedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupMemberJoinedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupMemberAddedUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupSelfInvitationRevokedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInvitationRevokedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupJoinRequestUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupJoinRequestApprovalUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupJoinRequestCanceledUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInviteLinkResetUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInviteLinkEnabledUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInviteLinkAdminApprovalUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupInviteLinkDisabledUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupMemberJoinedByLinkUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupV2MigrationUpdate) isGroupChangeChatUpdate_Update_Update() {} + +func (*GroupChangeChatUpdate_Update_GroupV2MigrationSelfInvitedUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupV2MigrationInvitedMembersUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +type GroupInvitationRevokedUpdate_Invitee struct { + state protoimpl.MessageState `protogen:"open.v1"` + InviterAci []byte `protobuf:"bytes,1,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` + // Prefer to use aci over pni. No need to set + // pni if aci is set. Both can be missing. + InviteeAci []byte `protobuf:"bytes,2,opt,name=inviteeAci,proto3,oneof" json:"inviteeAci,omitempty"` + InviteePni []byte `protobuf:"bytes,3,opt,name=inviteePni,proto3,oneof" json:"inviteePni,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { + *x = GroupInvitationRevokedUpdate_Invitee{} + mi := &file_backuppb_Backup_proto_msgTypes[118] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInvitationRevokedUpdate_Invitee) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} + +func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[118] + 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 GroupInvitationRevokedUpdate_Invitee.ProtoReflect.Descriptor instead. +func (*GroupInvitationRevokedUpdate_Invitee) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{61, 0} +} + +func (x *GroupInvitationRevokedUpdate_Invitee) GetInviterAci() []byte { + if x != nil { + return x.InviterAci + } + return nil +} + +func (x *GroupInvitationRevokedUpdate_Invitee) GetInviteeAci() []byte { + if x != nil { + return x.InviteeAci + } + return nil +} + +func (x *GroupInvitationRevokedUpdate_Invitee) GetInviteePni() []byte { + if x != nil { + return x.InviteePni + } + return nil +} + +type ChatStyle_Gradient struct { + state protoimpl.MessageState `protogen:"open.v1"` + Angle uint32 `protobuf:"varint,1,opt,name=angle,proto3" json:"angle,omitempty"` // degrees + Colors []uint32 `protobuf:"fixed32,2,rep,packed,name=colors,proto3" json:"colors,omitempty"` // 0xAARRGGBB + Positions []float32 `protobuf:"fixed32,3,rep,packed,name=positions,proto3" json:"positions,omitempty"` // percent from 0 to 1 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatStyle_Gradient) Reset() { + *x = ChatStyle_Gradient{} + mi := &file_backuppb_Backup_proto_msgTypes[119] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatStyle_Gradient) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatStyle_Gradient) ProtoMessage() {} + +func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[119] + 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 ChatStyle_Gradient.ProtoReflect.Descriptor instead. +func (*ChatStyle_Gradient) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 0} +} + +func (x *ChatStyle_Gradient) GetAngle() uint32 { + if x != nil { + return x.Angle + } + return 0 +} + +func (x *ChatStyle_Gradient) GetColors() []uint32 { + if x != nil { + return x.Colors + } + return nil +} + +func (x *ChatStyle_Gradient) GetPositions() []float32 { + if x != nil { + return x.Positions + } + return nil +} + +type ChatStyle_CustomChatColor struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // Types that are valid to be assigned to Color: + // + // *ChatStyle_CustomChatColor_Solid + // *ChatStyle_CustomChatColor_Gradient + Color isChatStyle_CustomChatColor_Color `protobuf_oneof:"color"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatStyle_CustomChatColor) Reset() { + *x = ChatStyle_CustomChatColor{} + mi := &file_backuppb_Backup_proto_msgTypes[120] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatStyle_CustomChatColor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatStyle_CustomChatColor) ProtoMessage() {} + +func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[120] + 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 ChatStyle_CustomChatColor.ProtoReflect.Descriptor instead. +func (*ChatStyle_CustomChatColor) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 1} +} + +func (x *ChatStyle_CustomChatColor) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *ChatStyle_CustomChatColor) GetColor() isChatStyle_CustomChatColor_Color { + if x != nil { + return x.Color + } + return nil +} + +func (x *ChatStyle_CustomChatColor) GetSolid() uint32 { + if x != nil { + if x, ok := x.Color.(*ChatStyle_CustomChatColor_Solid); ok { + return x.Solid + } + } + return 0 +} + +func (x *ChatStyle_CustomChatColor) GetGradient() *ChatStyle_Gradient { + if x != nil { + if x, ok := x.Color.(*ChatStyle_CustomChatColor_Gradient); ok { + return x.Gradient + } + } + return nil +} + +type isChatStyle_CustomChatColor_Color interface { + isChatStyle_CustomChatColor_Color() +} + +type ChatStyle_CustomChatColor_Solid struct { + Solid uint32 `protobuf:"fixed32,2,opt,name=solid,proto3,oneof"` // 0xAARRGGBB +} + +type ChatStyle_CustomChatColor_Gradient struct { + Gradient *ChatStyle_Gradient `protobuf:"bytes,3,opt,name=gradient,proto3,oneof"` +} + +func (*ChatStyle_CustomChatColor_Solid) isChatStyle_CustomChatColor_Color() {} + +func (*ChatStyle_CustomChatColor_Gradient) isChatStyle_CustomChatColor_Color() {} + +type ChatStyle_AutomaticBubbleColor struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatStyle_AutomaticBubbleColor) Reset() { + *x = ChatStyle_AutomaticBubbleColor{} + mi := &file_backuppb_Backup_proto_msgTypes[121] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatStyle_AutomaticBubbleColor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} + +func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[121] + 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 ChatStyle_AutomaticBubbleColor.ProtoReflect.Descriptor instead. +func (*ChatStyle_AutomaticBubbleColor) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 2} +} + +var File_backuppb_Backup_proto protoreflect.FileDescriptor + +//go:embed Backup.pb.raw +var file_backuppb_Backup_proto_rawDesc []byte + +var ( + file_backuppb_Backup_proto_rawDescOnce sync.Once + file_backuppb_Backup_proto_rawDescData = file_backuppb_Backup_proto_rawDesc +) + +func file_backuppb_Backup_proto_rawDescGZIP() []byte { + file_backuppb_Backup_proto_rawDescOnce.Do(func() { + file_backuppb_Backup_proto_rawDescData = protoimpl.X.CompressGZIP(file_backuppb_Backup_proto_rawDescData) + }) + return file_backuppb_Backup_proto_rawDescData +} + +var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 30) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 122) +var file_backuppb_Backup_proto_goTypes = []any{ + (GroupV2AccessLevel)(0), // 0: signal.backup.GroupV2AccessLevel + (AccountData_PhoneNumberSharingMode)(0), // 1: signal.backup.AccountData.PhoneNumberSharingMode + (AccountData_UsernameLink_Color)(0), // 2: signal.backup.AccountData.UsernameLink.Color + (Contact_IdentityState)(0), // 3: signal.backup.Contact.IdentityState + (Contact_Visibility)(0), // 4: signal.backup.Contact.Visibility + (Group_StorySendMode)(0), // 5: signal.backup.Group.StorySendMode + (Group_Member_Role)(0), // 6: signal.backup.Group.Member.Role + (Group_AccessControl_AccessRequired)(0), // 7: signal.backup.Group.AccessControl.AccessRequired + (CallLink_Restrictions)(0), // 8: signal.backup.CallLink.Restrictions + (AdHocCall_State)(0), // 9: signal.backup.AdHocCall.State + (DistributionList_PrivacyMode)(0), // 10: signal.backup.DistributionList.PrivacyMode + (SendStatus_Failed_FailureReason)(0), // 11: signal.backup.SendStatus.Failed.FailureReason + (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason)(0), // 12: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + (PaymentNotification_TransactionDetails_Transaction_Status)(0), // 13: signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + (GiftBadge_State)(0), // 14: signal.backup.GiftBadge.State + (ContactAttachment_Phone_Type)(0), // 15: signal.backup.ContactAttachment.Phone.Type + (ContactAttachment_Email_Type)(0), // 16: signal.backup.ContactAttachment.Email.Type + (ContactAttachment_PostalAddress_Type)(0), // 17: signal.backup.ContactAttachment.PostalAddress.Type + (MessageAttachment_Flag)(0), // 18: signal.backup.MessageAttachment.Flag + (Quote_Type)(0), // 19: signal.backup.Quote.Type + (BodyRange_Style)(0), // 20: signal.backup.BodyRange.Style + (IndividualCall_Type)(0), // 21: signal.backup.IndividualCall.Type + (IndividualCall_Direction)(0), // 22: signal.backup.IndividualCall.Direction + (IndividualCall_State)(0), // 23: signal.backup.IndividualCall.State + (GroupCall_State)(0), // 24: signal.backup.GroupCall.State + (SimpleChatUpdate_Type)(0), // 25: signal.backup.SimpleChatUpdate.Type + (ChatStyle_WallpaperPreset)(0), // 26: signal.backup.ChatStyle.WallpaperPreset + (ChatStyle_BubbleColorPreset)(0), // 27: signal.backup.ChatStyle.BubbleColorPreset + (NotificationProfile_DayOfWeek)(0), // 28: signal.backup.NotificationProfile.DayOfWeek + (ChatFolder_FolderType)(0), // 29: signal.backup.ChatFolder.FolderType + (*BackupInfo)(nil), // 30: signal.backup.BackupInfo + (*Frame)(nil), // 31: signal.backup.Frame + (*AccountData)(nil), // 32: signal.backup.AccountData + (*Recipient)(nil), // 33: signal.backup.Recipient + (*Contact)(nil), // 34: signal.backup.Contact + (*Group)(nil), // 35: signal.backup.Group + (*Self)(nil), // 36: signal.backup.Self + (*ReleaseNotes)(nil), // 37: signal.backup.ReleaseNotes + (*Chat)(nil), // 38: signal.backup.Chat + (*CallLink)(nil), // 39: signal.backup.CallLink + (*AdHocCall)(nil), // 40: signal.backup.AdHocCall + (*DistributionListItem)(nil), // 41: signal.backup.DistributionListItem + (*DistributionList)(nil), // 42: signal.backup.DistributionList + (*ChatItem)(nil), // 43: signal.backup.ChatItem + (*SendStatus)(nil), // 44: signal.backup.SendStatus + (*Text)(nil), // 45: signal.backup.Text + (*StandardMessage)(nil), // 46: signal.backup.StandardMessage + (*ContactMessage)(nil), // 47: signal.backup.ContactMessage + (*DirectStoryReplyMessage)(nil), // 48: signal.backup.DirectStoryReplyMessage + (*PaymentNotification)(nil), // 49: signal.backup.PaymentNotification + (*GiftBadge)(nil), // 50: signal.backup.GiftBadge + (*ViewOnceMessage)(nil), // 51: signal.backup.ViewOnceMessage + (*ContactAttachment)(nil), // 52: signal.backup.ContactAttachment + (*StickerMessage)(nil), // 53: signal.backup.StickerMessage + (*RemoteDeletedMessage)(nil), // 54: signal.backup.RemoteDeletedMessage + (*Sticker)(nil), // 55: signal.backup.Sticker + (*LinkPreview)(nil), // 56: signal.backup.LinkPreview + (*MessageAttachment)(nil), // 57: signal.backup.MessageAttachment + (*FilePointer)(nil), // 58: signal.backup.FilePointer + (*Quote)(nil), // 59: signal.backup.Quote + (*BodyRange)(nil), // 60: signal.backup.BodyRange + (*Reaction)(nil), // 61: signal.backup.Reaction + (*ChatUpdateMessage)(nil), // 62: signal.backup.ChatUpdateMessage + (*IndividualCall)(nil), // 63: signal.backup.IndividualCall + (*GroupCall)(nil), // 64: signal.backup.GroupCall + (*SimpleChatUpdate)(nil), // 65: signal.backup.SimpleChatUpdate + (*ExpirationTimerChatUpdate)(nil), // 66: signal.backup.ExpirationTimerChatUpdate + (*ProfileChangeChatUpdate)(nil), // 67: signal.backup.ProfileChangeChatUpdate + (*LearnedProfileChatUpdate)(nil), // 68: signal.backup.LearnedProfileChatUpdate + (*ThreadMergeChatUpdate)(nil), // 69: signal.backup.ThreadMergeChatUpdate + (*SessionSwitchoverChatUpdate)(nil), // 70: signal.backup.SessionSwitchoverChatUpdate + (*GroupChangeChatUpdate)(nil), // 71: signal.backup.GroupChangeChatUpdate + (*GenericGroupUpdate)(nil), // 72: signal.backup.GenericGroupUpdate + (*GroupCreationUpdate)(nil), // 73: signal.backup.GroupCreationUpdate + (*GroupNameUpdate)(nil), // 74: signal.backup.GroupNameUpdate + (*GroupAvatarUpdate)(nil), // 75: signal.backup.GroupAvatarUpdate + (*GroupDescriptionUpdate)(nil), // 76: signal.backup.GroupDescriptionUpdate + (*GroupMembershipAccessLevelChangeUpdate)(nil), // 77: signal.backup.GroupMembershipAccessLevelChangeUpdate + (*GroupAttributesAccessLevelChangeUpdate)(nil), // 78: signal.backup.GroupAttributesAccessLevelChangeUpdate + (*GroupAnnouncementOnlyChangeUpdate)(nil), // 79: signal.backup.GroupAnnouncementOnlyChangeUpdate + (*GroupAdminStatusUpdate)(nil), // 80: signal.backup.GroupAdminStatusUpdate + (*GroupMemberLeftUpdate)(nil), // 81: signal.backup.GroupMemberLeftUpdate + (*GroupMemberRemovedUpdate)(nil), // 82: signal.backup.GroupMemberRemovedUpdate + (*SelfInvitedToGroupUpdate)(nil), // 83: signal.backup.SelfInvitedToGroupUpdate + (*SelfInvitedOtherUserToGroupUpdate)(nil), // 84: signal.backup.SelfInvitedOtherUserToGroupUpdate + (*GroupUnknownInviteeUpdate)(nil), // 85: signal.backup.GroupUnknownInviteeUpdate + (*GroupInvitationAcceptedUpdate)(nil), // 86: signal.backup.GroupInvitationAcceptedUpdate + (*GroupInvitationDeclinedUpdate)(nil), // 87: signal.backup.GroupInvitationDeclinedUpdate + (*GroupMemberJoinedUpdate)(nil), // 88: signal.backup.GroupMemberJoinedUpdate + (*GroupMemberAddedUpdate)(nil), // 89: signal.backup.GroupMemberAddedUpdate + (*GroupSelfInvitationRevokedUpdate)(nil), // 90: signal.backup.GroupSelfInvitationRevokedUpdate + (*GroupInvitationRevokedUpdate)(nil), // 91: signal.backup.GroupInvitationRevokedUpdate + (*GroupJoinRequestUpdate)(nil), // 92: signal.backup.GroupJoinRequestUpdate + (*GroupJoinRequestApprovalUpdate)(nil), // 93: signal.backup.GroupJoinRequestApprovalUpdate + (*GroupJoinRequestCanceledUpdate)(nil), // 94: signal.backup.GroupJoinRequestCanceledUpdate + (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 95: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + (*GroupInviteLinkResetUpdate)(nil), // 96: signal.backup.GroupInviteLinkResetUpdate + (*GroupInviteLinkEnabledUpdate)(nil), // 97: signal.backup.GroupInviteLinkEnabledUpdate + (*GroupInviteLinkAdminApprovalUpdate)(nil), // 98: signal.backup.GroupInviteLinkAdminApprovalUpdate + (*GroupInviteLinkDisabledUpdate)(nil), // 99: signal.backup.GroupInviteLinkDisabledUpdate + (*GroupMemberJoinedByLinkUpdate)(nil), // 100: signal.backup.GroupMemberJoinedByLinkUpdate + (*GroupV2MigrationUpdate)(nil), // 101: signal.backup.GroupV2MigrationUpdate + (*GroupV2MigrationSelfInvitedUpdate)(nil), // 102: signal.backup.GroupV2MigrationSelfInvitedUpdate + (*GroupV2MigrationInvitedMembersUpdate)(nil), // 103: signal.backup.GroupV2MigrationInvitedMembersUpdate + (*GroupV2MigrationDroppedMembersUpdate)(nil), // 104: signal.backup.GroupV2MigrationDroppedMembersUpdate + (*GroupExpirationTimerUpdate)(nil), // 105: signal.backup.GroupExpirationTimerUpdate + (*StickerPack)(nil), // 106: signal.backup.StickerPack + (*ChatStyle)(nil), // 107: signal.backup.ChatStyle + (*NotificationProfile)(nil), // 108: signal.backup.NotificationProfile + (*ChatFolder)(nil), // 109: signal.backup.ChatFolder + (*AccountData_UsernameLink)(nil), // 110: signal.backup.AccountData.UsernameLink + (*AccountData_AccountSettings)(nil), // 111: signal.backup.AccountData.AccountSettings + (*AccountData_SubscriberData)(nil), // 112: signal.backup.AccountData.SubscriberData + (*AccountData_IAPSubscriberData)(nil), // 113: signal.backup.AccountData.IAPSubscriberData + (*Contact_Registered)(nil), // 114: signal.backup.Contact.Registered + (*Contact_NotRegistered)(nil), // 115: signal.backup.Contact.NotRegistered + (*Contact_Name)(nil), // 116: signal.backup.Contact.Name + (*Group_GroupSnapshot)(nil), // 117: signal.backup.Group.GroupSnapshot + (*Group_GroupAttributeBlob)(nil), // 118: signal.backup.Group.GroupAttributeBlob + (*Group_Member)(nil), // 119: signal.backup.Group.Member + (*Group_MemberPendingProfileKey)(nil), // 120: signal.backup.Group.MemberPendingProfileKey + (*Group_MemberPendingAdminApproval)(nil), // 121: signal.backup.Group.MemberPendingAdminApproval + (*Group_MemberBanned)(nil), // 122: signal.backup.Group.MemberBanned + (*Group_AccessControl)(nil), // 123: signal.backup.Group.AccessControl + (*ChatItem_IncomingMessageDetails)(nil), // 124: signal.backup.ChatItem.IncomingMessageDetails + (*ChatItem_OutgoingMessageDetails)(nil), // 125: signal.backup.ChatItem.OutgoingMessageDetails + (*ChatItem_DirectionlessMessageDetails)(nil), // 126: signal.backup.ChatItem.DirectionlessMessageDetails + (*SendStatus_Pending)(nil), // 127: signal.backup.SendStatus.Pending + (*SendStatus_Sent)(nil), // 128: signal.backup.SendStatus.Sent + (*SendStatus_Delivered)(nil), // 129: signal.backup.SendStatus.Delivered + (*SendStatus_Read)(nil), // 130: signal.backup.SendStatus.Read + (*SendStatus_Viewed)(nil), // 131: signal.backup.SendStatus.Viewed + (*SendStatus_Skipped)(nil), // 132: signal.backup.SendStatus.Skipped + (*SendStatus_Failed)(nil), // 133: signal.backup.SendStatus.Failed + (*DirectStoryReplyMessage_TextReply)(nil), // 134: signal.backup.DirectStoryReplyMessage.TextReply + (*PaymentNotification_TransactionDetails)(nil), // 135: signal.backup.PaymentNotification.TransactionDetails + (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 136: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 137: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + (*PaymentNotification_TransactionDetails_Transaction)(nil), // 138: signal.backup.PaymentNotification.TransactionDetails.Transaction + (*ContactAttachment_Name)(nil), // 139: signal.backup.ContactAttachment.Name + (*ContactAttachment_Phone)(nil), // 140: signal.backup.ContactAttachment.Phone + (*ContactAttachment_Email)(nil), // 141: signal.backup.ContactAttachment.Email + (*ContactAttachment_PostalAddress)(nil), // 142: signal.backup.ContactAttachment.PostalAddress + (*FilePointer_BackupLocator)(nil), // 143: signal.backup.FilePointer.BackupLocator + (*FilePointer_AttachmentLocator)(nil), // 144: signal.backup.FilePointer.AttachmentLocator + (*FilePointer_InvalidAttachmentLocator)(nil), // 145: signal.backup.FilePointer.InvalidAttachmentLocator + (*Quote_QuotedAttachment)(nil), // 146: signal.backup.Quote.QuotedAttachment + (*GroupChangeChatUpdate_Update)(nil), // 147: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 148: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 149: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 150: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 151: signal.backup.ChatStyle.AutomaticBubbleColor +} +var file_backuppb_Backup_proto_depIdxs = []int32{ + 32, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData + 33, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient + 38, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat + 43, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem + 106, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack + 40, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall + 108, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile + 109, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder + 110, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink + 112, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData + 111, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings + 113, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData + 34, // 12: signal.backup.Recipient.contact:type_name -> signal.backup.Contact + 35, // 13: signal.backup.Recipient.group:type_name -> signal.backup.Group + 41, // 14: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem + 36, // 15: signal.backup.Recipient.self:type_name -> signal.backup.Self + 37, // 16: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes + 39, // 17: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink + 4, // 18: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility + 114, // 19: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered + 115, // 20: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered + 3, // 21: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState + 116, // 22: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name + 5, // 23: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode + 117, // 24: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot + 107, // 25: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle + 8, // 26: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions + 9, // 27: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State + 42, // 28: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList + 10, // 29: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode + 43, // 30: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem + 124, // 31: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails + 125, // 32: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails + 126, // 33: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails + 46, // 34: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage + 47, // 35: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage + 53, // 36: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage + 54, // 37: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage + 62, // 38: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage + 49, // 39: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification + 50, // 40: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge + 51, // 41: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage + 48, // 42: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage + 127, // 43: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending + 128, // 44: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent + 129, // 45: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered + 130, // 46: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read + 131, // 47: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed + 132, // 48: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped + 133, // 49: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed + 60, // 50: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange + 59, // 51: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote + 45, // 52: signal.backup.StandardMessage.text:type_name -> signal.backup.Text + 57, // 53: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment + 56, // 54: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview + 58, // 55: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer + 61, // 56: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction + 52, // 57: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment + 61, // 58: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction + 134, // 59: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply + 61, // 60: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction + 135, // 61: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails + 14, // 62: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State + 57, // 63: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment + 61, // 64: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction + 139, // 65: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name + 140, // 66: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone + 141, // 67: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email + 142, // 68: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress + 58, // 69: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer + 55, // 70: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker + 61, // 71: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction + 58, // 72: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer + 58, // 73: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer + 58, // 74: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer + 18, // 75: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag + 143, // 76: signal.backup.FilePointer.backupLocator:type_name -> signal.backup.FilePointer.BackupLocator + 144, // 77: signal.backup.FilePointer.attachmentLocator:type_name -> signal.backup.FilePointer.AttachmentLocator + 145, // 78: signal.backup.FilePointer.invalidAttachmentLocator:type_name -> signal.backup.FilePointer.InvalidAttachmentLocator + 45, // 79: signal.backup.Quote.text:type_name -> signal.backup.Text + 146, // 80: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 19, // 81: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 20, // 82: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 65, // 83: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 71, // 84: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 66, // 85: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 67, // 86: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 69, // 87: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 70, // 88: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 63, // 89: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 64, // 90: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 68, // 91: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 21, // 92: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 22, // 93: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 23, // 94: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 24, // 95: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 25, // 96: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 147, // 97: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 0, // 98: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 0, // 99: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 148, // 100: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 26, // 101: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 58, // 102: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 151, // 103: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 27, // 104: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 28, // 105: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 29, // 106: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 2, // 107: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 1, // 108: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 107, // 109: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 150, // 110: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 118, // 111: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 118, // 112: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 118, // 113: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 123, // 114: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 119, // 115: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 120, // 116: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 121, // 117: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 122, // 118: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 6, // 119: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 119, // 120: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 7, // 121: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 7, // 122: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 7, // 123: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 44, // 124: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 11, // 125: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 45, // 126: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 58, // 127: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 138, // 128: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 137, // 129: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 12, // 130: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 13, // 131: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 136, // 132: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 15, // 133: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 16, // 134: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 17, // 135: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 57, // 136: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 72, // 137: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 73, // 138: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 74, // 139: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 75, // 140: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 76, // 141: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 77, // 142: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 78, // 143: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 79, // 144: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 80, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 81, // 146: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 82, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 83, // 148: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 84, // 149: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 85, // 150: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 86, // 151: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 87, // 152: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 88, // 153: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 89, // 154: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 90, // 155: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 91, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 92, // 157: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 93, // 158: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 94, // 159: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 96, // 160: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 97, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 98, // 162: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 99, // 163: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 100, // 164: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 101, // 165: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 102, // 166: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 103, // 167: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 104, // 168: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 95, // 169: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 105, // 170: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 149, // 171: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 172, // [172:172] is the sub-list for method output_type + 172, // [172:172] is the sub-list for method input_type + 172, // [172:172] is the sub-list for extension type_name + 172, // [172:172] is the sub-list for extension extendee + 0, // [0:172] is the sub-list for field type_name +} + +func init() { file_backuppb_Backup_proto_init() } +func file_backuppb_Backup_proto_init() { + if File_backuppb_Backup_proto != nil { + return + } + file_backuppb_Backup_proto_msgTypes[1].OneofWrappers = []any{ + (*Frame_Account)(nil), + (*Frame_Recipient)(nil), + (*Frame_Chat)(nil), + (*Frame_ChatItem)(nil), + (*Frame_StickerPack)(nil), + (*Frame_AdHocCall)(nil), + (*Frame_NotificationProfile)(nil), + (*Frame_ChatFolder)(nil), + } + file_backuppb_Backup_proto_msgTypes[2].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[3].OneofWrappers = []any{ + (*Recipient_Contact)(nil), + (*Recipient_Group)(nil), + (*Recipient_DistributionList)(nil), + (*Recipient_Self)(nil), + (*Recipient_ReleaseNotes)(nil), + (*Recipient_CallLink)(nil), + } + file_backuppb_Backup_proto_msgTypes[4].OneofWrappers = []any{ + (*Contact_Registered_)(nil), + (*Contact_NotRegistered_)(nil), + } + file_backuppb_Backup_proto_msgTypes[8].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[9].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[11].OneofWrappers = []any{ + (*DistributionListItem_DeletionTimestamp)(nil), + (*DistributionListItem_DistributionList)(nil), + } + file_backuppb_Backup_proto_msgTypes[13].OneofWrappers = []any{ + (*ChatItem_Incoming)(nil), + (*ChatItem_Outgoing)(nil), + (*ChatItem_Directionless)(nil), + (*ChatItem_StandardMessage)(nil), + (*ChatItem_ContactMessage)(nil), + (*ChatItem_StickerMessage)(nil), + (*ChatItem_RemoteDeletedMessage)(nil), + (*ChatItem_UpdateMessage)(nil), + (*ChatItem_PaymentNotification)(nil), + (*ChatItem_GiftBadge)(nil), + (*ChatItem_ViewOnceMessage)(nil), + (*ChatItem_DirectStoryReplyMessage)(nil), + } + file_backuppb_Backup_proto_msgTypes[14].OneofWrappers = []any{ + (*SendStatus_Pending_)(nil), + (*SendStatus_Sent_)(nil), + (*SendStatus_Delivered_)(nil), + (*SendStatus_Read_)(nil), + (*SendStatus_Viewed_)(nil), + (*SendStatus_Skipped_)(nil), + (*SendStatus_Failed_)(nil), + } + file_backuppb_Backup_proto_msgTypes[16].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[18].OneofWrappers = []any{ + (*DirectStoryReplyMessage_TextReply_)(nil), + (*DirectStoryReplyMessage_Emoji)(nil), + } + file_backuppb_Backup_proto_msgTypes[19].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[22].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[25].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[26].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[27].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[28].OneofWrappers = []any{ + (*FilePointer_BackupLocator_)(nil), + (*FilePointer_AttachmentLocator_)(nil), + (*FilePointer_InvalidAttachmentLocator_)(nil), + } + file_backuppb_Backup_proto_msgTypes[29].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[30].OneofWrappers = []any{ + (*BodyRange_MentionAci)(nil), + (*BodyRange_Style_)(nil), + } + file_backuppb_Backup_proto_msgTypes[32].OneofWrappers = []any{ + (*ChatUpdateMessage_SimpleUpdate)(nil), + (*ChatUpdateMessage_GroupChange)(nil), + (*ChatUpdateMessage_ExpirationTimerChange)(nil), + (*ChatUpdateMessage_ProfileChange)(nil), + (*ChatUpdateMessage_ThreadMerge)(nil), + (*ChatUpdateMessage_SessionSwitchover)(nil), + (*ChatUpdateMessage_IndividualCall)(nil), + (*ChatUpdateMessage_GroupCall)(nil), + (*ChatUpdateMessage_LearnedProfileChange)(nil), + } + file_backuppb_Backup_proto_msgTypes[33].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[34].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[38].OneofWrappers = []any{ + (*LearnedProfileChatUpdate_E164)(nil), + (*LearnedProfileChatUpdate_Username)(nil), + } + file_backuppb_Backup_proto_msgTypes[42].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[43].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[44].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[45].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[46].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[47].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[48].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[49].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[50].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[52].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[53].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[55].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[56].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[57].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[59].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[60].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[61].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[63].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[66].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[67].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[68].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[69].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[75].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[77].OneofWrappers = []any{ + (*ChatStyle_WallpaperPreset_)(nil), + (*ChatStyle_WallpaperPhoto)(nil), + (*ChatStyle_AutoBubbleColor)(nil), + (*ChatStyle_BubbleColorPreset_)(nil), + (*ChatStyle_CustomColorId)(nil), + } + file_backuppb_Backup_proto_msgTypes[78].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[81].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[83].OneofWrappers = []any{ + (*AccountData_IAPSubscriberData_PurchaseToken)(nil), + (*AccountData_IAPSubscriberData_OriginalTransactionId)(nil), + } + file_backuppb_Backup_proto_msgTypes[88].OneofWrappers = []any{ + (*Group_GroupAttributeBlob_Title)(nil), + (*Group_GroupAttributeBlob_Avatar)(nil), + (*Group_GroupAttributeBlob_DisappearingMessagesDuration)(nil), + (*Group_GroupAttributeBlob_DescriptionText)(nil), + } + file_backuppb_Backup_proto_msgTypes[94].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[105].OneofWrappers = []any{ + (*PaymentNotification_TransactionDetails_Transaction_)(nil), + (*PaymentNotification_TransactionDetails_FailedTransaction_)(nil), + } + file_backuppb_Backup_proto_msgTypes[108].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[113].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{ + (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupAvatarUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupDescriptionUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMembershipAccessLevelChangeUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupAttributesAccessLevelChangeUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupAnnouncementOnlyChangeUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupAdminStatusUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMemberLeftUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMemberRemovedUpdate)(nil), + (*GroupChangeChatUpdate_Update_SelfInvitedToGroupUpdate)(nil), + (*GroupChangeChatUpdate_Update_SelfInvitedOtherUserToGroupUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupUnknownInviteeUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInvitationAcceptedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInvitationDeclinedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMemberJoinedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMemberAddedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupSelfInvitationRevokedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInvitationRevokedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupJoinRequestUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupJoinRequestApprovalUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupJoinRequestCanceledUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInviteLinkResetUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInviteLinkEnabledUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInviteLinkAdminApprovalUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupInviteLinkDisabledUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMemberJoinedByLinkUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupV2MigrationUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupV2MigrationSelfInvitedUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupV2MigrationInvitedMembersUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), + } + file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{ + (*ChatStyle_CustomChatColor_Solid)(nil), + (*ChatStyle_CustomChatColor_Gradient)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_backuppb_Backup_proto_rawDesc, + NumEnums: 30, + NumMessages: 122, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_backuppb_Backup_proto_goTypes, + DependencyIndexes: file_backuppb_Backup_proto_depIdxs, + EnumInfos: file_backuppb_Backup_proto_enumTypes, + MessageInfos: file_backuppb_Backup_proto_msgTypes, + }.Build() + File_backuppb_Backup_proto = out.File + file_backuppb_Backup_proto_rawDesc = nil + file_backuppb_Backup_proto_goTypes = nil + file_backuppb_Backup_proto_depIdxs = nil +} diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.raw b/pkg/signalmeow/protobuf/backuppb/Backup.pb.raw new file mode 100644 index 0000000000000000000000000000000000000000..fa51eb6b784f0b88b8fbe3fc0af1a0b5b0eb0b1b GIT binary patch literal 31334 zcmc(IOKf9Hdfuf(NmNmksM9Ys`##T%=gwTuXl69`j_nzbZN4ONnj(1*Nwqt1hM~wK ziEfJI@X>u`Ac%nklQ@XszzZ(|8+jn!1x6OmCP;u7i8skEStLP#0NLfW$|8#Z0rLHS z)j6k5okL1)43bT^PSyYa_4@07)n7&N=%U+uwU|sUzFFWu4ky#`d~9WAgR4<@cqnV_ zf0GbG)>lTCW9vX{y>_Rw!FY6#_%QL+q~m>Bw%CyQI?=D6AW|Kj=E+ z@mvyp?%p1(19HcSsj)aXet_=f(Ea?F}Xa^o@s_J~}Wk z9j_jE0kHKok?dV}=RE54(E|gih$_G{i1nFB5ol%Z-W<@V(??HYz^NK2KB)CeB0ZZA zdavAR0}FdVa}XU@Gk^fHjzDAU_D{#XVs|(^*ko*TY|4ue*wG~|tBRES4SuL@r_EXcH&j+Kc*}*n1 z*C#7zt10p@9Fv4~A(XJ1g}ZSenD*CK(5~bgVH_u(RPKKz#E!l`B4#rnh!jBqT@T+ONb0e_Ls>)vi6S)nC-I z?^r33EL7X&Y{J?W8!t{Pt#Wpa3QwH!%j`N8)~l8CayChSqOe@cZdgKW)}4Iqq@3L( z*hZ!HJiA4ujkeRMmb0ncA8(62V+BZ5i~1 zE2BPb`|(tY{*<$%*7`(b=eHBEhK4~ZAmv2LsUJh^mB!S4J#gR5cw?X+dYM%a??UL5 z2D9E6OVYg9!{q2r8_N-NAqrPp6AUp<8733V(YA5 z5ziJQY}x6oJ1l=O8BAT$eAA}e8;|-k-clK76$s6sY<22ls?jWDX8C6P>jQ|mb?CSy zwS?Cn%qGL`ZK2!0a%Xj4($ZeT%*WRf-YeIgoGs>VpTy-XKkZ#(1byB|z>BXXyzA}^ z+w<(Ui3J|Gv&MAry4$-wNXz!(Ypw5z1Js;j<=lRKbTRHu`&f1&aeJ`Cm`m$Pna^Zf zSXo-s{y~OO%wp@8#Q{OyQac{QmPZn0mrx+LmqL&nKNTPF0Nl~Zbi9~w|H}P^)M3qQ z*PS2ianpB!S;yjiP%4gZCPNo<>}~L1><3vUbO)3*0AmCk+`R5iF>hz%zI(6_{N1B( zuaGJl>uZSMrC5SiNo4!(Wp^>06Gt@Xx6s!X8j0F7e!UaHfY{IW7FdNF0%FlMJ9q#d zP9J^M=&DcUuoy;gA`}YG#M92QrOo{$A$G%(outLg*K3f?Qm2Q?2u7Nez1t#9D4D6- zPNKhTTa&;`k-Rn z*d?yoK3xwRyH7;Y{q}c1M|0J4~Qw!(5$M+z(5G9l>_nRC0)T92CyI% zMz+2bavMnD?woGujss1~SH!OJEtCva8rCSazA3T_?!-6#NvCd~ZaR?~BK&Q!uMmy{ ze}Hu9_UV=rts)e77T1Hm%W6&O(4fHj8IeZiXpSW!H;5GG&S}cg3yH`NMaBbb&bxD$ zHRA5kvN^0Mk__vFQLUd7sS(^$cC1JrMz@N`73A$WKCoqpBohtX8fp zGNI+OJ{6A^qp8msWTDOG-J1#Ti=-1@nfp{EscGvWgb=L@LvKUa(1-O{Y)WTLDG&8! ze@|pW<0gSxDj(!Wc0_^j5Nc5go zN+nqH33wil<=>sNaoGQ3ZpBMT3Ow z@*!<&=|F+sw4yM_O1-Ob?5W7GQ9y17+eG9o?;e@q1@6irbG--Ygb@)aNzF#x$?SSO zS7JV%2$O0mNcei{uiT$*icF}^`hnQMPJ#(VW<~nQj0MO(@xS@GR6}lIIKFTsmQ`VK z4!@k0HCxwz1|p;iJY1SXKO(?7bQ^&hFGOIu;wkiHcQSFMY3a^pT{sf#z$nFe@4hdm z1j{;uXaI=QhMtaxD`y!#XaI@Oh5o6>9VsG}3F3~QiLD!#96fTm$l^5huAKBUhH*St z>slNrvUI-LlPvy__kWAQB9QoesP7$KlJ9l!1l5gwt&zG*0< zn8reA&MKM|XB~`QV~>$N(df=*Z^l#UZri7?y3=WE>Me2oZ&&3npq!2fdQS2LX@Ad9uwKM+`mW&i(x~X0&-SuCbHux`lfct zf!LIstgM)K9Q6%n=G{29E-j=;-N~+D4c4J} zyDo>GD~TORUoz$WDAG7|in;%`hN%t7tj~q$dQx77(4wBZ+#(@7I&y#@ble{=5L4r~XPHS?`X^SF{Hn<#1joXCVUd&JZ#Rhk4!rWW|WT$3MbHjE;2-E0^yx<6+B z+jWto&_u*{g|#yE4ssOxCLO(qqQPA+jwX#2|C_99L^`o`>r*bJm6x+?6gA0;qZ! z1yFG;Fo)qhxV$|cPtV957>{O^OO6z>yMzGhDi~;-jTy&|WVGKrFY=>4jsznO#lw;@ zQ%|f>I6vdW)UdIs%_N(ok$GV#ZC32xSraKb#UeFGCd3ryj)6_;eUkIrC7n!FET6DM zehJMYIUaN_!=5o55AqF8$=s$`0*7s7XgbCrQmr348Z7z#0Vb_cFcfd$olu$m3&gJ) z4wyQ0Fi@-4=wQIYjwA8j$u}BK{XAcVUqIm+Z+P~L`O!PaL z{!?0S@&jo~c8}gSRGHrd3~)fvs^dS>2GkyLxb(uLTn-o7ABzpfk{h2-KRV4;9>*Q; z&}Kd<*WgDLvkCi86XIc9JcrzG*a3c=$JfI~DY$UIkEjfBd(bDA?BIZCm30;qW}*p5 zAAMj7)0|o`!%x$v`7QDwV<` zM2ApOLMod=0TH1vn)OmVoVqs%UX@7Rxc(3+-j+TxgVat8D2T?AASZhIIQFotmxs= ziB}IA0WdKI9sJhen0lj=hf^j~(BYp31u7;Yk_eti?q$o7MCh$Y^8wG;R}Aiu>>Ggw z?PY{=f1D7H8m#2)3a%GgTNkQ~ z9iKXBXYy=tLP6-~^o4z~*9o_hYl_G5+u!;HA!dk=kUn0J4?}{@%)FuSngnn(;M{xS z*$M$b7MxrTh|KO#2`^727A%qN7-E{OJ5B7`|9w-4pl#D=k@KtDF=02;bl?!X+nUHw z5F0h=$XP|u)}iu_A!|Jx^6fEG-m#O(pBgUy99AIXUgm18Xc|cdeV|HS`JULMz2%>)nBfSmUD{nPVJZxotJ$jo!iRmOq|DHd zhTN2ZG*=1-i2;b2Bk`)Ql+uc(j~R}dmKZriT-5C6J|SlglZdUQb2!H*46e_8Q*8UQ zcP|7Gr|G&E?AOJnoT7U{V+3kWa=(X|ksKj%2R5;VXDYFB_sCS#+Kft!L;7zqg+w7N zM`7C~kqK3VO)%KcwQ}o4-FXfJ?5TKE!MQ@K(t6o>UVhm*t2EE@t>P)1hAbqJWHzLH z(B8LOB1xezvP&<1azwQ!1&~kl74E(6CSumg)AcIn;^0PQ5ib zP-zAPBo&~eBU!&F(!(GxiOu0?iX{hMW#*EjgCm_WH5`wwII<}ByqR@+jLp%2)rK<^ z*rh(SZ)wU5fMu2@ID&07vNRQBAtg3DJga>4L(|2Mq1O-luOOX59lNQqW0!iT@oFW^ zNmB6IBzXwZ9`<@E8N#%OV|r=-pEdDhiQ2Uq2oj>(thiN&zI8v1eMmFScwn1=2waN| z7+OfTBF5nWGk=CVFZtshokxJwno%MW$)v!YWEU6w7gLAj%nil1-#hDL#mJKJ&71>< zV>U)ch|d#>>sN44z(2J1Q!;!CkHiC+S`+H5{U3#R5M$U`AK^6VhO(s3#uq&IG+RLt z@#Qnfbl0VNIhzScZ2qQ7WDoGkE!isD;AsA$3RhS-uk=z{loh~cOZwuIfZ#Z>vXYF6(F=0>M$y%GDDtj4r1sAW5OyT+sj(8!_5XdAhg z;u#hMvZM%E()wa7kEgx#Y_f+Yi;Ll)Cu3sk2+RisRQt-kt=!PTAbQKSenAegm;FdD ztQ$j#wSP*(TcYdoF}ltR4{@w0&~=Z6RjD=G$H$do1uCy|+^&_HID7i1Ns-p((fW&G zbLJVl6xlj`yAfz4IRv(tIf}0J+X);!`l}LN62%ptzg?p%)*9!NOPZv;J@*50v_UDO zEGVK~ikuhD@j=F}`vvb#3QTKd1O(@WfdbJdBiL(>QBJ@JU(bVm&z9>Bg;lgd0(%cJ zTbYB*$v-=%xNxEhP;GxIHl=k!Mh*_OS`|b*-?0#9YPJh!l~&8kwP?1BMI=ldw<#cs zl#z}U(D|QonVGCFB&nh!?CQ4=LLRT+c|vcfTYyM>2a{s(&*y5T(F5m5#!KeF)0} zB41gCccYgH+L1_z=xpI&4y-_jKxCbozCcX#V@R!GUSi>zlKcayR^Cy$^bJ>73E0pI zmL|X!JLBn9cQp77$%~Yeh%{NfEccHRDoqNSf-|FN7NvDSF&uT7#kjk|#(|^XUBMv) zWx)@=P{%9kivqv1#U+)K3AGLR$zMe8X3*~sU2cwK%(kPIQ1I7JFQZX!2N`6!f1D5- zyi%0fh3t!k*I)U8T=FFDCU^(*X4E`p+9|2}umu$O7xn@?*dR+VVOI>d zF;44ebZUdmbyhE6cgg!4?47MsX|dgG)z7j??l-f@PpRKb>;FN&{~Zp+8#-$uqAF*Y zcINI;By=nTvVli&7{ZS2vE(Q@)66vUDW&YQsYyzgzG&Je+x6yV8G>i8Tq?CFMk#OF8xidP^uk#b-6Fp7qQ+1qwP^*Io(nN>v`XF{K)qVarc4F zNVh4~83y(Ama;ZhaR>N>If8|-;)r#rRIuMz(a3Zd`xY7T@>-wg!hH*I8d;)bvYC0U z;1QaUU~emiAB%@^L2LVu5(suE(zMZWA<;jLQ(rVQRPLX?BBmxk$plsX0un7~#t8}# zzEJKP%Lj;W`AOpIP$UuJ?5c>`3aRHX9DB#?``P~~A<~-TPA4>r=}<{E`jeUsa{Pj{ zBx?3Eu`wWfnfn?I2_;>)%!sXtj5jDoSv6-KD5As3%VGCQ*&e2vjkI!j3}A;*=qUJ2 zcUBs|84br>Bna`8rJQgf8J<0ybdKij#h}jG7URoH>@u<@jFoLy)8FKEO5AKN0WtrMaS8F{U_I_BGLYI@9TEgH(9 zyxFYa(cLfs>(`KWNkkkq;4`2lTi9lP(*D)LcuNP{j=lHpQN7p19~eh4{6WI z=0S<1m_vrjeuQ;tNT5V2f(!>3gYt`J&u@Xn5Hy5eKxh4n3CWkhC-od$vqGCmV&KS3 z(ws$Sk|s;dBp+EBt>tp!VA+-;#XXcVg@v`Yh1dxVvws1UI^iOJM{pq5V|P{o%-U=j zNKR&#Rq-uDdn{@HQBrJhKpnd40TLpv+<7P>$kR;$fw)SVGs=EjmWJWQ<)z$-3ul7Q z{J8u{I4(~qCg~$nr*K~n`Cm=Ig@g0oP$niV*>2>tQc@sEB~5l>xU5OglxfU#m<3a& z>2ikcPz)#}XK=nZzlJ9{B4<#}!<}w1wo`ya`-pB@=dqNrBYg1$dauK_@MK*w^Sp%>O3iT?bf?^^nt$Y>9V{7D#H5+v}T@LQf!(c!{bme)u zb?VgHC#SeWkBK>}*Xqqi9uu=cTM~KntnD?&fb#Ky4enK!; z1HwWZXq>jgOHDN7qbug2u3Tu;1ASZa1wO35ARgj6>=b#=p}AG3{pQW0stKy{lt43< z3~fA_@nru&QtXDuL2^gWX$2AWO>*bEq4pvMrr{;CvAEhjGDl$``>8KT z)bKFjFOhsy8Hc-(v@e51lR&-H*(33gWer|#zzhfSfs|a*iLE1hkGPc?OJxYzKd%%- z7O$Pimqj|Qmkmm-#g)W-yHu%nij;-Pn&KSk0qT1Vs%6_B6s{5Pd+4Q#Q!chDb$X%% zLE}oTSVso(2`J#J-fo@L>1)lt@?y@M&mT_f1!Nu(`i2bHqi?l(tK*k&Nj)LI4IAKG8hK470(E${#0}dc2SSOb7mo-UWrE;;#fc#XATI9{U z7I}+$;PF<6$Y)d9y7Tpb$mAEEiYGYqj+=Tu506d~T?@&YDiLx~4`G_}-vrmh2tAV! zW1e9say_}D2o zPqQfkg&Enw5;`xD!MzPH&1&Rdp5c78iQU_(oTKBVtU$;xz+Ob}nX_$lW;)YMV z(WpB>psn1h7wc6&e6vHtamuP1CfQjwLk3)-S}#6F3%g{kwQJtz9t@-dybNruw@38j16FT|6OS_>311(b1?@p>>`%rt*KR7T;>k^6?L*=2CNPy0vW zV3{t&D$Dm5$dV*~jK45W|3xx3#V8!1C8FE4jLaGhLrl8lY0PtIf` zz@WW^jP*MS@fB`CUb~!K4<_=SVAXx?4#6f+sH#QMQqfExZt+fJ^x&S&1U*9Ji64=1 zXUlp-3UNt~?nL%`bSI<*Kk_4vA>eG?Ysp-JUr&D<8 zObvkESXuJ2f@~lJjy9H(qGsrwAcXmF-@e}(b1zjh^45vzDbNMfIB;ra87bxmt+GD9 zcBgcuI^3YVonrEX)?hpyTK?!x;&?LQDNks7^lF528#x4TqsogcrqeDbBL*HVE+=Nq z#e3WmH^GvZcH;!|t0q=nafyAQVHpluTun5l)sl;oA$YN>Rry%W9j%6OVpM;trLwcH)=jn%cGT&h)(S_1T?sUT$p9JG4*Don%t+{+;WzQ zqM$*IWuo;KQtWMGfUFaZWzBKR<`a*`Kw}Wm{yoTtr5yJXSC9F%Of~Xn-2QSY7lVVQ zHQ5>i;J2#Ft->uWnQHaj<*hEm@mpO6;BV6NqqD)4d|g2`_Z~MFyGbL!Xh+JuNKIg+ zX;r>3^Y_d9+?c7Ac|}*@pM7 z+^dP$zLfBSGVY0m`|{zv`Vxm4*Oxdr3s2d6%=6MD>5L1c^-CqEXZaC=sPwLVCfR?3*i>=kd#VH-a zk>k#Xa6uX3fSeu^l-L#VfTsm1%bG|0R;2#2*ke+GdwVZ3xFmxFy*ECpihCp|Z7(Q| zcD=ACG94WR0qK3FqI<;m>jF|xk-VgQ1nxk}(Mrro`Nne%&kL;GUl>V)vc<7JcZG8$3VKylNcU2UzBm`F*_G zQ@#%yWG+2I@{ z(iJ2KD7uAFYty_0wV_<@QWG8&<%UwJ<>=DWRA@bK%sWE%Ly(D4P z>;*t8*iHj#;4N;M{mc>G9bqSVfNsf)e|0CG=gwBtv0~ zdlAL$w5LN3mhcOcQnP#OtBj820Ooq&2@Bg8WlV75|3k-`x*Ca#N!&*Wo1-l%qEe(w zm7vElB0`(j)lduvYIkZLyWE}jmy|`R)%b$e(>-`r^UFNp8juuGVJF-AmUtlLhgU9j zKlLc%#8t&nj`giUxgT=tLzH8x?5Wxcv7YMPXYL03#LE(Mt$tag)zu^V9W+WI|Fc~` zvVRj<1$1aF6H4*ZR&S7cHR(?9!)myki92RAmAfl`;^ajb9@5Vwfm^`40aZLiKIRR$ z`tA@?^};xKUThCp*yF6~QzrVs-B^~+wDStSJdBER5dG|CV7y~99N>#iF$f|*p z>9BibrYZ)+HJTCwl%r(uPGd&>Yz+PS6)a%RW&>=v7-@U>NuwKoHY=kN-ZbUs4P|=L zlG@z4NWoX>(*+{R#l^WY5{f1N%MZR+KyAwx4z`dh$X}FUi<^4`eg_p(x&Bq;Wcvj< zL~{3xpRb8L9E-Xa{4JD#>>}xf%LvczEO6NXH#yL>9+}x$kW7chm|_`eKBPA(4CSUSx~Gu z0Ey%yWCzNU67Hm`jA=$GmaBQB5g}t5iAWN}$yaK}br5gi2gs1QBTJD;P1$-`PBD^2 z$4(tETLJM}{`{p(ERq1#N;O|ZVv*lE|9+W3w#lvpD4(1(s`*+gn-2QitW=R6mEEzB zMRnrjOZ?tL6A4BbYliyc7uM<(2gyU|xLZV`TeEu@~Fa*^o=kfm1Bm2Lui~YzZ zqO3S?6$|YG-Z$Exe1;07r6_+E~#%I1MYRvk%^#s8(>P`yma_r_n6uvyUh{&M#?E zY96o7W4e&zi*wRpnz*(9eNsHoA7fOBXBc?!zybXf3KEHe`>>=QgXfIM%4Yi%VvZ%w zmin1NQoFd1M;99MbG&WJ>8H5j5)|?C?eySme#n{R@=^btO zJ&5qj0LY$&5Gm#9ZFFQgw(tWl^ud>PUX)8U`N_$&t<$!{l}XCEJ%&sI;07hu;=%N` zLtmRz1Mx?HZ}FuSdDHoyuM0t{M*e7OEJtCn@Z%_WSaW!*-VZ0%N;yU;Eh@nUKP+q zbo-NVDCdGNhiQ0P%Y7|hTmIk(lJ8ZoLUn}We!*i6mE$4>J)Im|XCDd?^dQU=>TzVg z!=xSoSo`GH)bD15;_6Ynw|iv2@O|+K-upPj8_NsahQ%+-+_;A`7r&n8;-O;o`_PB4 bkL2%0|C6;Hd9M``YCi5<;1v)2|DFE}gw`FM literal 0 HcmV?d00001 diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto new file mode 100644 index 0000000..48a6f24 --- /dev/null +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -0,0 +1,1260 @@ +syntax = "proto3"; + +package signal.backup; + +option java_package = "org.thoughtcrime.securesms.backup.v2.proto"; +option swift_prefix = "BackupProto_"; + +message BackupInfo { + uint64 version = 1; + uint64 backupTimeMs = 2; + bytes mediaRootBackupKey = 3; // 32-byte random value generated when the backup is uploaded for the first time. + string currentAppVersion = 4; + string firstAppVersion = 5; +} + +// Frames must follow in the following ordering rules: +// +// 1. There is exactly one AccountData and it is the first frame. +// 2. A frame referenced by ID must come before the referencing frame. +// e.g. a Recipient must come before any Chat referencing it. +// 3. All ChatItems must appear in global Chat rendering order. +// (The order in which they were received by the client.) +// 4. ChatFolders must appear in render order (e.g., left to right for +// LTR locales), but can appear anywhere relative to other frames respecting +// rule 2 (after Recipients and Chats). +// +// Recipients, Chats, StickerPacks, AdHocCalls, and NotificationProfiles +// can be in any order. (But must respect rule 2.) +// +// For example, Chats may all be together at the beginning, +// or may each immediately precede its first ChatItem. +message Frame { + oneof item { + AccountData account = 1; + Recipient recipient = 2; + Chat chat = 3; + ChatItem chatItem = 4; + StickerPack stickerPack = 5; + AdHocCall adHocCall = 6; + NotificationProfile notificationProfile = 7; + ChatFolder chatFolder = 8; + } +} + +message AccountData { + enum PhoneNumberSharingMode { + UNKNOWN = 0; + EVERYBODY = 1; + NOBODY = 2; + } + message UsernameLink { + enum Color { + UNKNOWN = 0; + BLUE = 1; + WHITE = 2; + GREY = 3; + OLIVE = 4; + GREEN = 5; + ORANGE = 6; + PINK = 7; + PURPLE = 8; + } + + bytes entropy = 1; // 32 bytes of entropy used for encryption + bytes serverId = 2; // 16 bytes of encoded UUID provided by the server + Color color = 3; + } + + message AccountSettings { + bool readReceipts = 1; + bool sealedSenderIndicators = 2; + bool typingIndicators = 3; + bool linkPreviews = 4; + bool notDiscoverableByPhoneNumber = 5; + bool preferContactAvatars = 6; + uint32 universalExpireTimerSeconds = 7; // 0 means no universal expire timer. + repeated string preferredReactionEmoji = 8; + bool displayBadgesOnProfile = 9; + bool keepMutedChatsArchived = 10; + bool hasSetMyStoriesPrivacy = 11; + bool hasViewedOnboardingStory = 12; + bool storiesDisabled = 13; + optional bool storyViewReceiptsEnabled = 14; + bool hasSeenGroupStoryEducationSheet = 15; + bool hasCompletedUsernameOnboarding = 16; + PhoneNumberSharingMode phoneNumberSharingMode = 17; + ChatStyle defaultChatStyle = 18; + repeated ChatStyle.CustomChatColor customChatColors = 19; + } + + message SubscriberData { + bytes subscriberId = 1; + string currencyCode = 2; + bool manuallyCancelled = 3; + } + + message IAPSubscriberData { + bytes subscriberId = 1; + + oneof iapSubscriptionId { + // Identifies an Android Play Store IAP subscription. + string purchaseToken = 2; + // Identifies an iOS App Store IAP subscription. + uint64 originalTransactionId = 3; + } + } + + bytes profileKey = 1; + optional string username = 2; + UsernameLink usernameLink = 3; + string givenName = 4; + string familyName = 5; + string avatarUrlPath = 6; + SubscriberData donationSubscriberData = 7; + reserved /*backupsSubscriberData*/ 8; // A deprecated format + AccountSettings accountSettings = 9; + IAPSubscriberData backupsSubscriberData = 10; +} + +message Recipient { + uint64 id = 1; // generated id for reference only within this file + oneof destination { + Contact contact = 2; + Group group = 3; + DistributionListItem distributionList = 4; + Self self = 5; + ReleaseNotes releaseNotes = 6; + CallLink callLink = 7; + } +} + +message Contact { + enum IdentityState { + DEFAULT = 0; + VERIFIED = 1; + UNVERIFIED = 2; + } + + message Registered {} + message NotRegistered { + uint64 unregisteredTimestamp = 1; + } + + enum Visibility { + VISIBLE = 0; + HIDDEN = 1; + HIDDEN_MESSAGE_REQUEST = 2; + } + + message Name { + string given = 1; + string family = 2; + } + + optional bytes aci = 1; // should be 16 bytes + optional bytes pni = 2; // should be 16 bytes + optional string username = 3; + optional uint64 e164 = 4; + bool blocked = 5; + Visibility visibility = 6; + + oneof registration { + Registered registered = 7; + NotRegistered notRegistered = 8; + } + + optional bytes profileKey = 9; + bool profileSharing = 10; + optional string profileGivenName = 11; + optional string profileFamilyName = 12; + bool hideStory = 13; + optional bytes identityKey = 14; + IdentityState identityState = 15; + Name nickname = 16; // absent iff both `given` and `family` are empty + string note = 17; +} + +message Group { + enum StorySendMode { + DEFAULT = 0; + DISABLED = 1; + ENABLED = 2; + } + + bytes masterKey = 1; + bool whitelisted = 2; + bool hideStory = 3; + StorySendMode storySendMode = 4; + GroupSnapshot snapshot = 5; + + // These are simply plaintext copies of the groups proto from Groups.proto. + // They should be kept completely in-sync with Groups.proto. + // These exist to allow us to have the latest snapshot of a group during restoration without having to hit the network. + // We would use Groups.proto if we could, but we want a plaintext version to improve export readability. + // For documentation, defer to Groups.proto. The only name change is Group -> GroupSnapshot to avoid the naming conflict. + message GroupSnapshot { + reserved /*publicKey*/ 1; // The field is deprecated in the context of static group state + GroupAttributeBlob title = 2; + GroupAttributeBlob description = 11; + string avatarUrl = 3; + GroupAttributeBlob disappearingMessagesTimer = 4; + AccessControl accessControl = 5; + uint32 version = 6; + repeated Member members = 7; + repeated MemberPendingProfileKey membersPendingProfileKey = 8; + repeated MemberPendingAdminApproval membersPendingAdminApproval = 9; + bytes inviteLinkPassword = 10; + bool announcements_only = 12; + repeated MemberBanned members_banned = 13; + } + + message GroupAttributeBlob { + oneof content { + string title = 1; + bytes avatar = 2; + uint32 disappearingMessagesDuration = 3; + string descriptionText = 4; + } + } + + message Member { + enum Role { + UNKNOWN = 0; + DEFAULT = 1; + ADMINISTRATOR = 2; + } + + bytes userId = 1; + Role role = 2; + reserved /*profileKey*/ 3; // This field is ignored in Backups, in favor of Contact frames for members + reserved /*presentation*/ 4; // This field is deprecated in the context of static group state + uint32 joinedAtVersion = 5; + } + + message MemberPendingProfileKey { + Member member = 1; + bytes addedByUserId = 2; + uint64 timestamp = 3; + } + + message MemberPendingAdminApproval { + bytes userId = 1; + reserved /*profileKey*/ 2; // This field is ignored in Backups, in favor of Contact frames for members + reserved /*presentation*/ 3; // This field is deprecated in the context of static group state + uint64 timestamp = 4; + } + + message MemberBanned { + bytes userId = 1; + uint64 timestamp = 2; + } + + message AccessControl { + enum AccessRequired { + UNKNOWN = 0; + ANY = 1; + MEMBER = 2; + ADMINISTRATOR = 3; + UNSATISFIABLE = 4; + } + + AccessRequired attributes = 1; + AccessRequired members = 2; + AccessRequired addFromInviteLink = 3; + } +} + +message Self {} + +message ReleaseNotes {} + +message Chat { + uint64 id = 1; // generated id for reference only within this file + uint64 recipientId = 2; + bool archived = 3; + optional uint32 pinnedOrder = 4; // will be displayed in ascending order + optional uint64 expirationTimerMs = 5; + optional uint64 muteUntilMs = 6; // INT64_MAX (2^63 - 1) = "always muted". + bool markedUnread = 7; + bool dontNotifyForMentionsIfMuted = 8; + ChatStyle style = 9; + uint32 expireTimerVersion = 10; +} + +/** + * Call Links have some associated data including a call, but unlike other recipients + * are not tied to threads because they do not have messages associated with them. + * + * note: + * - room id can be derived from the root key + * - the presence of an admin key means this user is a call admin + */ +message CallLink { + enum Restrictions { + UNKNOWN = 0; + NONE = 1; + ADMIN_APPROVAL = 2; + } + + bytes rootKey = 1; + optional bytes adminKey = 2; // Only present if the user is an admin + string name = 3; + Restrictions restrictions = 4; + uint64 expirationMs = 5; +} + +message AdHocCall { + enum State { + UNKNOWN_STATE = 0; + GENERIC = 1; + } + + uint64 callId = 1; + // Refers to a `CallLink` recipient. + uint64 recipientId = 2; + State state = 3; + uint64 callTimestamp = 4; +} + +message DistributionListItem { + // distribution ids are UUIDv4s. "My Story" is represented + // by an all-0 UUID (00000000-0000-0000-0000-000000000000). + bytes distributionId = 1; // distribution list ids are uuids + + oneof item { + uint64 deletionTimestamp = 2; + DistributionList distributionList = 3; + } +} + +message DistributionList { + enum PrivacyMode { + UNKNOWN = 0; + ONLY_WITH = 1; + ALL_EXCEPT = 2; + ALL = 3; + } + + string name = 1; + bool allowReplies = 2; + PrivacyMode privacyMode = 3; + repeated uint64 memberRecipientIds = 4; // generated recipient id +} + +message ChatItem { + message IncomingMessageDetails { + uint64 dateReceived = 1; + optional uint64 dateServerSent = 2; + bool read = 3; + bool sealedSender = 4; + } + + message OutgoingMessageDetails { + repeated SendStatus sendStatus = 1; + } + + message DirectionlessMessageDetails { + } + + uint64 chatId = 1; // conversation id + uint64 authorId = 2; // recipient id + uint64 dateSent = 3; + optional uint64 expireStartDate = 4; // timestamp of when expiration timer started ticking down + optional uint64 expiresInMs = 5; // how long timer of message is (ms) + repeated ChatItem revisions = 6; // ordered from oldest to newest + bool sms = 7; + + oneof directionalDetails { + IncomingMessageDetails incoming = 8; + OutgoingMessageDetails outgoing = 9; + DirectionlessMessageDetails directionless = 10; + } + + oneof item { + StandardMessage standardMessage = 11; + ContactMessage contactMessage = 12; + StickerMessage stickerMessage = 13; + RemoteDeletedMessage remoteDeletedMessage = 14; + ChatUpdateMessage updateMessage = 15; + PaymentNotification paymentNotification = 16; + GiftBadge giftBadge = 17; + ViewOnceMessage viewOnceMessage = 18; + DirectStoryReplyMessage directStoryReplyMessage = 19; // group story reply messages are not backed up + } +} + +message SendStatus { + message Pending {} + + message Sent { + bool sealedSender = 1; + } + + message Delivered { + bool sealedSender = 1; + } + + message Read { + bool sealedSender = 1; + } + + message Viewed { + bool sealedSender = 1; + } + + // e.g. user in group was blocked, so we skipped sending to them + message Skipped {} + + message Failed { + enum FailureReason { + UNKNOWN = 0; // A valid value -- could indicate a crash or lack of information + NETWORK = 1; + IDENTITY_KEY_MISMATCH = 2; + } + + FailureReason reason = 1; + } + + uint64 recipientId = 1; + uint64 timestamp = 2; // the time the status was last updated -- if from a receipt, it should be the sentTime of the receipt + + oneof deliveryStatus { + Pending pending = 3; + Sent sent = 4; + Delivered delivered = 5; + Read read = 6; + Viewed viewed = 7; + Skipped skipped = 8; + Failed failed = 9; + } +} + +message Text { + string body = 1; + repeated BodyRange bodyRanges = 2; +} + +message StandardMessage { + optional Quote quote = 1; + optional Text text = 2; + repeated MessageAttachment attachments = 3; + repeated LinkPreview linkPreview = 4; + optional FilePointer longText = 5; + repeated Reaction reactions = 6; +} + +message ContactMessage { + ContactAttachment contact = 1; + repeated Reaction reactions = 2; +} + +message DirectStoryReplyMessage { + message TextReply { + Text text = 1; + FilePointer longText = 2; + } + + oneof reply { + TextReply textReply = 1; + string emoji = 2; + } + + repeated Reaction reactions = 3; + optional uint64 storySentTimestamp = 4; +} + +message PaymentNotification { + message TransactionDetails { + message MobileCoinTxoIdentification { // Used to map to payments on the ledger + repeated bytes publicKey = 1; // for received transactions + repeated bytes keyImages = 2; // for sent transactions + } + + message FailedTransaction { // Failed payments can't be synced from the ledger + enum FailureReason { + GENERIC = 0; + NETWORK = 1; + INSUFFICIENT_FUNDS = 2; + } + FailureReason reason = 1; + } + + message Transaction { + enum Status { + INITIAL = 0; + SUBMITTED = 1; + SUCCESSFUL = 2; + } + Status status = 1; + + // This identification is used to map the payment table to the ledger + // and is likely required otherwise we may have issues reconciling with + // the ledger + MobileCoinTxoIdentification mobileCoinIdentification = 2; + optional uint64 timestamp = 3; + optional uint64 blockIndex = 4; + optional uint64 blockTimestamp = 5; + optional bytes transaction = 6; // mobile coin blobs + optional bytes receipt = 7; // mobile coin blobs + } + + oneof payment { + Transaction transaction = 1; + FailedTransaction failedTransaction = 2; + } + } + + optional string amountMob = 1; // stored as a decimal string, e.g. 1.00001 + optional string feeMob = 2; // stored as a decimal string, e.g. 1.00001 + optional string note = 3; + TransactionDetails transactionDetails = 4; +} + +message GiftBadge { + enum State { + UNOPENED = 0; + OPENED = 1; + REDEEMED = 2; + FAILED = 3; + } + + bytes receiptCredentialPresentation = 1; + State state = 2; +} + +message ViewOnceMessage { + // Will be null for viewed messages + MessageAttachment attachment = 1; + repeated Reaction reactions = 2; +} + +message ContactAttachment { + message Name { + string givenName = 1; + string familyName = 2; + string prefix = 3; + string suffix = 4; + string middleName = 5; + string nickname = 6; + } + + message Phone { + enum Type { + UNKNOWN = 0; + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + string value = 1; + Type type = 2; + string label = 3; + } + + message Email { + enum Type { + UNKNOWN = 0; + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + string value = 1; + Type type = 2; + string label = 3; + } + + message PostalAddress { + enum Type { + UNKNOWN = 0; + HOME = 1; + WORK = 2; + CUSTOM = 3; + } + + Type type = 1; + string label = 2; + string street = 3; + string pobox = 4; + string neighborhood = 5; + string city = 6; + string region = 7; + string postcode = 8; + string country = 9; + } + + optional Name name = 1; + repeated Phone number = 3; + repeated Email email = 4; + repeated PostalAddress address = 5; + optional FilePointer avatar = 6; + string organization = 7; +} + +message StickerMessage { + Sticker sticker = 1; + repeated Reaction reactions = 2; +} + +// Tombstone for remote delete +message RemoteDeletedMessage {} + +message Sticker { + bytes packId = 1; + bytes packKey = 2; + uint32 stickerId = 3; + optional string emoji = 4; + // Stickers are uploaded to be sent as attachments; we also + // back them up as normal attachments when they are in messages. + // DO NOT treat this as the definitive source of a sticker in + // an installed StickerPack that shares the same packId. + FilePointer data = 5; +} + +message LinkPreview { + string url = 1; + optional string title = 2; + optional FilePointer image = 3; + optional string description = 4; + optional uint64 date = 5; +} + +// A FilePointer on a message that has additional +// metadata that applies only to message attachments. +message MessageAttachment { + // Similar to SignalService.AttachmentPointer.Flags, + // but explicitly mutually exclusive. Note the different raw values + // (non-zero starting values are not supported in proto3.) + enum Flag { + NONE = 0; + VOICE_MESSAGE = 1; + BORDERLESS = 2; + GIF = 3; + } + + FilePointer pointer = 1; + Flag flag = 2; + bool wasDownloaded = 3; + // Cross-client identifier for this attachment among all attachments on the + // owning message. See: SignalService.AttachmentPointer.clientUuid. + optional bytes clientUuid = 4; +} + +message FilePointer { + // References attachments in the backup (media) storage tier. + message BackupLocator { + string mediaName = 1; + // If present, the cdn number of the succesful upload. + // If empty/0, may still have been uploaded, and clients + // can discover the cdn number via the list endpoint. + optional uint32 cdnNumber = 2; + bytes key = 3; + bytes digest = 4; + uint32 size = 5; + // Fallback in case backup tier upload failed. + optional string transitCdnKey = 6; + optional uint32 transitCdnNumber = 7; + } + + // References attachments in the transit storage tier. + // May be downloaded or not when the backup is generated; + // primarily for free-tier users who cannot copy the + // attachments to the backup (media) storage tier. + message AttachmentLocator { + string cdnKey = 1; + uint32 cdnNumber = 2; + optional uint64 uploadTimestamp = 3; + bytes key = 4; + bytes digest = 5; + uint32 size = 6; + } + + // References attachments that are invalid in such a way where download + // cannot be attempted. Could range from missing digests to missing + // CDN keys or anything else that makes download attempts impossible. + // This serves as a 'tombstone' so that the UX can show that an attachment + // did exist, but for whatever reason it's not retrievable. + message InvalidAttachmentLocator { + } + + oneof locator { + BackupLocator backupLocator = 1; + AttachmentLocator attachmentLocator = 2; + InvalidAttachmentLocator invalidAttachmentLocator = 3; + } + + optional string contentType = 4; + optional bytes incrementalMac = 5; + optional uint32 incrementalMacChunkSize = 6; + optional string fileName = 7; + optional uint32 width = 8; + optional uint32 height = 9; + optional string caption = 10; + optional string blurHash = 11; +} + +message Quote { + enum Type { + UNKNOWN = 0; + NORMAL = 1; + GIFT_BADGE = 2; + VIEW_ONCE = 3; + } + + message QuotedAttachment { + optional string contentType = 1; + optional string fileName = 2; + optional MessageAttachment thumbnail = 3; + } + + optional uint64 targetSentTimestamp = 1; // null if the target message could not be found at time of quote insert + uint64 authorId = 2; + optional Text text = 3; + repeated QuotedAttachment attachments = 4; + Type type = 5; +} + +message BodyRange { + enum Style { + NONE = 0; + BOLD = 1; + ITALIC = 2; + SPOILER = 3; + STRIKETHROUGH = 4; + MONOSPACE = 5; + } + + optional uint32 start = 1; + optional uint32 length = 2; + + oneof associatedValue { + bytes mentionAci = 3; + Style style = 4; + } +} + +message Reaction { + string emoji = 1; + uint64 authorId = 2; + uint64 sentTimestamp = 3; + // A higher sort order means that a reaction is more recent. Some clients may export this as + // incrementing numbers (e.g. 1, 2, 3), others as timestamps. + uint64 sortOrder = 4; +} + +message ChatUpdateMessage { + oneof update { + SimpleChatUpdate simpleUpdate = 1; + GroupChangeChatUpdate groupChange = 2; + ExpirationTimerChatUpdate expirationTimerChange = 3; + ProfileChangeChatUpdate profileChange = 4; + ThreadMergeChatUpdate threadMerge = 5; + SessionSwitchoverChatUpdate sessionSwitchover = 6; + IndividualCall individualCall = 7; + GroupCall groupCall = 8; + LearnedProfileChatUpdate learnedProfileChange = 9; + } +} + +message IndividualCall { + enum Type { + UNKNOWN_TYPE = 0; + AUDIO_CALL = 1; + VIDEO_CALL = 2; + } + + enum Direction { + UNKNOWN_DIRECTION = 0; + INCOMING = 1; + OUTGOING = 2; + } + + enum State { + UNKNOWN_STATE = 0; + ACCEPTED = 1; + NOT_ACCEPTED = 2; + // An incoming call that is no longer ongoing, which we neither accepted + // not actively declined. For example, it expired, was canceled by the + // sender, or was rejected due to being in another call. + MISSED = 3; + // We auto-declined an incoming call due to a notification profile. + MISSED_NOTIFICATION_PROFILE = 4; + } + + optional uint64 callId = 1; + Type type = 2; + Direction direction = 3; + State state = 4; + uint64 startedCallTimestamp = 5; + bool read = 6; +} + +message GroupCall { + enum State { + UNKNOWN_STATE = 0; + // A group call was started without ringing. + GENERIC = 1; + // We joined a group call that was started without ringing. + JOINED = 2; + // An incoming group call is actively ringing. + RINGING = 3; + // We accepted an incoming group ring. + ACCEPTED = 4; + // We declined an incoming group ring. + DECLINED = 5; + // We missed an incoming group ring, for example because it expired. + MISSED = 6; + // We auto-declined an incoming group ring due to a notification profile. + MISSED_NOTIFICATION_PROFILE = 7; + // An outgoing ring was started. We don't track any state for outgoing rings + // beyond that they started. + OUTGOING_RING = 8; + } + + optional uint64 callId = 1; + State state = 2; + optional uint64 ringerRecipientId = 3; + optional uint64 startedCallRecipientId = 4; + uint64 startedCallTimestamp = 5; + optional uint64 endedCallTimestamp = 6; // The time the call ended. + bool read = 7; +} + +message SimpleChatUpdate { + enum Type { + UNKNOWN = 0; + JOINED_SIGNAL = 1; + IDENTITY_UPDATE = 2; + IDENTITY_VERIFIED = 3; + IDENTITY_DEFAULT = 4; // marking as unverified + CHANGE_NUMBER = 5; + RELEASE_CHANNEL_DONATION_REQUEST = 6; + END_SESSION = 7; + CHAT_SESSION_REFRESH = 8; + BAD_DECRYPT = 9; + PAYMENTS_ACTIVATED = 10; + PAYMENT_ACTIVATION_REQUEST = 11; + UNSUPPORTED_PROTOCOL_MESSAGE = 12; + REPORTED_SPAM = 13; + BLOCKED = 14; + UNBLOCKED = 15; + MESSAGE_REQUEST_ACCEPTED = 16; + } + + Type type = 1; +} + +// For 1:1 chat updates only. +// For group thread updates use GroupExpirationTimerUpdate. +message ExpirationTimerChatUpdate { + uint64 expiresInMs = 1; // 0 means the expiration timer was disabled +} + +message ProfileChangeChatUpdate { + string previousName = 1; + string newName = 2; +} + +message LearnedProfileChatUpdate { + oneof previousName { + uint64 e164 = 1; + string username = 2; + } +} + +message ThreadMergeChatUpdate { + uint64 previousE164 = 1; +} + +message SessionSwitchoverChatUpdate { + uint64 e164 = 1; +} + +message GroupChangeChatUpdate { + message Update { + oneof update { + GenericGroupUpdate genericGroupUpdate = 1; + GroupCreationUpdate groupCreationUpdate = 2; + GroupNameUpdate groupNameUpdate = 3; + GroupAvatarUpdate groupAvatarUpdate = 4; + GroupDescriptionUpdate groupDescriptionUpdate = 5; + GroupMembershipAccessLevelChangeUpdate groupMembershipAccessLevelChangeUpdate = 6; + GroupAttributesAccessLevelChangeUpdate groupAttributesAccessLevelChangeUpdate = 7; + GroupAnnouncementOnlyChangeUpdate groupAnnouncementOnlyChangeUpdate = 8; + GroupAdminStatusUpdate groupAdminStatusUpdate = 9; + GroupMemberLeftUpdate groupMemberLeftUpdate = 10; + GroupMemberRemovedUpdate groupMemberRemovedUpdate = 11; + SelfInvitedToGroupUpdate selfInvitedToGroupUpdate = 12; + SelfInvitedOtherUserToGroupUpdate selfInvitedOtherUserToGroupUpdate = 13; + GroupUnknownInviteeUpdate groupUnknownInviteeUpdate = 14; + GroupInvitationAcceptedUpdate groupInvitationAcceptedUpdate = 15; + GroupInvitationDeclinedUpdate groupInvitationDeclinedUpdate = 16; + GroupMemberJoinedUpdate groupMemberJoinedUpdate = 17; + GroupMemberAddedUpdate groupMemberAddedUpdate = 18; + GroupSelfInvitationRevokedUpdate groupSelfInvitationRevokedUpdate = 19; + GroupInvitationRevokedUpdate groupInvitationRevokedUpdate = 20; + GroupJoinRequestUpdate groupJoinRequestUpdate = 21; + GroupJoinRequestApprovalUpdate groupJoinRequestApprovalUpdate = 22; + GroupJoinRequestCanceledUpdate groupJoinRequestCanceledUpdate = 23; + GroupInviteLinkResetUpdate groupInviteLinkResetUpdate = 24; + GroupInviteLinkEnabledUpdate groupInviteLinkEnabledUpdate = 25; + GroupInviteLinkAdminApprovalUpdate groupInviteLinkAdminApprovalUpdate = 26; + GroupInviteLinkDisabledUpdate groupInviteLinkDisabledUpdate = 27; + GroupMemberJoinedByLinkUpdate groupMemberJoinedByLinkUpdate = 28; + GroupV2MigrationUpdate groupV2MigrationUpdate = 29; + GroupV2MigrationSelfInvitedUpdate groupV2MigrationSelfInvitedUpdate = 30; + GroupV2MigrationInvitedMembersUpdate groupV2MigrationInvitedMembersUpdate = 31; + GroupV2MigrationDroppedMembersUpdate groupV2MigrationDroppedMembersUpdate = 32; + GroupSequenceOfRequestsAndCancelsUpdate groupSequenceOfRequestsAndCancelsUpdate = 33; + GroupExpirationTimerUpdate groupExpirationTimerUpdate = 34; + } + } + + // Must be one or more; all updates batched together came from + // a single batched group state update. + repeated Update updates = 1; +} + +message GenericGroupUpdate { + optional bytes updaterAci = 1; +} + +message GroupCreationUpdate { + optional bytes updaterAci = 1; +} + +message GroupNameUpdate { + optional bytes updaterAci = 1; + // Null value means the group name was removed. + optional string newGroupName = 2; +} + +message GroupAvatarUpdate { + optional bytes updaterAci = 1; + bool wasRemoved = 2; +} + +message GroupDescriptionUpdate { + optional bytes updaterAci = 1; + // Null value means the group description was removed. + optional string newDescription = 2; +} + +enum GroupV2AccessLevel { + UNKNOWN = 0; + ANY = 1; + MEMBER = 2; + ADMINISTRATOR = 3; + UNSATISFIABLE = 4; +} + +message GroupMembershipAccessLevelChangeUpdate { + optional bytes updaterAci = 1; + GroupV2AccessLevel accessLevel = 2; +} + +message GroupAttributesAccessLevelChangeUpdate { + optional bytes updaterAci = 1; + GroupV2AccessLevel accessLevel = 2; +} + +message GroupAnnouncementOnlyChangeUpdate { + optional bytes updaterAci = 1; + bool isAnnouncementOnly = 2; +} + +message GroupAdminStatusUpdate { + optional bytes updaterAci = 1; + // The aci who had admin status granted or revoked. + bytes memberAci = 2; + bool wasAdminStatusGranted = 3; +} + +message GroupMemberLeftUpdate { + bytes aci = 1; +} + +message GroupMemberRemovedUpdate { + optional bytes removerAci = 1; + bytes removedAci = 2; +} + +message SelfInvitedToGroupUpdate { + optional bytes inviterAci = 1; +} + +message SelfInvitedOtherUserToGroupUpdate { + // If no invitee id available, use GroupUnknownInviteeUpdate + bytes inviteeServiceId = 1; +} + +message GroupUnknownInviteeUpdate { + // Can be the self user. + optional bytes inviterAci = 1; + uint32 inviteeCount = 2; +} + +message GroupInvitationAcceptedUpdate { + optional bytes inviterAci = 1; + bytes newMemberAci = 2; +} + +message GroupInvitationDeclinedUpdate { + optional bytes inviterAci = 1; + // Note: if invited by pni, just set inviteeAci to nil. + optional bytes inviteeAci = 2; +} + +message GroupMemberJoinedUpdate { + bytes newMemberAci = 1; +} + +message GroupMemberAddedUpdate { + optional bytes updaterAci = 1; + bytes newMemberAci = 2; + bool hadOpenInvitation = 3; + // If hadOpenInvitation is true, optionally include aci of the inviter. + optional bytes inviterAci = 4; +} + +// An invitation to self was revoked. +message GroupSelfInvitationRevokedUpdate { + optional bytes revokerAci = 1; +} + +// These invitees should never be the local user. +// Use GroupSelfInvitationRevokedUpdate in those cases. +// The inviter or updater can be the local user. +message GroupInvitationRevokedUpdate { + message Invitee { + optional bytes inviterAci = 1; + // Prefer to use aci over pni. No need to set + // pni if aci is set. Both can be missing. + optional bytes inviteeAci = 2; + optional bytes inviteePni = 3; + } + + // The member that revoked the invite(s), not the inviter! + // Assumed to be an admin (at the time, may no longer be an + // admin or even a member). + optional bytes updaterAci = 1; + repeated Invitee invitees = 2; +} + +message GroupJoinRequestUpdate { + bytes requestorAci = 1; +} + +message GroupJoinRequestApprovalUpdate { + bytes requestorAci = 1; + // The aci that approved or rejected the request. + optional bytes updaterAci = 2; + bool wasApproved = 3; +} + +message GroupJoinRequestCanceledUpdate { + bytes requestorAci = 1; +} + +// A single requestor has requested to join and cancelled +// their request repeatedly with no other updates in between. +// The last action encompassed by this update is always a +// cancellation; if there was another open request immediately +// after, it will be a separate GroupJoinRequestUpdate, either +// in the same frame or in a subsequent frame. +message GroupSequenceOfRequestsAndCancelsUpdate { + bytes requestorAci = 1; + uint32 count = 2; +} + +message GroupInviteLinkResetUpdate { + optional bytes updaterAci = 1; +} + +message GroupInviteLinkEnabledUpdate { + optional bytes updaterAci = 1; + bool linkRequiresAdminApproval = 2; +} + +message GroupInviteLinkAdminApprovalUpdate { + optional bytes updaterAci = 1; + bool linkRequiresAdminApproval = 2; +} + +message GroupInviteLinkDisabledUpdate { + optional bytes updaterAci = 1; +} + +message GroupMemberJoinedByLinkUpdate { + bytes newMemberAci = 1; +} + +// A gv1->gv2 migration occurred. +message GroupV2MigrationUpdate {} + +// Another user migrated gv1->gv2 but was unable to add +// the local user and invited them instead. +message GroupV2MigrationSelfInvitedUpdate {} + +// The local user migrated gv1->gv2 but was unable to +// add some members and invited them instead. +// (Happens if we don't have the invitee's profile key) +message GroupV2MigrationInvitedMembersUpdate { + uint32 invitedMembersCount = 1; +} + +// The local user migrated gv1->gv2 but was unable to +// add or invite some members and dropped them instead. +// (Happens for e164 members where we don't have an aci). +message GroupV2MigrationDroppedMembersUpdate { + uint32 droppedMembersCount = 1; +} + +// For 1:1 timer updates, use ExpirationTimerChatUpdate. +message GroupExpirationTimerUpdate { + uint64 expiresInMs = 1; // 0 means the expiration timer was disabled + optional bytes updaterAci = 2; +} + +message StickerPack { + bytes packId = 1; + bytes packKey = 2; +} + +message ChatStyle { + message Gradient { + uint32 angle = 1; // degrees + repeated fixed32 colors = 2; // 0xAARRGGBB + repeated float positions = 3; // percent from 0 to 1 + } + + message CustomChatColor { + uint64 id = 1; + + oneof color { + fixed32 solid = 2; // 0xAARRGGBB + Gradient gradient = 3; + } + } + + message AutomaticBubbleColor { + } + + enum WallpaperPreset { + UNKNOWN_WALLPAPER_PRESET = 0; + SOLID_BLUSH = 1; + SOLID_COPPER = 2; + SOLID_DUST = 3; + SOLID_CELADON = 4; + SOLID_RAINFOREST = 5; + SOLID_PACIFIC = 6; + SOLID_FROST = 7; + SOLID_NAVY = 8; + SOLID_LILAC = 9; + SOLID_PINK = 10; + SOLID_EGGPLANT = 11; + SOLID_SILVER = 12; + GRADIENT_SUNSET = 13; + GRADIENT_NOIR = 14; + GRADIENT_HEATMAP = 15; + GRADIENT_AQUA = 16; + GRADIENT_IRIDESCENT = 17; + GRADIENT_MONSTERA = 18; + GRADIENT_BLISS = 19; + GRADIENT_SKY = 20; + GRADIENT_PEACH = 21; + } + + enum BubbleColorPreset { + UNKNOWN_BUBBLE_COLOR_PRESET = 0; + SOLID_ULTRAMARINE = 1; + SOLID_CRIMSON = 2; + SOLID_VERMILION = 3; + SOLID_BURLAP = 4; + SOLID_FOREST = 5; + SOLID_WINTERGREEN = 6; + SOLID_TEAL = 7; + SOLID_BLUE = 8; + SOLID_INDIGO = 9; + SOLID_VIOLET = 10; + SOLID_PLUM = 11; + SOLID_TAUPE = 12; + SOLID_STEEL = 13; + GRADIENT_EMBER = 14; + GRADIENT_MIDNIGHT = 15; + GRADIENT_INFRARED = 16; + GRADIENT_LAGOON = 17; + GRADIENT_FLUORESCENT = 18; + GRADIENT_BASIL = 19; + GRADIENT_SUBLIME = 20; + GRADIENT_SEA = 21; + GRADIENT_TANGERINE = 22; + } + + oneof wallpaper { + WallpaperPreset wallpaperPreset = 1; + // This `FilePointer` is expected not to contain a `fileName`, `width`, + // `height`, or `caption`. + FilePointer wallpaperPhoto = 2; + } + + oneof bubbleColor { + // Bubble setting is automatically determined based on the wallpaper setting, + // or `SOLID_ULTRAMARINE` for `noWallpaper` + AutomaticBubbleColor autoBubbleColor = 3; + BubbleColorPreset bubbleColorPreset = 4; + + // See AccountSettings.customChatColors + uint64 customColorId = 5; + } + + bool dimWallpaperInDarkMode = 7; +} + +message NotificationProfile { + enum DayOfWeek { + UNKNOWN = 0; + MONDAY = 1; + TUESDAY = 2; + WEDNESDAY = 3; + THURSDAY = 4; + FRIDAY = 5; + SATURDAY = 6; + SUNDAY = 7; + } + + string name = 1; + optional string emoji = 2; + fixed32 color = 3; // 0xAARRGGBB + uint64 createdAtMs = 4; + bool allowAllCalls = 5; + bool allowAllMentions = 6; + repeated uint64 allowedMembers = 7; // generated recipient id for allowed groups and contacts + bool scheduleEnabled = 8; + uint32 scheduleStartTime = 9; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + uint32 scheduleEndTime = 10; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + repeated DayOfWeek scheduleDaysEnabled = 11; +} + +message ChatFolder { + // Represents the default "All chats" folder record vs all other custom folders + enum FolderType { + UNKNOWN = 0; + ALL = 1; + CUSTOM = 2; + } + + string name = 1; + bool showOnlyUnread = 2; + bool showMutedChats = 3; + // Folder includes all 1:1 chats, unless excluded + bool includeAllIndividualChats = 4; + // Folder includes all group chats, unless excluded + bool includeAllGroupChats = 5; + FolderType folderType = 6; + repeated uint64 includedRecipientIds = 7; // generated recipient id of groups, contacts, and/or note to self + repeated uint64 excludedRecipientIds = 8; // generated recipient id of groups, contacts, and/or note to self +} diff --git a/pkg/signalmeow/protobuf/build-protos.sh b/pkg/signalmeow/protobuf/build-protos.sh index 8b9554e..86cc261 100755 --- a/pkg/signalmeow/protobuf/build-protos.sh +++ b/pkg/signalmeow/protobuf/build-protos.sh @@ -9,4 +9,9 @@ do --go_opt=embed_raw=true \ $file done +protoc --go_out=. \ + --go_opt=Mbackuppb/Backup.proto=$PKG_IMPORT_PATH/backuppb \ + --go_opt=paths=source_relative \ + --go_opt=embed_raw=true \ + backuppb/Backup.proto pre-commit run -a diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 1d81f0a..cf47a8c 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,22 +1,29 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-35a6c1e5c98a6adaf207e96161536624577106cd} -DESKTOP_GIT_REVISION=${1:-bfb53efb72bcbf799992805f63cdccbd937ad99c} +ANDROID_GIT_REVISION=${1:-50db945ef1673da9990affeff022da64e4caa264} +DESKTOP_GIT_REVISION=${1:-ca1d17354db10a14f9f5558dcb546af9f3bba578} update_proto() { case "$1" in Signal-Android) + REPO="Signal-Android" prefix="libsignal-service/src/main/protowire/" GIT_REVISION=$ANDROID_GIT_REVISION ;; + Signal-Android-App) + REPO="Signal-Android" + prefix="app/src/main/protowire/" + GIT_REVISION=$ANDROID_GIT_REVISION + ;; Signal-Desktop) + REPO="Signal-Desktop" prefix="protos/" GIT_REVISION=$DESKTOP_GIT_REVISION ;; esac - echo https://raw.githubusercontent.com/signalapp/${1}/${GIT_REVISION}/${prefix}${2} - curl -LOf https://raw.githubusercontent.com/signalapp/${1}/${GIT_REVISION}/${prefix}${2} + echo https://raw.githubusercontent.com/signalapp/${REPO}/${GIT_REVISION}/${prefix}${2} + curl -LOf https://raw.githubusercontent.com/signalapp/${REPO}/${GIT_REVISION}/${prefix}${2} } @@ -27,6 +34,9 @@ update_proto Signal-Android StickerResources.proto update_proto Signal-Android WebSocketResources.proto update_proto Signal-Android StorageService.proto +update_proto Signal-Android-App Backup.proto +mv Backup.proto backuppb/Backup.proto + update_proto Signal-Desktop DeviceName.proto update_proto Signal-Desktop UnidentifiedDelivery.proto # Android has CDSI.proto too, but the types have more generic names (since android uses a different package name) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 4aedc44..d6774ae 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -18,6 +18,7 @@ package signalmeow import ( "context" + "crypto/hmac" "encoding/base64" "encoding/json" "fmt" @@ -79,7 +80,7 @@ type ProvisioningResponse struct { Err error } -func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, deviceName string) chan ProvisioningResponse { +func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, deviceName string, allowBackup bool) chan ProvisioningResponse { log := zerolog.Ctx(ctx).With().Str("action", "perform provisioning").Logger() c := make(chan ProvisioningResponse, 4) go func() { @@ -100,7 +101,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev defer ws.Close(websocket.StatusInternalError, "Websocket StatusInternalError") provisioningCipher := NewProvisioningCipher() - provisioningURL, err := startProvisioning(timeoutCtx, ws, provisioningCipher) + provisioningURL, err := startProvisioning(timeoutCtx, ws, provisioningCipher, allowBackup) if err != nil { log.Err(err).Msg("startProvisioning error") c <- ProvisioningResponse{State: StateProvisioningError, Err: err} @@ -169,14 +170,23 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev Number: *provisioningMessage.Number, Password: password, MasterKey: provisioningMessage.GetMasterKey(), + AccountEntropyPool: libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()), + EphemeralBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetEphemeralBackupKey()), + MediaRootBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetMediaRootBackupKey()), } - if provisioningMessage.GetMasterKey() == nil && provisioningMessage.GetAccountEntropyPool() != "" { - data.MasterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey() + if provisioningMessage.GetAccountEntropyPool() != "" { + var masterKey []byte + masterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey() if err != nil { log.Err(err).Msg("Failed to derive master key from account entropy pool") } else { log.Debug().Msg("Derived master key from account entropy pool") } + if data.MasterKey == nil { + data.MasterKey = masterKey + } else if !hmac.Equal(data.MasterKey, masterKey) { + log.Warn().Msg("Master key mismatch") + } } // Store the provisioning data @@ -267,7 +277,7 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev } // Returns the provisioningUrl and an error -func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCipher *ProvisioningCipher) (string, error) { +func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCipher *ProvisioningCipher, allowBackup bool) (string, error) { log := zerolog.Ctx(ctx).With().Str("action", "start provisioning").Logger() pubKey := provisioningCipher.GetPublicKey() @@ -289,13 +299,17 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) } + linkCapabilities := []string{"backup"} + if !allowBackup { + linkCapabilities = []string{} + } provisioningURL := (&url.URL{ Scheme: "sgnl", Host: "linkdevice", RawQuery: url.Values{ "uuid": []string{provisioningBody.GetAddress()}, "pub_key": []string{base64.StdEncoding.EncodeToString(exerrors.Must(pubKey.Serialize()))}, - "capabilities": []string{""}, // Will contain "backup" in the future + "capabilities": linkCapabilities, }.Encode(), }).String() diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 8f81490..7437ac5 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -37,7 +37,8 @@ const getAllDevicesQuery = ` SELECT aci_uuid, aci_identity_key_pair, registration_id, pni_uuid, pni_identity_key_pair, pni_registration_id, - device_id, number, password, master_key, account_record + device_id, number, password, master_key, account_record, + account_entropy_pool, ephemeral_backup_key, media_root_backup_key FROM signalmeow_device ` @@ -50,13 +51,14 @@ func (c *Container) Upgrade(ctx context.Context) error { func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { var device Device - var aciIdentityKeyPair, pniIdentityKeyPair, accountRecordBytes []byte + var accountEntropyPool sql.NullString + var aciIdentityKeyPair, pniIdentityKeyPair, accountRecordBytes, ephemeralBackupKey, mediaRootBackupKey []byte err := row.Scan( &device.ACI, &aciIdentityKeyPair, &device.ACIRegistrationID, &device.PNI, &pniIdentityKeyPair, &device.PNIRegistrationID, - &device.DeviceID, &device.Number, &device.Password, &device.MasterKey, - &accountRecordBytes, + &device.DeviceID, &device.Number, &device.Password, &device.MasterKey, &accountRecordBytes, + &accountEntropyPool, &ephemeralBackupKey, &mediaRootBackupKey, ) if err != nil { return nil, fmt.Errorf("failed to scan session: %w", err) @@ -80,6 +82,9 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { return nil, fmt.Errorf("failed to unmarshal account record: %w", err) } } + device.AccountEntropyPool = libsignalgo.AccountEntropyPool(accountEntropyPool.String) + device.EphemeralBackupKey = libsignalgo.BytesToBackupKey(ephemeralBackupKey) + device.MediaRootBackupKey = libsignalgo.BytesToBackupKey(mediaRootBackupKey) baseStore := &sqlStore{Container: c, AccountID: device.ACI} aciStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.ACIServiceID()} pniStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.PNIServiceID()} @@ -147,9 +152,10 @@ const ( INSERT INTO signalmeow_device ( aci_uuid, aci_identity_key_pair, registration_id, pni_uuid, pni_identity_key_pair, pni_registration_id, - device_id, number, password, master_key, account_record + device_id, number, password, master_key, account_record, + account_entropy_pool, ephemeral_backup_key, media_root_backup_key ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ON CONFLICT (aci_uuid) DO UPDATE SET aci_identity_key_pair=excluded.aci_identity_key_pair, registration_id=excluded.registration_id, @@ -160,7 +166,10 @@ const ( number=excluded.number, password=excluded.password, master_key=excluded.master_key, - account_record=excluded.account_record + account_record=excluded.account_record, + account_entropy_pool=excluded.account_entropy_pool, + ephemeral_backup_key=excluded.ephemeral_backup_key, + media_root_backup_key=excluded.media_root_backup_key ` deleteDeviceQuery = `DELETE FROM signalmeow_device WHERE aci_uuid=$1` ) @@ -194,7 +203,8 @@ func (c *Container) PutDevice(ctx context.Context, device *DeviceData) error { device.ACI, aciIdentityKeyPair, device.ACIRegistrationID, device.PNI, pniIdentityKeyPair, device.PNIRegistrationID, device.DeviceID, device.Number, device.Password, device.MasterKey, - accountRecordBytes, + accountRecordBytes, device.AccountEntropyPool, + device.EphemeralBackupKey.Slice(), device.MediaRootBackupKey.Slice(), ) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("failed to insert device") diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index eb823c8..262f868 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -37,6 +37,9 @@ type DeviceData struct { Password string MasterKey []byte AccountRecord *signalpb.AccountRecord + AccountEntropyPool libsignalgo.AccountEntropyPool + EphemeralBackupKey *libsignalgo.BackupKey + MediaRootBackupKey *libsignalgo.BackupKey } func (d *DeviceData) ACIServiceID() libsignalgo.ServiceID { diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 38ed5b2..05dd524 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v17 (compatible with v13+): Latest revision +-- v0 -> v18 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -13,8 +13,11 @@ CREATE TABLE signalmeow_device ( number TEXT NOT NULL DEFAULT '', password TEXT NOT NULL DEFAULT '', - master_key bytea, - account_record bytea + master_key bytea, + account_record bytea, + account_entropy_pool TEXT, + ephemeral_backup_key bytea, + media_root_backup_key bytea ); CREATE TABLE signalmeow_pre_keys ( diff --git a/pkg/signalmeow/store/upgrades/18-store-backup-keys.sql b/pkg/signalmeow/store/upgrades/18-store-backup-keys.sql new file mode 100644 index 0000000..e478324 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/18-store-backup-keys.sql @@ -0,0 +1,4 @@ +-- v18 (compatible with v13+): Store account entropy pool and ephemeral backup keys +ALTER TABLE signalmeow_device ADD COLUMN account_entropy_pool TEXT; +ALTER TABLE signalmeow_device ADD COLUMN ephemeral_backup_key bytea; +ALTER TABLE signalmeow_device ADD COLUMN media_root_backup_key bytea; From 33c1b7910a07d883d81ad92801cc25d9d61b5f81 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 18 Jan 2025 15:17:30 +0200 Subject: [PATCH 396/718] msgconv: add utilities for converting backup messages --- pkg/connector/handlesignal.go | 4 +- pkg/msgconv/from-signal-backup.go | 251 ++++++++++++++++++++++++++++++ pkg/msgconv/from-signal.go | 57 ++++--- pkg/msgconv/urlpreview.go | 8 +- 4 files changed, 295 insertions(+), 25 deletions(-) create mode 100644 pkg/msgconv/from-signal-backup.go diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index d39f250..16cfb50 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -315,7 +315,7 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po if !ok { return nil, fmt.Errorf("ConvertMessage() called for non-DataMessage event") } - converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, dataMsg) + converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, dataMsg, nil) if converted.Disappear.Type != "" { evtTS := evt.GetTimestamp() if !dataMsg.GetIsViewOnce() { @@ -334,7 +334,7 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event") } // TODO tell converter about existing parts to avoid reupload? - converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, editMsg.GetDataMessage()) + converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, 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]) editPart.Part.EditCount++ diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go new file mode 100644 index 0000000..1b99b85 --- /dev/null +++ b/pkg/msgconv/from-signal-backup.go @@ -0,0 +1,251 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package msgconv + +import ( + "github.com/google/uuid" + "go.mau.fi/util/exslices" + "go.mau.fi/util/ptr" + "golang.org/x/exp/slices" + + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb" +) + +func boolToInt(b bool) int { + if b { + return 1 + } + return 0 +} + +type AttachmentMap map[uuid.UUID]*backuppb.FilePointer_BackupLocator + +func BackupToDataMessage(ci *backuppb.ChatItem, attMap AttachmentMap) (*signalpb.DataMessage, []*backuppb.Reaction) { + var dm signalpb.DataMessage + var reactions []*backuppb.Reaction + switch ti := ci.Item.(type) { + case *backuppb.ChatItem_StandardMessage: + reactions = ti.StandardMessage.Reactions + if text := ti.StandardMessage.Text; text != nil { + dm.Body = &text.Body + dm.BodyRanges = slices.DeleteFunc(exslices.CastFunc(text.BodyRanges, backupToSignalBodyRange), deleteNil) + } + dm.Attachments = make([]*signalpb.AttachmentPointer, 0, len(ti.StandardMessage.Attachments)+boolToInt(ti.StandardMessage.LongText != nil)) + if ti.StandardMessage.LongText != nil { + randomUUID := uuid.New() + dm.Attachments = append( + dm.Attachments, + backupToSignalAttachment(ti.StandardMessage.LongText, 0, randomUUID, attMap), + ) + } + for _, att := range ti.StandardMessage.Attachments { + var clientUUID uuid.UUID + if len(att.ClientUuid) == 16 { + clientUUID = uuid.UUID(att.ClientUuid) + } else { + clientUUID = uuid.New() + } + dm.Attachments = append( + dm.Attachments, + backupToSignalAttachment(att.Pointer, att.Flag, clientUUID, attMap), + ) + } + dm.Preview = exslices.CastFunc(ti.StandardMessage.LinkPreview, func(from *backuppb.LinkPreview) *signalpb.Preview { + return backupToSignalLinkPreview(from, attMap) + }) + case *backuppb.ChatItem_ContactMessage: + reactions = ti.ContactMessage.Reactions + dm.Contact = []*signalpb.DataMessage_Contact{backupToSignalContact(ti.ContactMessage.Contact, attMap)} + case *backuppb.ChatItem_StickerMessage: + reactions = ti.StickerMessage.Reactions + dm.Sticker = &signalpb.DataMessage_Sticker{ + PackId: ti.StickerMessage.Sticker.PackId, + PackKey: ti.StickerMessage.Sticker.PackKey, + StickerId: &ti.StickerMessage.Sticker.StickerId, + Emoji: ti.StickerMessage.Sticker.Emoji, + Data: backupToSignalAttachment(ti.StickerMessage.Sticker.Data, 0, uuid.New(), attMap), + } + case *backuppb.ChatItem_RemoteDeletedMessage: + // TODO handle some other way? (also disappeared view-once messages) + return nil, nil + case *backuppb.ChatItem_PaymentNotification: + dm.Payment = &signalpb.DataMessage_Payment{ + Item: &signalpb.DataMessage_Payment_Notification_{ + Notification: &signalpb.DataMessage_Payment_Notification{ + Transaction: nil, + Note: ti.PaymentNotification.Note, + }, + }, + } + case *backuppb.ChatItem_GiftBadge: + dm.GiftBadge = &signalpb.DataMessage_GiftBadge{ + ReceiptCredentialPresentation: ti.GiftBadge.ReceiptCredentialPresentation, + } + case *backuppb.ChatItem_ViewOnceMessage: + reactions = ti.ViewOnceMessage.Reactions + if ti.ViewOnceMessage.Attachment == nil { + // TODO handle some other way? + return nil, reactions + } + dm.IsViewOnce = ptr.Ptr(true) + var clientUUID uuid.UUID + if len(ti.ViewOnceMessage.Attachment.ClientUuid) == 16 { + clientUUID = uuid.UUID(ti.ViewOnceMessage.Attachment.ClientUuid) + } else { + clientUUID = uuid.New() + } + dm.Attachments = []*signalpb.AttachmentPointer{backupToSignalAttachment( + ti.ViewOnceMessage.Attachment.Pointer, + ti.ViewOnceMessage.Attachment.Flag, + clientUUID, + attMap, + )} + } + return &dm, reactions +} + +func backupToSignalContact(from *backuppb.ContactAttachment, attMap AttachmentMap) *signalpb.DataMessage_Contact { + var contact signalpb.DataMessage_Contact + if from.Name != nil { + contact.Name = &signalpb.DataMessage_Contact_Name{ + GivenName: &from.Name.GivenName, + FamilyName: &from.Name.FamilyName, + Prefix: &from.Name.Prefix, + Suffix: &from.Name.Suffix, + MiddleName: &from.Name.MiddleName, + Nickname: &from.Name.Nickname, + } + } + contact.Number = exslices.CastFunc(from.Number, func(from *backuppb.ContactAttachment_Phone) *signalpb.DataMessage_Contact_Phone { + return &signalpb.DataMessage_Contact_Phone{ + Value: &from.Value, + Type: ptr.NonZero(signalpb.DataMessage_Contact_Phone_Type(from.Type)), + Label: &from.Label, + } + }) + contact.Email = exslices.CastFunc(from.Email, func(from *backuppb.ContactAttachment_Email) *signalpb.DataMessage_Contact_Email { + return &signalpb.DataMessage_Contact_Email{ + Value: &from.Value, + Type: ptr.NonZero(signalpb.DataMessage_Contact_Email_Type(from.Type)), + Label: &from.Label, + } + }) + contact.Address = exslices.CastFunc(from.Address, func(from *backuppb.ContactAttachment_PostalAddress) *signalpb.DataMessage_Contact_PostalAddress { + return &signalpb.DataMessage_Contact_PostalAddress{ + Type: ptr.NonZero(signalpb.DataMessage_Contact_PostalAddress_Type(from.Type)), + Label: &from.Label, + Street: &from.Street, + Pobox: &from.Pobox, + Neighborhood: &from.Neighborhood, + City: &from.City, + Region: &from.Region, + Postcode: &from.Postcode, + Country: &from.Country, + } + }) + if from.Avatar != nil { + contact.Avatar = &signalpb.DataMessage_Contact_Avatar{ + Avatar: backupToSignalAttachment(from.Avatar, 0, uuid.New(), attMap), + } + } + contact.Organization = ptr.NonZero(from.Organization) + return &contact +} + +func backupToSignalLinkPreview(from *backuppb.LinkPreview, attMap AttachmentMap) *signalpb.Preview { + var ap *signalpb.AttachmentPointer + if from.Image != nil { + ap = backupToSignalAttachment(from.Image, 0, uuid.New(), attMap) + } + return &signalpb.Preview{ + Url: &from.Url, + Title: from.Title, + Image: ap, + Description: from.Description, + Date: from.Date, + } +} + +func backupToSignalAttachment( + fp *backuppb.FilePointer, + flag backuppb.MessageAttachment_Flag, + clientUUID uuid.UUID, + atts map[uuid.UUID]*backuppb.FilePointer_BackupLocator, +) *signalpb.AttachmentPointer { + sig := &signalpb.AttachmentPointer{ + ContentType: fp.ContentType, + IncrementalMac: fp.IncrementalMac, + IncrementalMacChunkSize: fp.IncrementalMacChunkSize, + FileName: fp.FileName, + Flags: ptr.NonZero(uint32(backupToSignalAttachmentFlag(flag))), + Width: fp.Width, + Height: fp.Height, + Caption: nil, // is this field deprecated or something? + BlurHash: fp.BlurHash, + Uuid: clientUUID[:], + } + switch loc := fp.Locator.(type) { + case *backuppb.FilePointer_AttachmentLocator_: + sig.AttachmentIdentifier = &signalpb.AttachmentPointer_CdnKey{CdnKey: loc.AttachmentLocator.CdnKey} + sig.Key = loc.AttachmentLocator.Key + sig.Size = &loc.AttachmentLocator.Size + sig.Digest = loc.AttachmentLocator.Digest + sig.CdnNumber = &loc.AttachmentLocator.CdnNumber + case *backuppb.FilePointer_BackupLocator_: + atts[clientUUID] = loc.BackupLocator + case *backuppb.FilePointer_InvalidAttachmentLocator_: + atts[clientUUID] = nil + } + return sig +} + +func backupToSignalAttachmentFlag(flag backuppb.MessageAttachment_Flag) signalpb.AttachmentPointer_Flags { + switch flag { + case backuppb.MessageAttachment_VOICE_MESSAGE: + return signalpb.AttachmentPointer_VOICE_MESSAGE + case backuppb.MessageAttachment_BORDERLESS: + return signalpb.AttachmentPointer_BORDERLESS + case backuppb.MessageAttachment_GIF: + return compatFlagGIF + case backuppb.MessageAttachment_NONE: + fallthrough + default: + return 0 + } +} + +func deleteNil(bodyRange *signalpb.BodyRange) bool { + return bodyRange == nil +} + +func backupToSignalBodyRange(from *backuppb.BodyRange) *signalpb.BodyRange { + var out signalpb.BodyRange + out.Start = from.Start + out.Length = from.Length + switch av := from.AssociatedValue.(type) { + case *backuppb.BodyRange_MentionAci: + // TODO confirm this is correct + if len(av.MentionAci) != 16 { + return nil + } + out.AssociatedValue = &signalpb.BodyRange_MentionAci{MentionAci: uuid.UUID(av.MentionAci).String()} + case *backuppb.BodyRange_Style_: + out.AssociatedValue = &signalpb.BodyRange_Style_{Style: signalpb.BodyRange_Style(av.Style)} + } + return &out +} diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index a7ceb0d..714b723 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -83,6 +83,7 @@ func (mc *MessageConverter) ToMatrix( portal *bridgev2.Portal, intent bridgev2.MatrixAPI, dm *signalpb.DataMessage, + attMap AttachmentMap, ) *bridgev2.ConvertedMessage { ctx = context.WithValue(ctx, contextKeyClient, client) ctx = context.WithValue(ctx, contextKeyPortal, portal) @@ -102,15 +103,15 @@ func (mc *MessageConverter) ToMatrix( cm.Disappear.Timer = time.Duration(dm.GetExpireTimer()) * time.Second } if dm.Sticker != nil { - cm.Parts = append(cm.Parts, mc.convertStickerToMatrix(ctx, dm.Sticker)) + cm.Parts = append(cm.Parts, mc.convertStickerToMatrix(ctx, dm.Sticker, attMap)) // Don't allow any other parts in a sticker message return cm } for i, att := range dm.GetAttachments() { if att.GetContentType() != "text/x-signal-plain" { - cm.Parts = append(cm.Parts, mc.convertAttachmentToMatrix(ctx, i, att)) + cm.Parts = append(cm.Parts, mc.convertAttachmentToMatrix(ctx, i, att, attMap)) } else { - longBody, err := mc.downloadSignalLongText(ctx, att) + longBody, err := mc.downloadSignalLongText(ctx, att, attMap) if err == nil { dm.Body = longBody } else { @@ -119,7 +120,7 @@ func (mc *MessageConverter) ToMatrix( } } for _, contact := range dm.GetContact() { - cm.Parts = append(cm.Parts, mc.convertContactToMatrix(ctx, contact)) + cm.Parts = append(cm.Parts, mc.convertContactToMatrix(ctx, contact, attMap)) } if dm.Payment != nil { cm.Parts = append(cm.Parts, mc.convertPaymentToMatrix(ctx, dm.Payment)) @@ -128,7 +129,7 @@ func (mc *MessageConverter) ToMatrix( cm.Parts = append(cm.Parts, mc.convertGiftBadgeToMatrix(ctx, dm.GiftBadge)) } if dm.Body != nil { - cm.Parts = append(cm.Parts, mc.convertTextToMatrix(ctx, dm)) + cm.Parts = append(cm.Parts, mc.convertTextToMatrix(ctx, dm, attMap)) } if len(cm.Parts) == 0 && dm.GetRequiredProtocolVersion() > uint32(signalpb.DataMessage_CURRENT) { cm.Parts = append(cm.Parts, &bridgev2.ConvertedMessagePart{ @@ -205,11 +206,11 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C return part } -func (mc *MessageConverter) convertTextToMatrix(ctx context.Context, dm *signalpb.DataMessage) *bridgev2.ConvertedMessagePart { +func (mc *MessageConverter) convertTextToMatrix(ctx context.Context, dm *signalpb.DataMessage, attMap AttachmentMap) *bridgev2.ConvertedMessagePart { content := signalfmt.Parse(ctx, dm.GetBody(), dm.GetBodyRanges(), mc.SignalFmtParams) extra := map[string]any{} if len(dm.Preview) > 0 { - content.BeeperLinkPreviews = mc.convertURLPreviewsToBeeper(ctx, dm.Preview) + content.BeeperLinkPreviews = mc.convertURLPreviewsToBeeper(ctx, dm.Preview, attMap) } return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, @@ -244,7 +245,7 @@ func (mc *MessageConverter) convertGiftBadgeToMatrix(_ context.Context, giftBadg } } -func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact *signalpb.DataMessage_Contact) vcard.Card { +func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact *signalpb.DataMessage_Contact, attMap AttachmentMap) vcard.Card { card := make(vcard.Card) card.SetValue(vcard.FieldVersion, "4.0") name := contact.GetName() @@ -306,7 +307,7 @@ func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact * card.Add(vcard.FieldTelephone, &field) } if contact.GetAvatar().GetAvatar() != nil { - avatarData, err := signalmeow.DownloadAttachment(ctx, contact.GetAvatar().GetAvatar()) + avatarData, err := mc.downloadAttachment(ctx, contact.GetAvatar().GetAvatar(), attMap) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to download contact avatar") } else { @@ -320,8 +321,8 @@ func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact * return card } -func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact *signalpb.DataMessage_Contact) *bridgev2.ConvertedMessagePart { - card := mc.convertContactToVCard(ctx, contact) +func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact *signalpb.DataMessage_Contact, attMap AttachmentMap) *bridgev2.ConvertedMessagePart { + card := mc.convertContactToVCard(ctx, contact, attMap) contact.Avatar = nil extraData := map[string]any{ "fi.mau.signal.contact": contact, @@ -380,8 +381,8 @@ func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact } } -func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index int, att *signalpb.AttachmentPointer) *bridgev2.ConvertedMessagePart { - part, err := mc.reuploadAttachment(ctx, att) +func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index int, att *signalpb.AttachmentPointer, attMap AttachmentMap) *bridgev2.ConvertedMessagePart { + part, err := mc.reuploadAttachment(ctx, att, attMap) if err != nil { zerolog.Ctx(ctx).Err(err).Int("attachment_index", index).Msg("Failed to handle attachment") return &bridgev2.ConvertedMessagePart{ @@ -395,8 +396,8 @@ func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index return part } -func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker *signalpb.DataMessage_Sticker) *bridgev2.ConvertedMessagePart { - converted, err := mc.reuploadAttachment(ctx, sticker.GetData()) +func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker *signalpb.DataMessage_Sticker, attMap AttachmentMap) *bridgev2.ConvertedMessagePart { + converted, err := mc.reuploadAttachment(ctx, sticker.GetData(), attMap) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to handle sticker") return &bridgev2.ConvertedMessagePart{ @@ -430,8 +431,8 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker return converted } -func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *signalpb.AttachmentPointer) (*string, error) { - data, err := signalmeow.DownloadAttachment(ctx, att) +func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*string, error) { + data, err := mc.downloadAttachment(ctx, att, attMap) if err != nil { return nil, fmt.Errorf("failed to download attachment: %w", err) } @@ -439,8 +440,26 @@ func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *sig return &longBody, nil } -func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer) (*bridgev2.ConvertedMessagePart, error) { - data, err := signalmeow.DownloadAttachment(ctx, att) +func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) ([]byte, error) { + if att.AttachmentIdentifier == nil { + if len(att.GetUuid()) != 16 { + return nil, fmt.Errorf("no attachment identifier found") + } + target, ok := attMap[uuid.UUID(att.GetUuid())] + if !ok { + return nil, fmt.Errorf("no attachment identifier and attachment not found in map") + } else if target == nil { + return nil, fmt.Errorf("attachment not available in backup") + } else { + // TODO add support for downloading attachments from backup + return nil, fmt.Errorf("downloading attachments from backup is not yet supported") + } + } + return signalmeow.DownloadAttachment(ctx, att) +} + +func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*bridgev2.ConvertedMessagePart, error) { + data, err := mc.downloadAttachment(ctx, att, attMap) if err != nil { return nil, fmt.Errorf("failed to download attachment: %w", err) } diff --git a/pkg/msgconv/urlpreview.go b/pkg/msgconv/urlpreview.go index 5731a0b..fcb32fb 100644 --- a/pkg/msgconv/urlpreview.go +++ b/pkg/msgconv/urlpreview.go @@ -27,15 +27,15 @@ import ( signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) -func (mc *MessageConverter) convertURLPreviewsToBeeper(ctx context.Context, preview []*signalpb.Preview) []*event.BeeperLinkPreview { +func (mc *MessageConverter) convertURLPreviewsToBeeper(ctx context.Context, preview []*signalpb.Preview, attMap AttachmentMap) []*event.BeeperLinkPreview { output := make([]*event.BeeperLinkPreview, len(preview)) for i, p := range preview { - output[i] = mc.convertURLPreviewToBeeper(ctx, p) + output[i] = mc.convertURLPreviewToBeeper(ctx, p, attMap) } return output } -func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, preview *signalpb.Preview) *event.BeeperLinkPreview { +func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, preview *signalpb.Preview, attMap AttachmentMap) *event.BeeperLinkPreview { output := &event.BeeperLinkPreview{ MatchedURL: preview.GetUrl(), LinkPreview: event.LinkPreview{ @@ -45,7 +45,7 @@ func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, previ }, } if preview.Image != nil { - msg, err := mc.reuploadAttachment(ctx, preview.Image) + msg, err := mc.reuploadAttachment(ctx, preview.Image, attMap) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to reupload link preview image") } else { From fc6a95375e095b1658261c45a2cf84bee581527e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 18 Jan 2025 15:19:24 +0200 Subject: [PATCH 397/718] msgconv: switch from exp/slices to stdlib slices --- pkg/msgconv/from-signal-backup.go | 3 ++- pkg/msgconv/matrixfmt/html.go | 2 +- pkg/msgconv/signalfmt/convert.go | 2 +- pkg/signalmeow/storageservice.go | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index 1b99b85..bf479ac 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -17,10 +17,11 @@ package msgconv import ( + "slices" + "github.com/google/uuid" "go.mau.fi/util/exslices" "go.mau.fi/util/ptr" - "golang.org/x/exp/slices" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb" diff --git a/pkg/msgconv/matrixfmt/html.go b/pkg/msgconv/matrixfmt/html.go index 5c4a37f..958ccc3 100644 --- a/pkg/msgconv/matrixfmt/html.go +++ b/pkg/msgconv/matrixfmt/html.go @@ -4,11 +4,11 @@ import ( "context" "fmt" "math" + "slices" "strconv" "strings" "github.com/google/uuid" - "golang.org/x/exp/slices" "golang.org/x/net/html" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" diff --git a/pkg/msgconv/signalfmt/convert.go b/pkg/msgconv/signalfmt/convert.go index 06bbe7b..f950a59 100644 --- a/pkg/msgconv/signalfmt/convert.go +++ b/pkg/msgconv/signalfmt/convert.go @@ -19,11 +19,11 @@ package signalfmt import ( "context" "html" + "slices" "strings" "github.com/google/uuid" "golang.org/x/exp/maps" - "golang.org/x/exp/slices" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index ae003ae..28412b6 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "net/http" + "slices" "strings" "github.com/google/uuid" @@ -31,7 +32,6 @@ import ( "go.mau.fi/util/exerrors" "golang.org/x/crypto/hkdf" "golang.org/x/exp/maps" - "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" From 8cdc01f21d65b24a961b7e99c3f50adb3fa3c022 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 18 Jan 2025 23:39:15 +0200 Subject: [PATCH 398/718] chatinfo: stop using deprecated Members list --- pkg/connector/chatinfo.go | 14 +++++++----- pkg/connector/groupinfo.go | 45 +++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 7bd392f..4071e68 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -227,11 +227,12 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { name := "" topic := PrivateChatTopic + selfUser := s.makeEventSender(s.Client.Store.ACI) members := &bridgev2.ChatMemberList{ IsFull: true, - Members: []bridgev2.ChatMember{ - { - EventSender: s.makeEventSender(s.Client.Store.ACI), + MemberMap: map[networkid.UserID]bridgev2.ChatMember{ + selfUser.Sender: { + EventSender: selfUser, Membership: event.MembershipJoin, PowerLevel: &moderatorPL, }, @@ -257,11 +258,12 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev } } else { // The other user is only present if their ACI is known - members.Members = append(members.Members, bridgev2.ChatMember{ - EventSender: s.makeEventSender(recipient.ACI), + recipientUser := s.makeEventSender(recipient.ACI) + members.MemberMap[recipientUser.Sender] = bridgev2.ChatMember{ + EventSender: recipientUser, Membership: event.MembershipJoin, PowerLevel: &moderatorPL, - }) + } } serviceID = libsignalgo.NewACIServiceID(recipient.ACI) } diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 843a18e..e5c1fc5 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -25,6 +25,7 @@ import ( "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -47,7 +48,7 @@ func roleToPL(role signalmeow.GroupMemberRole) *int { } } -func applyAnnouncementsOnly(plc *bridgev2.PowerLevelChanges, announcementsOnly bool) { +func applyAnnouncementsOnly(plc *bridgev2.PowerLevelOverrides, announcementsOnly bool) { if announcementsOnly { plc.EventsDefault = &moderatorPL } else { @@ -55,7 +56,7 @@ func applyAnnouncementsOnly(plc *bridgev2.PowerLevelChanges, announcementsOnly b } } -func applyAttributesAccess(plc *bridgev2.PowerLevelChanges, attributeAccess signalmeow.AccessControl) { +func applyAttributesAccess(plc *bridgev2.PowerLevelOverrides, attributeAccess signalmeow.AccessControl) { attributePL := defaultPL if attributeAccess == signalmeow.AccessControl_ADMINISTRATOR { attributePL = moderatorPL @@ -65,7 +66,7 @@ func applyAttributesAccess(plc *bridgev2.PowerLevelChanges, attributeAccess sign plc.Events[event.StateTopic] = attributePL } -func applyMembersAccess(plc *bridgev2.PowerLevelChanges, memberAccess signalmeow.AccessControl) { +func applyMembersAccess(plc *bridgev2.PowerLevelOverrides, memberAccess signalmeow.AccessControl) { if memberAccess == signalmeow.AccessControl_ADMINISTRATOR { plc.Invite = &moderatorPL } else { @@ -98,9 +99,9 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden return nil, err } members := &bridgev2.ChatMemberList{ - IsFull: true, - Members: make([]bridgev2.ChatMember, len(groupInfo.Members), len(groupInfo.Members)+len(groupInfo.PendingMembers)+len(groupInfo.RequestingMembers)+len(groupInfo.BannedMembers)), - PowerLevels: &bridgev2.PowerLevelChanges{ + IsFull: true, + MemberMap: make(map[networkid.UserID]bridgev2.ChatMember, len(groupInfo.Members)+len(groupInfo.PendingMembers)+len(groupInfo.RequestingMembers)+len(groupInfo.BannedMembers)), + PowerLevels: &bridgev2.PowerLevelOverrides{ Events: map[event.Type]int{ event.StatePowerLevels: moderatorPL, }, @@ -113,9 +114,10 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden applyMembersAccess(members.PowerLevels, groupInfo.AccessControl.Members) joinRule = inviteLinkToJoinRule(groupInfo.AccessControl.AddFromInviteLink) } - for i, member := range groupInfo.Members { - members.Members[i] = bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ACI), + for _, member := range groupInfo.Members { + evtSender := s.makeEventSender(member.ACI) + members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ + EventSender: evtSender, PowerLevel: roleToPL(member.Role), Membership: event.MembershipJoin, } @@ -125,27 +127,30 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden if aci == nil { continue } - members.Members = append(members.Members, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), + evtSender := s.makeEventSender(*aci) + members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ + EventSender: evtSender, PowerLevel: roleToPL(member.Role), Membership: event.MembershipInvite, - }) + } } for _, member := range groupInfo.RequestingMembers { - members.Members = append(members.Members, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ACI), + evtSender := s.makeEventSender(member.ACI) + members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ + EventSender: evtSender, Membership: event.MembershipKnock, - }) + } } for _, member := range groupInfo.BannedMembers { aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) if aci == nil { continue } - members.Members = append(members.Members, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), + evtSender := s.makeEventSender(*aci) + members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ + EventSender: evtSender, Membership: event.MembershipBan, - }) + } } return &bridgev2.ChatInfo{ Name: &groupInfo.Title, @@ -203,11 +208,11 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint } } - var pls *bridgev2.PowerLevelChanges + var pls *bridgev2.PowerLevelOverrides if groupChange.ModifyAnnouncementsOnly != nil || groupChange.ModifyAttributesAccess != nil || groupChange.ModifyMemberAccess != nil { - pls = &bridgev2.PowerLevelChanges{Events: make(map[event.Type]int)} + pls = &bridgev2.PowerLevelOverrides{Events: make(map[event.Type]int)} if groupChange.ModifyAnnouncementsOnly != nil { applyAnnouncementsOnly(pls, *groupChange.ModifyAnnouncementsOnly) } From 030c83c197ea3499b924fa753204c4c8caac25aa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 13:58:03 +0200 Subject: [PATCH 399/718] chatinfo: only clear avatar after fetching profile with no avatar --- pkg/connector/chatinfo.go | 10 +++++----- pkg/signalmeow/profile.go | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 4071e68..e3eef59 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -102,6 +102,11 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use return contact.ContactAvatar.Image, nil }, } + } else if contact.Profile.AvatarPath == "clear" { + ui.Avatar = &bridgev2.Avatar{ + ID: "", + Remove: true, + } } else if contact.Profile.AvatarPath != "" { ui.Avatar = &bridgev2.Avatar{ ID: makeAvatarPathID(contact.Profile.AvatarPath), @@ -109,11 +114,6 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use return s.Client.DownloadUserAvatar(ctx, contact.Profile.AvatarPath, contact.Profile.Key) }, } - } else { - ui.Avatar = &bridgev2.Avatar{ - ID: "", - Remove: true, - } } return ui } diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 1a7571c..440fe1b 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -243,7 +243,11 @@ func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID u } } // TODO store other metadata fields? - profile.AvatarPath = profileResponse.Avatar + if profileResponse.Avatar == "" { + profile.AvatarPath = "clear" + } else { + profile.AvatarPath = profileResponse.Avatar + } profile.Credential = profileResponse.Credential profile.Key = *profileKey From dd3aab051fe9a25f10d6deb6f28c0120764de031 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 18 Jan 2025 16:29:20 +0200 Subject: [PATCH 400/718] signalmeow: store history transfer data in db --- pkg/libsignalgo/groupsecretparams.go | 13 + pkg/signalmeow/backup.go | 66 +++- pkg/signalmeow/groups.go | 13 +- pkg/signalmeow/store/backup_store.go | 331 ++++++++++++++++++ pkg/signalmeow/store/container.go | 4 + pkg/signalmeow/store/device.go | 3 + pkg/signalmeow/store/upgrades/00-latest.sql | 77 +++- .../store/upgrades/19-store-backup-data.sql | 52 +++ 8 files changed, 515 insertions(+), 44 deletions(-) create mode 100644 pkg/signalmeow/store/backup_store.go create mode 100644 pkg/signalmeow/store/upgrades/19-store-backup-data.sql diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 8ad9b39..c6189af 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -23,6 +23,7 @@ package libsignalgo import "C" import ( "crypto/rand" + "fmt" "runtime" "unsafe" @@ -54,6 +55,18 @@ func GenerateGroupSecretParams() (GroupSecretParams, error) { return GenerateGroupSecretParamsWithRandomness(GenerateRandomness()) } +func (gmk GroupMasterKey) GroupIdentifier() (*GroupIdentifier, error) { + if groupSecretParams, err := DeriveGroupSecretParamsFromMasterKey(gmk); err != nil { + return nil, fmt.Errorf("DeriveGroupSecretParamsFromMasterKey error: %w", err) + } else if groupPublicParams, err := groupSecretParams.GetPublicParams(); err != nil { + return nil, fmt.Errorf("GetPublicParams error: %w", err) + } else if groupIdentifier, err := GetGroupIdentifier(*groupPublicParams); err != nil { + return nil, fmt.Errorf("GetGroupIdentifier error: %w", err) + } else { + return groupIdentifier, nil + } +} + 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))) diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index 536302d..d69a729 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -41,12 +41,14 @@ import ( const transferArchiveFetchTimeout = 1 * time.Hour var ( - ErrTransferRelinkRequested = errors.New("relink requested") - ErrTransferContinueWithoutUpload = errors.New("continue without upload") - ErrNoEphemeralBackupKey = errors.New("no ephemeral backup key") ) +const ( + TransferErrorRelinkRequested = "RELINK_REQUESTED" + TransferErrorContinueWithoutUpload = "CONTINUE_WITHOUT_UPLOAD" +) + type TransferArchiveMetadata struct { CDN uint32 `json:"cdn"` Key string `json:"key"` @@ -55,14 +57,7 @@ type TransferArchiveMetadata struct { func (cli *Client) FetchAndProcessTransfer(ctx context.Context, meta *TransferArchiveMetadata) error { if meta.Error != "" { - switch meta.Error { - case "RELINK_REQUESTED": - return ErrTransferRelinkRequested - case "CONTINUE_WITHOUT_UPLOAD": - return ErrTransferContinueWithoutUpload - default: - return fmt.Errorf("transfer archive error: %s", meta.Error) - } + return fmt.Errorf("transfer archive error: %s", meta.Error) } aesKey, hmacKey, err := cli.deriveTransferKeys() if err != nil { @@ -98,15 +93,29 @@ func (cli *Client) FetchAndProcessTransfer(ctx context.Context, meta *TransferAr if err != nil { return fmt.Errorf("failed to seek to start of file: %w", err) } - err = cli.processTransferArchive(ctx, aesKey, hmacKey, file, stat.Size()) + err = cli.Store.DoTxn(ctx, func(ctx context.Context) error { + err = cli.Store.BackupStore.ClearBackup(ctx) + if err != nil { + return fmt.Errorf("failed to clear backup: %w", err) + } + err = cli.processTransferArchive(ctx, aesKey, hmacKey, file, stat.Size()) + if err != nil { + return err + } + err = cli.Store.BackupStore.RecalculateChatCounts(ctx) + if err != nil { + return fmt.Errorf("failed to calculate message counts: %w", err) + } + cli.Store.EphemeralBackupKey = nil + err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + if err != nil { + return fmt.Errorf("failed to save device data after clearing ephemeral backup key: %w", err) + } + return nil + }) if err != nil { return err } - cli.Store.EphemeralBackupKey = nil - err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) - if err != nil { - return fmt.Errorf("failed to save device data after clearing ephemeral backup key: %w", err) - } return nil } @@ -185,8 +194,27 @@ func (acp *archiveChunkProcessor) processChunk(buf []byte) error { } func (acp *archiveChunkProcessor) processFrame(frame *backuppb.Frame) error { - acp.cli.Log.Info().Any("backup_frame", frame).Msg("Received backup frame") - return nil + acp.cli.Log.Trace().Any("backup_frame", frame).Msg("Processing backup frame") + switch item := frame.Item.(type) { + case *backuppb.Frame_Recipient: + return acp.cli.Store.BackupStore.AddBackupRecipient(acp.ctx, item.Recipient) + case *backuppb.Frame_Chat: + return acp.cli.Store.BackupStore.AddBackupChat(acp.ctx, item.Chat) + case *backuppb.Frame_ChatItem: + switch item.ChatItem.Item.(type) { + case *backuppb.ChatItem_DirectStoryReplyMessage, *backuppb.ChatItem_UpdateMessage: + zerolog.Ctx(acp.ctx).Debug(). + Uint64("chat_id", item.ChatItem.ChatId). + Uint64("message_id", item.ChatItem.DateSent). + Type("frame_type", item). + Msg("Not saving unsupported chat item type") + return nil + } + return acp.cli.Store.BackupStore.AddBackupChatItem(acp.ctx, item.ChatItem) + default: + zerolog.Ctx(acp.ctx).Debug().Type("frame_type", item).Msg("Ignoring backup frame") + return nil + } } func (cli *Client) deriveTransferKeys() (aesKey, hmacKey [32]byte, err error) { diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 9031194..7037b9c 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -469,18 +469,9 @@ func InviteLinkPasswordFromBytes(inviteLinkPassword []byte) types.SerializedInvi } func groupIdentifierFromMasterKey(masterKey types.SerializedGroupMasterKey) (types.GroupIdentifier, error) { - groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(masterKey)) + groupIdentifier, err := masterKeyToBytes(masterKey).GroupIdentifier() if err != nil { - return "", fmt.Errorf("DeriveGroupSecretParamsFromMasterKey error: %w", err) - } - // Get the "group identifier" that isn't just the master key - groupPublicParams, err := groupSecretParams.GetPublicParams() - if err != nil { - return "", fmt.Errorf("GetPublicParams error: %w", err) - } - groupIdentifier, err := libsignalgo.GetGroupIdentifier(*groupPublicParams) - if err != nil { - return "", fmt.Errorf("GetGroupIdentifier error: %w", err) + return "", err } base64GroupIdentifier := base64.StdEncoding.EncodeToString(groupIdentifier[:]) gid := types.GroupIdentifier(base64GroupIdentifier) diff --git a/pkg/signalmeow/store/backup_store.go b/pkg/signalmeow/store/backup_store.go new file mode 100644 index 0000000..823fe54 --- /dev/null +++ b/pkg/signalmeow/store/backup_store.go @@ -0,0 +1,331 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package store + +import ( + "context" + "database/sql" + "encoding/base64" + "errors" + "fmt" + "strings" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/dbutil" + "go.mau.fi/util/ptr" + "google.golang.org/protobuf/proto" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +type BackupChat struct { + *backuppb.Chat + TotalMessages int + LatestMessageID uint64 +} + +type BackupStore interface { + AddBackupRecipient(ctx context.Context, recipient *backuppb.Recipient) error + AddBackupChat(ctx context.Context, chat *backuppb.Chat) error + AddBackupChatItem(ctx context.Context, item *backuppb.ChatItem) error + RecalculateChatCounts(ctx context.Context) error + ClearBackup(ctx context.Context) error + + GetBackupRecipient(ctx context.Context, recipientID uint64) (*backuppb.Recipient, error) + GetBackupChatByUserID(ctx context.Context, userID libsignalgo.ServiceID) (*BackupChat, error) + GetBackupChatByGroupID(ctx context.Context, groupID types.GroupIdentifier) (*BackupChat, error) + GetBackupChats(ctx context.Context) ([]*BackupChat, error) + GetBackupChatItems(ctx context.Context, chatID uint64, anchor time.Time, forward bool, limit int) ([]*backuppb.ChatItem, error) + DeleteBackupChat(ctx context.Context, chatID uint64) error + DeleteBackupChatItems(ctx context.Context, chatID uint64, minTime time.Time) error +} + +var _ BackupStore = (*sqlStore)(nil) + +const ( + addBackupRecipientQuery = ` + INSERT INTO signalmeow_backup_recipient (account_id, recipient_id, aci_uuid, pni_uuid, group_master_key, data) + VALUES ($1, $2, $3, $4, $5, $6) + ` + addBackupChatQuery = ` + INSERT INTO signalmeow_backup_chat (account_id, chat_id, recipient_id, data) + VALUES ($1, $2, $3, $4) + ` + addBackupChatItemQuery = ` + INSERT INTO signalmeow_backup_message (account_id, chat_id, sender_id, message_id, data) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT DO NOTHING + ` + + getBackupRecipientQuery = ` + SELECT data FROM signalmeow_backup_recipient WHERE account_id=$1 AND recipient_id=$2 + ` + getBackupChatByACIQuery = ` + SELECT chat.data, chat.latest_message_id, chat.total_message_count FROM signalmeow_backup_recipient rcp + INNER JOIN signalmeow_backup_chat chat ON rcp.account_id=chat.account_id AND rcp.recipient_id=chat.recipient_id + WHERE rcp.account_id=$1 AND rcp.aci_uuid=$2 + ` + getBackupChatByPNIQuery = ` + SELECT chat.data, chat.latest_message_id, chat.total_message_count FROM signalmeow_backup_recipient rcp + INNER JOIN signalmeow_backup_chat chat ON rcp.account_id=chat.account_id AND rcp.recipient_id=chat.recipient_id + WHERE rcp.account_id=$1 AND rcp.pni_uuid=$2 + ` + getBackupChatByGroupIDQuery = ` + SELECT chat.data, chat.latest_message_id, chat.total_message_count FROM signalmeow_groups g + INNER JOIN signalmeow_backup_recipient rcp ON g.account_id=rcp.account_id AND g.master_key=rcp.group_master_key + INNER JOIN signalmeow_backup_chat chat ON rcp.account_id=chat.account_id AND rcp.recipient_id=chat.recipient_id + WHERE g.account_id=$1 AND g.group_identifier=$2 + ` + getAllBackupChatsQuery = ` + SELECT data, latest_message_id, total_message_count + FROM signalmeow_backup_chat + WHERE account_id=$1 + ` + getBackupChatItemsQuery = ` + SELECT data + FROM signalmeow_backup_message + WHERE account_id=$1 AND chat_id=$2 AND message_id > $3 AND message_id < $4 + ORDER BY message_id DESC + LIMIT $5 + ` + deleteBackupChatQuery = ` + DELETE FROM signalmeow_backup_chat WHERE account_id=$1 AND chat_id=$2 + ` + deleteBackupChatItemsQuery = ` + DELETE FROM signalmeow_backup_message WHERE account_id=$1 AND chat_id=$2 AND message_id >= $3 + ` + recalculateChatCountsQuery = ` + UPDATE signalmeow_backup_chat + SET latest_message_id = ( + SELECT message_id + FROM signalmeow_backup_message + WHERE account_id=signalmeow_backup_chat.account_id AND chat_id=signalmeow_backup_chat.chat_id + ORDER BY message_id DESC + LIMIT 1 + ), + total_message_count = ( + SELECT COUNT(*) + FROM signalmeow_backup_message + WHERE account_id=signalmeow_backup_chat.account_id AND chat_id=signalmeow_backup_chat.chat_id + ) + WHERE account_id=$1 + ` +) + +func tryCastUUID(b []byte) uuid.UUID { + if len(b) == 16 { + return uuid.UUID(b) + } + return uuid.Nil +} + +func (s *sqlStore) AddBackupRecipient(ctx context.Context, recipient *backuppb.Recipient) error { + recipientData, err := proto.Marshal(recipient) + if err != nil { + return fmt.Errorf("failed to marshal recipient %d: %w", recipient.Id, err) + } + var aci, pni uuid.UUID + var groupMasterKey types.SerializedGroupMasterKey + switch dest := recipient.Destination.(type) { + case *backuppb.Recipient_Contact: + aci = tryCastUUID(dest.Contact.Aci) + pni = tryCastUUID(dest.Contact.Pni) + // TODO save identity key + trust level + if aci != uuid.Nil || pni != uuid.Nil { + _, err := s.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (changed bool, err error) { + oldRecipient := ptr.Clone(recipient) + if dest.Contact.E164 != nil { + recipient.E164 = fmt.Sprintf("+%d", *dest.Contact.E164) + } + if len(dest.Contact.ProfileKey) == libsignalgo.ProfileKeyLength { + recipient.Profile.Key = libsignalgo.ProfileKey(dest.Contact.ProfileKey) + } + if dest.Contact.ProfileGivenName != nil || dest.Contact.ProfileFamilyName != nil { + recipient.Profile.Name = strings.TrimSpace(fmt.Sprintf("%s %s", dest.Contact.GetProfileGivenName(), dest.Contact.GetProfileFamilyName())) + } + changed = oldRecipient.E164 != recipient.E164 || + oldRecipient.Profile.Key != recipient.Profile.Key || + oldRecipient.Profile.Name != recipient.Profile.Name + return + }) + if err != nil { + return fmt.Errorf("failed to save info for recipient %d: %w", recipient.Id, err) + } + } else if dest.Contact.GetRegistered() != nil { + zerolog.Ctx(ctx).Warn(). + Uint64("recipient_id", recipient.Id). + Any("entry", dest.Contact). + Msg("Both ACI and PNI are invalid for registered contact recipient") + } + case *backuppb.Recipient_Group: + groupMasterKey = types.SerializedGroupMasterKey(base64.StdEncoding.EncodeToString(dest.Group.MasterKey)) + if len(dest.Group.MasterKey) == libsignalgo.GroupMasterKeyLength { + gid, err := libsignalgo.GroupMasterKey(dest.Group.MasterKey).GroupIdentifier() + if err != nil { + zerolog.Ctx(ctx).Err(err). + Uint64("recipient_id", recipient.Id). + Msg("Failed to get group identifier from master key") + } else if err = s.StoreMasterKey(ctx, types.GroupIdentifier(base64.StdEncoding.EncodeToString(gid[:])), groupMasterKey); err != nil { + return fmt.Errorf("failed to save group master key for recipient %d: %w", recipient.Id, err) + } + } else { + zerolog.Ctx(ctx).Warn(). + Uint64("recipient_id", recipient.Id). + Msg("Invalid group master key length") + } + case *backuppb.Recipient_Self: + aci = s.AccountID + default: + } + _, err = s.db.Exec(ctx, addBackupRecipientQuery, s.AccountID, recipient.Id, ptr.NonZero(aci), ptr.NonZero(pni), ptr.NonZero(groupMasterKey), recipientData) + if err != nil { + return fmt.Errorf("failed to add backup recipient %d: %w", recipient.Id, err) + } + return nil +} + +func (s *sqlStore) AddBackupChat(ctx context.Context, chat *backuppb.Chat) error { + chatData, err := proto.Marshal(chat) + if err != nil { + return fmt.Errorf("failed to marshal chat %d: %w", chat.Id, err) + } + _, err = s.db.Exec(ctx, addBackupChatQuery, s.AccountID, chat.Id, chat.RecipientId, chatData) + if err != nil { + return fmt.Errorf("failed to add backup chat %d: %w", chat.Id, err) + } + return nil +} + +func (s *sqlStore) AddBackupChatItem(ctx context.Context, item *backuppb.ChatItem) error { + itemData, err := proto.Marshal(item) + if err != nil { + return fmt.Errorf("failed to marshal chat item %d: %w", item.DateSent, err) + } + _, err = s.db.Exec(ctx, addBackupChatItemQuery, s.AccountID, item.ChatId, item.AuthorId, item.DateSent, itemData) + if err != nil { + return fmt.Errorf("failed to add backup chat item %d: %w", item.DateSent, err) + } + return nil +} + +func (s *sqlStore) ClearBackup(ctx context.Context) error { + _, err := s.db.Exec(ctx, "DELETE FROM signalmeow_backup_message WHERE account_id=$1", s.AccountID) + if err != nil { + return err + } + _, err = s.db.Exec(ctx, "DELETE FROM signalmeow_backup_chat WHERE account_id=$1", s.AccountID) + if err != nil { + return err + } + _, err = s.db.Exec(ctx, "DELETE FROM signalmeow_backup_recipient WHERE account_id=$1", s.AccountID) + return err +} + +func scanProto[T proto.Message](row dbutil.Scannable) (val T, err error) { + var data []byte + err = row.Scan(&data) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + err = nil + } + return + } + val = val.ProtoReflect().New().Interface().(T) + err = proto.Unmarshal(data, val) + return +} + +func scanChat(row dbutil.Scannable) (*BackupChat, error) { + var data []byte + var latestMessageID, totalMessageCount sql.NullInt64 + err := row.Scan(&data, &latestMessageID, &totalMessageCount) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, err + } + var chat backuppb.Chat + err = proto.Unmarshal(data, &chat) + if err != nil { + return nil, err + } + return &BackupChat{ + Chat: &chat, + TotalMessages: int(totalMessageCount.Int64), + LatestMessageID: uint64(totalMessageCount.Int64), + }, nil +} + +var chatScanner = dbutil.ConvertRowFn[*BackupChat](scanChat) +var messageScanner = dbutil.ConvertRowFn[*backuppb.ChatItem](scanProto[*backuppb.ChatItem]) + +func (s *sqlStore) GetBackupRecipient(ctx context.Context, recipientID uint64) (*backuppb.Recipient, error) { + return scanProto[*backuppb.Recipient](s.db.QueryRow(ctx, getBackupRecipientQuery, s.AccountID, recipientID)) +} + +func (s *sqlStore) GetBackupChatByUserID(ctx context.Context, userID libsignalgo.ServiceID) (*BackupChat, error) { + query := getBackupChatByACIQuery + if userID.Type == libsignalgo.ServiceIDTypePNI { + query = getBackupChatByPNIQuery + } + return scanChat(s.db.QueryRow(ctx, query, s.AccountID, userID.UUID)) +} + +func (s *sqlStore) GetBackupChatByGroupID(ctx context.Context, groupID types.GroupIdentifier) (*BackupChat, error) { + return scanChat(s.db.QueryRow(ctx, getBackupChatByGroupIDQuery, s.AccountID, groupID)) +} + +func (s *sqlStore) GetBackupChats(ctx context.Context) ([]*BackupChat, error) { + return chatScanner.NewRowIter(s.db.Query(ctx, getAllBackupChatsQuery, s.AccountID)).AsList() +} + +func (s *sqlStore) GetBackupChatItems(ctx context.Context, chatID uint64, anchor time.Time, forward bool, limit int) ([]*backuppb.ChatItem, error) { + var minTS, maxTS int64 + if anchor.IsZero() { + maxTS = time.Now().Add(24 * time.Hour).UnixMilli() + } else if forward { + minTS = anchor.UnixMilli() + maxTS = time.Now().Add(24 * time.Hour).UnixMilli() + } else { + maxTS = anchor.UnixMilli() + } + return messageScanner.NewRowIter(s.db.Query(ctx, getBackupChatItemsQuery, s.AccountID, chatID, minTS, maxTS, limit)).AsList() +} + +func (s *sqlStore) DeleteBackupChatItems(ctx context.Context, chatID uint64, minTime time.Time) error { + anchorTS := minTime.UnixMilli() + if minTime.IsZero() { + anchorTS = 0 + } + _, err := s.db.Exec(ctx, deleteBackupChatItemsQuery, s.AccountID, chatID, anchorTS) + return err +} + +func (s *sqlStore) DeleteBackupChat(ctx context.Context, chatID uint64) error { + _, err := s.db.Exec(ctx, deleteBackupChatQuery, s.AccountID, chatID) + return err +} + +func (s *sqlStore) RecalculateChatCounts(ctx context.Context) error { + _, err := s.db.Exec(ctx, recalculateChatCountsQuery, s.AccountID) + return err +} diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 7437ac5..0839689 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -107,6 +107,10 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.GroupStore = baseStore device.RecipientStore = baseStore device.DeviceStore = baseStore + device.BackupStore = baseStore + device.DoTxn = func(ctx context.Context, fn func(context.Context) error) error { + return c.db.DoTxn(ctx, nil, fn) + } return &device, nil } diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index 262f868..bcd4a88 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -77,6 +77,9 @@ type Device struct { GroupStore GroupStore RecipientStore RecipientStore DeviceStore DeviceStore + BackupStore BackupStore + + DoTxn func(context.Context, func(context.Context) error) error } func (d *Device) ClearDeviceKeys(ctx context.Context) error { diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 05dd524..f4839d1 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v18 (compatible with v13+): Latest revision +-- v0 -> v19 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -43,10 +43,10 @@ CREATE TABLE signalmeow_kyber_pre_keys ( ); CREATE TABLE signalmeow_identity_keys ( - account_id TEXT NOT NULL, - their_service_id TEXT NOT NULL, - key bytea NOT NULL, - trust_level TEXT NOT NULL, + account_id TEXT NOT NULL, + their_service_id TEXT NOT NULL, + key bytea NOT NULL, + trust_level TEXT NOT NULL, PRIMARY KEY (account_id, their_service_id), FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE @@ -84,7 +84,7 @@ CREATE TABLE signalmeow_sender_keys ( ); CREATE TABLE signalmeow_groups ( - account_id TEXT NOT NULL, + account_id TEXT NOT NULL, group_identifier TEXT NOT NULL, master_key TEXT NOT NULL, @@ -92,17 +92,17 @@ CREATE TABLE signalmeow_groups ( ); CREATE TABLE signalmeow_recipients ( - account_id TEXT NOT NULL, + account_id TEXT NOT NULL, aci_uuid TEXT, pni_uuid TEXT, - e164_number TEXT NOT NULL DEFAULT '', - contact_name TEXT NOT NULL DEFAULT '', - contact_avatar_hash TEXT NOT NULL DEFAULT '', + e164_number TEXT NOT NULL DEFAULT '', + contact_name TEXT NOT NULL DEFAULT '', + contact_avatar_hash TEXT NOT NULL DEFAULT '', profile_key bytea, - profile_name TEXT NOT NULL DEFAULT '', - profile_about TEXT NOT NULL DEFAULT '', - profile_about_emoji TEXT NOT NULL DEFAULT '', - profile_avatar_path TEXT NOT NULL DEFAULT '', + profile_name TEXT NOT NULL DEFAULT '', + profile_about TEXT NOT NULL DEFAULT '', + profile_about_emoji TEXT NOT NULL DEFAULT '', + profile_avatar_path TEXT NOT NULL DEFAULT '', profile_fetched_at BIGINT, needs_pni_signature BOOLEAN NOT NULL DEFAULT false, @@ -111,3 +111,52 @@ CREATE TABLE signalmeow_recipients ( CONSTRAINT signalmeow_contacts_aci_unique UNIQUE (account_id, aci_uuid), CONSTRAINT signalmeow_contacts_pni_unique UNIQUE (account_id, pni_uuid) ); + +CREATE TABLE signalmeow_backup_recipient ( + account_id TEXT NOT NULL, + recipient_id BIGINT NOT NULL, + + aci_uuid TEXT, + pni_uuid TEXT, + + group_master_key TEXT, + + data bytea NOT NULL, + + PRIMARY KEY (account_id, recipient_id), + CONSTRAINT signalmeow_backup_recipient_device_fkey FOREIGN KEY (account_id) + REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX signalmeow_backup_recipient_group_idx ON signalmeow_backup_recipient (account_id, group_master_key); +CREATE INDEX signalmeow_backup_recipient_aci_idx ON signalmeow_backup_recipient (account_id, aci_uuid); + +CREATE TABLE signalmeow_backup_chat ( + account_id TEXT NOT NULL, + chat_id BIGINT NOT NULL, + recipient_id BIGINT NOT NULL, + data bytea NOT NULL, + + PRIMARY KEY (account_id, chat_id), + CONSTRAINT signalmeow_backup_chat_device_fkey FOREIGN KEY (account_id) + REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_backup_chat_recipient_fkey FOREIGN KEY (account_id, recipient_id) + REFERENCES signalmeow_backup_recipient (account_id, recipient_id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX signalmeow_backup_chat_recipient_id_idx ON signalmeow_backup_chat (account_id, recipient_id); + +CREATE TABLE signalmeow_backup_message ( + account_id TEXT NOT NULL, + chat_id BIGINT NOT NULL, + sender_id BIGINT NOT NULL, + message_id BIGINT NOT NULL, + data bytea NOT NULL, + + PRIMARY KEY (account_id, sender_id, message_id), + CONSTRAINT signalmeow_backup_message_chat_fkey FOREIGN KEY (account_id, chat_id) + REFERENCES signalmeow_backup_chat (account_id, chat_id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_backup_message_sender_fkey FOREIGN KEY (account_id, sender_id) + REFERENCES signalmeow_backup_recipient (account_id, recipient_id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_backup_message_device_fkey FOREIGN KEY (account_id) + REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX signalmeow_backup_chat_recipient_id_idx ON signalmeow_backup_chat (account_id, chat_id); diff --git a/pkg/signalmeow/store/upgrades/19-store-backup-data.sql b/pkg/signalmeow/store/upgrades/19-store-backup-data.sql new file mode 100644 index 0000000..9189337 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/19-store-backup-data.sql @@ -0,0 +1,52 @@ +-- v19 (compatible with v13+): Add tables for caching parsed backup data +CREATE TABLE signalmeow_backup_recipient ( + account_id TEXT NOT NULL, + recipient_id BIGINT NOT NULL, + + aci_uuid TEXT, + pni_uuid TEXT, + + group_master_key TEXT, + + data bytea NOT NULL, + + PRIMARY KEY (account_id, recipient_id), + CONSTRAINT signalmeow_backup_recipient_device_fkey FOREIGN KEY (account_id) + REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX signalmeow_backup_recipient_group_idx ON signalmeow_backup_recipient (account_id, group_master_key); +CREATE INDEX signalmeow_backup_recipient_aci_idx ON signalmeow_backup_recipient (account_id, aci_uuid); + +CREATE TABLE signalmeow_backup_chat ( + account_id TEXT NOT NULL, + chat_id BIGINT NOT NULL, + recipient_id BIGINT NOT NULL, + data bytea NOT NULL, + + latest_message_id BIGINT, + total_message_count INTEGER, + + PRIMARY KEY (account_id, chat_id), + CONSTRAINT signalmeow_backup_chat_device_fkey FOREIGN KEY (account_id) + REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_backup_chat_recipient_fkey FOREIGN KEY (account_id, recipient_id) + REFERENCES signalmeow_backup_recipient (account_id, recipient_id) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX signalmeow_backup_chat_recipient_id_idx ON signalmeow_backup_chat (account_id, recipient_id); + +CREATE TABLE signalmeow_backup_message ( + account_id TEXT NOT NULL, + chat_id BIGINT NOT NULL, + sender_id BIGINT NOT NULL, + message_id BIGINT NOT NULL, + data bytea NOT NULL, + + PRIMARY KEY (account_id, sender_id, message_id), + CONSTRAINT signalmeow_backup_message_chat_fkey FOREIGN KEY (account_id, chat_id) + REFERENCES signalmeow_backup_chat (account_id, chat_id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_backup_message_sender_fkey FOREIGN KEY (account_id, sender_id) + REFERENCES signalmeow_backup_recipient (account_id, recipient_id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT signalmeow_backup_message_device_fkey FOREIGN KEY (account_id) + REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +CREATE INDEX signalmeow_backup_chat_recipient_id_idx ON signalmeow_backup_chat (account_id, chat_id); From dd0f10ab7095f8f6cb10c75fe1bf6fbeebedabf2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 13:26:23 +0200 Subject: [PATCH 401/718] connector: implement chat list sync and backfill Fixes #1 --- pkg/connector/backfill.go | 192 ++++++++++++++++++++++++++++++++++ pkg/connector/chatinfo.go | 22 ++-- pkg/connector/chatsync.go | 157 +++++++++++++++++++++++++++ pkg/connector/client.go | 11 ++ pkg/connector/dbmeta.go | 6 +- pkg/connector/groupinfo.go | 13 ++- pkg/connector/login.go | 19 +++- pkg/msgconv/from-signal.go | 31 +++++- pkg/signalid/dbmeta.go | 4 + pkg/signalmeow/attachments.go | 4 + 10 files changed, 440 insertions(+), 19 deletions(-) create mode 100644 pkg/connector/backfill.go create mode 100644 pkg/connector/chatsync.go diff --git a/pkg/connector/backfill.go b/pkg/connector/backfill.go new file mode 100644 index 0000000..c0416b1 --- /dev/null +++ b/pkg/connector/backfill.go @@ -0,0 +1,192 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "fmt" + "slices" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/ptr" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/msgconv" + "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" +) + +var _ bridgev2.BackfillingNetworkAPI = (*SignalClient)(nil) + +func tryCastUUID(b []byte) uuid.UUID { + if len(b) == 16 { + return uuid.UUID(b) + } + return uuid.Nil +} + +func (s *SignalClient) FetchMessages(ctx context.Context, params bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) { + if !s.IsLoggedIn() { + return nil, bridgev2.ErrNotLoggedIn + } + userID, groupID, err := signalid.ParsePortalID(params.Portal.ID) + if err != nil { + return nil, fmt.Errorf("failed to parse portal ID: %w", err) + } + var chat *store.BackupChat + if groupID != "" { + chat, err = s.Client.Store.BackupStore.GetBackupChatByGroupID(ctx, groupID) + } else { + chat, err = s.Client.Store.BackupStore.GetBackupChatByUserID(ctx, userID) + } + if err != nil { + return nil, fmt.Errorf("failed to get chat: %w", err) + } else if chat == nil { + zerolog.Ctx(ctx).Debug().Msg("Chat not found, returning nil response for backfill") + return nil, nil + } + var anchorTS time.Time + if params.AnchorMessage != nil { + anchorTS = params.AnchorMessage.Timestamp + } + minTS := anchorTS + items, err := s.Client.Store.BackupStore.GetBackupChatItems(ctx, chat.Id, anchorTS, params.Forward, params.Count) + if err != nil { + return nil, fmt.Errorf("failed to get chat items: %w", err) + } + if len(items) > 0 { + minTS = time.UnixMilli(int64(items[0].DateSent)) + } + // GetBackupChatItems returns in reverse chronological order, so flip the list + slices.Reverse(items) + var firstDirectionfulProcessed bool + var isRead bool + convertedMessages := make([]*bridgev2.BackfillMessage, 0, len(items)) + attMap := make(msgconv.AttachmentMap) + recipientMap := make(map[uint64]*backuppb.Recipient) + getRecipientACI := func(id uint64) (uuid.UUID, error) { + recipient, ok := recipientMap[id] + if !ok { + recipient, err = s.Client.Store.BackupStore.GetBackupRecipient(ctx, id) + if err != nil { + return uuid.Nil, fmt.Errorf("failed to get recipient %d: %w", id, err) + } else if len(recipient.GetContact().GetAci()) != 16 && recipient.GetSelf() == nil { + zerolog.Ctx(ctx).Warn(). + Uint64("recipient_id", id). + Type("recipient_type", recipient.GetDestination()). + Msg("ACI not found for recipient") + } + recipientMap[id] = recipient + } + + switch dest := recipient.Destination.(type) { + case *backuppb.Recipient_Self: + return s.Client.Store.ACI, nil + case *backuppb.Recipient_Contact: + if len(dest.Contact.GetAci()) == 16 { + return uuid.UUID(dest.Contact.GetAci()), nil + } + } + return uuid.Nil, nil + } + for _, item := range items { + var streamOrder int64 + switch dt := item.DirectionalDetails.(type) { + case *backuppb.ChatItem_Incoming: + streamOrder = int64(dt.Incoming.GetDateServerSent()) + if !firstDirectionfulProcessed { + firstDirectionfulProcessed = true + isRead = dt.Incoming.Read + } + case *backuppb.ChatItem_Outgoing: + // TODO stream order? + if !firstDirectionfulProcessed { + firstDirectionfulProcessed = true + isRead = true + } + } + if len(attMap) > 0 { + clear(attMap) + } + senderACI, err := getRecipientACI(item.AuthorId) + if err != nil { + return nil, err + } else if senderACI == uuid.Nil { + continue + } + dm, reactions := msgconv.BackupToDataMessage(item, attMap) + if dm == nil { + continue + } + cm := s.Main.MsgConv.ToMatrix(ctx, s.Client, params.Portal, s.Main.Bridge.Bot, dm, attMap) + convertedReactions := make([]*bridgev2.BackfillReaction, 0, len(reactions)) + for _, reaction := range reactions { + reactionSenderACI, err := getRecipientACI(reaction.AuthorId) + if err != nil { + return nil, err + } else if reactionSenderACI == uuid.Nil { + continue + } + convertedReactions = append(convertedReactions, &bridgev2.BackfillReaction{ + TargetPart: ptr.Ptr(networkid.PartID("")), + Timestamp: time.UnixMilli(int64(reaction.SentTimestamp)), + Sender: s.makeEventSender(reactionSenderACI), + Emoji: reaction.GetEmoji(), + }) + } + msgID := signalid.MakeMessageID(senderACI, item.DateSent) + convertedMessages = append(convertedMessages, &bridgev2.BackfillMessage{ + ConvertedMessage: cm, + Sender: s.makeEventSender(senderACI), + ID: msgID, + TxnID: networkid.TransactionID(msgID), + Timestamp: time.UnixMilli(int64(item.DateSent)), + StreamOrder: streamOrder, + Reactions: convertedReactions, + }) + } + return &bridgev2.FetchMessagesResponse{ + Messages: convertedMessages, + HasMore: len(items) >= params.Count, + Forward: params.Forward, + MarkRead: isRead, + ApproxTotalCount: chat.TotalMessages, + CompleteCallback: func() { + // When reaching the last backwards backfill batch, delete the chat from the backup store. + // If backwards backfilling isn't enabled, delete immediately after the first backfill request. + if (!params.Forward && len(items) < params.Count) || !s.Main.Bridge.Config.Backfill.Queue.Enabled { + err := s.Client.Store.BackupStore.DeleteBackupChat(ctx, chat.Id) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to delete chat from backup store") + } else { + zerolog.Ctx(ctx).Debug().Msg("Deleted chat from backup store as backfill seems finished") + } + } else { + err := s.Client.Store.BackupStore.DeleteBackupChatItems(ctx, chat.Id, minTS) + if err != nil { + zerolog.Ctx(ctx).Err(err).Time("min_ts", minTS).Msg("Failed to delete messages from backup store") + } else { + zerolog.Ctx(ctx).Debug().Time("min_ts", minTS).Msg("Deleted messages from backup store") + } + } + }, + }, nil +} diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index e3eef59..c73b5d5 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -34,6 +34,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -62,14 +63,14 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) return nil, err } if groupID != "" { - return s.getGroupInfo(ctx, groupID, 0) + return s.getGroupInfo(ctx, groupID, 0, nil) } else { aci, pni := userID.ToACIAndPNI() contact, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) if err != nil { return nil, err } - return s.makeCreateDMResponse(contact).PortalInfo, nil + return s.makeCreateDMResponse(ctx, contact, nil).PortalInfo, nil } } @@ -182,13 +183,13 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre UserID: signalid.MakeUserID(aci), UserInfo: s.contactToUserInfo(recipient), Ghost: ghost, - Chat: s.makeCreateDMResponse(recipient), + Chat: s.makeCreateDMResponse(ctx, recipient, nil), }, nil } else { return &bridgev2.ResolveIdentifierResponse{ UserID: signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), UserInfo: s.contactToUserInfo(recipient), - Chat: s.makeCreateDMResponse(recipient), + Chat: s.makeCreateDMResponse(ctx, recipient, nil), }, nil } } @@ -207,7 +208,7 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI for i, recipient := range recipients { recipientResp := &bridgev2.ResolveIdentifierResponse{ UserInfo: s.contactToUserInfo(recipient), - Chat: s.makeCreateDMResponse(recipient), + Chat: s.makeCreateDMResponse(ctx, recipient, nil), } if recipient.ACI != uuid.Nil { recipientResp.UserID = signalid.MakeUserID(recipient.ACI) @@ -224,7 +225,7 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI return resp, nil } -func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev2.CreateChatResponse { +func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *types.Recipient, backupChat *store.BackupChat) *bridgev2.CreateChatResponse { name := "" topic := PrivateChatTopic selfUser := s.makeEventSender(s.Client.Store.ACI) @@ -247,6 +248,13 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev name = s.Main.Config.FormatDisplayname(recipient) serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) } else { + if backupChat == nil { + var err error + backupChat, err = s.Client.Store.BackupStore.GetBackupChatByUserID(ctx, libsignalgo.NewACIServiceID(recipient.ACI)) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get backup chat for recipient") + } + } members.OtherUserID = signalid.MakeUserID(recipient.ACI) if recipient.ACI == s.Client.Store.ACI { name = NoteToSelfName @@ -275,6 +283,8 @@ func (s *SignalClient) makeCreateDMResponse(recipient *types.Recipient) *bridgev Topic: &topic, Members: members, Type: ptr.Ptr(database.RoomTypeDM), + + CanBackfill: backupChat != nil, }, } } diff --git a/pkg/connector/chatsync.go b/pkg/connector/chatsync.go new file mode 100644 index 0000000..5d982e7 --- /dev/null +++ b/pkg/connector/chatsync.go @@ -0,0 +1,157 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + "encoding/base64" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/simplevent" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +func (s *SignalClient) syncChats(ctx context.Context) { + if s.UserLogin.Metadata.(*signalid.UserLoginMetadata).ChatsSynced { + return + } + if s.Client.Store.EphemeralBackupKey != nil { + zerolog.Ctx(ctx).Info().Msg("Fetching transfer archive before syncing chats") + meta, err := s.Client.WaitForTransfer(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to request transfer archive") + return + } else if meta.Error != "" { + zerolog.Ctx(ctx).Error().Str("error_type", meta.Error).Msg("Transfer archive request was rejected") + s.UserLogin.Metadata.(*signalid.UserLoginMetadata).ChatsSynced = true + err = s.UserLogin.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save user login metadata after transfer archive request was rejected") + } + return + } + err = s.Client.FetchAndProcessTransfer(ctx, meta) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to fetch and process transfer archive") + return + } + zerolog.Ctx(ctx).Info().Msg("Transfer archive fetched and processed, syncing chats") + } + chats, err := s.Client.Store.BackupStore.GetBackupChats(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get chats from backup store") + return + } + zerolog.Ctx(ctx).Info().Int("chat_count", len(chats)).Msg("Fetched chats to sync from database") + for _, chat := range chats { + recipient, err := s.Client.Store.BackupStore.GetBackupRecipient(ctx, chat.RecipientId) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get recipient for chat") + continue + } + resyncEvt := &simplevent.ChatResync{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatResync, + LogContext: func(c zerolog.Context) zerolog.Context { + return c. + Int("message_count", chat.TotalMessages). + Uint64("backup_chat_id", chat.Id). + Uint64("backup_recipient_id", chat.RecipientId) + }, + CreatePortal: true, + }, + LatestMessageTS: time.UnixMilli(int64(chat.LatestMessageID)), + } + switch dest := recipient.Destination.(type) { + case *backuppb.Recipient_Contact: + aci := tryCastUUID(dest.Contact.GetAci()) + pni := tryCastUUID(dest.Contact.GetPni()) + if chat.TotalMessages == 0 { + zerolog.Ctx(ctx).Debug(). + Stringer("aci", aci). + Stringer("pni", pni). + Uint64("e164", dest.Contact.GetE164()). + Msg("Skipping direct chat with no messages and deleting data") + err = s.Client.Store.BackupStore.DeleteBackupChat(ctx, chat.Id) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to delete chat from backup store") + } + continue + } + processedRecipient, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get full recipient data") + continue + } + dmInfo := s.makeCreateDMResponse(ctx, processedRecipient, chat) + resyncEvt.PortalKey = dmInfo.PortalKey + resyncEvt.ChatInfo = dmInfo.PortalInfo + case *backuppb.Recipient_Self: + processedRecipient, err := s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, s.Client.Store.ACI, uuid.Nil, nil) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get full recipient data") + continue + } + dmInfo := s.makeCreateDMResponse(ctx, processedRecipient, chat) + resyncEvt.PortalKey = dmInfo.PortalKey + resyncEvt.ChatInfo = dmInfo.PortalInfo + case *backuppb.Recipient_Group: + if len(dest.Group.MasterKey) != libsignalgo.GroupMasterKeyLength { + continue + } + rawGroupID, err := libsignalgo.GroupMasterKey(dest.Group.MasterKey).GroupIdentifier() + if err != nil { + zerolog.Ctx(ctx).Err(err). + Uint64("recipient_id", recipient.Id). + Msg("Failed to get group identifier from master key") + continue + } + groupID := types.GroupIdentifier(base64.StdEncoding.EncodeToString(rawGroupID[:])) + groupInfo, err := s.getGroupInfo(ctx, groupID, dest.Group.GetSnapshot().GetVersion(), chat) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get full group info") + continue + } + resyncEvt.PortalKey = s.makePortalKey(string(groupID)) + resyncEvt.ChatInfo = groupInfo + default: + zerolog.Ctx(ctx).Debug(). + Type("destination_type", dest). + Uint64("backup_chat_id", chat.Id). + Uint64("backup_recipient_id", chat.RecipientId). + Msg("Ignoring and deleting chat with unsupported destination type") + err = s.Client.Store.BackupStore.DeleteBackupChat(ctx, chat.Id) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to delete chat from backup store") + } + continue + } + s.UserLogin.QueueRemoteEvent(resyncEvt) + } + s.UserLogin.Metadata.(*signalid.UserLoginMetadata).ChatsSynced = true + err = s.UserLogin.Save(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to save user login metadata after syncing chats") + } +} diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 2f2925c..ece6753 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -206,6 +206,16 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } } +func (s *SignalClient) postLoginConnect(ctx context.Context) { + // TODO it would be more proper to only connect after syncing, + // but currently syncing will fetch group info online, so it has to be connected. + s.Connect(ctx) + s.syncChats(ctx) + if s.Client.Store.MasterKey != nil { + s.Client.SyncStorage(ctx) + } +} + func (s *SignalClient) Connect(ctx context.Context) { if s.Client == nil { s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You're not logged into Signal"}) @@ -283,6 +293,7 @@ func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { } } else { go s.bridgeStateLoop(ch) + go s.syncChats(ctx) } } diff --git a/pkg/connector/dbmeta.go b/pkg/connector/dbmeta.go index 4ee3b08..d8f644e 100644 --- a/pkg/connector/dbmeta.go +++ b/pkg/connector/dbmeta.go @@ -33,7 +33,9 @@ func (s *SignalConnector) GetDBMetaTypes() database.MetaTypes { Message: func() any { return &signalid.MessageMetadata{} }, - Reaction: nil, - UserLogin: nil, + Reaction: nil, + UserLogin: func() any { + return &signalid.UserLoginMetadata{} + }, } } diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index e5c1fc5..0cb3ce5 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -31,6 +31,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -93,7 +94,7 @@ func inviteLinkToJoinRule(inviteLinkAccess signalmeow.AccessControl) event.JoinR } } -func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32) (*bridgev2.ChatInfo, error) { +func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32, backupChat *store.BackupChat) (*bridgev2.ChatInfo, error) { groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, minRevision) if err != nil { return nil, err @@ -152,6 +153,13 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden Membership: event.MembershipBan, } } + if backupChat == nil { + // TODO allow using backup chat for data too instead of asking server? + backupChat, err = s.Client.Store.BackupStore.GetBackupChatByGroupID(ctx, groupID) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get backup chat for group") + } + } return &bridgev2.ChatInfo{ Name: &groupInfo.Title, Topic: &groupInfo.Description, @@ -164,6 +172,7 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden Type: ptr.Ptr(database.RoomTypeDefault), JoinRule: &event.JoinRulesEventContent{JoinRule: joinRule}, ExtraUpdates: makeRevisionUpdater(groupInfo.Revision), + CanBackfill: backupChat != nil, }, nil } @@ -366,7 +375,7 @@ func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal Logger() if fromRevision == 0 { log.Info().Msg("Syncing full group info") - info, err := s.getGroupInfo(ctx, types.GroupIdentifier(portal.ID), toRevision) + info, err := s.getGroupInfo(ctx, types.GroupIdentifier(portal.ID), toRevision, nil) if err != nil { log.Err(err).Msg("Failed to get group info") } else { diff --git a/pkg/connector/login.go b/pkg/connector/login.go index e2f2e98..3b81b0a 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -79,7 +79,9 @@ func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { provCtx, cancel := context.WithCancel(log.WithContext(context.Background())) qr.cancelChan = cancel // Don't use the start context here: the channel will outlive the start request. - qr.ProvChan = signalmeow.PerformProvisioning(provCtx, qr.Main.Store, qr.Main.Config.DeviceName, false) + qr.ProvChan = signalmeow.PerformProvisioning( + provCtx, qr.Main.Store, qr.Main.Config.DeviceName, qr.Main.Bridge.Config.Backfill.Enabled, + ) var resp signalmeow.ProvisioningResponse select { case resp = <-qr.ProvChan: @@ -165,6 +167,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err RemoteProfile: status.RemoteProfile{ Phone: qr.ProvData.Number, }, + Metadata: &signalid.UserLoginMetadata{}, }, &bridgev2.NewLoginParams{ DeleteOnConflict: true, }) @@ -172,10 +175,16 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err return nil, fmt.Errorf("failed to create user login: %w", err) } backgroundCtx := ul.Log.WithContext(context.Background()) - ul.Client.Connect(backgroundCtx) - if signalClient := ul.Client.(*SignalClient).Client; signalClient.Store.MasterKey != nil { - zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") - go signalClient.SyncStorage(backgroundCtx) + signalClient := ul.Client.(*SignalClient).Client + if signalClient.Store.EphemeralBackupKey != nil { + zerolog.Ctx(ctx).Info().Msg("Received ephemeral backup key in login, syncing chats before connecting") + go ul.Client.(*SignalClient).postLoginConnect(backgroundCtx) + } else { + ul.Client.Connect(backgroundCtx) + if signalClient.Store.MasterKey != nil { + zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") + go signalClient.SyncStorage(backgroundCtx) + } } return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 714b723..7ee29b7 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -20,6 +20,7 @@ import ( "bytes" "context" "encoding/base64" + "errors" "fmt" "net/http" "strings" @@ -41,6 +42,11 @@ import ( signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) +var ( + ErrAttachmentNotInBackup = errors.New("attachment not found in backup") + ErrBackupNotSupported = errors.New("downloading attachments from server-side backup is not yet supported") +) + func calculateLength(dm *signalpb.DataMessage) int { if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { return 1 @@ -384,6 +390,23 @@ func (mc *MessageConverter) convertContactToMatrix(ctx context.Context, contact func (mc *MessageConverter) convertAttachmentToMatrix(ctx context.Context, index int, att *signalpb.AttachmentPointer, attMap AttachmentMap) *bridgev2.ConvertedMessagePart { part, err := mc.reuploadAttachment(ctx, att, attMap) if err != nil { + if (errors.Is(err, signalmeow.ErrAttachmentNotFound) || errors.Is(err, ErrAttachmentNotInBackup)) && attMap != nil { + return &bridgev2.ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: fmt.Sprintf("Attachment no longer available %s", att.GetFileName()), + }, + } + } else if errors.Is(err, ErrBackupNotSupported) { + return &bridgev2.ConvertedMessagePart{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: "Downloading attachments from backup is not yet supported", + }, + } + } zerolog.Ctx(ctx).Err(err).Int("attachment_index", index).Msg("Failed to handle attachment") return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, @@ -434,7 +457,7 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*string, error) { data, err := mc.downloadAttachment(ctx, att, attMap) if err != nil { - return nil, fmt.Errorf("failed to download attachment: %w", err) + return nil, err } longBody := string(data) return &longBody, nil @@ -449,10 +472,10 @@ func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalp if !ok { return nil, fmt.Errorf("no attachment identifier and attachment not found in map") } else if target == nil { - return nil, fmt.Errorf("attachment not available in backup") + return nil, ErrAttachmentNotInBackup } else { // TODO add support for downloading attachments from backup - return nil, fmt.Errorf("downloading attachments from backup is not yet supported") + return nil, ErrBackupNotSupported } } return signalmeow.DownloadAttachment(ctx, att) @@ -461,7 +484,7 @@ func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalp func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*bridgev2.ConvertedMessagePart, error) { data, err := mc.downloadAttachment(ctx, att, attMap) if err != nil { - return nil, fmt.Errorf("failed to download attachment: %w", err) + return nil, err } mimeType := att.GetContentType() if mimeType == "" { diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index f3811af..76ee217 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -29,6 +29,10 @@ type MessageMetadata struct { ContainsAttachments bool `json:"contains_attachments,omitempty"` } +type UserLoginMetadata struct { + ChatsSynced bool `json:"chats_synced,omitempty"` +} + type GhostMetadata struct { ProfileFetchedAt jsontime.UnixMilli `json:"profile_fetched_at"` } diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 4d5d6d6..d733b40 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -57,6 +57,7 @@ func getAttachmentPath(id uint64, key string) string { // ErrInvalidMACForAttachment signals that the downloaded attachment has an invalid MAC. var ErrInvalidMACForAttachment = errors.New("invalid MAC for attachment") var ErrInvalidDigestForAttachment = errors.New("invalid digest for attachment") +var ErrAttachmentNotFound = errors.New("attachment not found on server") func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]byte, error) { path := getAttachmentPath(a.GetCdnId(), a.GetCdnKey()) @@ -77,6 +78,9 @@ func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]b } else if len(body) < 1024 { zerolog.Ctx(ctx).Debug().Bytes("response_data", body).Msg("Failed download response data") } + if resp.StatusCode == http.StatusNotFound { + return nil, ErrAttachmentNotFound + } return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } From ee976eaab3ccd6cc7fbcced88e44dc4ae0196fb4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 14:21:55 +0200 Subject: [PATCH 402/718] signalmeow: fix caching profile fetch errors --- pkg/signalmeow/profile.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 440fe1b..5182c23 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -131,16 +131,15 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) } err, ok := cli.ProfileCache.errors[signalID.String()] if ok { - return nil, *err + return nil, fmt.Errorf("%w: %w", ErrCachedError, *err) } } // If we get here, we don't have a cached profile, so fetch it profile, err := cli.fetchProfileByID(ctx, signalID) if err != nil { - // TODO this check is wrong and most likely doesn't work, errors shouldn't use string comparisons // If we get a 401 or 5xx error, we should not retry until the cache expires - if strings.HasPrefix(err.Error(), "401") || strings.HasPrefix(err.Error(), "5") { + if errors.Is(err, ErrProfileUnauthorized) || errors.Is(err, ErrProfileInternalError) { cli.ProfileCache.errors[signalID.String()] = &err cli.ProfileCache.lastFetched[signalID.String()] = time.Now() } @@ -169,6 +168,13 @@ func (cli *Client) fetchProfileByID(ctx context.Context, signalID uuid.UUID) (*t return cli.fetchProfileWithRequestAndKey(ctx, signalID, credentialRequest, profileKey) } +var ( + ErrCachedError = errors.New("cached error") + ErrProfileUnauthorized = errors.New("profile get returned 401") + ErrProfileNotFound = errors.New("profile get returned 404") + ErrProfileInternalError = errors.New("profile get returned") +) + func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID uuid.UUID, credentialRequest []byte, profileKey *libsignalgo.ProfileKey) (*types.Profile, error) { log := zerolog.Ctx(ctx) profileKeyVersion, err := profileKey.GetProfileKeyVersion(signalID) @@ -215,7 +221,14 @@ func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID u } logEvt.Msg("Got profile response") if *resp.Status < 200 || *resp.Status >= 300 { - return nil, fmt.Errorf("error getting profile (unsuccessful status code %d)", *resp.Status) + if *resp.Status == 401 { + return nil, ErrProfileUnauthorized + } else if *resp.Status == 404 { + return nil, ErrProfileNotFound + } else if *resp.Status >= 500 { + return nil, fmt.Errorf("%w %d", ErrProfileInternalError, *resp.Status) + } + return nil, fmt.Errorf("unexpected status code %d", *resp.Status) } var profileResponse ProfileResponse err = json.Unmarshal(resp.Body, &profileResponse) From 5b0df8b8930a1e3d344113ab50ece7063fa7953d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 14:32:44 +0200 Subject: [PATCH 403/718] signalmeow/store: fix constraint in db upgrade --- pkg/signalmeow/store/upgrades/00-latest.sql | 2 +- pkg/signalmeow/store/upgrades/19-store-backup-data.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index f4839d1..23c3762 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -159,4 +159,4 @@ CREATE TABLE signalmeow_backup_message ( CONSTRAINT signalmeow_backup_message_device_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); -CREATE INDEX signalmeow_backup_chat_recipient_id_idx ON signalmeow_backup_chat (account_id, chat_id); +CREATE INDEX signalmeow_backup_message_chat_id_idx ON signalmeow_backup_message (account_id, chat_id); diff --git a/pkg/signalmeow/store/upgrades/19-store-backup-data.sql b/pkg/signalmeow/store/upgrades/19-store-backup-data.sql index 9189337..6354ef8 100644 --- a/pkg/signalmeow/store/upgrades/19-store-backup-data.sql +++ b/pkg/signalmeow/store/upgrades/19-store-backup-data.sql @@ -49,4 +49,4 @@ CREATE TABLE signalmeow_backup_message ( CONSTRAINT signalmeow_backup_message_device_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); -CREATE INDEX signalmeow_backup_chat_recipient_id_idx ON signalmeow_backup_chat (account_id, chat_id); +CREATE INDEX signalmeow_backup_message_chat_id_idx ON signalmeow_backup_message (account_id, chat_id); From 430b7317dbadb529890a224edb4c00b6eb24306e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 19:12:20 +0200 Subject: [PATCH 404/718] signalmeow/backup: sleep between requests if server is acting weird --- pkg/signalmeow/backup.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index d69a729..64247db 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -270,10 +270,19 @@ func (cli *Client) WaitForTransfer(ctx context.Context) (*TransferArchiveMetadat if remainingTime < 0 { return nil, fmt.Errorf("timed out") } - resp, err := cli.tryRequestTransferArchive(ctx, min(remainingTime, 5*time.Minute)) + reqStart := time.Now() + reqTimeout := min(remainingTime, 5*time.Minute) + resp, err := cli.tryRequestTransferArchive(ctx, reqTimeout) if resp != nil || err != nil { return resp, err } + reqDuration := time.Since(reqStart) + if reqDuration < reqTimeout-10*time.Second { + // There seems to be a bug or feature when the transfer fails that causes the server to + // immediately return 204 until the user clicks "Continue" on their phone, so sleep for + // a bit to avoid sending requests too often. + time.Sleep(15 * time.Second) + } } } From bd09149e636c85df0d3642f554798633ed133953 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 19:13:18 +0200 Subject: [PATCH 405/718] changelog: update --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da0850e..e833eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v0.8.0 (unreleased) + +* Added support for history transfer. +* Updated libsignal to v0.65.2. + # v0.7.5 (2025-01-16) * Added support for bridging mp4 gifs in both directions. From 1e622b7bc6d6cb59d28ac89b3f8b0db254fcf685 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 19:16:21 +0200 Subject: [PATCH 406/718] login: remove duplicate sync chats call --- pkg/connector/client.go | 10 ---------- pkg/connector/login.go | 15 ++++++--------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index ece6753..44a1d2a 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -206,16 +206,6 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } } -func (s *SignalClient) postLoginConnect(ctx context.Context) { - // TODO it would be more proper to only connect after syncing, - // but currently syncing will fetch group info online, so it has to be connected. - s.Connect(ctx) - s.syncChats(ctx) - if s.Client.Store.MasterKey != nil { - s.Client.SyncStorage(ctx) - } -} - func (s *SignalClient) Connect(ctx context.Context) { if s.Client == nil { s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You're not logged into Signal"}) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 3b81b0a..e654971 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -176,15 +176,12 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err } backgroundCtx := ul.Log.WithContext(context.Background()) signalClient := ul.Client.(*SignalClient).Client - if signalClient.Store.EphemeralBackupKey != nil { - zerolog.Ctx(ctx).Info().Msg("Received ephemeral backup key in login, syncing chats before connecting") - go ul.Client.(*SignalClient).postLoginConnect(backgroundCtx) - } else { - ul.Client.Connect(backgroundCtx) - if signalClient.Store.MasterKey != nil { - zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") - go signalClient.SyncStorage(backgroundCtx) - } + // TODO it would be more proper to only connect after syncing, + // but currently syncing will fetch group info online, so it has to be connected. + ul.Client.Connect(backgroundCtx) + if signalClient.Store.MasterKey != nil { + zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") + go signalClient.SyncStorage(backgroundCtx) } return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, From dceab3c8b340ab78c5198dc917b9007ed3d4d9f2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 19:18:44 +0200 Subject: [PATCH 407/718] signalmeow/backup: remove incorrect comment The early returns are caused by duplicate calls to WaitForTransfer --- pkg/signalmeow/backup.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index 64247db..1d01b90 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -278,9 +278,6 @@ func (cli *Client) WaitForTransfer(ctx context.Context) (*TransferArchiveMetadat } reqDuration := time.Since(reqStart) if reqDuration < reqTimeout-10*time.Second { - // There seems to be a bug or feature when the transfer fails that causes the server to - // immediately return 204 until the user clicks "Continue" on their phone, so sleep for - // a bit to avoid sending requests too often. time.Sleep(15 * time.Second) } } From 3db54fd574d5291be6fbf8609ba9122c50126067 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 19 Jan 2025 20:47:07 +0200 Subject: [PATCH 408/718] client: unlink device when logging out --- pkg/connector/client.go | 4 ++++ pkg/signalmeow/provisioning.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 44a1d2a..7bf6884 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -90,6 +90,10 @@ func (s *SignalClient) LogoutRemote(ctx context.Context) { if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") } + err = s.Client.Unlink(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to unlink device") + } err = s.Main.Store.DeleteDevice(context.TODO(), &s.Client.Store.DeviceData) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to delete device from store") diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index d6774ae..f0e4ff8 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -385,6 +385,20 @@ func (cli *Client) RegisterCapabilities(ctx context.Context) error { return nil } +func (cli *Client) Unlink(ctx context.Context) error { + username, password := cli.Store.BasicAuthCreds() + resp, err := web.SendHTTPRequest(ctx, http.MethodDelete, fmt.Sprintf("/v1/devices/%d", cli.Store.DeviceID), &web.HTTPReqOpt{ + Username: &username, + Password: &password, + }) + if err != nil { + return err + } else if resp.StatusCode >= 400 { + return fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + return nil +} + func confirmDevice( ctx context.Context, username string, From 121945a445ec9f5b36eb53d9cb7c379d8cab78de Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 20 Jan 2025 19:55:51 +0200 Subject: [PATCH 409/718] signalmeow/storageservice: process updates in transaction --- pkg/signalmeow/groups.go | 2 +- pkg/signalmeow/storageservice.go | 30 ++++++++++++++++++------------ pkg/signalmeow/store/container.go | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 7037b9c..ae44e12 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -767,7 +767,7 @@ func (cli *Client) StoreMasterKey(ctx context.Context, groupMasterKey types.Seri } err = cli.Store.GroupStore.StoreMasterKey(ctx, groupIdentifier, groupMasterKey) if err != nil { - return "", fmt.Errorf("StoreMasterKey error: %w", err) + return groupIdentifier, fmt.Errorf("StoreMasterKey error: %w", err) } return groupIdentifier, nil } diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 28412b6..e8a5e5e 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -49,6 +49,16 @@ func (cli *Client) SyncStorage(ctx context.Context) { log.Err(err).Msg("Failed to fetch storage") return } + err = cli.Store.DoTxn(ctx, func(ctx context.Context) error { + return cli.processStorageInTxn(ctx, update) + }) + if err != nil { + log.Err(err).Msg("Failed to process storage update") + } +} + +func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdate) error { + log := zerolog.Ctx(ctx) for _, record := range update.NewRecords { switch data := record.StorageRecord.GetRecord().(type) { case *signalpb.StorageRecord_Contact: @@ -64,7 +74,7 @@ func (cli *Client) SyncStorage(ctx context.Context) { continue } contact := data.Contact - _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (changed bool, err error) { + _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (changed bool, err error) { if len(contact.ProfileKey) == libsignalgo.ProfileKeyLength { newProfileKey := libsignalgo.ProfileKey(contact.ProfileKey) changed = changed || recipient.Profile.Key != newProfileKey @@ -85,10 +95,7 @@ func (cli *Client) SyncStorage(ctx context.Context) { return }) if err != nil { - log.Err(err). - Stringer("aci", aci). - Stringer("pni", pni). - Msg("Failed to update contact") + return fmt.Errorf("failed to update contact %s/%s: %w", aci, pni, err) } case *signalpb.StorageRecord_GroupV2: if len(data.GroupV2.MasterKey) != libsignalgo.GroupMasterKeyLength { @@ -98,25 +105,24 @@ func (cli *Client) SyncStorage(ctx context.Context) { masterKey := libsignalgo.GroupMasterKey(data.GroupV2.MasterKey) groupID, err := cli.StoreMasterKey(ctx, masterKeyFromBytes(masterKey)) if err != nil { - log.Err(err).Msg("Failed to store group master key from storage service") - } else { - log.Debug().Stringer("group_id", groupID).Msg("Stored group master key from storage service") + return fmt.Errorf("failed to store group master key for %s: %w", groupID, err) } + log.Debug().Stringer("group_id", groupID).Msg("Stored group master key from storage service") case *signalpb.StorageRecord_Account: log.Trace().Any("account_record", data.Account).Msg("Found account record") cli.Store.AccountRecord = data.Account - err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + err := cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) if err != nil { - log.Err(err).Msg("Failed to save device after receiving account record") - } else { - log.Debug().Msg("Saved device after receiving account record") + return fmt.Errorf("failed to save device after receiving account record: %w", err) } + log.Debug().Msg("Saved device after receiving account record") case *signalpb.StorageRecord_GroupV1, *signalpb.StorageRecord_StoryDistributionList: // irrelevant data default: log.Warn().Type("type", data).Str("item_id", record.StorageID).Msg("Unknown storage record type") } } + return nil } type StorageUpdate struct { diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 0839689..42b8ea5 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -109,7 +109,7 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.DeviceStore = baseStore device.BackupStore = baseStore device.DoTxn = func(ctx context.Context, fn func(context.Context) error) error { - return c.db.DoTxn(ctx, nil, fn) + return c.db.DoTxn(context.WithValue(ctx, dbutil.ContextKeyDoTxnCallerSkip, 1), nil, fn) } return &device, nil From 0b4d63a62b4d08597753da9609ad82a88f3083fe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 20 Jan 2025 20:09:06 +0200 Subject: [PATCH 410/718] login: only sync storage after chats --- pkg/connector/client.go | 27 +++++++++++++++++++++++---- pkg/connector/login.go | 11 +---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 7bf6884..89901eb 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -216,7 +216,7 @@ func (s *SignalClient) Connect(ctx context.Context) { return } s.updateRemoteProfile(ctx, false) - s.tryConnect(ctx, 0) + s.tryConnect(ctx, 0, true) } func (s *SignalClient) ConnectBackground(ctx context.Context) error { @@ -266,7 +266,24 @@ func (s *SignalClient) Disconnect() { } } -func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { +func (s *SignalClient) postLoginConnect() { + ctx := s.UserLogin.Log.WithContext(context.Background()) + // TODO it would be more proper to only connect after syncing, + // but currently syncing will fetch group info online, so it has to be connected. + s.tryConnect(ctx, 0, false) + if s.Client.Store.EphemeralBackupKey != nil { + go func() { + s.syncChats(ctx) + if s.Client.Store.MasterKey != nil { + s.Client.SyncStorage(ctx) + } + }() + } else if s.Client.Store.MasterKey != nil { + go s.Client.SyncStorage(ctx) + } +} + +func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bool) { err := s.Client.RegisterCapabilities(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to register capabilities") @@ -281,13 +298,15 @@ func (s *SignalClient) tryConnect(ctx context.Context, retryCount int) { retryInSeconds := 2 << retryCount zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") time.Sleep(time.Duration(retryInSeconds) * time.Second) - s.tryConnect(ctx, retryCount+1) + s.tryConnect(ctx, retryCount+1, doSync) } else { s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) } } else { go s.bridgeStateLoop(ch) - go s.syncChats(ctx) + if doSync { + go s.syncChats(ctx) + } } } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index e654971..8d30da9 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/google/uuid" - "github.com/rs/zerolog" "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -174,15 +173,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err if err != nil { return nil, fmt.Errorf("failed to create user login: %w", err) } - backgroundCtx := ul.Log.WithContext(context.Background()) - signalClient := ul.Client.(*SignalClient).Client - // TODO it would be more proper to only connect after syncing, - // but currently syncing will fetch group info online, so it has to be connected. - ul.Client.Connect(backgroundCtx) - if signalClient.Store.MasterKey != nil { - zerolog.Ctx(ctx).Info().Msg("Received master key in login, syncing storage immediately") - go signalClient.SyncStorage(backgroundCtx) - } + ul.Client.(*SignalClient).postLoginConnect() return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, StepID: LoginStepComplete, From 15485eb0fd0e8bb43c54413406aebac6e7c27351 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 22 Jan 2025 19:05:17 +0200 Subject: [PATCH 411/718] signalmeow/attachments: fix splitting stream with chunks over 8192 bytes --- pkg/signalmeow/attachments_stream.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/attachments_stream.go b/pkg/signalmeow/attachments_stream.go index a410df0..1dcd9f9 100644 --- a/pkg/signalmeow/attachments_stream.go +++ b/pkg/signalmeow/attachments_stream.go @@ -151,7 +151,7 @@ func splitChunksStream(input io.Reader, callback func([]byte) error) error { continue } if msgLen > uint64(len(cachedBuf)) { - cachedBuf = make([]byte, min(msgLen, 8192)) + cachedBuf = make([]byte, max(msgLen, 8192)) } buf := cachedBuf[:msgLen] _, err = io.ReadFull(input, buf) From f5c818b3607cc995a17fe7ba6bf67e27b555eca0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 23 Jan 2025 15:08:09 +0200 Subject: [PATCH 412/718] client: update ConnectBackground function signature --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 040c374..93db751 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/net v0.34.0 google.golang.org/protobuf v1.36.3 - maunium.net/go/mautrix v0.23.0 + maunium.net/go/mautrix v0.23.1-0.20250123130650-2d79ce4eed56 ) require ( diff --git a/go.sum b/go.sum index 1ee4934..5eaa1a4 100644 --- a/go.sum +++ b/go.sum @@ -100,5 +100,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.23.0 h1:HNlR19eew5lvrNSL2muhExaGhYdaGk5FfEiA82QqUP4= -maunium.net/go/mautrix v0.23.0/go.mod h1:AGnnaz3ylGikUo1I1MJVn9QLsl2No1/ZNnGDyO0QD5s= +maunium.net/go/mautrix v0.23.1-0.20250123130650-2d79ce4eed56 h1:31T/WEOtfzmtF5CD7jeeSys35EZ9jhSkkZ6gB9eOVyU= +maunium.net/go/mautrix v0.23.1-0.20250123130650-2d79ce4eed56/go.mod h1:AGnnaz3ylGikUo1I1MJVn9QLsl2No1/ZNnGDyO0QD5s= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 89901eb..2007088 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -219,7 +219,7 @@ func (s *SignalClient) Connect(ctx context.Context) { s.tryConnect(ctx, 0, true) } -func (s *SignalClient) ConnectBackground(ctx context.Context) error { +func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.ConnectBackgroundParams) error { s.queueEmptyWaiter.Clear() ch, err := s.Client.StartAuthedWS(ctx) if err != nil { From e4bb6db825f78f05ccf6a532b759ba84fc5f16f9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Jan 2025 12:41:05 +0200 Subject: [PATCH 413/718] signalmeow: update protobufs --- pkg/msgconv/from-signal-backup.go | 4 +- pkg/signalmeow/backup.go | 6 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 138 +++++++++++------- .../protobuf/backuppb/Backup.pb.raw | Bin 31334 -> 31259 bytes pkg/signalmeow/protobuf/backuppb/Backup.proto | 88 ++++++----- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 6 files changed, 153 insertions(+), 87 deletions(-) diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index bf479ac..ccb4e50 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -236,8 +236,8 @@ func deleteNil(bodyRange *signalpb.BodyRange) bool { func backupToSignalBodyRange(from *backuppb.BodyRange) *signalpb.BodyRange { var out signalpb.BodyRange - out.Start = from.Start - out.Length = from.Length + out.Start = &from.Start + out.Length = &from.Length switch av := from.AssociatedValue.(type) { case *backuppb.BodyRange_MentionAci: // TODO confirm this is correct diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index 1d01b90..2302cd5 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -197,12 +197,16 @@ func (acp *archiveChunkProcessor) processFrame(frame *backuppb.Frame) error { acp.cli.Log.Trace().Any("backup_frame", frame).Msg("Processing backup frame") switch item := frame.Item.(type) { case *backuppb.Frame_Recipient: + if item.Recipient.Destination == nil { + zerolog.Ctx(acp.ctx).Debug().Msg("Ignoring recipient frame with no destination") + return nil + } return acp.cli.Store.BackupStore.AddBackupRecipient(acp.ctx, item.Recipient) case *backuppb.Frame_Chat: return acp.cli.Store.BackupStore.AddBackupChat(acp.ctx, item.Chat) case *backuppb.Frame_ChatItem: switch item.ChatItem.Item.(type) { - case *backuppb.ChatItem_DirectStoryReplyMessage, *backuppb.ChatItem_UpdateMessage: + case *backuppb.ChatItem_DirectStoryReplyMessage, *backuppb.ChatItem_UpdateMessage, nil: zerolog.Ctx(acp.ctx).Debug(). Uint64("chat_id", item.ChatItem.ChatId). Uint64("message_id", item.ChatItem.DateSent). diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 1df6d19..a9700d1 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -25,7 +25,7 @@ const ( type GroupV2AccessLevel int32 const ( - GroupV2AccessLevel_UNKNOWN GroupV2AccessLevel = 0 + GroupV2AccessLevel_UNKNOWN GroupV2AccessLevel = 0 // Interpret as "Unsatisfiable" GroupV2AccessLevel_ANY GroupV2AccessLevel = 1 GroupV2AccessLevel_MEMBER GroupV2AccessLevel = 2 GroupV2AccessLevel_ADMINISTRATOR GroupV2AccessLevel = 3 @@ -80,7 +80,7 @@ func (GroupV2AccessLevel) EnumDescriptor() ([]byte, []int) { type AccountData_PhoneNumberSharingMode int32 const ( - AccountData_UNKNOWN AccountData_PhoneNumberSharingMode = 0 + AccountData_UNKNOWN AccountData_PhoneNumberSharingMode = 0 // Interpret as "Nobody" AccountData_EVERYBODY AccountData_PhoneNumberSharingMode = 1 AccountData_NOBODY AccountData_PhoneNumberSharingMode = 2 ) @@ -129,7 +129,7 @@ func (AccountData_PhoneNumberSharingMode) EnumDescriptor() ([]byte, []int) { type AccountData_UsernameLink_Color int32 const ( - AccountData_UsernameLink_UNKNOWN AccountData_UsernameLink_Color = 0 + AccountData_UsernameLink_UNKNOWN AccountData_UsernameLink_Color = 0 // Interpret as "Blue" AccountData_UsernameLink_BLUE AccountData_UsernameLink_Color = 1 AccountData_UsernameLink_WHITE AccountData_UsernameLink_Color = 2 AccountData_UsernameLink_GREY AccountData_UsernameLink_Color = 3 @@ -196,9 +196,9 @@ func (AccountData_UsernameLink_Color) EnumDescriptor() ([]byte, []int) { type Contact_IdentityState int32 const ( - Contact_DEFAULT Contact_IdentityState = 0 + Contact_DEFAULT Contact_IdentityState = 0 // A valid value -- indicates unset by the user Contact_VERIFIED Contact_IdentityState = 1 - Contact_UNVERIFIED Contact_IdentityState = 2 + Contact_UNVERIFIED Contact_IdentityState = 2 // Was once verified and is now unverified ) // Enum value maps for Contact_IdentityState. @@ -245,7 +245,7 @@ func (Contact_IdentityState) EnumDescriptor() ([]byte, []int) { type Contact_Visibility int32 const ( - Contact_VISIBLE Contact_Visibility = 0 + Contact_VISIBLE Contact_Visibility = 0 // A valid value -- the contact is not hidden Contact_HIDDEN Contact_Visibility = 1 Contact_HIDDEN_MESSAGE_REQUEST Contact_Visibility = 2 ) @@ -294,7 +294,7 @@ func (Contact_Visibility) EnumDescriptor() ([]byte, []int) { type Group_StorySendMode int32 const ( - Group_DEFAULT Group_StorySendMode = 0 + Group_DEFAULT Group_StorySendMode = 0 // A valid value -- indicates unset by the user Group_DISABLED Group_StorySendMode = 1 Group_ENABLED Group_StorySendMode = 2 ) @@ -343,7 +343,7 @@ func (Group_StorySendMode) EnumDescriptor() ([]byte, []int) { type Group_Member_Role int32 const ( - Group_Member_UNKNOWN Group_Member_Role = 0 + Group_Member_UNKNOWN Group_Member_Role = 0 // Intepret as "Default" Group_Member_DEFAULT Group_Member_Role = 1 Group_Member_ADMINISTRATOR Group_Member_Role = 2 ) @@ -392,7 +392,7 @@ func (Group_Member_Role) EnumDescriptor() ([]byte, []int) { type Group_AccessControl_AccessRequired int32 const ( - Group_AccessControl_UNKNOWN Group_AccessControl_AccessRequired = 0 + Group_AccessControl_UNKNOWN Group_AccessControl_AccessRequired = 0 // Intepret as "Unsatisfiable" Group_AccessControl_ANY Group_AccessControl_AccessRequired = 1 Group_AccessControl_MEMBER Group_AccessControl_AccessRequired = 2 Group_AccessControl_ADMINISTRATOR Group_AccessControl_AccessRequired = 3 @@ -447,7 +447,7 @@ func (Group_AccessControl_AccessRequired) EnumDescriptor() ([]byte, []int) { type CallLink_Restrictions int32 const ( - CallLink_UNKNOWN CallLink_Restrictions = 0 + CallLink_UNKNOWN CallLink_Restrictions = 0 // Interpret as "Admin Approval" CallLink_NONE CallLink_Restrictions = 1 CallLink_ADMIN_APPROVAL CallLink_Restrictions = 2 ) @@ -496,7 +496,7 @@ func (CallLink_Restrictions) EnumDescriptor() ([]byte, []int) { type AdHocCall_State int32 const ( - AdHocCall_UNKNOWN_STATE AdHocCall_State = 0 + AdHocCall_UNKNOWN_STATE AdHocCall_State = 0 // Interpret as "Generic" AdHocCall_GENERIC AdHocCall_State = 1 ) @@ -542,7 +542,7 @@ func (AdHocCall_State) EnumDescriptor() ([]byte, []int) { type DistributionList_PrivacyMode int32 const ( - DistributionList_UNKNOWN DistributionList_PrivacyMode = 0 + DistributionList_UNKNOWN DistributionList_PrivacyMode = 0 // Interpret as "Only with" DistributionList_ONLY_WITH DistributionList_PrivacyMode = 1 DistributionList_ALL_EXCEPT DistributionList_PrivacyMode = 2 DistributionList_ALL DistributionList_PrivacyMode = 3 @@ -643,7 +643,7 @@ func (SendStatus_Failed_FailureReason) EnumDescriptor() ([]byte, []int) { type PaymentNotification_TransactionDetails_FailedTransaction_FailureReason int32 const ( - PaymentNotification_TransactionDetails_FailedTransaction_GENERIC PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 0 + PaymentNotification_TransactionDetails_FailedTransaction_GENERIC PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 0 // A valid value -- reason unknown PaymentNotification_TransactionDetails_FailedTransaction_NETWORK PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 1 PaymentNotification_TransactionDetails_FailedTransaction_INSUFFICIENT_FUNDS PaymentNotification_TransactionDetails_FailedTransaction_FailureReason = 2 ) @@ -692,7 +692,7 @@ func (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) En type PaymentNotification_TransactionDetails_Transaction_Status int32 const ( - PaymentNotification_TransactionDetails_Transaction_INITIAL PaymentNotification_TransactionDetails_Transaction_Status = 0 + PaymentNotification_TransactionDetails_Transaction_INITIAL PaymentNotification_TransactionDetails_Transaction_Status = 0 // A valid value -- state unconfirmed PaymentNotification_TransactionDetails_Transaction_SUBMITTED PaymentNotification_TransactionDetails_Transaction_Status = 1 PaymentNotification_TransactionDetails_Transaction_SUCCESSFUL PaymentNotification_TransactionDetails_Transaction_Status = 2 ) @@ -741,7 +741,7 @@ func (PaymentNotification_TransactionDetails_Transaction_Status) EnumDescriptor( type GiftBadge_State int32 const ( - GiftBadge_UNOPENED GiftBadge_State = 0 + GiftBadge_UNOPENED GiftBadge_State = 0 // A valid state GiftBadge_OPENED GiftBadge_State = 1 GiftBadge_REDEEMED GiftBadge_State = 2 GiftBadge_FAILED GiftBadge_State = 3 @@ -793,7 +793,7 @@ func (GiftBadge_State) EnumDescriptor() ([]byte, []int) { type ContactAttachment_Phone_Type int32 const ( - ContactAttachment_Phone_UNKNOWN ContactAttachment_Phone_Type = 0 + ContactAttachment_Phone_UNKNOWN ContactAttachment_Phone_Type = 0 // Interpret as "Home" ContactAttachment_Phone_HOME ContactAttachment_Phone_Type = 1 ContactAttachment_Phone_MOBILE ContactAttachment_Phone_Type = 2 ContactAttachment_Phone_WORK ContactAttachment_Phone_Type = 3 @@ -848,7 +848,7 @@ func (ContactAttachment_Phone_Type) EnumDescriptor() ([]byte, []int) { type ContactAttachment_Email_Type int32 const ( - ContactAttachment_Email_UNKNOWN ContactAttachment_Email_Type = 0 + ContactAttachment_Email_UNKNOWN ContactAttachment_Email_Type = 0 // Intepret as "Home" ContactAttachment_Email_HOME ContactAttachment_Email_Type = 1 ContactAttachment_Email_MOBILE ContactAttachment_Email_Type = 2 ContactAttachment_Email_WORK ContactAttachment_Email_Type = 3 @@ -903,7 +903,7 @@ func (ContactAttachment_Email_Type) EnumDescriptor() ([]byte, []int) { type ContactAttachment_PostalAddress_Type int32 const ( - ContactAttachment_PostalAddress_UNKNOWN ContactAttachment_PostalAddress_Type = 0 + ContactAttachment_PostalAddress_UNKNOWN ContactAttachment_PostalAddress_Type = 0 // Interpret as "Home" ContactAttachment_PostalAddress_HOME ContactAttachment_PostalAddress_Type = 1 ContactAttachment_PostalAddress_WORK ContactAttachment_PostalAddress_Type = 2 ContactAttachment_PostalAddress_CUSTOM ContactAttachment_PostalAddress_Type = 3 @@ -958,7 +958,7 @@ func (ContactAttachment_PostalAddress_Type) EnumDescriptor() ([]byte, []int) { type MessageAttachment_Flag int32 const ( - MessageAttachment_NONE MessageAttachment_Flag = 0 + MessageAttachment_NONE MessageAttachment_Flag = 0 // A valid value -- no flag applied MessageAttachment_VOICE_MESSAGE MessageAttachment_Flag = 1 MessageAttachment_BORDERLESS MessageAttachment_Flag = 2 MessageAttachment_GIF MessageAttachment_Flag = 3 @@ -1010,7 +1010,7 @@ func (MessageAttachment_Flag) EnumDescriptor() ([]byte, []int) { type Quote_Type int32 const ( - Quote_UNKNOWN Quote_Type = 0 + Quote_UNKNOWN Quote_Type = 0 // Interpret as "Normal" Quote_NORMAL Quote_Type = 1 Quote_GIFT_BADGE Quote_Type = 2 Quote_VIEW_ONCE Quote_Type = 3 @@ -1062,7 +1062,7 @@ func (Quote_Type) EnumDescriptor() ([]byte, []int) { type BodyRange_Style int32 const ( - BodyRange_NONE BodyRange_Style = 0 + BodyRange_NONE BodyRange_Style = 0 // Importers should ignore the body range without throwing an error. BodyRange_BOLD BodyRange_Style = 1 BodyRange_ITALIC BodyRange_Style = 2 BodyRange_SPOILER BodyRange_Style = 3 @@ -1120,7 +1120,7 @@ func (BodyRange_Style) EnumDescriptor() ([]byte, []int) { type IndividualCall_Type int32 const ( - IndividualCall_UNKNOWN_TYPE IndividualCall_Type = 0 + IndividualCall_UNKNOWN_TYPE IndividualCall_Type = 0 // Interpret as "Audio call" IndividualCall_AUDIO_CALL IndividualCall_Type = 1 IndividualCall_VIDEO_CALL IndividualCall_Type = 2 ) @@ -1169,7 +1169,7 @@ func (IndividualCall_Type) EnumDescriptor() ([]byte, []int) { type IndividualCall_Direction int32 const ( - IndividualCall_UNKNOWN_DIRECTION IndividualCall_Direction = 0 + IndividualCall_UNKNOWN_DIRECTION IndividualCall_Direction = 0 // Interpret as "Incoming" IndividualCall_INCOMING IndividualCall_Direction = 1 IndividualCall_OUTGOING IndividualCall_Direction = 2 ) @@ -1218,7 +1218,7 @@ func (IndividualCall_Direction) EnumDescriptor() ([]byte, []int) { type IndividualCall_State int32 const ( - IndividualCall_UNKNOWN_STATE IndividualCall_State = 0 + IndividualCall_UNKNOWN_STATE IndividualCall_State = 0 // Interpret as "Accepted" IndividualCall_ACCEPTED IndividualCall_State = 1 IndividualCall_NOT_ACCEPTED IndividualCall_State = 2 // An incoming call that is no longer ongoing, which we neither accepted @@ -1277,7 +1277,7 @@ func (IndividualCall_State) EnumDescriptor() ([]byte, []int) { type GroupCall_State int32 const ( - GroupCall_UNKNOWN_STATE GroupCall_State = 0 + GroupCall_UNKNOWN_STATE GroupCall_State = 0 // Interpret as "Generic" // A group call was started without ringing. GroupCall_GENERIC GroupCall_State = 1 // We joined a group call that was started without ringing. @@ -1353,7 +1353,7 @@ func (GroupCall_State) EnumDescriptor() ([]byte, []int) { type SimpleChatUpdate_Type int32 const ( - SimpleChatUpdate_UNKNOWN SimpleChatUpdate_Type = 0 + SimpleChatUpdate_UNKNOWN SimpleChatUpdate_Type = 0 // Importers should skip the update without throwing an error. SimpleChatUpdate_JOINED_SIGNAL SimpleChatUpdate_Type = 1 SimpleChatUpdate_IDENTITY_UPDATE SimpleChatUpdate_Type = 2 SimpleChatUpdate_IDENTITY_VERIFIED SimpleChatUpdate_Type = 3 @@ -1444,7 +1444,7 @@ func (SimpleChatUpdate_Type) EnumDescriptor() ([]byte, []int) { type ChatStyle_WallpaperPreset int32 const ( - ChatStyle_UNKNOWN_WALLPAPER_PRESET ChatStyle_WallpaperPreset = 0 + ChatStyle_UNKNOWN_WALLPAPER_PRESET ChatStyle_WallpaperPreset = 0 // Interpret as the wallpaper being unset ChatStyle_SOLID_BLUSH ChatStyle_WallpaperPreset = 1 ChatStyle_SOLID_COPPER ChatStyle_WallpaperPreset = 2 ChatStyle_SOLID_DUST ChatStyle_WallpaperPreset = 3 @@ -1550,7 +1550,7 @@ func (ChatStyle_WallpaperPreset) EnumDescriptor() ([]byte, []int) { type ChatStyle_BubbleColorPreset int32 const ( - ChatStyle_UNKNOWN_BUBBLE_COLOR_PRESET ChatStyle_BubbleColorPreset = 0 + ChatStyle_UNKNOWN_BUBBLE_COLOR_PRESET ChatStyle_BubbleColorPreset = 0 // Interpret as the user's default chat bubble color ChatStyle_SOLID_ULTRAMARINE ChatStyle_BubbleColorPreset = 1 ChatStyle_SOLID_CRIMSON ChatStyle_BubbleColorPreset = 2 ChatStyle_SOLID_VERMILION ChatStyle_BubbleColorPreset = 3 @@ -1659,7 +1659,7 @@ func (ChatStyle_BubbleColorPreset) EnumDescriptor() ([]byte, []int) { type NotificationProfile_DayOfWeek int32 const ( - NotificationProfile_UNKNOWN NotificationProfile_DayOfWeek = 0 + NotificationProfile_UNKNOWN NotificationProfile_DayOfWeek = 0 // Interpret as "Monday" NotificationProfile_MONDAY NotificationProfile_DayOfWeek = 1 NotificationProfile_TUESDAY NotificationProfile_DayOfWeek = 2 NotificationProfile_WEDNESDAY NotificationProfile_DayOfWeek = 3 @@ -1724,7 +1724,7 @@ func (NotificationProfile_DayOfWeek) EnumDescriptor() ([]byte, []int) { type ChatFolder_FolderType int32 const ( - ChatFolder_UNKNOWN ChatFolder_FolderType = 0 + ChatFolder_UNKNOWN ChatFolder_FolderType = 0 // Interpret as "Custom" ChatFolder_ALL ChatFolder_FolderType = 1 ChatFolder_CUSTOM ChatFolder_FolderType = 2 ) @@ -1864,6 +1864,8 @@ func (x *BackupInfo) GetFirstAppVersion() string { // or may each immediately precede its first ChatItem. type Frame struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should skip this frame without throwing an error. + // // Types that are valid to be assigned to Item: // // *Frame_Account @@ -2151,6 +2153,8 @@ func (x *AccountData) GetBackupsSubscriberData() *AccountData_IAPSubscriberData type Recipient struct { state protoimpl.MessageState `protogen:"open.v1"` Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // generated id for reference only within this file + // If unset, importers should skip this frame without throwing an error. + // // Types that are valid to be assigned to Destination: // // *Recipient_Contact @@ -2310,6 +2314,8 @@ type Contact struct { E164 *uint64 `protobuf:"varint,4,opt,name=e164,proto3,oneof" json:"e164,omitempty"` Blocked bool `protobuf:"varint,5,opt,name=blocked,proto3" json:"blocked,omitempty"` Visibility Contact_Visibility `protobuf:"varint,6,opt,name=visibility,proto3,enum=signal.backup.Contact_Visibility" json:"visibility,omitempty"` + // If unset, consider the user to be registered + // // Types that are valid to be assigned to Registration: // // *Contact_Registered_ @@ -2511,6 +2517,7 @@ type Group struct { HideStory bool `protobuf:"varint,3,opt,name=hideStory,proto3" json:"hideStory,omitempty"` StorySendMode Group_StorySendMode `protobuf:"varint,4,opt,name=storySendMode,proto3,enum=signal.backup.Group_StorySendMode" json:"storySendMode,omitempty"` Snapshot *Group_GroupSnapshot `protobuf:"bytes,5,opt,name=snapshot,proto3" json:"snapshot,omitempty"` + Blocked bool `protobuf:"varint,6,opt,name=blocked,proto3" json:"blocked,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2580,6 +2587,13 @@ func (x *Group) GetSnapshot() *Group_GroupSnapshot { return nil } +func (x *Group) GetBlocked() bool { + if x != nil { + return x.Blocked + } + return false +} + type Self struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -2925,6 +2939,8 @@ type DistributionListItem struct { // distribution ids are UUIDv4s. "My Story" is represented // by an all-0 UUID (00000000-0000-0000-0000-000000000000). DistributionId []byte `protobuf:"bytes,1,opt,name=distributionId,proto3" json:"distributionId,omitempty"` // distribution list ids are uuids + // If unset, importers should skip the item entirely without showing an error. + // // Types that are valid to be assigned to Item: // // *DistributionListItem_DeletionTimestamp @@ -3089,12 +3105,16 @@ type ChatItem struct { ExpiresInMs *uint64 `protobuf:"varint,5,opt,name=expiresInMs,proto3,oneof" json:"expiresInMs,omitempty"` // how long timer of message is (ms) Revisions []*ChatItem `protobuf:"bytes,6,rep,name=revisions,proto3" json:"revisions,omitempty"` // ordered from oldest to newest Sms bool `protobuf:"varint,7,opt,name=sms,proto3" json:"sms,omitempty"` + // If unset, importers should skip this item without throwing an error. + // // Types that are valid to be assigned to DirectionalDetails: // // *ChatItem_Incoming // *ChatItem_Outgoing // *ChatItem_Directionless DirectionalDetails isChatItem_DirectionalDetails `protobuf_oneof:"directionalDetails"` + // If unset, importers should skip this item without throwing an error. + // // Types that are valid to be assigned to Item: // // *ChatItem_StandardMessage @@ -3396,6 +3416,8 @@ type SendStatus struct { state protoimpl.MessageState `protogen:"open.v1"` RecipientId uint64 `protobuf:"varint,1,opt,name=recipientId,proto3" json:"recipientId,omitempty"` Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // the time the status was last updated -- if from a receipt, it should be the sentTime of the receipt + // If unset, importers should consider the status to be "pending" + // // Types that are valid to be assigned to DeliveryStatus: // // *SendStatus_Pending_ @@ -3760,15 +3782,16 @@ func (x *ContactMessage) GetReactions() []*Reaction { type DirectStoryReplyMessage struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should ignore the message without throwing an error. + // // Types that are valid to be assigned to Reply: // // *DirectStoryReplyMessage_TextReply_ // *DirectStoryReplyMessage_Emoji - Reply isDirectStoryReplyMessage_Reply `protobuf_oneof:"reply"` - Reactions []*Reaction `protobuf:"bytes,3,rep,name=reactions,proto3" json:"reactions,omitempty"` - StorySentTimestamp *uint64 `protobuf:"varint,4,opt,name=storySentTimestamp,proto3,oneof" json:"storySentTimestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Reply isDirectStoryReplyMessage_Reply `protobuf_oneof:"reply"` + Reactions []*Reaction `protobuf:"bytes,3,rep,name=reactions,proto3" json:"reactions,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DirectStoryReplyMessage) Reset() { @@ -3833,13 +3856,6 @@ func (x *DirectStoryReplyMessage) GetReactions() []*Reaction { return nil } -func (x *DirectStoryReplyMessage) GetStorySentTimestamp() uint64 { - if x != nil && x.StorySentTimestamp != nil { - return *x.StorySentTimestamp - } - return 0 -} - type isDirectStoryReplyMessage_Reply interface { isDirectStoryReplyMessage_Reply() } @@ -4432,6 +4448,8 @@ func (x *MessageAttachment) GetClientUuid() []byte { type FilePointer struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. + // // Types that are valid to be assigned to Locator: // // *FilePointer_BackupLocator_ @@ -4669,9 +4687,13 @@ func (x *Quote) GetType() Quote_Type { } type BodyRange struct { - state protoimpl.MessageState `protogen:"open.v1"` - Start *uint32 `protobuf:"varint,1,opt,name=start,proto3,oneof" json:"start,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length,proto3,oneof" json:"length,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + // 'start' and 'length' are measured in UTF-16 code units. + // They may refer to offsets in a longText attachment. + Start uint32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` + Length uint32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"` + // If unset, importers should ignore the body range without throwing an error. + // // Types that are valid to be assigned to AssociatedValue: // // *BodyRange_MentionAci @@ -4712,15 +4734,15 @@ func (*BodyRange) Descriptor() ([]byte, []int) { } func (x *BodyRange) GetStart() uint32 { - if x != nil && x.Start != nil { - return *x.Start + if x != nil { + return x.Start } return 0 } func (x *BodyRange) GetLength() uint32 { - if x != nil && x.Length != nil { - return *x.Length + if x != nil { + return x.Length } return 0 } @@ -4838,6 +4860,8 @@ func (x *Reaction) GetSortOrder() uint64 { type ChatUpdateMessage struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should ignore the update message without throwing an error. + // // Types that are valid to be assigned to Update: // // *ChatUpdateMessage_SimpleUpdate @@ -5350,6 +5374,8 @@ func (x *ProfileChangeChatUpdate) GetNewName() string { type LearnedProfileChatUpdate struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should consider the previous name to be an empty string. + // // Types that are valid to be assigned to PreviousName: // // *LearnedProfileChatUpdate_E164 @@ -7305,11 +7331,15 @@ func (x *StickerPack) GetPackKey() []byte { type ChatStyle struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should consider there to be no wallpaper. + // // Types that are valid to be assigned to Wallpaper: // // *ChatStyle_WallpaperPreset_ // *ChatStyle_WallpaperPhoto Wallpaper isChatStyle_Wallpaper `protobuf_oneof:"wallpaper"` + // If unset, importers should consider it to be AutomaticBubbleColor + // // Types that are valid to be assigned to BubbleColor: // // *ChatStyle_AutoBubbleColor @@ -7997,6 +8027,8 @@ func (x *AccountData_SubscriberData) GetManuallyCancelled() bool { type AccountData_IAPSubscriberData struct { state protoimpl.MessageState `protogen:"open.v1"` SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` + // If unset, importers should ignore the subscriber data without throwing an error. + // // Types that are valid to be assigned to IapSubscriptionId: // // *AccountData_IAPSubscriberData_PurchaseToken @@ -8359,6 +8391,8 @@ func (x *Group_GroupSnapshot) GetMembersBanned() []*Group_MemberBanned { type Group_GroupAttributeBlob struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, consider the field it represents to not be present + // // Types that are valid to be assigned to Content: // // *Group_GroupAttributeBlob_Title @@ -9250,6 +9284,8 @@ func (x *DirectStoryReplyMessage_TextReply) GetLongText() *FilePointer { type PaymentNotification_TransactionDetails struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should treat the transaction as successful with no metadata. + // // Types that are valid to be assigned to Payment: // // *PaymentNotification_TransactionDetails_Transaction_ @@ -10123,6 +10159,8 @@ func (x *Quote_QuotedAttachment) GetThumbnail() *MessageAttachment { type GroupChangeChatUpdate_Update struct { state protoimpl.MessageState `protogen:"open.v1"` + // If unset, importers should consider it to be a GenericGroupUpdate with unset updaterAci + // // Types that are valid to be assigned to Update: // // *GroupChangeChatUpdate_Update_GenericGroupUpdate @@ -10864,6 +10902,8 @@ func (x *ChatStyle_Gradient) GetPositions() []float32 { type ChatStyle_CustomChatColor struct { state protoimpl.MessageState `protogen:"open.v1"` Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // If unset, use the default chat color + // // Types that are valid to be assigned to Color: // // *ChatStyle_CustomChatColor_Solid diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.raw b/pkg/signalmeow/protobuf/backuppb/Backup.pb.raw index fa51eb6b784f0b88b8fbe3fc0af1a0b5b0eb0b1b..7a030359a9583e852063511073a9fec4c60b91d5 100644 GIT binary patch delta 146 zcmaF%g>m*5#tnf&jC&>r34M?flHg)b%E?d8PECOKo!zEF##}U{6be*%yljk7pGHxN@Y-DUV5sKBo`~t z*rE~%Mxe30Kw}|Xph-f~Tx>b1dFdq?5=>w@rXVOEWR084QBfxjE;gVwK;2H9T K#hbZZ1xx|mnM4o( diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 48a6f24..42f3e8d 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -30,6 +30,7 @@ message BackupInfo { // For example, Chats may all be together at the beginning, // or may each immediately precede its first ChatItem. message Frame { + // If unset, importers should skip this frame without throwing an error. oneof item { AccountData account = 1; Recipient recipient = 2; @@ -44,13 +45,13 @@ message Frame { message AccountData { enum PhoneNumberSharingMode { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Nobody" EVERYBODY = 1; NOBODY = 2; } message UsernameLink { enum Color { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Blue" BLUE = 1; WHITE = 2; GREY = 3; @@ -97,6 +98,7 @@ message AccountData { message IAPSubscriberData { bytes subscriberId = 1; + // If unset, importers should ignore the subscriber data without throwing an error. oneof iapSubscriptionId { // Identifies an Android Play Store IAP subscription. string purchaseToken = 2; @@ -119,6 +121,7 @@ message AccountData { message Recipient { uint64 id = 1; // generated id for reference only within this file + // If unset, importers should skip this frame without throwing an error. oneof destination { Contact contact = 2; Group group = 3; @@ -131,9 +134,9 @@ message Recipient { message Contact { enum IdentityState { - DEFAULT = 0; + DEFAULT = 0; // A valid value -- indicates unset by the user VERIFIED = 1; - UNVERIFIED = 2; + UNVERIFIED = 2; // Was once verified and is now unverified } message Registered {} @@ -142,7 +145,7 @@ message Contact { } enum Visibility { - VISIBLE = 0; + VISIBLE = 0; // A valid value -- the contact is not hidden HIDDEN = 1; HIDDEN_MESSAGE_REQUEST = 2; } @@ -159,6 +162,7 @@ message Contact { bool blocked = 5; Visibility visibility = 6; + // If unset, consider the user to be registered oneof registration { Registered registered = 7; NotRegistered notRegistered = 8; @@ -177,7 +181,7 @@ message Contact { message Group { enum StorySendMode { - DEFAULT = 0; + DEFAULT = 0; // A valid value -- indicates unset by the user DISABLED = 1; ENABLED = 2; } @@ -187,6 +191,7 @@ message Group { bool hideStory = 3; StorySendMode storySendMode = 4; GroupSnapshot snapshot = 5; + bool blocked = 6; // These are simply plaintext copies of the groups proto from Groups.proto. // They should be kept completely in-sync with Groups.proto. @@ -210,6 +215,7 @@ message Group { } message GroupAttributeBlob { + // If unset, consider the field it represents to not be present oneof content { string title = 1; bytes avatar = 2; @@ -220,7 +226,7 @@ message Group { message Member { enum Role { - UNKNOWN = 0; + UNKNOWN = 0; // Intepret as "Default" DEFAULT = 1; ADMINISTRATOR = 2; } @@ -252,7 +258,7 @@ message Group { message AccessControl { enum AccessRequired { - UNKNOWN = 0; + UNKNOWN = 0; // Intepret as "Unsatisfiable" ANY = 1; MEMBER = 2; ADMINISTRATOR = 3; @@ -292,7 +298,7 @@ message Chat { */ message CallLink { enum Restrictions { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Admin Approval" NONE = 1; ADMIN_APPROVAL = 2; } @@ -306,7 +312,7 @@ message CallLink { message AdHocCall { enum State { - UNKNOWN_STATE = 0; + UNKNOWN_STATE = 0; // Interpret as "Generic" GENERIC = 1; } @@ -322,6 +328,7 @@ message DistributionListItem { // by an all-0 UUID (00000000-0000-0000-0000-000000000000). bytes distributionId = 1; // distribution list ids are uuids + // If unset, importers should skip the item entirely without showing an error. oneof item { uint64 deletionTimestamp = 2; DistributionList distributionList = 3; @@ -330,7 +337,7 @@ message DistributionListItem { message DistributionList { enum PrivacyMode { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Only with" ONLY_WITH = 1; ALL_EXCEPT = 2; ALL = 3; @@ -365,12 +372,14 @@ message ChatItem { repeated ChatItem revisions = 6; // ordered from oldest to newest bool sms = 7; + // If unset, importers should skip this item without throwing an error. oneof directionalDetails { IncomingMessageDetails incoming = 8; OutgoingMessageDetails outgoing = 9; DirectionlessMessageDetails directionless = 10; } + // If unset, importers should skip this item without throwing an error. oneof item { StandardMessage standardMessage = 11; ContactMessage contactMessage = 12; @@ -419,6 +428,7 @@ message SendStatus { uint64 recipientId = 1; uint64 timestamp = 2; // the time the status was last updated -- if from a receipt, it should be the sentTime of the receipt + // If unset, importers should consider the status to be "pending" oneof deliveryStatus { Pending pending = 3; Sent sent = 4; @@ -455,13 +465,14 @@ message DirectStoryReplyMessage { FilePointer longText = 2; } + // If unset, importers should ignore the message without throwing an error. oneof reply { TextReply textReply = 1; string emoji = 2; } repeated Reaction reactions = 3; - optional uint64 storySentTimestamp = 4; + reserved /*storySentTimestamp*/ 4; } message PaymentNotification { @@ -473,7 +484,7 @@ message PaymentNotification { message FailedTransaction { // Failed payments can't be synced from the ledger enum FailureReason { - GENERIC = 0; + GENERIC = 0; // A valid value -- reason unknown NETWORK = 1; INSUFFICIENT_FUNDS = 2; } @@ -482,7 +493,7 @@ message PaymentNotification { message Transaction { enum Status { - INITIAL = 0; + INITIAL = 0; // A valid value -- state unconfirmed SUBMITTED = 1; SUCCESSFUL = 2; } @@ -499,6 +510,7 @@ message PaymentNotification { optional bytes receipt = 7; // mobile coin blobs } + // If unset, importers should treat the transaction as successful with no metadata. oneof payment { Transaction transaction = 1; FailedTransaction failedTransaction = 2; @@ -513,7 +525,7 @@ message PaymentNotification { message GiftBadge { enum State { - UNOPENED = 0; + UNOPENED = 0; // A valid state OPENED = 1; REDEEMED = 2; FAILED = 3; @@ -541,7 +553,7 @@ message ContactAttachment { message Phone { enum Type { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Home" HOME = 1; MOBILE = 2; WORK = 3; @@ -555,7 +567,7 @@ message ContactAttachment { message Email { enum Type { - UNKNOWN = 0; + UNKNOWN = 0; // Intepret as "Home" HOME = 1; MOBILE = 2; WORK = 3; @@ -569,7 +581,7 @@ message ContactAttachment { message PostalAddress { enum Type { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Home" HOME = 1; WORK = 2; CUSTOM = 3; @@ -629,7 +641,7 @@ message MessageAttachment { // but explicitly mutually exclusive. Note the different raw values // (non-zero starting values are not supported in proto3.) enum Flag { - NONE = 0; + NONE = 0; // A valid value -- no flag applied VOICE_MESSAGE = 1; BORDERLESS = 2; GIF = 3; @@ -680,6 +692,7 @@ message FilePointer { message InvalidAttachmentLocator { } + // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. oneof locator { BackupLocator backupLocator = 1; AttachmentLocator attachmentLocator = 2; @@ -698,7 +711,7 @@ message FilePointer { message Quote { enum Type { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Normal" NORMAL = 1; GIFT_BADGE = 2; VIEW_ONCE = 3; @@ -719,7 +732,7 @@ message Quote { message BodyRange { enum Style { - NONE = 0; + NONE = 0; // Importers should ignore the body range without throwing an error. BOLD = 1; ITALIC = 2; SPOILER = 3; @@ -727,9 +740,12 @@ message BodyRange { MONOSPACE = 5; } - optional uint32 start = 1; - optional uint32 length = 2; + // 'start' and 'length' are measured in UTF-16 code units. + // They may refer to offsets in a longText attachment. + uint32 start = 1; + uint32 length = 2; + // If unset, importers should ignore the body range without throwing an error. oneof associatedValue { bytes mentionAci = 3; Style style = 4; @@ -746,6 +762,7 @@ message Reaction { } message ChatUpdateMessage { + // If unset, importers should ignore the update message without throwing an error. oneof update { SimpleChatUpdate simpleUpdate = 1; GroupChangeChatUpdate groupChange = 2; @@ -761,19 +778,19 @@ message ChatUpdateMessage { message IndividualCall { enum Type { - UNKNOWN_TYPE = 0; + UNKNOWN_TYPE = 0; // Interpret as "Audio call" AUDIO_CALL = 1; VIDEO_CALL = 2; } enum Direction { - UNKNOWN_DIRECTION = 0; + UNKNOWN_DIRECTION = 0; // Interpret as "Incoming" INCOMING = 1; OUTGOING = 2; } enum State { - UNKNOWN_STATE = 0; + UNKNOWN_STATE = 0; // Interpret as "Accepted" ACCEPTED = 1; NOT_ACCEPTED = 2; // An incoming call that is no longer ongoing, which we neither accepted @@ -794,7 +811,7 @@ message IndividualCall { message GroupCall { enum State { - UNKNOWN_STATE = 0; + UNKNOWN_STATE = 0; // Interpret as "Generic" // A group call was started without ringing. GENERIC = 1; // We joined a group call that was started without ringing. @@ -825,7 +842,7 @@ message GroupCall { message SimpleChatUpdate { enum Type { - UNKNOWN = 0; + UNKNOWN = 0; // Importers should skip the update without throwing an error. JOINED_SIGNAL = 1; IDENTITY_UPDATE = 2; IDENTITY_VERIFIED = 3; @@ -859,6 +876,7 @@ message ProfileChangeChatUpdate { } message LearnedProfileChatUpdate { + // If unset, importers should consider the previous name to be an empty string. oneof previousName { uint64 e164 = 1; string username = 2; @@ -875,6 +893,7 @@ message SessionSwitchoverChatUpdate { message GroupChangeChatUpdate { message Update { + // If unset, importers should consider it to be a GenericGroupUpdate with unset updaterAci oneof update { GenericGroupUpdate genericGroupUpdate = 1; GroupCreationUpdate groupCreationUpdate = 2; @@ -944,7 +963,7 @@ message GroupDescriptionUpdate { } enum GroupV2AccessLevel { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Unsatisfiable" ANY = 1; MEMBER = 2; ADMINISTRATOR = 3; @@ -1134,6 +1153,7 @@ message ChatStyle { message CustomChatColor { uint64 id = 1; + // If unset, use the default chat color oneof color { fixed32 solid = 2; // 0xAARRGGBB Gradient gradient = 3; @@ -1144,7 +1164,7 @@ message ChatStyle { } enum WallpaperPreset { - UNKNOWN_WALLPAPER_PRESET = 0; + UNKNOWN_WALLPAPER_PRESET = 0; // Interpret as the wallpaper being unset SOLID_BLUSH = 1; SOLID_COPPER = 2; SOLID_DUST = 3; @@ -1169,7 +1189,7 @@ message ChatStyle { } enum BubbleColorPreset { - UNKNOWN_BUBBLE_COLOR_PRESET = 0; + UNKNOWN_BUBBLE_COLOR_PRESET = 0; // Interpret as the user's default chat bubble color SOLID_ULTRAMARINE = 1; SOLID_CRIMSON = 2; SOLID_VERMILION = 3; @@ -1194,6 +1214,7 @@ message ChatStyle { GRADIENT_TANGERINE = 22; } + // If unset, importers should consider there to be no wallpaper. oneof wallpaper { WallpaperPreset wallpaperPreset = 1; // This `FilePointer` is expected not to contain a `fileName`, `width`, @@ -1201,6 +1222,7 @@ message ChatStyle { FilePointer wallpaperPhoto = 2; } + // If unset, importers should consider it to be AutomaticBubbleColor oneof bubbleColor { // Bubble setting is automatically determined based on the wallpaper setting, // or `SOLID_ULTRAMARINE` for `noWallpaper` @@ -1216,7 +1238,7 @@ message ChatStyle { message NotificationProfile { enum DayOfWeek { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Monday" MONDAY = 1; TUESDAY = 2; WEDNESDAY = 3; @@ -1242,7 +1264,7 @@ message NotificationProfile { message ChatFolder { // Represents the default "All chats" folder record vs all other custom folders enum FolderType { - UNKNOWN = 0; + UNKNOWN = 0; // Interpret as "Custom" ALL = 1; CUSTOM = 2; } diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index cf47a8c..1699017 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-50db945ef1673da9990affeff022da64e4caa264} -DESKTOP_GIT_REVISION=${1:-ca1d17354db10a14f9f5558dcb546af9f3bba578} +ANDROID_GIT_REVISION=${1:-aa9c87ee67364a28977a2a5ba3bb7f5e715e19a0} +DESKTOP_GIT_REVISION=${1:-3f0536f5a58b6a20949690afd76093f41931843c} update_proto() { case "$1" in From 872c2843f39510bd3ef8791f0367e4597e68513e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Jan 2025 12:47:23 +0200 Subject: [PATCH 414/718] libsignal: update to v0.65.4 --- CHANGELOG.md | 2 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/version.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e833eaa..435e8be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # v0.8.0 (unreleased) * Added support for history transfer. -* Updated libsignal to v0.65.2. +* Updated libsignal to v0.65.4. # v0.7.5 (2025-01-16) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 864a1a1..4da852b 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 864a1a1a87d08b30516fdf5734ae426b0508f445 +Subproject commit 4da852be7529372a53123a0a097ed6f252961fce diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 528ebe6..8a399dd 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.65.2" +const Version = "v0.65.4" From 0ca656a5e164ecab5969b538c3b0e85695083621 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Jan 2025 14:57:16 +0200 Subject: [PATCH 415/718] signalmeow: update backup capability id --- pkg/signalmeow/provisioning.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index f0e4ff8..94a4176 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -299,7 +299,7 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) } - linkCapabilities := []string{"backup"} + linkCapabilities := []string{"backup3"} if !allowBackup { linkCapabilities = []string{} } From f07723070d8ae4d07347cc4b989f78f9def082a6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Jan 2025 18:11:06 +0200 Subject: [PATCH 416/718] signalmeow/store: add logs for recipient updates --- pkg/signalmeow/store/recipient_store.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index bdcd0c0..84f9af9 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -25,6 +25,7 @@ import ( "time" "github.com/google/uuid" + "github.com/rs/zerolog" "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -166,6 +167,10 @@ func (s *sqlStore) mergeRecipients(ctx context.Context, first, second *types.Rec first, second = second, first } first.PNI = second.PNI + zerolog.Ctx(ctx).Debug(). + Stringer("aci", first.ACI). + Stringer("pni", first.PNI). + Msg("Merging recipient entries in database") if second.E164 != "" { first.E164 = second.E164 } @@ -247,6 +252,10 @@ func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUI // SQL only supports one ON CONFLICT clause, which means StoreRecipient will key on the ACI if it's present. // If we're adding an ACI to a PNI row, just delete the PNI row first to avoid conflicts on the PNI key. if outRecipient.PNI != uuid.Nil && outRecipient.ACI == uuid.Nil && aci != uuid.Nil { + zerolog.Ctx(ctx).Debug(). + Stringer("aci", outRecipient.ACI). + Stringer("pni", outRecipient.PNI). + Msg("Deleting old PNI-only row before inserting row with both IDs") err = s.DeleteRecipientByPNI(ctx, outRecipient.PNI) if err != nil { return fmt.Errorf("failed to delete old PNI row: %w", err) @@ -261,6 +270,10 @@ func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUI changed = true } if changed || len(entries) == 0 { + zerolog.Ctx(ctx).Trace(). + Stringer("aci", outRecipient.ACI). + Stringer("pni", outRecipient.PNI). + Msg("Saving recipient row") err = s.StoreRecipient(ctx, outRecipient) if err != nil { return fmt.Errorf("failed to store updated recipient row: %w", err) From 3781461b28effca4dcecb667c61925f06e8d4469 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 4 Feb 2025 11:48:31 +0200 Subject: [PATCH 417/718] signalmeow/store: fix locking recipient store --- pkg/signalmeow/backup.go | 2 +- pkg/signalmeow/receiving.go | 38 ++++++++++++++----------- pkg/signalmeow/storageservice.go | 2 +- pkg/signalmeow/store/container.go | 6 ++-- pkg/signalmeow/store/device.go | 18 +++++++++++- pkg/signalmeow/store/recipient_store.go | 6 ++-- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index 2302cd5..43c2f78 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -93,7 +93,7 @@ func (cli *Client) FetchAndProcessTransfer(ctx context.Context, meta *TransferAr if err != nil { return fmt.Errorf("failed to seek to start of file: %w", err) } - err = cli.Store.DoTxn(ctx, func(ctx context.Context) error { + err = cli.Store.DoContactTxn(ctx, func(ctx context.Context) error { err = cli.Store.BackupStore.ClearBackup(ctx) if err != nil { return fmt.Errorf("failed to clear backup: %w", err) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 4d913e2..a2aa551 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -805,24 +805,30 @@ func (cli *Client) handleDecryptedResult( } log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") convertedContacts := make([]*types.Recipient, 0, len(contacts)) - for i, signalContact := range contacts { - if signalContact.Aci == nil || *signalContact.Aci == "" { - // TODO lookup PNI via CDSI and store that when ACI is missing? - log.Info(). - Any("contact", signalContact). - Msg("Signal Contact UUID is nil, skipping") - continue + err = cli.Store.DoContactTxn(ctx, func(ctx context.Context) error { + for i, signalContact := range contacts { + if signalContact.Aci == nil || *signalContact.Aci == "" { + // TODO lookup PNI via CDSI and store that when ACI is missing? + log.Info(). + Any("contact", signalContact). + Msg("Signal Contact UUID is nil, skipping") + continue + } + contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) + if err != nil { + return err + } + convertedContacts = append(convertedContacts, contact) } - contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) - if err != nil { - log.Err(err).Msg("StoreContactDetailsAsContact error") - continue - } - convertedContacts = append(convertedContacts, contact) - } - cli.handleEvent(&events.ContactList{ - Contacts: convertedContacts, + return nil }) + if err != nil { + log.Err(err).Msg("Error storing contacts") + } else { + cli.handleEvent(&events.ContactList{ + Contacts: convertedContacts, + }) + } } } if content.SyncMessage.Read != nil { diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index e8a5e5e..26d52ff 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -49,7 +49,7 @@ func (cli *Client) SyncStorage(ctx context.Context) { log.Err(err).Msg("Failed to fetch storage") return } - err = cli.Store.DoTxn(ctx, func(ctx context.Context) error { + err = cli.Store.DoContactTxn(ctx, func(ctx context.Context) error { return cli.processStorageInTxn(ctx, update) }) if err != nil { diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 42b8ea5..18f9b99 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -108,10 +108,8 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.RecipientStore = baseStore device.DeviceStore = baseStore device.BackupStore = baseStore - device.DoTxn = func(ctx context.Context, fn func(context.Context) error) error { - return c.db.DoTxn(context.WithValue(ctx, dbutil.ContextKeyDoTxnCallerSkip, 1), nil, fn) - } - + device.sqlStore = baseStore + device.db = c.db return &device, nil } diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index bcd4a88..fc7fac6 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -79,7 +80,22 @@ type Device struct { DeviceStore DeviceStore BackupStore BackupStore - DoTxn func(context.Context, func(context.Context) error) error + sqlStore *sqlStore + db *dbutil.Database +} + +type contextKey int64 + +const ( + contextKeyContactLock contextKey = 1 +) + +func (d *Device) DoContactTxn(ctx context.Context, fn func(context.Context) error) error { + d.sqlStore.contactLock.Lock() + defer d.sqlStore.contactLock.Unlock() + ctx = context.WithValue(ctx, dbutil.ContextKeyDoTxnCallerSkip, 1) + ctx = context.WithValue(ctx, contextKeyContactLock, true) + return d.db.DoTxn(ctx, nil, fn) } func (d *Device) ClearDeviceKeys(ctx context.Context) error { diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 84f9af9..03608a2 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -204,8 +204,10 @@ func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUI return false, nil } } - s.contactLock.Lock() - defer s.contactLock.Unlock() + if ctx.Value(contextKeyContactLock) == nil { + s.contactLock.Lock() + defer s.contactLock.Unlock() + } outErr = s.db.DoTxn(ctx, nil, func(ctx context.Context) error { var entries []*types.Recipient var err error From 985898a7084e49d70bc5dfe49af319e6fc82e3b3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 4 Feb 2025 11:52:37 +0200 Subject: [PATCH 418/718] build: fix passing arguments to build.sh Fixes #583 --- build-go.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-go.sh b/build-go.sh index faaac6f..eeab2d7 100755 --- a/build-go.sh +++ b/build-go.sh @@ -6,4 +6,4 @@ if [ "$DBG" = 1 ]; then else GO_LDFLAGS="-s -w ${GO_LDFLAGS}" fi -go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal ./cmd/mautrix-signal "$@" +go build -gcflags="$GO_GCFLAGS" -ldflags="$GO_LDFLAGS" -o mautrix-signal "$@" ./cmd/mautrix-signal From 5c7cd643faee575612210cca817c0c2ba0f83c59 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 4 Feb 2025 12:51:01 +0200 Subject: [PATCH 419/718] dependencies: update mautrix-go --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 93db751..238c27e 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.4 + go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003 golang.org/x/crypto v0.32.0 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 + golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c golang.org/x/net v0.34.0 google.golang.org/protobuf v1.36.3 - maunium.net/go/mautrix v0.23.1-0.20250123130650-2d79ce4eed56 + maunium.net/go/mautrix v0.23.1-0.20250203222456-475c4bf39d91 ) require ( diff --git a/go.sum b/go.sum index 5eaa1a4..5aaee56 100644 --- a/go.sum +++ b/go.sum @@ -70,14 +70,14 @@ 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.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.4 h1:mVKlJcXWfVo8ZW3f4vqtjGpqtZqJvX4ETekxawt2vnQ= -go.mau.fi/util v0.8.4/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= +go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003 h1:ye5l+QpYW5CpGVMedb3EHlmflGMQsMtw8mC4K/U8hIw= +go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc= +golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= @@ -100,5 +100,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.23.1-0.20250123130650-2d79ce4eed56 h1:31T/WEOtfzmtF5CD7jeeSys35EZ9jhSkkZ6gB9eOVyU= -maunium.net/go/mautrix v0.23.1-0.20250123130650-2d79ce4eed56/go.mod h1:AGnnaz3ylGikUo1I1MJVn9QLsl2No1/ZNnGDyO0QD5s= +maunium.net/go/mautrix v0.23.1-0.20250203222456-475c4bf39d91 h1:jbga2dSYVTd3MgAKugiz5+mIYp+qxUOCDokUGZOEWRg= +maunium.net/go/mautrix v0.23.1-0.20250203222456-475c4bf39d91/go.mod h1:q2U2IRLSFpglDhIpSjd8TnCNVzBNrUJBD8pmYCGQiwc= From 3d5f873cfca36c5af0e271e70a3e4f24fa502ad3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Feb 2025 18:43:57 +0200 Subject: [PATCH 420/718] connector: connect unauthed websocket in background mode --- pkg/connector/client.go | 2 +- pkg/signalmeow/receiving.go | 45 ++++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 2007088..4aebc69 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -221,7 +221,7 @@ func (s *SignalClient) Connect(ctx context.Context) { func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.ConnectBackgroundParams) error { s.queueEmptyWaiter.Clear() - ch, err := s.Client.StartAuthedWS(ctx) + ch, _, err := s.Client.StartWebsockets(ctx) if err != nil { return err } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index a2aa551..2eb622f 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -68,34 +68,43 @@ type SignalConnectionStatus struct { Err error } -func (cli *Client) StartAuthedWS(ctx context.Context) (chan web.SignalWebsocketConnectionStatus, error) { - ctx, cancel := context.WithCancel(ctx) - cli.WSCancel = cancel - authChan, err := cli.connectAuthedWS(ctx, cli.incomingRequestHandler) +func (cli *Client) StartWebsockets(ctx context.Context) (authChan, unauthChan chan web.SignalWebsocketConnectionStatus, err error) { + authChan, unauthChan, _, _, err = cli.startWebsocketsInternal(ctx) + return +} + +func (cli *Client) startWebsocketsInternal( + ctx context.Context, +) ( + authChan, unauthChan chan web.SignalWebsocketConnectionStatus, + cancelCtx context.Context, + cancelFunc context.CancelFunc, + err error, +) { + cancelCtx, cancelFunc = context.WithCancel(ctx) + cli.WSCancel = cancelFunc + unauthChan, err = cli.connectUnauthedWS(cancelCtx) if err != nil { - cancel() - return nil, err + cancelFunc() + return + } + zerolog.Ctx(ctx).Info().Msg("Unauthed websocket connecting") + authChan, err = cli.connectAuthedWS(cancelCtx, cli.incomingRequestHandler) + if err != nil { + cancelFunc() + return } zerolog.Ctx(ctx).Info().Msg("Authed websocket connecting") - return authChan, nil + return } func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnectionStatus, error) { log := zerolog.Ctx(ctx).With().Str("action", "start receive loops").Logger() - ctx, cancel := context.WithCancel(log.WithContext(ctx)) - cli.WSCancel = cancel - authChan, err := cli.connectAuthedWS(ctx, cli.incomingRequestHandler) + ctx = log.WithContext(ctx) + authChan, unauthChan, ctx, cancel, err := cli.startWebsocketsInternal(log.WithContext(ctx)) if err != nil { - cancel() return nil, err } - log.Info().Msg("Authed websocket connecting") - unauthChan, err := cli.connectUnauthedWS(ctx) - if err != nil { - cancel() - return nil, err - } - log.Info().Msg("Unauthed websocket connecting") statusChan := make(chan SignalConnectionStatus, 10000) initialConnectChan := make(chan struct{}) From 6abb21cfac777426e9d114fdffbdac0d8c1f0245 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Feb 2025 18:44:14 +0200 Subject: [PATCH 421/718] userinfo: don't fetch info in background mode unless necessary --- pkg/connector/chatinfo.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index c73b5d5..5b142cf 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -46,6 +46,10 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( if err != nil { return nil, err } + if ghost.Name != "" && s.Main.Bridge.Background { + // Don't do unnecessary fetches in background mode + return nil, nil + } contact, err := s.Client.ContactByACI(ctx, userID) if err != nil { return nil, err From 36f25e257d38d22560bdabad291cbef731cf0a13 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Feb 2025 13:50:14 +0200 Subject: [PATCH 422/718] libsignal: update to v0.66.1 --- CHANGELOG.md | 2 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 115 ++++++-------------------------- pkg/libsignalgo/version.go | 2 +- 4 files changed, 23 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435e8be..a2bf687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # v0.8.0 (unreleased) * Added support for history transfer. -* Updated libsignal to v0.65.4. +* Updated libsignal to v0.66.1. # v0.7.5 (2025-01-16) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 4da852b..c1ba7d5 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 4da852be7529372a53123a0a097ed6f252961fce +Subproject commit c1ba7d54f16ddcf9b49ddcf2bde7e7419be8ab32 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 457d343..b2627d8 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -228,10 +228,6 @@ typedef struct SignalAuthenticatedChatConnection SignalAuthenticatedChatConnecti typedef struct SignalCdsiLookup SignalCdsiLookup; -typedef struct SignalChatAuthChatService SignalChatAuthChatService; - -typedef struct SignalChatUnauthChatService SignalChatUnauthChatService; - typedef struct SignalCiphertextMessage SignalCiphertextMessage; /** @@ -241,6 +237,8 @@ typedef struct SignalConnectionInfo SignalConnectionInfo; typedef struct SignalConnectionManager SignalConnectionManager; +typedef struct SignalConnectionProxyConfig SignalConnectionProxyConfig; + typedef struct SignalDecryptionErrorMessage SignalDecryptionErrorMessage; typedef struct SignalFingerprint SignalFingerprint; @@ -789,6 +787,14 @@ typedef struct { SignalConnectionInfo *raw; } SignalMutPointerConnectionInfo; +typedef struct { + SignalConnectionProxyConfig *raw; +} SignalMutPointerConnectionProxyConfig; + +typedef struct { + const SignalConnectionProxyConfig *raw; +} SignalConstPointerConnectionProxyConfig; + typedef struct { SignalConnectionManager *raw; } SignalMutPointerConnectionManager; @@ -854,18 +860,6 @@ typedef struct { SignalCancellationId cancellation_id; } SignalCPromiseFfiCdsiLookupResponse; -typedef SignalChatAuthChatService SignalAuthChat; - -typedef struct { - SignalAuthChat *raw; -} SignalMutPointerAuthChat; - -typedef SignalChatUnauthChatService SignalUnauthChat; - -typedef struct { - SignalUnauthChat *raw; -} SignalMutPointerUnauthChat; - typedef struct { SignalHttpRequest *raw; } SignalMutPointerHttpRequest; @@ -1002,55 +996,6 @@ typedef struct { const SignalAuthenticatedChatConnection *raw; } SignalConstPointerAuthenticatedChatConnection; -typedef struct { - const SignalUnauthChat *raw; -} SignalConstPointerUnauthChat; - -typedef struct { - const SignalAuthChat *raw; -} SignalConstPointerAuthChat; - -typedef struct { - uint8_t raw_ip_type; - double duration_secs; - const char *connection_info; -} SignalFfiChatServiceDebugInfo; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiChatServiceDebugInfo *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseFfiChatServiceDebugInfo; - -typedef struct { - SignalFfiChatResponse response; - SignalFfiChatServiceDebugInfo debug_info; -} SignalFfiResponseAndDebugInfo; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiResponseAndDebugInfo *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseFfiResponseAndDebugInfo; - typedef struct { SignalServerMessageAck *raw; } SignalMutPointerServerMessageAck; @@ -1905,11 +1850,19 @@ SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalFfiError *signal_connection_info_destroy(SignalMutPointerConnectionInfo p); +SignalFfiError *signal_connection_proxy_config_destroy(SignalMutPointerConnectionProxyConfig p); + +SignalFfiError *signal_connection_proxy_config_clone(SignalMutPointerConnectionProxyConfig *new_obj, SignalConstPointerConnectionProxyConfig obj); + +SignalFfiError *signal_connection_proxy_config_new(SignalMutPointerConnectionProxyConfig *out, const char *scheme, const char *host, int32_t port, const char *username, const char *password); + SignalFfiError *signal_connection_manager_destroy(SignalMutPointerConnectionManager p); SignalFfiError *signal_connection_manager_new(SignalMutPointerConnectionManager *out, uint8_t environment, const char *user_agent); -SignalFfiError *signal_connection_manager_set_proxy(SignalConstPointerConnectionManager connection_manager, const char *host, int32_t port); +SignalFfiError *signal_connection_manager_set_proxy(SignalConstPointerConnectionManager connection_manager, SignalConstPointerConnectionProxyConfig proxy); + +SignalFfiError *signal_connection_manager_set_invalid_proxy(SignalConstPointerConnectionManager connection_manager); SignalFfiError *signal_connection_manager_clear_proxy(SignalConstPointerConnectionManager connection_manager); @@ -1941,10 +1894,6 @@ SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, SignalConstPoin SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerCdsiLookup lookup); -SignalFfiError *signal_auth_chat_destroy(SignalMutPointerAuthChat p); - -SignalFfiError *signal_unauth_chat_destroy(SignalMutPointerUnauthChat p); - SignalFfiError *signal_http_request_destroy(SignalMutPointerHttpRequest p); SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); @@ -1963,10 +1912,6 @@ SignalFfiError *signal_chat_connection_info_ip_version(uint8_t *out, SignalConst SignalFfiError *signal_chat_connection_info_description(const char **out, SignalConstPointerChatConnectionInfo connection_info); -SignalFfiError *signal_chat_service_new_unauth(SignalMutPointerUnauthChat *out, SignalConstPointerConnectionManager connection_manager); - -SignalFfiError *signal_chat_service_new_auth(SignalMutPointerAuthChat *out, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); - SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); @@ -1987,26 +1932,6 @@ SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebo SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat); -SignalFfiError *signal_chat_service_disconnect_unauth(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat); - -SignalFfiError *signal_chat_service_disconnect_auth(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat); - -SignalFfiError *signal_chat_service_connect_unauth(SignalCPromiseFfiChatServiceDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat); - -SignalFfiError *signal_chat_service_connect_auth(SignalCPromiseFfiChatServiceDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat); - -SignalFfiError *signal_chat_service_unauth_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); - -SignalFfiError *signal_chat_service_unauth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); - -SignalFfiError *signal_chat_service_auth_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); - -SignalFfiError *signal_chat_service_auth_send_and_debug(SignalCPromiseFfiResponseAndDebugInfo *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthChat chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); - -SignalFfiError *signal_chat_service_set_listener_auth(SignalConstPointerTokioAsyncContext runtime, SignalConstPointerAuthChat chat, SignalConstPointerFfiChatListenerStruct listener); - -SignalFfiError *signal_chat_service_set_listener_unauth(SignalConstPointerTokioAsyncContext runtime, SignalConstPointerUnauthChat chat, SignalConstPointerFfiChatListenerStruct listener); - SignalFfiError *signal_server_message_ack_destroy(SignalMutPointerServerMessageAck p); SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerServerMessageAck ack); @@ -2103,7 +2028,7 @@ SignalFfiError *signal_online_backup_validator_finalize(SignalMutPointerOnlineBa SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); -SignalFfiError *signal_username_proof(SignalOwnedBuffer *out, const char *username, SignalBorrowedBuffer randomness); +SignalFfiError *signal_username_proof(SignalOwnedBuffer *out, const char *username, const uint8_t (*randomness)[32]); SignalFfiError *signal_username_verify(SignalBorrowedBuffer proof, SignalBorrowedBuffer hash); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 8a399dd..219f19f 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.65.4" +const Version = "v0.66.1" From 50b9a51c1efcaf38a263cc48957b8eefdfa1dd9c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Feb 2025 13:51:43 +0200 Subject: [PATCH 423/718] dependencies: update go --- .github/workflows/go.yml | 8 ++++---- CHANGELOG.md | 1 + go.mod | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c2496f6..5d8ebfa 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,8 +11,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.22", "1.23"] - name: Lint ${{ matrix.go-version == '1.23' && '(latest)' || '(old)' }} + go-version: ["1.23", "1.24"] + name: Lint ${{ matrix.go-version == '1.24' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 @@ -40,8 +40,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.22", "1.23"] - name: Test ${{ matrix.go-version == '1.23' && '(latest)' || '(old)' }} + go-version: ["1.23", "1.24"] + name: Test ${{ matrix.go-version == '1.24' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index a2bf687..8c90bcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # v0.8.0 (unreleased) +* Bumped minimum Go version to 1.23. * Added support for history transfer. * Updated libsignal to v0.66.1. diff --git a/go.mod b/go.mod index 238c27e..50527e5 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module go.mau.fi/mautrix-signal -go 1.22.0 +go 1.23.0 -toolchain go1.23.5 +toolchain go1.24.0 require ( github.com/coder/websocket v1.8.12 From 79776c13bc90cfa0f5ff402b064ce6e439533bb9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Feb 2025 14:59:44 +0200 Subject: [PATCH 424/718] signalmeow/store: fix missing columns in signalmeow_backup_chat table --- pkg/signalmeow/store/upgrades/00-latest.sql | 5 ++- .../upgrades/20-fix-backup-chat-columns.go | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 pkg/signalmeow/store/upgrades/20-fix-backup-chat-columns.go diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 23c3762..670f0e0 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v19 (compatible with v13+): Latest revision +-- v0 -> v20 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -136,6 +136,9 @@ CREATE TABLE signalmeow_backup_chat ( recipient_id BIGINT NOT NULL, data bytea NOT NULL, + latest_message_id BIGINT, + total_message_count INTEGER, + PRIMARY KEY (account_id, chat_id), CONSTRAINT signalmeow_backup_chat_device_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE, diff --git a/pkg/signalmeow/store/upgrades/20-fix-backup-chat-columns.go b/pkg/signalmeow/store/upgrades/20-fix-backup-chat-columns.go new file mode 100644 index 0000000..d409fe6 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/20-fix-backup-chat-columns.go @@ -0,0 +1,36 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package upgrades + +import ( + "context" + + "go.mau.fi/util/dbutil" +) + +func init() { + Table.Register(-1, 20, 13, "Add missing columns for backup chat table", dbutil.TxnModeOn, func(ctx context.Context, db *dbutil.Database) (err error) { + var exists bool + if exists, err = db.ColumnExists(ctx, "signalmeow_backup_chat", "latest_message_id"); err == nil && !exists { + _, err = db.Exec(ctx, ` + ALTER TABLE signalmeow_backup_chat ADD COLUMN latest_message_id BIGINT; + ALTER TABLE signalmeow_backup_chat ADD COLUMN total_message_count INTEGER; + `) + } + return + }) +} From daadb450e3af60c9ad9187e7cd018a5a47ed8035 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Feb 2025 15:28:32 +0200 Subject: [PATCH 425/718] ci: disable gotestfmt It doesn't like build warnings in Go 1.24's new json format --- .github/workflows/go.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 5d8ebfa..6bbfaef 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -52,10 +52,10 @@ jobs: go-version: ${{ matrix.go-version }} cache: true - - name: Set up gotestfmt - uses: GoTestTools/gotestfmt-action@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} + #- name: Set up gotestfmt + # uses: GoTestTools/gotestfmt-action@v2 + # with: + # token: ${{ secrets.GITHUB_TOKEN }} - name: Install libolm run: sudo apt-get install libolm-dev @@ -68,4 +68,5 @@ jobs: run: | set -euo pipefail export LIBRARY_PATH=. - go test -v -json ./... -cover | gotestfmt + #go test -v -json ./... -cover | gotestfmt + go test ./... From 8c22feeb53c1c777c31e08eb5ade803dbbf2a517 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Feb 2025 17:23:04 +0200 Subject: [PATCH 426/718] dependencies: update --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 50527e5..ae5a99e 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003 - golang.org/x/crypto v0.32.0 - golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c - golang.org/x/net v0.34.0 - google.golang.org/protobuf v1.36.3 - maunium.net/go/mautrix v0.23.1-0.20250203222456-475c4bf39d91 + go.mau.fi/util v0.8.5 + golang.org/x/crypto v0.33.0 + golang.org/x/exp v0.0.0-20250215185904-eff6e970281f + golang.org/x/net v0.35.0 + google.golang.org/protobuf v1.36.5 + maunium.net/go/mautrix v0.23.1 ) require ( @@ -31,7 +31,7 @@ require ( 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.24 // indirect - github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect + github.com/petermattis/goid v0.0.0-20250211185408-f2b9d978cd7a // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -41,9 +41,9 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.8 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 5aaee56..8ffc192 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 h1:ah1dvbqPMN5+ocrg/ZSgZ6k8bOk+kcZQ7fnyx6UvOm4= -github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20250211185408-f2b9d978cd7a h1:ckxP/kGzsxvxXo8jO6E/0QJ8MMmwI7IRj4Fys9QbAZA= +github.com/petermattis/goid v0.0.0-20250211185408-f2b9d978cd7a/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -70,27 +70,27 @@ 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.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003 h1:ye5l+QpYW5CpGVMedb3EHlmflGMQsMtw8mC4K/U8hIw= -go.mau.fi/util v0.8.5-0.20250203220331-1c0d19ea6003/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY= +go.mau.fi/util v0.8.5 h1:PwCAAtcfK0XxZ4sdErJyfBMkTEWoQU33aB7QqDDzQRI= +go.mau.fi/util v0.8.5/go.mod h1:Ycug9mrbztlahHPEJ6H5r8Nu/xqZaWbE5vPHVWmfz6M= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc= -golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/exp v0.0.0-20250215185904-eff6e970281f h1:oFMYAjX0867ZD2jcNiLBrI9BdpmEkvPyi5YrBGXbamg= +golang.org/x/exp v0.0.0-20250215185904-eff6e970281f/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -100,5 +100,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.23.1-0.20250203222456-475c4bf39d91 h1:jbga2dSYVTd3MgAKugiz5+mIYp+qxUOCDokUGZOEWRg= -maunium.net/go/mautrix v0.23.1-0.20250203222456-475c4bf39d91/go.mod h1:q2U2IRLSFpglDhIpSjd8TnCNVzBNrUJBD8pmYCGQiwc= +maunium.net/go/mautrix v0.23.1 h1:xZtX43YZF3WRxkdR+oMUrpiQe+jbjc+LeXLxHuXP5IM= +maunium.net/go/mautrix v0.23.1/go.mod h1:kldoZQDneV/jquIhwG1MmMw5j2A2M/MnQYRSWt863cY= From 143cd120f54bbd95fc3f01859db03b1a841c3d6c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Feb 2025 17:27:27 +0200 Subject: [PATCH 427/718] libsignal: update to v0.66.2 --- CHANGELOG.md | 2 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/version.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c90bcd..eb175af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ * Bumped minimum Go version to 1.23. * Added support for history transfer. -* Updated libsignal to v0.66.1. +* Updated libsignal to v0.66.2. # v0.7.5 (2025-01-16) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index c1ba7d5..525e8bc 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit c1ba7d54f16ddcf9b49ddcf2bde7e7419be8ab32 +Subproject commit 525e8bce0c84576014268ab5b3982612b765f598 diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 219f19f..1760c96 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.66.1" +const Version = "v0.66.2" From 2e44f2ca133efcce94ecbfe4c05359bcbb69736b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Feb 2025 17:30:24 +0200 Subject: [PATCH 428/718] Bump version to v0.8.0 --- CHANGELOG.md | 2 +- cmd/mautrix-signal/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb175af..5804dc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v0.8.0 (unreleased) +# v0.8.0 (2025-02-16) * Bumped minimum Go version to 1.23. * Added support for history transfer. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 1cd74ce..2cbed46 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.7.5", + Version: "0.8.0", Connector: &connector.SignalConnector{}, } From 79985bffa9fc291569147726d59913d331274c85 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Tue, 18 Feb 2025 10:42:12 -0500 Subject: [PATCH 429/718] login: open new WS and refresh QR code after 45s (#585) --- pkg/connector/login.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 8d30da9..50ba0ae 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -19,6 +19,7 @@ package connector import ( "context" "fmt" + "time" "github.com/google/uuid" "maunium.net/go/mautrix/bridge/status" @@ -50,6 +51,7 @@ type QRLogin struct { Main *SignalConnector cancelChan context.CancelFunc ProvChan chan signalmeow.ProvisioningResponse + newQRCount int ProvData *store.DeviceData } @@ -139,6 +141,17 @@ func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { Type: bridgev2.LoginDisplayTypeNothing, }, }, nil + + // 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): + qr.cancelChan() + qr.newQRCount++ + if qr.newQRCount >= 6 { + return nil, fmt.Errorf("too many QR code refreshes") + } + return qr.Start(ctx) + case <-ctx.Done(): qr.cancelChan() return nil, ctx.Err() From 6e22103e1c1d3653a29f02d468f2ddadcf968c0b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 22 Feb 2025 23:47:24 +0200 Subject: [PATCH 430/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ae5a99e..e5ba156 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250215185904-eff6e970281f golang.org/x/net v0.35.0 google.golang.org/protobuf v1.36.5 - maunium.net/go/mautrix v0.23.1 + maunium.net/go/mautrix v0.23.2-0.20250224184759-0115ba0258cb ) require ( diff --git a/go.sum b/go.sum index 8ffc192..bcd6305 100644 --- a/go.sum +++ b/go.sum @@ -100,5 +100,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.23.1 h1:xZtX43YZF3WRxkdR+oMUrpiQe+jbjc+LeXLxHuXP5IM= -maunium.net/go/mautrix v0.23.1/go.mod h1:kldoZQDneV/jquIhwG1MmMw5j2A2M/MnQYRSWt863cY= +maunium.net/go/mautrix v0.23.2-0.20250224184759-0115ba0258cb h1:neXlaiDrKjZsLmNm+ufCQGuEB050TKWVi7w9Qta+lFM= +maunium.net/go/mautrix v0.23.2-0.20250224184759-0115ba0258cb/go.mod h1:kldoZQDneV/jquIhwG1MmMw5j2A2M/MnQYRSWt863cY= From 272f38297ff3ba6fef89d9756c1e15fc13bc91c7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Feb 2025 18:22:24 +0200 Subject: [PATCH 431/718] libsignal: update to v0.67.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 6 ++++-- pkg/libsignalgo/version.go | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 525e8bc..865d879 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 525e8bce0c84576014268ab5b3982612b765f598 +Subproject commit 865d879ec91396abf3c34f78cd7416708591c6ae diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index b2627d8..860963e 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -204,7 +204,7 @@ typedef enum { SignalErrorCodeCdsiInvalidToken = 147, SignalErrorCodeConnectionFailed = 148, SignalErrorCodeChatServiceInactive = 149, - SignalErrorCodeChatServiceIntentionallyDisconnected = 150, + SignalErrorCodeRequestTimedOut = 150, SignalErrorCodeSvrDataMissing = 160, SignalErrorCodeSvrRestoreFailed = 161, SignalErrorCodeSvrRotationMachineTooManySteps = 162, @@ -1890,6 +1890,8 @@ SignalFfiError *signal_cdsi_lookup_destroy(SignalMutPointerCdsiLookup p); SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseMutPointerCdsiLookup *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, SignalConstPointerLookupRequest request); +SignalFfiError *signal_cdsi_lookup_new_routes(SignalCPromiseMutPointerCdsiLookup *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, SignalConstPointerLookupRequest request); + SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, SignalConstPointerCdsiLookup lookup); SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerCdsiLookup lookup); @@ -1934,7 +1936,7 @@ SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatCo SignalFfiError *signal_server_message_ack_destroy(SignalMutPointerServerMessageAck p); -SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerServerMessageAck ack); +SignalFfiError *signal_server_message_ack_send(SignalConstPointerServerMessageAck ack); SignalFfiError *signal_tokio_async_context_destroy(SignalMutPointerTokioAsyncContext p); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 1760c96..aa85777 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.66.2" +const Version = "v0.67.0" From 4713ddfcd1c421234572a00b2f271704f3787fff Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Fri, 21 Feb 2025 11:57:01 +0000 Subject: [PATCH 432/718] signalmeow: block until stop completes Currently the disconnect/stop bridge call will complete before all the loops have returned. This switches them all to use a shared cancelable context and wait group to block on stop until all loops exit. --- pkg/signalmeow/client.go | 4 +- pkg/signalmeow/keys.go | 81 ++++++++++++++++++------------------- pkg/signalmeow/receiving.go | 44 +++++++++++--------- 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 7ef1abb..e5e4c88 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -48,9 +48,11 @@ type Client struct { AuthedWS *web.SignalWebsocket UnauthedWS *web.SignalWebsocket - WSCancel context.CancelFunc lastConnectionStatus SignalConnectionStatus + loopCancel context.CancelFunc + loopWg sync.WaitGroup + EventHandler func(events.SignalEvent) storageAuthLock sync.Mutex diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index ad717ac..bc86789 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -599,49 +599,48 @@ func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, pks store.PreKe return nil } -func (cli *Client) StartKeyCheckLoop(ctx context.Context) { +func (cli *Client) keyCheckLoop(ctx context.Context) { log := zerolog.Ctx(ctx).With().Str("action", "start key check loop").Logger() - go func() { - // Do the initial check in 5-10 minutes after starting the loop - window_start := 0 - window_size := 1 - for { - random_minutes_in_window := rand.Intn(window_size) + window_start - check_time := time.Duration(random_minutes_in_window) * time.Minute - log.Debug().Dur("check_time", check_time).Msg("Waiting to check for new prekeys") - select { - case <-ctx.Done(): - return - case <-time.After(check_time): - err := cli.CheckAndUploadNewPreKeys(ctx, cli.Store.ACIPreKeyStore) - if err != nil { - log.Err(err).Msg("Error checking and uploading new prekeys for ACI identity") - // Retry within half an hour - window_start = 5 - window_size = 25 - continue - } - err = cli.CheckAndUploadNewPreKeys(ctx, cli.Store.PNIPreKeyStore) - if err != nil { - if errors.Is(err, errPrekeyUpload422) { - log.Err(err).Msg("Got 422 error while uploading PNI prekeys, deleting session") - disconnectErr := cli.ClearKeysAndDisconnect(ctx) - if disconnectErr != nil { - log.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") - } - return - } - log.Err(err).Msg("Error checking and uploading new prekeys for PNI identity") - // Retry within half an hour - window_start = 5 - window_size = 25 - continue - } - // After a successful check, check again in 36 to 60 hours - window_start = 36 * 60 - window_size = 24 * 60 + // Do the initial check in 5-10 minutes after starting the loop + window_start := 0 + window_size := 1 + for { + random_minutes_in_window := rand.Intn(window_size) + window_start + check_time := time.Duration(random_minutes_in_window) * time.Minute + log.Debug().Dur("check_time", check_time).Msg("Waiting to check for new prekeys") + + select { + case <-ctx.Done(): + return + case <-time.After(check_time): + err := cli.CheckAndUploadNewPreKeys(ctx, cli.Store.ACIPreKeyStore) + if err != nil { + log.Err(err).Msg("Error checking and uploading new prekeys for ACI identity") + // Retry within half an hour + window_start = 5 + window_size = 25 + continue } + err = cli.CheckAndUploadNewPreKeys(ctx, cli.Store.PNIPreKeyStore) + if err != nil { + if errors.Is(err, errPrekeyUpload422) { + log.Err(err).Msg("Got 422 error while uploading PNI prekeys, deleting session") + disconnectErr := cli.ClearKeysAndDisconnect(ctx) + if disconnectErr != nil { + log.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") + } + return + } + log.Err(err).Msg("Error checking and uploading new prekeys for PNI identity") + // Retry within half an hour + window_start = 5 + window_size = 25 + continue + } + // After a successful check, check again in 36 to 60 hours + window_start = 36 * 60 + window_size = 24 * 60 } - }() + } } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 2eb622f..8fa4ffa 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -77,31 +77,30 @@ func (cli *Client) startWebsocketsInternal( ctx context.Context, ) ( authChan, unauthChan chan web.SignalWebsocketConnectionStatus, - cancelCtx context.Context, - cancelFunc context.CancelFunc, + loopCtx context.Context, loopCancel context.CancelFunc, err error, ) { - cancelCtx, cancelFunc = context.WithCancel(ctx) - cli.WSCancel = cancelFunc - unauthChan, err = cli.connectUnauthedWS(cancelCtx) + loopCtx, loopCancel = context.WithCancel(ctx) + unauthChan, err = cli.connectUnauthedWS(loopCtx) if err != nil { - cancelFunc() + loopCancel() return } zerolog.Ctx(ctx).Info().Msg("Unauthed websocket connecting") - authChan, err = cli.connectAuthedWS(cancelCtx, cli.incomingRequestHandler) + authChan, err = cli.connectAuthedWS(loopCtx, cli.incomingRequestHandler) if err != nil { - cancelFunc() + loopCancel() return } zerolog.Ctx(ctx).Info().Msg("Authed websocket connecting") + cli.loopCancel = loopCancel return } func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnectionStatus, error) { log := zerolog.Ctx(ctx).With().Str("action", "start receive loops").Logger() - ctx = log.WithContext(ctx) - authChan, unauthChan, ctx, cancel, err := cli.startWebsocketsInternal(log.WithContext(ctx)) + + authChan, unauthChan, loopCtx, loopCancel, err := cli.startWebsocketsInternal(log.WithContext(ctx)) if err != nil { return nil, err } @@ -110,13 +109,15 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection initialConnectChan := make(chan struct{}) // Combine both websocket status channels into a single, more generic "Signal" connection status channel + cli.loopWg.Add(1) go func() { + defer cli.loopWg.Done() defer close(statusChan) - defer cancel() + defer loopCancel() var currentStatus, lastAuthStatus, lastUnauthStatus web.SignalWebsocketConnectionStatus for { select { - case <-ctx.Done(): + case <-loopCtx.Done(): log.Info().Msg("Context done, exiting websocket status loop") return case status := <-authChan: @@ -201,19 +202,21 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection }() // Send sync message once both websockets are connected + cli.loopWg.Add(1) go func() { + defer cli.loopWg.Done() for { select { - case <-ctx.Done(): + case <-loopCtx.Done(): return case <-initialConnectChan: log.Info().Msg("Both websockets connected, sending contacts sync request") // TODO hacky if cli.SyncContactsOnConnect { - cli.SendContactSyncRequest(ctx) + cli.SendContactSyncRequest(loopCtx) } if cli.Store.MasterKey == nil { - cli.SendStorageMasterKeyRequest(ctx) + cli.SendStorageMasterKeyRequest(loopCtx) } return } @@ -221,7 +224,11 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection }() // Start loop to check for and upload more prekeys - cli.StartKeyCheckLoop(ctx) + cli.loopWg.Add(1) + go func() { + defer cli.loopWg.Done() + cli.keyCheckLoop(loopCtx) + }() return statusChan, nil } @@ -233,8 +240,9 @@ func (cli *Client) StopReceiveLoops() error { }() authErr := cli.AuthedWS.Close() unauthErr := cli.UnauthedWS.Close() - if cli.WSCancel != nil { - cli.WSCancel() + if cli.loopCancel != nil { + cli.loopCancel() + cli.loopWg.Wait() } if authErr != nil { return authErr From 870f0d152e156cc5dc95abbfb807833ebac31eda Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 26 Feb 2025 16:47:51 +0200 Subject: [PATCH 433/718] signalmeow: fix propagating errors when disconnected --- pkg/connector/client.go | 1 - pkg/signalmeow/receiving.go | 2 +- pkg/signalmeow/web/signalwebsocket.go | 47 ++++++++------------------- 3 files changed, 14 insertions(+), 36 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 4aebc69..1bf8742 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -236,7 +236,6 @@ func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.Connec log.Info().Msg("Authed websocket connected") case web.SignalWebsocketConnectionEventDisconnected: log.Err(status.Err).Msg("Authed websocket disconnected") - return fmt.Errorf("authed websocket disconnected: %w", status.Err) case web.SignalWebsocketConnectionEventLoggedOut: log.Err(status.Err).Msg("Authed websocket logged out") return fmt.Errorf("authed websocket logged out: %w", status.Err) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 8fa4ffa..f5e2390 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -285,7 +285,7 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web if *req.Verb == http.MethodPut && *req.Path == "/api/v1/message" { return cli.incomingAPIMessageHandler(ctx, req) } else if *req.Verb == http.MethodPut && *req.Path == "/api/v1/queue/empty" { - log.Trace().Msg("Received queue empty") + log.Debug().Msg("Received queue empty notice") cli.handleEvent(&events.QueueEmpty{}) } else { log.Warn().Any("req", req).Msg("Unknown websocket request message") diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index c273c31..d837dc7 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -195,7 +195,7 @@ func (s *SignalWebsocket) connectLoop( log.Warn().Dur("backoff", backoff).Msg("Failed to connect, waiting to retry...") time.Sleep(backoff) backoff += backoffIncrement - } else if !isFirstConnect && s.basicAuth != nil { + } else if !isFirstConnect && s.basicAuth != nil && ctx.Err() == nil { time.Sleep(initialBackoff) } if ctx.Err() != nil { @@ -331,42 +331,21 @@ func (s *SignalWebsocket) connectLoop( }() // Wait for read or write or ping loop to exit (which means there was an error) - log.Info().Msg("Waiting for read or write loop to exit") - select { - case <-loopCtx.Done(): - log.Info().Msg("received loopCtx done") - if context.Cause(loopCtx) != nil { - err := context.Cause(loopCtx) - if err != nil && err != context.Canceled { - log.Err(err).Msg("loopCtx error") - errorCount++ - } + log.Debug().Msg("Finished preparing connection, waiting for loop context to finish") + <-loopCtx.Done() + ctxCauseErr := context.Cause(loopCtx) + log.Debug().AnErr("ctx_cause_err", ctxCauseErr).Msg("Read or write loop exited") + if ctxCauseErr == nil || errors.Is(ctxCauseErr, context.Canceled) { + s.statusChannel <- SignalWebsocketConnectionStatus{ + Event: SignalWebsocketConnectionEventCleanShutdown, } - if context.Cause(loopCtx) != nil && context.Cause(loopCtx) == context.Canceled { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventCleanShutdown, - } - } else { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventDisconnected, - Err: err, - } - } - case <-ctx.Done(): - log.Info().AnErr("ctx_err", ctx.Err()).AnErr("ctx_cause", context.Cause(ctx)).Msg("received ctx done") - if context.Cause(ctx) != nil && context.Cause(ctx) == context.Canceled { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventCleanShutdown, - } - return - } else { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventDisconnected, - Err: err, - } + } else { + errorCount++ + s.statusChannel <- SignalWebsocketConnectionStatus{ + Event: SignalWebsocketConnectionEventDisconnected, + Err: ctxCauseErr, } } - log.Info().Msg("Read or write loop exited") // Clean up ws.Close(websocket.StatusGoingAway, "Going away") From 9e7a24a7bab3c678e6a84ef60674869bf9a4c9a4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 4 Mar 2025 14:49:17 +0200 Subject: [PATCH 434/718] client: don't propagate background timeouts if connection was successful --- pkg/connector/client.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 1bf8742..3cb4700 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -228,12 +228,14 @@ func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.Connec defer s.Disconnect() log := zerolog.Ctx(ctx) queueEmpty := s.queueEmptyWaiter.GetChan() + didConnect := false for { select { case status := <-ch: switch status.Event { case web.SignalWebsocketConnectionEventConnected: log.Info().Msg("Authed websocket connected") + didConnect = true case web.SignalWebsocketConnectionEventDisconnected: log.Err(status.Err).Msg("Authed websocket disconnected") case web.SignalWebsocketConnectionEventLoggedOut: @@ -247,6 +249,10 @@ func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.Connec } case <-ctx.Done(): log.Warn().Msg("Context finished before queue empty event") + if didConnect { + // Don't propagate timeout errors if the connection was successful at least once + return nil + } return ctx.Err() case <-queueEmpty: log.Info().Msg("Received queue empty event") From d7c598dbf45e9e2f9fd7c8c26216bf446f6fcfd5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 7 Mar 2025 17:20:20 +0200 Subject: [PATCH 435/718] client: enable registering apns pushers --- pkg/connector/client.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 3cb4700..8c0db20 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -76,10 +76,14 @@ func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType b if s.Client == nil { return bridgev2.ErrNotLoggedIn } - if pushType != bridgev2.PushTypeFCM { + switch pushType { + case bridgev2.PushTypeFCM: + return s.Client.RegisterFCM(ctx, token) + case bridgev2.PushTypeAPNs: + return s.Client.RegisterAPNs(ctx, token) + default: return fmt.Errorf("unsupported push type: %s", pushType) } - return s.Client.RegisterFCM(ctx, token) } func (s *SignalClient) LogoutRemote(ctx context.Context) { From cc42285a53bf74fb2b8e338526fd6103b68b08c5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 10 Mar 2025 17:58:52 +0200 Subject: [PATCH 436/718] capabilities: resend to include gif info --- pkg/connector/capabilities.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 1be2d45..072c6fa 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -180,5 +180,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 2 + return 1, 3 } From 89e2a3a5f2bc09a058415cc96aa459c76c876164 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Tue, 11 Mar 2025 14:08:13 +0000 Subject: [PATCH 437/718] dependencies: upgrade mautrix-go --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index e5ba156..fd62047 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.5 + go.mau.fi/util v0.8.6-0.20250227184636-7ff63b0b9d95 golang.org/x/crypto v0.33.0 golang.org/x/exp v0.0.0-20250215185904-eff6e970281f golang.org/x/net v0.35.0 google.golang.org/protobuf v1.36.5 - maunium.net/go/mautrix v0.23.2-0.20250224184759-0115ba0258cb + maunium.net/go/mautrix v0.23.2-0.20250311105500-a6d948f7c2bb ) require ( diff --git a/go.sum b/go.sum index bcd6305..ef886d9 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.5 h1:PwCAAtcfK0XxZ4sdErJyfBMkTEWoQU33aB7QqDDzQRI= -go.mau.fi/util v0.8.5/go.mod h1:Ycug9mrbztlahHPEJ6H5r8Nu/xqZaWbE5vPHVWmfz6M= +go.mau.fi/util v0.8.6-0.20250227184636-7ff63b0b9d95 h1:5EfVWWjU2Hte9uE6B/hBgvjnVfBx/7SYDZBnsuo+EBs= +go.mau.fi/util v0.8.6-0.20250227184636-7ff63b0b9d95/go.mod h1:Ycug9mrbztlahHPEJ6H5r8Nu/xqZaWbE5vPHVWmfz6M= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= @@ -100,5 +100,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.23.2-0.20250224184759-0115ba0258cb h1:neXlaiDrKjZsLmNm+ufCQGuEB050TKWVi7w9Qta+lFM= -maunium.net/go/mautrix v0.23.2-0.20250224184759-0115ba0258cb/go.mod h1:kldoZQDneV/jquIhwG1MmMw5j2A2M/MnQYRSWt863cY= +maunium.net/go/mautrix v0.23.2-0.20250311105500-a6d948f7c2bb h1:HAKsPqJiBsugs8qOy9mMmASEpmqpJ/Cbc/2Bj6wuNYQ= +maunium.net/go/mautrix v0.23.2-0.20250311105500-a6d948f7c2bb/go.mod h1:IHMaSJh7YIxMrZSDVefS+nLdr3RbeLowsCSa6ibONZ0= From 13a4881fdb550303ca1367f6ac2cda3ee803c889 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Tue, 11 Mar 2025 14:08:25 +0000 Subject: [PATCH 438/718] backfill: don't delete all backfill messages if will paginate flag set --- pkg/connector/backfill.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/connector/backfill.go b/pkg/connector/backfill.go index c0416b1..ae6d196 100644 --- a/pkg/connector/backfill.go +++ b/pkg/connector/backfill.go @@ -172,7 +172,7 @@ func (s *SignalClient) FetchMessages(ctx context.Context, params bridgev2.FetchM CompleteCallback: func() { // When reaching the last backwards backfill batch, delete the chat from the backup store. // If backwards backfilling isn't enabled, delete immediately after the first backfill request. - if (!params.Forward && len(items) < params.Count) || !s.Main.Bridge.Config.Backfill.Queue.Enabled { + if (!params.Forward && len(items) < params.Count) || (!s.Main.Bridge.Config.Backfill.Queue.Enabled && !s.Main.Bridge.Config.Backfill.WillPaginateManually) { err := s.Client.Store.BackupStore.DeleteBackupChat(ctx, chat.Id) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to delete chat from backup store") From e9ae079903c09eea88c8cf912bd0bba7b77b2b23 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 12 Mar 2025 14:21:21 +0200 Subject: [PATCH 439/718] libsignal: update to v0.67.4 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 7 +++++++ pkg/libsignalgo/version.go | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 865d879..7b293c1 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 865d879ec91396abf3c34f78cd7416708591c6ae +Subproject commit 7b293c19e0c71f204d4596e8f31f95ec993ea080 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 860963e..7470062 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -905,6 +905,8 @@ typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envel typedef void (*SignalReceivedQueueEmpty)(void *ctx); +typedef void (*SignalReceivedAlerts)(void *ctx, SignalStringArray alerts); + typedef void (*SignalConnectionInterrupted)(void *ctx, SignalFfiError *error); typedef void (*SignalDestroyChatListener)(void *ctx); @@ -928,6 +930,7 @@ typedef struct { void *ctx; SignalReceivedIncomingMessage received_incoming_message; SignalReceivedQueueEmpty received_queue_empty; + SignalReceivedAlerts received_alerts; SignalConnectionInterrupted connection_interrupted; SignalDestroyChatListener destroy; } SignalFfiChatListenerStruct; @@ -1666,6 +1669,8 @@ SignalFfiError *signal_server_secret_params_get_public_params(SignalMutPointerSe SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], SignalConstPointerServerSecretParams params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); +SignalFfiError *signal_server_public_params_get_endorsement_public_key(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params); + SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params, const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); @@ -1924,6 +1929,8 @@ SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromise SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); +SignalFfiError *signal_authenticated_chat_connection_preconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); + SignalFfiError *signal_authenticated_chat_connection_connect(SignalCPromiseMutPointerAuthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index aa85777..30d8666 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.67.0" +const Version = "v0.67.4" From 521f5e569de2467c0479a60ee8c4297d88416be6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 14:48:09 +0200 Subject: [PATCH 440/718] signalmeow/web: add logs for missing responses --- pkg/signalmeow/web/signalwebsocket.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index d837dc7..eb57a11 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -162,14 +162,16 @@ func (s *SignalWebsocket) connectLoop( response, err := (*requestHandler)(ctx, request) if err != nil { - log.Err(err).Msg("Error handling request") - continue - } - if response != nil && s.sendChannel != nil { + log.Err(err).Uint64("request_id", request.GetId()).Msg("Error handling request") + } else if response != nil && s.sendChannel != nil { s.sendChannel <- SignalWebsocketSendMessage{ RequestMessage: request, ResponseMessage: response, } + } else if response == nil { + log.Warn().Uint64("request_id", request.GetId()).Msg("Request handler didn't return a response nor an error") + } else { + log.Warn().Uint64("request_id", request.GetId()).Msg("sendChannel is nil, can't send response") } } } From f09966c1484351d8fcacbb785a5d9753db4fd7c7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 14:49:40 +0200 Subject: [PATCH 441/718] signalmeow/web: remove redundant use of function pointer --- pkg/signalmeow/client.go | 2 +- pkg/signalmeow/web/signalwebsocket.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index e5e4c88..0f03354 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -87,7 +87,7 @@ func (cli *Client) connectAuthedWS(ctx context.Context, requestHandler web.Reque Logger() ctx = log.WithContext(ctx) authedWS := web.NewSignalWebsocket(url.UserPassword(username, password)) - statusChan := authedWS.Connect(ctx, &requestHandler) + statusChan := authedWS.Connect(ctx, requestHandler) cli.AuthedWS = authedWS return statusChan, nil } diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index eb57a11..40c97b7 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -104,14 +104,14 @@ func (s *SignalWebsocket) Close() error { return nil } -func (s *SignalWebsocket) Connect(ctx context.Context, requestHandler *RequestHandlerFunc) chan SignalWebsocketConnectionStatus { +func (s *SignalWebsocket) Connect(ctx context.Context, requestHandler RequestHandlerFunc) chan SignalWebsocketConnectionStatus { go s.connectLoop(ctx, requestHandler) return s.statusChannel } func (s *SignalWebsocket) connectLoop( ctx context.Context, - requestHandler *RequestHandlerFunc, + requestHandler RequestHandlerFunc, ) { log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_connect_loop"). @@ -159,7 +159,7 @@ func (s *SignalWebsocket) connectLoop( } // Handle the request with the request handler function - response, err := (*requestHandler)(ctx, request) + response, err := requestHandler(ctx, request) if err != nil { log.Err(err).Uint64("request_id", request.GetId()).Msg("Error handling request") From 562ed0559371b6b9d30dca8cdf8692ff6e3060a5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 14:52:11 +0200 Subject: [PATCH 442/718] signalmeow: add request id to all incoming request logs --- pkg/signalmeow/receiving.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index f5e2390..d86f910 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -280,6 +280,7 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web Str("handler", "incoming request handler"). Str("verb", *req.Verb). Str("path", *req.Path). + Uint64("request_id", *req.Id). Logger() ctx = log.WithContext(ctx) if *req.Verb == http.MethodPut && *req.Path == "/api/v1/message" { @@ -296,7 +297,7 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web } func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { - log := *zerolog.Ctx(ctx) + log := zerolog.Ctx(ctx) envelope := &signalpb.Envelope{} err := proto.Unmarshal(req.Body, envelope) if err != nil { From 85cee8308eed7edfaf545611834c60ab11b62054 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 14:54:29 +0200 Subject: [PATCH 443/718] signalmeow: remove unnecessarily big channel buffer --- pkg/signalmeow/receiving.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index d86f910..073909b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -104,7 +104,7 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection if err != nil { return nil, err } - statusChan := make(chan SignalConnectionStatus, 10000) + statusChan := make(chan SignalConnectionStatus, 128) initialConnectChan := make(chan struct{}) From e55601d0e09ba9949124d15dacd84b261f98bce0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 16:41:39 +0200 Subject: [PATCH 444/718] signalmeow/web: fix another oversized channel --- pkg/signalmeow/web/signalwebsocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 40c97b7..4af77af 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -118,7 +118,7 @@ func (s *SignalWebsocket) connectLoop( Logger() ctx, cancel := context.WithCancel(ctx) - incomingRequestChan := make(chan *signalpb.WebSocketRequestMessage, 10000) + incomingRequestChan := make(chan *signalpb.WebSocketRequestMessage, 256) defer func() { close(incomingRequestChan) close(s.statusChannel) From 074a2a9befa57775c6f5c54d4c3ce30aa0aa3126 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 17:38:14 +0200 Subject: [PATCH 445/718] client: consume unauth websocket status in ConnectBackground --- pkg/connector/client.go | 15 ++++++++++++++- pkg/signalmeow/receiving.go | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 8c0db20..8ffd0e0 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -225,7 +225,7 @@ func (s *SignalClient) Connect(ctx context.Context) { func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.ConnectBackgroundParams) error { s.queueEmptyWaiter.Clear() - ch, _, err := s.Client.StartWebsockets(ctx) + ch, unauthCh, err := s.Client.StartWebsockets(ctx) if err != nil { return err } @@ -251,6 +251,19 @@ func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.Connec case web.SignalWebsocketConnectionEventCleanShutdown: log.Info().Msg("Authed websocket clean shutdown") } + case status := <-unauthCh: + switch status.Event { + case web.SignalWebsocketConnectionEventConnected: + log.Info().Msg("Unauthed websocket connected") + case web.SignalWebsocketConnectionEventDisconnected: + log.Err(status.Err).Msg("Unauthed websocket disconnected") + case web.SignalWebsocketConnectionEventLoggedOut: + log.Err(status.Err).Msg("Unauthed websocket logged out") + case web.SignalWebsocketConnectionEventError: + log.Err(status.Err).Msg("Unauthed websocket error") + case web.SignalWebsocketConnectionEventCleanShutdown: + log.Info().Msg("Unauthed websocket clean shutdown") + } case <-ctx.Done(): log.Warn().Msg("Context finished before queue empty event") if didConnect { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 073909b..34fcd55 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -280,7 +280,7 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web Str("handler", "incoming request handler"). Str("verb", *req.Verb). Str("path", *req.Path). - Uint64("request_id", *req.Id). + Uint64("incoming_request_id", *req.Id). Logger() ctx = log.WithContext(ctx) if *req.Verb == http.MethodPut && *req.Path == "/api/v1/message" { From 72b0616261f3b8dff5b01864dc0d6f6a71c9e63d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 13 Mar 2025 17:43:11 +0200 Subject: [PATCH 446/718] signalmeow/web: don't deadlock on status channel --- pkg/signalmeow/web/signalwebsocket.go | 56 +++++++++++---------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 4af77af..ac280be 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -109,6 +109,19 @@ func (s *SignalWebsocket) Connect(ctx context.Context, requestHandler RequestHan return s.statusChannel } +func (s *SignalWebsocket) pushStatus(ctx context.Context, status SignalWebsocketConnectionEvent, err error) { + select { + case s.statusChannel <- SignalWebsocketConnectionStatus{ + Event: status, + Err: err, + }: + case <-ctx.Done(): + return + case <-time.After(5 * time.Second): + zerolog.Ctx(ctx).Error().Msg("Status channel didn't accept status") + } +} + func (s *SignalWebsocket) connectLoop( ctx context.Context, requestHandler RequestHandlerFunc, @@ -212,30 +225,18 @@ func (s *SignalWebsocket) connectLoop( // Server didn't want to open websocket if resp.StatusCode >= 500 { // We can try again if it's a 5xx - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventDisconnected, - Err: fmt.Errorf("5xx opening websocket: %v", resp.Status), - } + s.pushStatus(ctx, SignalWebsocketConnectionEventDisconnected, fmt.Errorf("5xx opening websocket: %v", resp.Status)) } else if resp.StatusCode == 403 { // We are logged out, so we should stop trying to reconnect - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventLoggedOut, - Err: fmt.Errorf("403 opening websocket, we are logged out"), - } + s.pushStatus(ctx, SignalWebsocketConnectionEventLoggedOut, fmt.Errorf("403 opening websocket, we are logged out")) return // NOT RETRYING, KILLING THE CONNECTION LOOP } else if resp.StatusCode > 0 && resp.StatusCode < 500 { // Unexpected status code - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventError, - Err: fmt.Errorf("bad status opening websocket: %v", resp.Status), - } + s.pushStatus(ctx, SignalWebsocketConnectionEventError, fmt.Errorf("unexpected status opening websocket: %v", resp.Status)) return // NOT RETRYING, KILLING THE CONNECTION LOOP } else { // Something is very wrong - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventError, - Err: fmt.Errorf("unexpected error opening websocket: %v", resp.Status), - } + s.pushStatus(ctx, SignalWebsocketConnectionEventError, fmt.Errorf("unexpected error opening websocket: %v", resp.Status)) } // Retry the connection retrying = true @@ -245,24 +246,16 @@ func (s *SignalWebsocket) connectLoop( if err != nil { // Unexpected error opening websocket if backoff < maxBackoff { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventDisconnected, - Err: fmt.Errorf("hopefully transient error opening websocket: %w", err), - } + s.pushStatus(ctx, SignalWebsocketConnectionEventDisconnected, fmt.Errorf("transient error opening websocket: %w", err)) } else { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventError, - Err: fmt.Errorf("continuing error opening websocket: %w", err), - } + s.pushStatus(ctx, SignalWebsocketConnectionEventError, fmt.Errorf("continuing error opening websocket: %w", err)) } retrying = true continue } // Succssfully connected - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventConnected, - } + s.pushStatus(ctx, SignalWebsocketConnectionEventConnected, nil) s.ws = ws retrying = false backoff = initialBackoff @@ -338,15 +331,10 @@ func (s *SignalWebsocket) connectLoop( ctxCauseErr := context.Cause(loopCtx) log.Debug().AnErr("ctx_cause_err", ctxCauseErr).Msg("Read or write loop exited") if ctxCauseErr == nil || errors.Is(ctxCauseErr, context.Canceled) { - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventCleanShutdown, - } + s.pushStatus(ctx, SignalWebsocketConnectionEventCleanShutdown, nil) } else { errorCount++ - s.statusChannel <- SignalWebsocketConnectionStatus{ - Event: SignalWebsocketConnectionEventDisconnected, - Err: ctxCauseErr, - } + s.pushStatus(ctx, SignalWebsocketConnectionEventError, ctxCauseErr) } // Clean up From 03d675c465b67b596fa277bff00505031ea048b7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Mar 2025 16:53:21 +0200 Subject: [PATCH 447/718] Bump version to v0.8.1 --- CHANGELOG.md | 5 +++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 22 ++++++++++----------- go.sum | 40 +++++++++++++++++++------------------- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5804dc1..01410df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v0.8.1 (2025-03-16) + +* Added QR refreshing when logging in. +* Updated libsignal to v0.67.4. + # v0.8.0 (2025-02-16) * Bumped minimum Go version to 1.23. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 2cbed46..c97a5d2 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.0", + Version: "0.8.1", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index fd62047..bb606a4 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,10 @@ module go.mau.fi/mautrix-signal go 1.23.0 -toolchain go1.24.0 +toolchain go1.24.1 require ( - github.com/coder/websocket v1.8.12 + github.com/coder/websocket v1.8.13 github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.6-0.20250227184636-7ff63b0b9d95 - golang.org/x/crypto v0.33.0 - golang.org/x/exp v0.0.0-20250215185904-eff6e970281f - golang.org/x/net v0.35.0 + go.mau.fi/util v0.8.6 + golang.org/x/crypto v0.36.0 + golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 + golang.org/x/net v0.37.0 google.golang.org/protobuf v1.36.5 - maunium.net/go/mautrix v0.23.2-0.20250311105500-a6d948f7c2bb + maunium.net/go/mautrix v0.23.2 ) require ( @@ -31,7 +31,7 @@ require ( 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.24 // indirect - github.com/petermattis/goid v0.0.0-20250211185408-f2b9d978cd7a // indirect + github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -41,9 +41,9 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.8 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index ef886d9..1926fed 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 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/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= -github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= +github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -40,8 +40,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20250211185408-f2b9d978cd7a h1:ckxP/kGzsxvxXo8jO6E/0QJ8MMmwI7IRj4Fys9QbAZA= -github.com/petermattis/goid v0.0.0-20250211185408-f2b9d978cd7a/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 h1:E7Kmf11E4K7B5hDti2K2NqPb1nlYlGYsu02S1JNd/Bs= +github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -70,25 +70,25 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -go.mau.fi/util v0.8.6-0.20250227184636-7ff63b0b9d95 h1:5EfVWWjU2Hte9uE6B/hBgvjnVfBx/7SYDZBnsuo+EBs= -go.mau.fi/util v0.8.6-0.20250227184636-7ff63b0b9d95/go.mod h1:Ycug9mrbztlahHPEJ6H5r8Nu/xqZaWbE5vPHVWmfz6M= +go.mau.fi/util v0.8.6 h1:AEK13rfgtiZJL2YsNK+W4ihhYCuukcRom8WPP/w/L54= +go.mau.fi/util v0.8.6/go.mod h1:uNB3UTXFbkpp7xL1M/WvQks90B/L4gvbLpbS0603KOE= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/exp v0.0.0-20250215185904-eff6e970281f h1:oFMYAjX0867ZD2jcNiLBrI9BdpmEkvPyi5YrBGXbamg= -golang.org/x/exp v0.0.0-20250215185904-eff6e970281f/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -100,5 +100,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.23.2-0.20250311105500-a6d948f7c2bb h1:HAKsPqJiBsugs8qOy9mMmASEpmqpJ/Cbc/2Bj6wuNYQ= -maunium.net/go/mautrix v0.23.2-0.20250311105500-a6d948f7c2bb/go.mod h1:IHMaSJh7YIxMrZSDVefS+nLdr3RbeLowsCSa6ibONZ0= +maunium.net/go/mautrix v0.23.2 h1:Bo3tPrQJwkxyL7aMmy/T+d2tqIrypZjHqeHe8fyeAOg= +maunium.net/go/mautrix v0.23.2/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= From c4797ab292a04b23117e73ae70977943bf1a0513 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Mar 2025 16:52:52 +0200 Subject: [PATCH 448/718] dependencies: update mautrix-go --- cmd/mautrix-signal/legacyprovision.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 2 +- pkg/connector/login.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/mautrix-signal/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go index 177d4a5..8bad469 100644 --- a/cmd/mautrix-signal/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -28,8 +28,8 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog" "maunium.net/go/mautrix" - "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/status" "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/pkg/connector" diff --git a/go.mod b/go.mod index bb606a4..7e2044e 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 golang.org/x/net v0.37.0 google.golang.org/protobuf v1.36.5 - maunium.net/go/mautrix v0.23.2 + maunium.net/go/mautrix v0.23.3-0.20250320134109-06f200da0d10 ) require ( diff --git a/go.sum b/go.sum index 1926fed..b049d15 100644 --- a/go.sum +++ b/go.sum @@ -100,5 +100,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.23.2 h1:Bo3tPrQJwkxyL7aMmy/T+d2tqIrypZjHqeHe8fyeAOg= -maunium.net/go/mautrix v0.23.2/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= +maunium.net/go/mautrix v0.23.3-0.20250320134109-06f200da0d10 h1:XE2szxSvJVngk+qHqlKO2fiBZwcAp3oYq+9P5jlAm6w= +maunium.net/go/mautrix v0.23.3-0.20250320134109-06f200da0d10/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 8ffd0e0..7a4d003 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -23,9 +23,9 @@ import ( "github.com/rs/zerolog" "go.mau.fi/util/exsync" - "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/bridgev2/status" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 50ba0ae..15a48c3 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -22,9 +22,9 @@ import ( "time" "github.com/google/uuid" - "maunium.net/go/mautrix/bridge/status" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/status" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" From 833d64a25806680e247d8225fad84dbf1658b948 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Mar 2025 16:53:40 +0200 Subject: [PATCH 449/718] signalmeow/profile: add nil check when fetching expiring credentials --- pkg/signalmeow/profile.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 5182c23..c21fb5f 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -364,6 +364,8 @@ func (cli *Client) FetchExpiringProfileKeyCredentialById(ctx context.Context, si profileKey, err := cli.ProfileKeyForSignalID(ctx, signalACI) if err != nil { return nil, fmt.Errorf("error getting profile key for ACI: %w", err) + } else if profileKey == nil { + return nil, errProfileKeyNotFound } requestContext, err := libsignalgo.CreateProfileKeyCredentialRequestContext( prodServerPublicParams, From 6d621fc2aafcdf079c16380abfcd2b58259df037 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Mar 2025 17:37:53 +0200 Subject: [PATCH 450/718] signalmeow/web: fix error type on disconnects --- pkg/signalmeow/web/signalwebsocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index ac280be..6e625e3 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -334,7 +334,7 @@ func (s *SignalWebsocket) connectLoop( s.pushStatus(ctx, SignalWebsocketConnectionEventCleanShutdown, nil) } else { errorCount++ - s.pushStatus(ctx, SignalWebsocketConnectionEventError, ctxCauseErr) + s.pushStatus(ctx, SignalWebsocketConnectionEventDisconnected, ctxCauseErr) } // Clean up From ebf7e9a60dc7eb124ecc21de91aa723a3094f09c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Mar 2025 12:52:13 +0200 Subject: [PATCH 451/718] signalmeow/web: fix writing to send channel during close --- pkg/signalmeow/web/signalwebsocket.go | 47 ++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 6e625e3..47cc2e3 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -29,6 +29,7 @@ import ( "github.com/coder/websocket" "github.com/rs/zerolog" + "go.mau.fi/util/exsync" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" "go.mau.fi/mautrix-signal/pkg/signalmeow/wspb" @@ -47,6 +48,8 @@ type SignalWebsocket struct { basicAuth *url.Userinfo sendChannel chan SignalWebsocketSendMessage statusChannel chan SignalWebsocketConnectionStatus + closeLock sync.RWMutex + closeEvt *exsync.Event } func NewSignalWebsocket(basicAuth *url.Userinfo) *SignalWebsocket { @@ -54,6 +57,7 @@ func NewSignalWebsocket(basicAuth *url.Userinfo) *SignalWebsocket { basicAuth: basicAuth, sendChannel: make(chan SignalWebsocketSendMessage), statusChannel: make(chan SignalWebsocketConnectionStatus), + closeEvt: exsync.NewEvent(), } } @@ -122,6 +126,22 @@ func (s *SignalWebsocket) pushStatus(ctx context.Context, status SignalWebsocket } } +func (s *SignalWebsocket) pushOutgoing(ctx context.Context, send SignalWebsocketSendMessage) error { + s.closeLock.RLock() + defer s.closeLock.RUnlock() + if s.sendChannel == nil { + return errors.New("connection is not open") + } + select { + case s.sendChannel <- send: + return nil + case <-ctx.Done(): + return ctx.Err() + case <-s.closeEvt.GetChan(): + return errors.New("connection closed before send could be queued") + } +} + func (s *SignalWebsocket) connectLoop( ctx context.Context, requestHandler RequestHandlerFunc, @@ -133,13 +153,17 @@ func (s *SignalWebsocket) connectLoop( incomingRequestChan := make(chan *signalpb.WebSocketRequestMessage, 256) defer func() { + s.closeEvt.Set() + cancel() + + s.closeLock.Lock() + defer s.closeLock.Unlock() close(incomingRequestChan) close(s.statusChannel) close(s.sendChannel) incomingRequestChan = nil s.statusChannel = nil s.sendChannel = nil - cancel() }() const initialBackoff = 2 * time.Second @@ -176,15 +200,16 @@ func (s *SignalWebsocket) connectLoop( if err != nil { log.Err(err).Uint64("request_id", request.GetId()).Msg("Error handling request") - } else if response != nil && s.sendChannel != nil { - s.sendChannel <- SignalWebsocketSendMessage{ + } else if response != nil { + err = s.pushOutgoing(ctx, SignalWebsocketSendMessage{ RequestMessage: request, ResponseMessage: response, + }) + if err != nil { + log.Err(err).Uint64("request_id", request.GetId()).Msg("Error queuing response message") } - } else if response == nil { - log.Warn().Uint64("request_id", request.GetId()).Msg("Request handler didn't return a response nor an error") } else { - log.Warn().Uint64("request_id", request.GetId()).Msg("sendChannel is nil, can't send response") + log.Warn().Uint64("request_id", request.GetId()).Msg("Request handler didn't return a response nor an error") } } } @@ -527,13 +552,13 @@ func (s *SignalWebsocket) sendRequestInternal( request.Headers = append(request.Headers, "authorization:Basic "+s.basicAuth.String()) } responseChannel := make(chan *signalpb.WebSocketResponseMessage, 1) - if s.sendChannel == nil { - return nil, errors.New("Send channel not initialized") - } - s.sendChannel <- SignalWebsocketSendMessage{ + err := s.pushOutgoing(ctx, SignalWebsocketSendMessage{ RequestMessage: request, ResponseChannel: responseChannel, RequestTime: startTime, + }) + if err != nil { + return nil, err } response := <-responseChannel @@ -544,7 +569,7 @@ func (s *SignalWebsocket) sendRequestInternal( if ctx.Err() != nil { return nil, fmt.Errorf("retried 3 times, giving up: %w", ctx.Err()) } else { - return nil, errors.New("Retried 3 times, giving up") + return nil, errors.New("retried 3 times, giving up") } } if ctx.Err() != nil { From 8aaa6f6f7628af3e3fb72e79d4e65119b80a5031 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 9 Apr 2025 15:25:04 +0300 Subject: [PATCH 452/718] signalmeow/profile: lock cache when writing --- pkg/signalmeow/profile.go | 40 +++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index c21fb5f..bbd31f3 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -30,6 +30,7 @@ import ( "io" "net/http" "strings" + "sync" "time" "github.com/google/uuid" @@ -76,6 +77,7 @@ type ProfileCache struct { profiles map[string]*types.Profile errors map[string]*error lastFetched map[string]time.Time + lock sync.RWMutex } func (cli *Client) ProfileKeyCredentialRequest(ctx context.Context, signalACI uuid.UUID) ([]byte, error) { @@ -112,17 +114,9 @@ func (cli *Client) ProfileKeyForSignalID(ctx context.Context, signalACI uuid.UUI var errProfileKeyNotFound = errors.New("profile key not found") -func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) (*types.Profile, error) { - if cli.ProfileCache == nil { - cli.ProfileCache = &ProfileCache{ - profiles: make(map[string]*types.Profile), - errors: make(map[string]*error), - lastFetched: make(map[string]time.Time), - } - } - - // Check if we have a cached profile that is less than an hour old - // or if we have a cached error that is less than an hour old +func (cli *Client) getCachedProfileByID(signalID uuid.UUID) (*types.Profile, error) { + cli.ProfileCache.lock.RLock() + defer cli.ProfileCache.lock.RUnlock() lastFetched, ok := cli.ProfileCache.lastFetched[signalID.String()] if ok && time.Since(lastFetched) < 1*time.Hour { profile, ok := cli.ProfileCache.profiles[signalID.String()] @@ -134,12 +128,32 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) return nil, fmt.Errorf("%w: %w", ErrCachedError, *err) } } + return nil, nil +} + +func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) (*types.Profile, error) { + if cli.ProfileCache == nil { + cli.ProfileCache = &ProfileCache{ + profiles: make(map[string]*types.Profile), + errors: make(map[string]*error), + lastFetched: make(map[string]time.Time), + } + } + + // Check if we have a cached profile that is less than an hour old + // or if we have a cached error that is less than an hour old + profile, err := cli.getCachedProfileByID(signalID) + if err != nil || profile != nil { + return profile, err + } // If we get here, we don't have a cached profile, so fetch it - profile, err := cli.fetchProfileByID(ctx, signalID) + profile, err = cli.fetchProfileByID(ctx, signalID) if err != nil { // If we get a 401 or 5xx error, we should not retry until the cache expires if errors.Is(err, ErrProfileUnauthorized) || errors.Is(err, ErrProfileInternalError) { + cli.ProfileCache.lock.Lock() + defer cli.ProfileCache.lock.Unlock() cli.ProfileCache.errors[signalID.String()] = &err cli.ProfileCache.lastFetched[signalID.String()] = time.Now() } @@ -147,6 +161,8 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) } // If we get here, we have a valid profile, so cache it + cli.ProfileCache.lock.Lock() + defer cli.ProfileCache.lock.Unlock() cli.ProfileCache.profiles[signalID.String()] = profile cli.ProfileCache.lastFetched[signalID.String()] = time.Now() From be83b6133fa1556e623dc57e4cc43ac0a9fe1f3c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 10 Apr 2025 18:30:43 +0300 Subject: [PATCH 453/718] backfill: set stream order for outgoing items (#593) --- pkg/connector/backfill.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pkg/connector/backfill.go b/pkg/connector/backfill.go index ae6d196..2dde03f 100644 --- a/pkg/connector/backfill.go +++ b/pkg/connector/backfill.go @@ -107,17 +107,32 @@ func (s *SignalClient) FetchMessages(ctx context.Context, params bridgev2.FetchM } return uuid.Nil, nil } - for _, item := range items { + var prevStreamOrder int64 + findNextStreamOrder := func(i int) int64 { + for ; i < len(items); i++ { + inc, ok := items[i].DirectionalDetails.(*backuppb.ChatItem_Incoming) + if ok { + return int64(inc.Incoming.GetDateServerSent()) + } + } + return time.Now().UnixMilli() + } + for i, item := range items { var streamOrder int64 switch dt := item.DirectionalDetails.(type) { case *backuppb.ChatItem_Incoming: streamOrder = int64(dt.Incoming.GetDateServerSent()) + prevStreamOrder = streamOrder if !firstDirectionfulProcessed { firstDirectionfulProcessed = true isRead = dt.Incoming.Read } case *backuppb.ChatItem_Outgoing: - // TODO stream order? + streamOrder = int64(item.GetDateSent()) + // Ensure stream order is higher than previous incoming item, but lower than next incoming item + streamOrder = min(streamOrder, findNextStreamOrder(i+1)-1) + streamOrder = max(streamOrder, prevStreamOrder+1) + if !firstDirectionfulProcessed { firstDirectionfulProcessed = true isRead = true From 1a32ce06cc4ff087c885f3eb4f45396809a13eca Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Apr 2025 15:20:37 +0300 Subject: [PATCH 454/718] libsignal: update to v0.70.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 2622 ++++++++++++++++--------------- pkg/libsignalgo/version.go | 2 +- 3 files changed, 1326 insertions(+), 1300 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 7b293c1..efe13e9 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 7b293c19e0c71f204d4596e8f31f95ec993ea080 +Subproject commit efe13e9b363d2c115dba61b76e5e53bbfc2874bc diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 7470062..82f1f7f 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -29,11 +29,6 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalBackupId_LEN 16 -/** - * The encoded length of a [`FourCC`], in bytes. - */ -#define SignalFourCC_ENCODED_LEN 4 - #define SignalNUM_AUTH_CRED_ATTRIBUTES 3 #define SignalNUM_PROFILE_KEY_CRED_ATTRIBUTES 4 @@ -125,6 +120,11 @@ SPDX-License-Identifier: AGPL-3.0-only */ #define SignalSECONDS_PER_DAY 86400 +/** + * The encoded length of a [`FourCC`], in bytes. + */ +#define SignalFourCC_ENCODED_LEN 4 + typedef enum { SignalCiphertextMessageTypeWhisper = 2, SignalCiphertextMessageTypePreKey = 3, @@ -210,6 +210,8 @@ typedef enum { SignalErrorCodeSvrRotationMachineTooManySteps = 162, SignalErrorCodeAppExpired = 170, SignalErrorCodeDeviceDeregistered = 171, + SignalErrorCodeConnectionInvalidated = 172, + SignalErrorCodeConnectedElsewhere = 173, SignalErrorCodeBackupValidation = 180, } SignalErrorCode; @@ -226,6 +228,8 @@ typedef struct SignalAes256GcmSiv SignalAes256GcmSiv; typedef struct SignalAuthenticatedChatConnection SignalAuthenticatedChatConnection; +typedef struct SignalBridgedStringMap SignalBridgedStringMap; + typedef struct SignalCdsiLookup SignalCdsiLookup; typedef struct SignalCiphertextMessage SignalCiphertextMessage; @@ -329,6 +333,165 @@ typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMe typedef struct SignalValidatingMac SignalValidatingMac; +typedef struct { + SignalProtocolAddress *raw; +} SignalMutPointerProtocolAddress; + +typedef struct { + const SignalProtocolAddress *raw; +} SignalConstPointerProtocolAddress; + +typedef struct { + SignalAes256Ctr32 *raw; +} SignalMutPointerAes256Ctr32; + +typedef struct { + const unsigned char *base; + size_t length; +} SignalBorrowedBuffer; + +typedef struct { + unsigned char *base; + size_t length; +} SignalBorrowedMutableBuffer; + +typedef struct { + SignalAes256GcmDecryption *raw; +} SignalMutPointerAes256GcmDecryption; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + unsigned char *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBuffer; + +typedef struct { + SignalAes256GcmEncryption *raw; +} SignalMutPointerAes256GcmEncryption; + +typedef struct { + const SignalAes256GcmSiv *raw; +} SignalConstPointerAes256GcmSiv; + +typedef struct { + SignalAes256GcmSiv *raw; +} SignalMutPointerAes256GcmSiv; + +typedef struct { + SignalAuthenticatedChatConnection *raw; +} SignalMutPointerAuthenticatedChatConnection; + +typedef uint64_t SignalCancellationId; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerAuthenticatedChatConnection *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerAuthenticatedChatConnection; + +typedef struct { + const SignalTokioAsyncContext *raw; +} SignalConstPointerTokioAsyncContext; + +typedef struct { + const SignalConnectionManager *raw; +} SignalConstPointerConnectionManager; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const bool *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromisebool; + +typedef struct { + const SignalAuthenticatedChatConnection *raw; +} SignalConstPointerAuthenticatedChatConnection; + +typedef SignalConnectionInfo SignalChatConnectionInfo; + +typedef struct { + SignalChatConnectionInfo *raw; +} SignalMutPointerChatConnectionInfo; + +typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envelope, uint64_t timestamp_millis, SignalServerMessageAck *cleanup); + +typedef void (*SignalReceivedQueueEmpty)(void *ctx); + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + size_t *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfusize; + +typedef struct { + SignalOwnedBuffer bytes; + SignalOwnedBufferOfusize lengths; +} SignalBytestringArray; + +typedef SignalBytestringArray SignalStringArray; + +typedef void (*SignalReceivedAlerts)(void *ctx, SignalStringArray alerts); + +typedef void (*SignalConnectionInterrupted)(void *ctx, SignalFfiError *error); + +typedef void (*SignalDestroyChatListener)(void *ctx); + +/** + * Callbacks for [`ChatListener`]. + * + * Callbacks will be serialized (i.e. two calls will not come in at the same time), but may not + * always happen on the same thread. Calls should be responded to promptly to avoid blocking later + * messages. + * + * # Safety + * + * This type contains raw pointers. Code that constructs an instance of this type must ensure + * memory safety assuming that + * - the callback function pointer fields are called with `ctx` as an argument; + * - the `destroy` function pointer field is called with `ctx` as an argument; + * - no function pointer fields are called after `destroy` is called. + */ +typedef struct { + void *ctx; + SignalReceivedIncomingMessage received_incoming_message; + SignalReceivedQueueEmpty received_queue_empty; + SignalReceivedAlerts received_alerts; + SignalConnectionInterrupted connection_interrupted; + SignalDestroyChatListener destroy; +} SignalFfiChatListenerStruct; + +typedef struct { + const SignalFfiChatListenerStruct *raw; +} SignalConstPointerFfiChatListenerStruct; + /** * A type alias to be used with [`OwnedBufferOf`], so that `OwnedBufferOf` and * `OwnedBufferOf<*const c_char>` get distinct names. @@ -346,6 +509,55 @@ typedef struct { size_t length; } SignalOwnedBufferOfCStringPtr; +typedef struct { + uint16_t status; + const char *message; + SignalOwnedBufferOfCStringPtr headers; + SignalOwnedBuffer body; +} SignalFfiChatResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiChatResponse; + +typedef struct { + const SignalHttpRequest *raw; +} SignalConstPointerHttpRequest; + +/** + * The fixed-width binary representation of a ServiceId. + * + * Rarely used. The variable-width format that privileges ACIs is preferred. + */ +typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; + +typedef struct { + SignalPrivateKey *raw; +} SignalMutPointerPrivateKey; + +typedef struct { + SignalBridgedStringMap *raw; +} SignalMutPointerBridgedStringMap; + +typedef struct { + const SignalBridgedStringMap *raw; +} SignalConstPointerBridgedStringMap; + +typedef struct { + SignalSgxClientState *raw; +} SignalMutPointerSgxClientState; + typedef struct { /** * Telephone number, as an unformatted e164. @@ -366,64 +578,93 @@ typedef struct { size_t length; } SignalOwnedBufferOfFfiCdsiLookupResponseEntry; -/** - * A representation of a array allocated on the Rust heap for use in C code. - */ typedef struct { - unsigned char *base; - /** - * The number of elements in the buffer (not necessarily the number of bytes). - */ - size_t length; -} SignalOwnedBuffer; + SignalOwnedBufferOfFfiCdsiLookupResponseEntry entries; + int32_t debug_permits_used; +} SignalFfiCdsiLookupResponse; /** - * A representation of a array allocated on the Rust heap for use in C code. + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. */ typedef struct { - size_t *base; - /** - * The number of elements in the buffer (not necessarily the number of bytes). - */ - size_t length; -} SignalOwnedBufferOfusize; + void (*complete)(SignalFfiError *error, const SignalFfiCdsiLookupResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiCdsiLookupResponse; typedef struct { - SignalOwnedBuffer bytes; - SignalOwnedBufferOfusize lengths; -} SignalBytestringArray; + const SignalCdsiLookup *raw; +} SignalConstPointerCdsiLookup; typedef struct { - SignalProtocolAddress *raw; -} SignalMutPointerProtocolAddress; + SignalCdsiLookup *raw; +} SignalMutPointerCdsiLookup; -typedef SignalBytestringArray SignalStringArray; +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerCdsiLookup *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerCdsiLookup; typedef struct { - SignalPrivateKey *raw; -} SignalMutPointerPrivateKey; + const SignalLookupRequest *raw; +} SignalConstPointerLookupRequest; typedef struct { - SignalPublicKey *raw; -} SignalMutPointerPublicKey; + const SignalChatConnectionInfo *raw; +} SignalConstPointerChatConnectionInfo; typedef struct { - const unsigned char *base; - size_t length; -} SignalBorrowedBuffer; + SignalCiphertextMessage *raw; +} SignalMutPointerCiphertextMessage; typedef struct { - const SignalPublicKey *raw; -} SignalConstPointerPublicKey; + const SignalPlaintextContent *raw; +} SignalConstPointerPlaintextContent; + +typedef struct { + const SignalCiphertextMessage *raw; +} SignalConstPointerCiphertextMessage; + +typedef struct { + SignalConnectionInfo *raw; +} SignalMutPointerConnectionInfo; + +typedef struct { + SignalConnectionManager *raw; +} SignalMutPointerConnectionManager; + +typedef struct { + const SignalConnectionProxyConfig *raw; +} SignalConstPointerConnectionProxyConfig; + +typedef struct { + SignalConnectionProxyConfig *raw; +} SignalMutPointerConnectionProxyConfig; + +typedef struct { + const SignalMessage *raw; +} SignalConstPointerSignalMessage; typedef struct { SignalSessionRecord *raw; } SignalMutPointerSessionRecord; -typedef struct { - const SignalProtocolAddress *raw; -} SignalConstPointerProtocolAddress; - typedef int (*SignalLoadSession)(void *store_ctx, SignalMutPointerSessionRecord *recordp, SignalConstPointerProtocolAddress address); typedef struct { @@ -446,8 +687,16 @@ typedef int (*SignalGetIdentityKeyPair)(void *store_ctx, SignalMutPointerPrivate typedef int (*SignalGetLocalRegistrationId)(void *store_ctx, uint32_t *idp); +typedef struct { + const SignalPublicKey *raw; +} SignalConstPointerPublicKey; + typedef int (*SignalSaveIdentityKey)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerPublicKey public_key); +typedef struct { + SignalPublicKey *raw; +} SignalMutPointerPublicKey; + typedef int (*SignalGetIdentityKey)(void *store_ctx, SignalMutPointerPublicKey *public_keyp, SignalConstPointerProtocolAddress address); typedef int (*SignalIsTrustedIdentity)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerPublicKey public_key, unsigned int direction); @@ -465,6 +714,10 @@ typedef struct { const SignalIdentityKeyStore *raw; } SignalConstPointerFfiIdentityKeyStoreStruct; +typedef struct { + const SignalPreKeySignalMessage *raw; +} SignalConstPointerPreKeySignalMessage; + typedef struct { SignalPreKeyRecord *raw; } SignalMutPointerPreKeyRecord; @@ -512,44 +765,30 @@ typedef struct { const SignalSignedPreKeyStore *raw; } SignalConstPointerFfiSignedPreKeyStoreStruct; -typedef void (*SignalLogCallback)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); +typedef struct { + SignalKyberPreKeyRecord *raw; +} SignalMutPointerKyberPreKeyRecord; -typedef void (*SignalLogFlushCallback)(void *ctx); +typedef int (*SignalLoadKyberPreKey)(void *store_ctx, SignalMutPointerKyberPreKeyRecord *recordp, uint32_t id); + +typedef struct { + const SignalKyberPreKeyRecord *raw; +} SignalConstPointerKyberPreKeyRecord; + +typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, SignalConstPointerKyberPreKeyRecord record); + +typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id); typedef struct { void *ctx; - SignalLogCallback log; - SignalLogFlushCallback flush; -} SignalFfiLogger; + SignalLoadKyberPreKey load_kyber_pre_key; + SignalStoreKyberPreKey store_kyber_pre_key; + SignalMarkKyberPreKeyUsed mark_kyber_pre_key_used; +} SignalKyberPreKeyStore; typedef struct { - SignalAes256GcmSiv *raw; -} SignalMutPointerAes256GcmSiv; - -typedef struct { - SignalAes256Ctr32 *raw; -} SignalMutPointerAes256Ctr32; - -typedef struct { - SignalAes256GcmEncryption *raw; -} SignalMutPointerAes256GcmEncryption; - -typedef struct { - SignalAes256GcmDecryption *raw; -} SignalMutPointerAes256GcmDecryption; - -typedef struct { - unsigned char *base; - size_t length; -} SignalBorrowedMutableBuffer; - -typedef struct { - const SignalAes256GcmSiv *raw; -} SignalConstPointerAes256GcmSiv; - -typedef struct { - SignalCiphertextMessage *raw; -} SignalMutPointerCiphertextMessage; + const SignalKyberPreKeyStore *raw; +} SignalConstPointerFfiKyberPreKeyStoreStruct; typedef struct { SignalDecryptionErrorMessage *raw; @@ -568,92 +807,69 @@ typedef struct { } SignalConstPointerFingerprint; typedef struct { - SignalPlaintextContent *raw; -} SignalMutPointerPlaintextContent; + SignalSenderKeyRecord *raw; +} SignalMutPointerSenderKeyRecord; + +typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalMutPointerSenderKeyRecord*, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16]); typedef struct { - const SignalPlaintextContent *raw; -} SignalConstPointerPlaintextContent; + const SignalSenderKeyRecord *raw; +} SignalConstPointerSenderKeyRecord; + +typedef int (*SignalStoreSenderKey)(void *store_ctx, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16], SignalConstPointerSenderKeyRecord); typedef struct { - SignalPreKeyBundle *raw; -} SignalMutPointerPreKeyBundle; + void *ctx; + SignalLoadSenderKey load_sender_key; + SignalStoreSenderKey store_sender_key; +} SignalSenderKeyStore; typedef struct { - const SignalPreKeyBundle *raw; -} SignalConstPointerPreKeyBundle; + const SignalSenderKeyStore *raw; +} SignalConstPointerFfiSenderKeyStoreStruct; typedef struct { - SignalPreKeySignalMessage *raw; -} SignalMutPointerPreKeySignalMessage; + const SignalServerSecretParams *raw; +} SignalConstPointerServerSecretParams; typedef struct { - const SignalPreKeySignalMessage *raw; -} SignalConstPointerPreKeySignalMessage; + const SignalBorrowedBuffer *base; + size_t length; +} SignalBorrowedSliceOfBuffers; + +typedef struct { + const SignalServerPublicParams *raw; +} SignalConstPointerServerPublicParams; + +typedef struct { + SignalHsmEnclaveClient *raw; +} SignalMutPointerHsmEnclaveClient; + +typedef struct { + const SignalHsmEnclaveClient *raw; +} SignalConstPointerHsmEnclaveClient; + +typedef struct { + SignalHttpRequest *raw; +} SignalMutPointerHttpRequest; typedef struct { const SignalPrivateKey *raw; } SignalConstPointerPrivateKey; typedef struct { - SignalSenderCertificate *raw; -} SignalMutPointerSenderCertificate; + SignalIncrementalMac *raw; +} SignalMutPointerIncrementalMac; + +typedef void (*SignalLogCallback)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); + +typedef void (*SignalLogFlushCallback)(void *ctx); typedef struct { - const SignalSenderCertificate *raw; -} SignalConstPointerSenderCertificate; - -typedef struct { - SignalSenderKeyDistributionMessage *raw; -} SignalMutPointerSenderKeyDistributionMessage; - -typedef struct { - const SignalSenderKeyDistributionMessage *raw; -} SignalConstPointerSenderKeyDistributionMessage; - -typedef struct { - SignalSenderKeyMessage *raw; -} SignalMutPointerSenderKeyMessage; - -typedef struct { - const SignalSenderKeyMessage *raw; -} SignalConstPointerSenderKeyMessage; - -typedef struct { - SignalSenderKeyRecord *raw; -} SignalMutPointerSenderKeyRecord; - -typedef struct { - const SignalSenderKeyRecord *raw; -} SignalConstPointerSenderKeyRecord; - -typedef struct { - SignalServerCertificate *raw; -} SignalMutPointerServerCertificate; - -typedef struct { - const SignalServerCertificate *raw; -} SignalConstPointerServerCertificate; - -typedef struct { - SignalMessage *raw; -} SignalMutPointerSignalMessage; - -typedef struct { - const SignalMessage *raw; -} SignalConstPointerSignalMessage; - -typedef struct { - SignalKyberPreKeyRecord *raw; -} SignalMutPointerKyberPreKeyRecord; - -typedef struct { - const SignalKyberPreKeyRecord *raw; -} SignalConstPointerKyberPreKeyRecord; - -typedef struct { - SignalUnidentifiedSenderMessageContent *raw; -} SignalMutPointerUnidentifiedSenderMessageContent; + void *ctx; + SignalLogCallback log; + SignalLogFlushCallback flush; +} SignalFfiLogger; typedef SignalKeyPair SignalKyberKeyPair; @@ -671,10 +887,6 @@ typedef struct { SignalKyberPublicKey *raw; } SignalMutPointerKyberPublicKey; -typedef struct { - const SignalKyberPublicKey *raw; -} SignalConstPointerKyberPublicKey; - /** * A KEM secret key with the ability to decapsulate a shared secret. */ @@ -686,359 +898,30 @@ typedef struct { SignalKyberSecretKey *raw; } SignalMutPointerKyberSecretKey; +typedef struct { + const SignalKyberPublicKey *raw; +} SignalConstPointerKyberPublicKey; + typedef struct { const SignalKyberSecretKey *raw; } SignalConstPointerKyberSecretKey; -/** - * The fixed-width binary representation of a ServiceId. - * - * Rarely used. The variable-width format that privileges ACIs is preferred. - */ -typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; - -typedef struct { - const SignalUnidentifiedSenderMessageContent *raw; -} SignalConstPointerUnidentifiedSenderMessageContent; - -typedef struct { - const SignalCiphertextMessage *raw; -} SignalConstPointerCiphertextMessage; - -typedef int (*SignalLoadKyberPreKey)(void *store_ctx, SignalMutPointerKyberPreKeyRecord *recordp, uint32_t id); - -typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, SignalConstPointerKyberPreKeyRecord record); - -typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id); - -typedef struct { - void *ctx; - SignalLoadKyberPreKey load_kyber_pre_key; - SignalStoreKyberPreKey store_kyber_pre_key; - SignalMarkKyberPreKeyUsed mark_kyber_pre_key_used; -} SignalKyberPreKeyStore; - -typedef struct { - const SignalKyberPreKeyStore *raw; -} SignalConstPointerFfiKyberPreKeyStoreStruct; - -typedef struct { - const SignalConstPointerProtocolAddress *base; - size_t length; -} SignalBorrowedSliceOfConstPointerProtocolAddress; - -typedef struct { - const SignalConstPointerSessionRecord *base; - size_t length; -} SignalBorrowedSliceOfConstPointerSessionRecord; - -typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalMutPointerSenderKeyRecord*, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16]); - -typedef int (*SignalStoreSenderKey)(void *store_ctx, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16], SignalConstPointerSenderKeyRecord); - -typedef struct { - void *ctx; - SignalLoadSenderKey load_sender_key; - SignalStoreSenderKey store_sender_key; -} SignalSenderKeyStore; - -typedef struct { - const SignalSenderKeyStore *raw; -} SignalConstPointerFfiSenderKeyStoreStruct; - -typedef struct { - SignalSgxClientState *raw; -} SignalMutPointerSgxClientState; - -typedef struct { - SignalHsmEnclaveClient *raw; -} SignalMutPointerHsmEnclaveClient; - -typedef struct { - const SignalHsmEnclaveClient *raw; -} SignalConstPointerHsmEnclaveClient; - -typedef struct { - const SignalSgxClientState *raw; -} SignalConstPointerSgxClientState; - -typedef struct { - SignalServerPublicParams *raw; -} SignalMutPointerServerPublicParams; - -typedef struct { - const SignalServerPublicParams *raw; -} SignalConstPointerServerPublicParams; - -typedef struct { - SignalServerSecretParams *raw; -} SignalMutPointerServerSecretParams; - -typedef struct { - const SignalServerSecretParams *raw; -} SignalConstPointerServerSecretParams; - -typedef struct { - const SignalBorrowedBuffer *base; - size_t length; -} SignalBorrowedSliceOfBuffers; - -typedef struct { - SignalConnectionInfo *raw; -} SignalMutPointerConnectionInfo; - -typedef struct { - SignalConnectionProxyConfig *raw; -} SignalMutPointerConnectionProxyConfig; - -typedef struct { - const SignalConnectionProxyConfig *raw; -} SignalConstPointerConnectionProxyConfig; - -typedef struct { - SignalConnectionManager *raw; -} SignalMutPointerConnectionManager; - -typedef struct { - const SignalConnectionManager *raw; -} SignalConstPointerConnectionManager; - typedef struct { SignalLookupRequest *raw; } SignalMutPointerLookupRequest; -typedef struct { - const SignalLookupRequest *raw; -} SignalConstPointerLookupRequest; - -typedef struct { - SignalCdsiLookup *raw; -} SignalMutPointerCdsiLookup; - -typedef uint64_t SignalCancellationId; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalMutPointerCdsiLookup *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseMutPointerCdsiLookup; - -typedef struct { - const SignalTokioAsyncContext *raw; -} SignalConstPointerTokioAsyncContext; - -typedef struct { - const SignalCdsiLookup *raw; -} SignalConstPointerCdsiLookup; - -typedef struct { - SignalOwnedBufferOfFfiCdsiLookupResponseEntry entries; - int32_t debug_permits_used; -} SignalFfiCdsiLookupResponse; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiCdsiLookupResponse *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseFfiCdsiLookupResponse; - -typedef struct { - SignalHttpRequest *raw; -} SignalMutPointerHttpRequest; - -typedef struct { - SignalUnauthenticatedChatConnection *raw; -} SignalMutPointerUnauthenticatedChatConnection; - -typedef struct { - SignalAuthenticatedChatConnection *raw; -} SignalMutPointerAuthenticatedChatConnection; - -typedef struct { - const SignalHttpRequest *raw; -} SignalConstPointerHttpRequest; - -typedef SignalConnectionInfo SignalChatConnectionInfo; - -typedef struct { - const SignalChatConnectionInfo *raw; -} SignalConstPointerChatConnectionInfo; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalMutPointerUnauthenticatedChatConnection *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseMutPointerUnauthenticatedChatConnection; - -typedef struct { - const SignalUnauthenticatedChatConnection *raw; -} SignalConstPointerUnauthenticatedChatConnection; - -typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envelope, uint64_t timestamp_millis, SignalServerMessageAck *cleanup); - -typedef void (*SignalReceivedQueueEmpty)(void *ctx); - -typedef void (*SignalReceivedAlerts)(void *ctx, SignalStringArray alerts); - -typedef void (*SignalConnectionInterrupted)(void *ctx, SignalFfiError *error); - -typedef void (*SignalDestroyChatListener)(void *ctx); - -/** - * Callbacks for [`ChatListener`]. - * - * Callbacks will be serialized (i.e. two calls will not come in at the same time), but may not - * always happen on the same thread. Calls should be responded to promptly to avoid blocking later - * messages. - * - * # Safety - * - * This type contains raw pointers. Code that constructs an instance of this type must ensure - * memory safety assuming that - * - the callback function pointer fields are called with `ctx` as an argument; - * - the `destroy` function pointer field is called with `ctx` as an argument; - * - no function pointer fields are called after `destroy` is called. - */ -typedef struct { - void *ctx; - SignalReceivedIncomingMessage received_incoming_message; - SignalReceivedQueueEmpty received_queue_empty; - SignalReceivedAlerts received_alerts; - SignalConnectionInterrupted connection_interrupted; - SignalDestroyChatListener destroy; -} SignalFfiChatListenerStruct; - -typedef struct { - const SignalFfiChatListenerStruct *raw; -} SignalConstPointerFfiChatListenerStruct; - -typedef struct { - uint16_t status; - const char *message; - SignalOwnedBufferOfCStringPtr headers; - SignalOwnedBuffer body; -} SignalFfiChatResponse; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalFfiChatResponse *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseFfiChatResponse; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const bool *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromisebool; - -typedef struct { - SignalChatConnectionInfo *raw; -} SignalMutPointerChatConnectionInfo; - -/** - * A C callback used to report the results of Rust futures. - * - * cbindgen will produce independent C types like `SignalCPromisei32` and - * `SignalCPromiseProtocolAddress`. - * - * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be - * completed once. - */ -typedef struct { - void (*complete)(SignalFfiError *error, const SignalMutPointerAuthenticatedChatConnection *result, const void *context); - const void *context; - SignalCancellationId cancellation_id; -} SignalCPromiseMutPointerAuthenticatedChatConnection; - -typedef struct { - const SignalAuthenticatedChatConnection *raw; -} SignalConstPointerAuthenticatedChatConnection; - -typedef struct { - SignalServerMessageAck *raw; -} SignalMutPointerServerMessageAck; - -typedef struct { - const SignalServerMessageAck *raw; -} SignalConstPointerServerMessageAck; - -typedef struct { - SignalTokioAsyncContext *raw; -} SignalMutPointerTokioAsyncContext; - -typedef struct { - SignalPinHash *raw; -} SignalMutPointerPinHash; - -typedef struct { - const SignalPinHash *raw; -} SignalConstPointerPinHash; - -typedef struct { - SignalIncrementalMac *raw; -} SignalMutPointerIncrementalMac; - -typedef struct { - SignalValidatingMac *raw; -} SignalMutPointerValidatingMac; - typedef struct { SignalMessageBackupKey *raw; } SignalMutPointerMessageBackupKey; -typedef struct { - SignalMessageBackupValidationOutcome *raw; -} SignalMutPointerMessageBackupValidationOutcome; - typedef struct { const SignalMessageBackupKey *raw; } SignalConstPointerMessageBackupKey; +typedef struct { + SignalMessageBackupValidationOutcome *raw; +} SignalMutPointerMessageBackupValidationOutcome; + typedef struct { const SignalMessageBackupValidationOutcome *raw; } SignalConstPointerMessageBackupValidationOutcome; @@ -1058,17 +941,146 @@ typedef struct { } SignalConstPointerFfiInputStreamStruct; typedef struct { - SignalOnlineBackupValidator *raw; -} SignalMutPointerOnlineBackupValidator; + SignalMessage *raw; +} SignalMutPointerSignalMessage; typedef struct { SignalSanitizedMetadata *raw; } SignalMutPointerSanitizedMetadata; +typedef struct { + SignalOnlineBackupValidator *raw; +} SignalMutPointerOnlineBackupValidator; + +typedef struct { + const SignalPinHash *raw; +} SignalConstPointerPinHash; + +typedef struct { + SignalPinHash *raw; +} SignalMutPointerPinHash; + +typedef struct { + SignalPlaintextContent *raw; +} SignalMutPointerPlaintextContent; + +typedef struct { + SignalPreKeyBundle *raw; +} SignalMutPointerPreKeyBundle; + +typedef struct { + const SignalPreKeyBundle *raw; +} SignalConstPointerPreKeyBundle; + +typedef struct { + SignalPreKeySignalMessage *raw; +} SignalMutPointerPreKeySignalMessage; + +typedef struct { + const SignalSenderKeyDistributionMessage *raw; +} SignalConstPointerSenderKeyDistributionMessage; + typedef struct { const SignalSanitizedMetadata *raw; } SignalConstPointerSanitizedMetadata; +typedef struct { + const SignalConstPointerProtocolAddress *base; + size_t length; +} SignalBorrowedSliceOfConstPointerProtocolAddress; + +typedef struct { + const SignalConstPointerSessionRecord *base; + size_t length; +} SignalBorrowedSliceOfConstPointerSessionRecord; + +typedef struct { + const SignalUnidentifiedSenderMessageContent *raw; +} SignalConstPointerUnidentifiedSenderMessageContent; + +typedef struct { + SignalUnidentifiedSenderMessageContent *raw; +} SignalMutPointerUnidentifiedSenderMessageContent; + +typedef struct { + SignalSenderCertificate *raw; +} SignalMutPointerSenderCertificate; + +typedef struct { + const SignalSenderCertificate *raw; +} SignalConstPointerSenderCertificate; + +typedef struct { + SignalServerCertificate *raw; +} SignalMutPointerServerCertificate; + +typedef struct { + const SignalServerCertificate *raw; +} SignalConstPointerServerCertificate; + +typedef struct { + SignalSenderKeyDistributionMessage *raw; +} SignalMutPointerSenderKeyDistributionMessage; + +typedef struct { + SignalSenderKeyMessage *raw; +} SignalMutPointerSenderKeyMessage; + +typedef struct { + const SignalSenderKeyMessage *raw; +} SignalConstPointerSenderKeyMessage; + +typedef struct { + SignalServerMessageAck *raw; +} SignalMutPointerServerMessageAck; + +typedef struct { + const SignalServerMessageAck *raw; +} SignalConstPointerServerMessageAck; + +typedef struct { + SignalServerPublicParams *raw; +} SignalMutPointerServerPublicParams; + +typedef struct { + SignalServerSecretParams *raw; +} SignalMutPointerServerSecretParams; + +typedef struct { + const SignalSgxClientState *raw; +} SignalConstPointerSgxClientState; + +typedef struct { + SignalTokioAsyncContext *raw; +} SignalMutPointerTokioAsyncContext; + +typedef struct { + SignalUnauthenticatedChatConnection *raw; +} SignalMutPointerUnauthenticatedChatConnection; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerUnauthenticatedChatConnection *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerUnauthenticatedChatConnection; + +typedef struct { + const SignalUnauthenticatedChatConnection *raw; +} SignalConstPointerUnauthenticatedChatConnection; + +typedef struct { + SignalValidatingMac *raw; +} SignalMutPointerValidatingMac; + typedef SignalInputStream SignalSyncInputStream; typedef struct { @@ -1077,57 +1089,31 @@ typedef struct { typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN]; -void signal_print_ptr(const void *p); +SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy); -void signal_free_string(const char *buf); +SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy); -void signal_free_buffer(const unsigned char *buf, size_t buf_len); +SignalFfiError *signal_account_entropy_pool_generate(const char **out); -void signal_free_list_of_strings(SignalOwnedBufferOfCStringPtr buffer); +SignalFfiError *signal_account_entropy_pool_is_valid(bool *out, const char *account_entropy); -void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); +SignalFfiError *signal_address_clone(SignalMutPointerProtocolAddress *new_obj, SignalConstPointerProtocolAddress obj); -void signal_free_bytestring_array(SignalBytestringArray array); +SignalFfiError *signal_address_destroy(SignalMutPointerProtocolAddress p); -SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); +SignalFfiError *signal_address_get_device_id(uint32_t *out, SignalConstPointerProtocolAddress obj); -SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalMutPointerProtocolAddress *out); +SignalFfiError *signal_address_get_name(const char **out, SignalConstPointerProtocolAddress obj); -SignalFfiError *signal_error_get_uuid(const SignalFfiError *err, uint8_t (*out)[16]); - -uint32_t signal_error_get_type(const SignalFfiError *err); - -SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); - -SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); - -SignalFfiError *signal_error_get_unknown_fields(const SignalFfiError *err, SignalStringArray *out); - -void signal_error_free(SignalFfiError *err); - -SignalFfiError *signal_identitykeypair_deserialize(SignalMutPointerPrivateKey *private_key, SignalMutPointerPublicKey *public_key, SignalBorrowedBuffer input); - -SignalFfiError *signal_sealed_session_cipher_decrypt(SignalOwnedBuffer *out, const char **sender_e164, const char **sender_uuid, uint32_t *sender_device_id, SignalBorrowedBuffer ctext, SignalConstPointerPublicKey trust_root, uint64_t timestamp, const char *local_e164, const char *local_uuid, unsigned int local_device_id, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store); - -bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); - -SignalFfiError *signal_aes256_gcm_siv_destroy(SignalMutPointerAes256GcmSiv p); +SignalFfiError *signal_address_new(SignalMutPointerProtocolAddress *out, const char *name, uint32_t device_id); SignalFfiError *signal_aes256_ctr32_destroy(SignalMutPointerAes256Ctr32 p); -SignalFfiError *signal_aes256_gcm_encryption_destroy(SignalMutPointerAes256GcmEncryption p); - -SignalFfiError *signal_aes256_gcm_decryption_destroy(SignalMutPointerAes256GcmDecryption p); - SignalFfiError *signal_aes256_ctr32_new(SignalMutPointerAes256Ctr32 *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, uint32_t initial_ctr); SignalFfiError *signal_aes256_ctr32_process(SignalMutPointerAes256Ctr32 ctr, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); -SignalFfiError *signal_aes256_gcm_encryption_new(SignalMutPointerAes256GcmEncryption *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); - -SignalFfiError *signal_aes256_gcm_encryption_update(SignalMutPointerAes256GcmEncryption gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); - -SignalFfiError *signal_aes256_gcm_encryption_compute_tag(SignalOwnedBuffer *out, SignalMutPointerAes256GcmEncryption gcm); +SignalFfiError *signal_aes256_gcm_decryption_destroy(SignalMutPointerAes256GcmDecryption p); SignalFfiError *signal_aes256_gcm_decryption_new(SignalMutPointerAes256GcmDecryption *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); @@ -1135,677 +1121,47 @@ SignalFfiError *signal_aes256_gcm_decryption_update(SignalMutPointerAes256GcmDec SignalFfiError *signal_aes256_gcm_decryption_verify_tag(bool *out, SignalMutPointerAes256GcmDecryption gcm, SignalBorrowedBuffer tag); -SignalFfiError *signal_aes256_gcm_siv_new(SignalMutPointerAes256GcmSiv *out, SignalBorrowedBuffer key); +SignalFfiError *signal_aes256_gcm_encryption_compute_tag(SignalOwnedBuffer *out, SignalMutPointerAes256GcmEncryption gcm); -SignalFfiError *signal_aes256_gcm_siv_encrypt(SignalOwnedBuffer *out, SignalConstPointerAes256GcmSiv aes_gcm_siv_obj, SignalBorrowedBuffer ptext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); +SignalFfiError *signal_aes256_gcm_encryption_destroy(SignalMutPointerAes256GcmEncryption p); + +SignalFfiError *signal_aes256_gcm_encryption_new(SignalMutPointerAes256GcmEncryption *out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); + +SignalFfiError *signal_aes256_gcm_encryption_update(SignalMutPointerAes256GcmEncryption gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length); SignalFfiError *signal_aes256_gcm_siv_decrypt(SignalOwnedBuffer *out, SignalConstPointerAes256GcmSiv aes_gcm_siv, SignalBorrowedBuffer ctext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); -SignalFfiError *signal_ciphertext_message_destroy(SignalMutPointerCiphertextMessage p); +SignalFfiError *signal_aes256_gcm_siv_destroy(SignalMutPointerAes256GcmSiv p); -SignalFfiError *signal_decryption_error_message_destroy(SignalMutPointerDecryptionErrorMessage p); +SignalFfiError *signal_aes256_gcm_siv_encrypt(SignalOwnedBuffer *out, SignalConstPointerAes256GcmSiv aes_gcm_siv_obj, SignalBorrowedBuffer ptext, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data); -SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); - -SignalFfiError *signal_fingerprint_destroy(SignalMutPointerFingerprint p); - -SignalFfiError *signal_fingerprint_clone(SignalMutPointerFingerprint *new_obj, SignalConstPointerFingerprint obj); - -SignalFfiError *signal_plaintext_content_destroy(SignalMutPointerPlaintextContent p); - -SignalFfiError *signal_plaintext_content_clone(SignalMutPointerPlaintextContent *new_obj, SignalConstPointerPlaintextContent obj); - -SignalFfiError *signal_pre_key_bundle_destroy(SignalMutPointerPreKeyBundle p); - -SignalFfiError *signal_pre_key_bundle_clone(SignalMutPointerPreKeyBundle *new_obj, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_record_destroy(SignalMutPointerPreKeyRecord p); - -SignalFfiError *signal_pre_key_record_clone(SignalMutPointerPreKeyRecord *new_obj, SignalConstPointerPreKeyRecord obj); - -SignalFfiError *signal_pre_key_signal_message_destroy(SignalMutPointerPreKeySignalMessage p); - -SignalFfiError *signal_pre_key_signal_message_clone(SignalMutPointerPreKeySignalMessage *new_obj, SignalConstPointerPreKeySignalMessage obj); - -SignalFfiError *signal_privatekey_destroy(SignalMutPointerPrivateKey p); - -SignalFfiError *signal_privatekey_clone(SignalMutPointerPrivateKey *new_obj, SignalConstPointerPrivateKey obj); - -SignalFfiError *signal_address_destroy(SignalMutPointerProtocolAddress p); - -SignalFfiError *signal_address_clone(SignalMutPointerProtocolAddress *new_obj, SignalConstPointerProtocolAddress obj); - -SignalFfiError *signal_publickey_destroy(SignalMutPointerPublicKey p); - -SignalFfiError *signal_publickey_clone(SignalMutPointerPublicKey *new_obj, SignalConstPointerPublicKey obj); - -SignalFfiError *signal_sender_certificate_destroy(SignalMutPointerSenderCertificate p); - -SignalFfiError *signal_sender_certificate_clone(SignalMutPointerSenderCertificate *new_obj, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_key_distribution_message_destroy(SignalMutPointerSenderKeyDistributionMessage p); - -SignalFfiError *signal_sender_key_distribution_message_clone(SignalMutPointerSenderKeyDistributionMessage *new_obj, SignalConstPointerSenderKeyDistributionMessage obj); - -SignalFfiError *signal_sender_key_message_destroy(SignalMutPointerSenderKeyMessage p); - -SignalFfiError *signal_sender_key_message_clone(SignalMutPointerSenderKeyMessage *new_obj, SignalConstPointerSenderKeyMessage obj); - -SignalFfiError *signal_sender_key_record_destroy(SignalMutPointerSenderKeyRecord p); - -SignalFfiError *signal_sender_key_record_clone(SignalMutPointerSenderKeyRecord *new_obj, SignalConstPointerSenderKeyRecord obj); - -SignalFfiError *signal_server_certificate_destroy(SignalMutPointerServerCertificate p); - -SignalFfiError *signal_server_certificate_clone(SignalMutPointerServerCertificate *new_obj, SignalConstPointerServerCertificate obj); - -SignalFfiError *signal_session_record_destroy(SignalMutPointerSessionRecord p); - -SignalFfiError *signal_session_record_clone(SignalMutPointerSessionRecord *new_obj, SignalConstPointerSessionRecord obj); - -SignalFfiError *signal_message_destroy(SignalMutPointerSignalMessage p); - -SignalFfiError *signal_message_clone(SignalMutPointerSignalMessage *new_obj, SignalConstPointerSignalMessage obj); - -SignalFfiError *signal_signed_pre_key_record_destroy(SignalMutPointerSignedPreKeyRecord p); - -SignalFfiError *signal_signed_pre_key_record_clone(SignalMutPointerSignedPreKeyRecord *new_obj, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_destroy(SignalMutPointerKyberPreKeyRecord p); - -SignalFfiError *signal_kyber_pre_key_record_clone(SignalMutPointerKyberPreKeyRecord *new_obj, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_unidentified_sender_message_content_destroy(SignalMutPointerUnidentifiedSenderMessageContent p); - -SignalFfiError *signal_kyber_key_pair_destroy(SignalMutPointerKyberKeyPair p); - -SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj); - -SignalFfiError *signal_kyber_public_key_destroy(SignalMutPointerKyberPublicKey p); - -SignalFfiError *signal_kyber_public_key_clone(SignalMutPointerKyberPublicKey *new_obj, SignalConstPointerKyberPublicKey obj); - -SignalFfiError *signal_kyber_secret_key_destroy(SignalMutPointerKyberSecretKey p); - -SignalFfiError *signal_kyber_secret_key_clone(SignalMutPointerKyberSecretKey *new_obj, SignalConstPointerKyberSecretKey obj); - -SignalFfiError *signal_hkdf_derive(SignalBorrowedMutableBuffer output, SignalBorrowedBuffer ikm, SignalBorrowedBuffer label, SignalBorrowedBuffer salt); - -SignalFfiError *signal_service_id_service_id_binary(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *value); - -SignalFfiError *signal_service_id_service_id_string(const char **out, const SignalServiceIdFixedWidthBinaryBytes *value); - -SignalFfiError *signal_service_id_service_id_log(const char **out, const SignalServiceIdFixedWidthBinaryBytes *value); - -SignalFfiError *signal_service_id_parse_from_service_id_binary(SignalServiceIdFixedWidthBinaryBytes *out, SignalBorrowedBuffer input); - -SignalFfiError *signal_service_id_parse_from_service_id_string(SignalServiceIdFixedWidthBinaryBytes *out, const char *input); - -SignalFfiError *signal_address_new(SignalMutPointerProtocolAddress *out, const char *name, uint32_t device_id); - -SignalFfiError *signal_publickey_deserialize(SignalMutPointerPublicKey *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_publickey_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); - -SignalFfiError *signal_publickey_get_public_key_bytes(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); - -SignalFfiError *signal_address_get_device_id(uint32_t *out, SignalConstPointerProtocolAddress obj); - -SignalFfiError *signal_address_get_name(const char **out, SignalConstPointerProtocolAddress obj); - -SignalFfiError *signal_publickey_equals(bool *out, SignalConstPointerPublicKey lhs, SignalConstPointerPublicKey rhs); - -SignalFfiError *signal_publickey_compare(int32_t *out, SignalConstPointerPublicKey key1, SignalConstPointerPublicKey key2); - -SignalFfiError *signal_publickey_verify(bool *out, SignalConstPointerPublicKey key, SignalBorrowedBuffer message, SignalBorrowedBuffer signature); - -SignalFfiError *signal_privatekey_deserialize(SignalMutPointerPrivateKey *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstPointerPrivateKey obj); - -SignalFfiError *signal_privatekey_generate(SignalMutPointerPrivateKey *out); - -SignalFfiError *signal_privatekey_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPrivateKey k); - -SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); - -SignalFfiError *signal_privatekey_agree(SignalOwnedBuffer *out, SignalConstPointerPrivateKey private_key, SignalConstPointerPublicKey public_key); - -SignalFfiError *signal_kyber_public_key_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberPublicKey obj); - -SignalFfiError *signal_kyber_public_key_deserialize(SignalMutPointerKyberPublicKey *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_kyber_secret_key_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberSecretKey obj); - -SignalFfiError *signal_kyber_secret_key_deserialize(SignalMutPointerKyberSecretKey *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_kyber_public_key_equals(bool *out, SignalConstPointerKyberPublicKey lhs, SignalConstPointerKyberPublicKey rhs); - -SignalFfiError *signal_kyber_key_pair_generate(SignalMutPointerKyberKeyPair *out); - -SignalFfiError *signal_kyber_key_pair_get_public_key(SignalMutPointerKyberPublicKey *out, SignalConstPointerKyberKeyPair key_pair); - -SignalFfiError *signal_kyber_key_pair_get_secret_key(SignalMutPointerKyberSecretKey *out, SignalConstPointerKyberKeyPair key_pair); - -SignalFfiError *signal_identitykeypair_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key); - -SignalFfiError *signal_identitykeypair_sign_alternate_identity(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key, SignalConstPointerPublicKey other_identity); - -SignalFfiError *signal_identitykey_verify_alternate_identity(bool *out, SignalConstPointerPublicKey public_key, SignalConstPointerPublicKey other_identity, SignalBorrowedBuffer signature); - -SignalFfiError *signal_fingerprint_new(SignalMutPointerFingerprint *out, uint32_t iterations, uint32_t version, SignalBorrowedBuffer local_identifier, SignalConstPointerPublicKey local_key, SignalBorrowedBuffer remote_identifier, SignalConstPointerPublicKey remote_key); - -SignalFfiError *signal_fingerprint_scannable_encoding(SignalOwnedBuffer *out, SignalConstPointerFingerprint obj); - -SignalFfiError *signal_fingerprint_display_string(const char **out, SignalConstPointerFingerprint obj); - -SignalFfiError *signal_fingerprint_compare(bool *out, SignalBorrowedBuffer fprint1, SignalBorrowedBuffer fprint2); - -SignalFfiError *signal_message_deserialize(SignalMutPointerSignalMessage *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_message_get_body(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); - -SignalFfiError *signal_message_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); - -SignalFfiError *signal_message_get_counter(uint32_t *out, SignalConstPointerSignalMessage obj); - -SignalFfiError *signal_message_get_message_version(uint32_t *out, SignalConstPointerSignalMessage obj); - -SignalFfiError *signal_message_new(SignalMutPointerSignalMessage *out, uint8_t message_version, SignalBorrowedBuffer mac_key, SignalConstPointerPublicKey sender_ratchet_key, uint32_t counter, uint32_t previous_counter, SignalBorrowedBuffer ciphertext, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key); - -SignalFfiError *signal_message_verify_mac(bool *out, SignalConstPointerSignalMessage msg, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key, SignalBorrowedBuffer mac_key); - -SignalFfiError *signal_message_get_sender_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerSignalMessage m); - -SignalFfiError *signal_pre_key_signal_message_new(SignalMutPointerPreKeySignalMessage *out, uint8_t message_version, uint32_t registration_id, uint32_t pre_key_id, uint32_t signed_pre_key_id, SignalConstPointerPublicKey base_key, SignalConstPointerPublicKey identity_key, SignalConstPointerSignalMessage signal_message); - -SignalFfiError *signal_pre_key_signal_message_get_base_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeySignalMessage m); - -SignalFfiError *signal_pre_key_signal_message_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeySignalMessage m); - -SignalFfiError *signal_pre_key_signal_message_get_signal_message(SignalMutPointerSignalMessage *out, SignalConstPointerPreKeySignalMessage m); - -SignalFfiError *signal_pre_key_signal_message_deserialize(SignalMutPointerPreKeySignalMessage *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_pre_key_signal_message_serialize(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage obj); - -SignalFfiError *signal_pre_key_signal_message_get_registration_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); - -SignalFfiError *signal_pre_key_signal_message_get_signed_pre_key_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); - -SignalFfiError *signal_pre_key_signal_message_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); - -SignalFfiError *signal_pre_key_signal_message_get_version(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); - -SignalFfiError *signal_sender_key_message_deserialize(SignalMutPointerSenderKeyMessage *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_sender_key_message_get_cipher_text(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); - -SignalFfiError *signal_sender_key_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); - -SignalFfiError *signal_sender_key_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyMessage obj); - -SignalFfiError *signal_sender_key_message_get_chain_id(uint32_t *out, SignalConstPointerSenderKeyMessage obj); - -SignalFfiError *signal_sender_key_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyMessage obj); - -SignalFfiError *signal_sender_key_message_new(SignalMutPointerSenderKeyMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer ciphertext, SignalConstPointerPrivateKey pk); - -SignalFfiError *signal_sender_key_message_verify_signature(bool *out, SignalConstPointerSenderKeyMessage skm, SignalConstPointerPublicKey pubkey); - -SignalFfiError *signal_sender_key_distribution_message_deserialize(SignalMutPointerSenderKeyDistributionMessage *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_sender_key_distribution_message_get_chain_key(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); - -SignalFfiError *signal_sender_key_distribution_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); - -SignalFfiError *signal_sender_key_distribution_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyDistributionMessage obj); - -SignalFfiError *signal_sender_key_distribution_message_get_chain_id(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); - -SignalFfiError *signal_sender_key_distribution_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); - -SignalFfiError *signal_sender_key_distribution_message_new(SignalMutPointerSenderKeyDistributionMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer chainkey, SignalConstPointerPublicKey pk); - -SignalFfiError *signal_sender_key_distribution_message_get_signature_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderKeyDistributionMessage m); - -SignalFfiError *signal_decryption_error_message_deserialize(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_decryption_error_message_get_timestamp(uint64_t *out, SignalConstPointerDecryptionErrorMessage obj); - -SignalFfiError *signal_decryption_error_message_get_device_id(uint32_t *out, SignalConstPointerDecryptionErrorMessage obj); - -SignalFfiError *signal_decryption_error_message_serialize(SignalOwnedBuffer *out, SignalConstPointerDecryptionErrorMessage obj); - -SignalFfiError *signal_decryption_error_message_get_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerDecryptionErrorMessage m); - -SignalFfiError *signal_decryption_error_message_for_original_message(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer original_bytes, uint8_t original_type, uint64_t original_timestamp, uint32_t original_sender_device_id); - -SignalFfiError *signal_decryption_error_message_extract_from_serialized_content(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer bytes); - -SignalFfiError *signal_plaintext_content_deserialize(SignalMutPointerPlaintextContent *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_plaintext_content_serialize(SignalOwnedBuffer *out, SignalConstPointerPlaintextContent obj); - -SignalFfiError *signal_plaintext_content_get_body(SignalOwnedBuffer *out, SignalConstPointerPlaintextContent obj); - -SignalFfiError *signal_plaintext_content_from_decryption_error_message(SignalMutPointerPlaintextContent *out, SignalConstPointerDecryptionErrorMessage m); - -SignalFfiError *signal_pre_key_bundle_new(SignalMutPointerPreKeyBundle *out, uint32_t registration_id, uint32_t device_id, uint32_t prekey_id, SignalConstPointerPublicKey prekey, uint32_t signed_prekey_id, SignalConstPointerPublicKey signed_prekey, SignalBorrowedBuffer signed_prekey_signature, SignalConstPointerPublicKey identity_key, uint32_t kyber_prekey_id, SignalConstPointerKyberPublicKey kyber_prekey, SignalBorrowedBuffer kyber_prekey_signature); - -SignalFfiError *signal_pre_key_bundle_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle p); - -SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_registration_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_device_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_pre_key_public(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_public(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); - -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalMutPointerKyberPublicKey *out, SignalConstPointerPreKeyBundle bundle); - -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle bundle); - -SignalFfiError *signal_signed_pre_key_record_deserialize(SignalMutPointerSignedPreKeyRecord *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_signed_pre_key_record_get_signature(SignalOwnedBuffer *out, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_signed_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_signed_pre_key_record_get_id(uint32_t *out, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_signed_pre_key_record_get_timestamp(uint64_t *out, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_signed_pre_key_record_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_signed_pre_key_record_get_private_key(SignalMutPointerPrivateKey *out, SignalConstPointerSignedPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_deserialize(SignalMutPointerKyberPreKeyRecord *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_kyber_pre_key_record_get_signature(SignalOwnedBuffer *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_get_id(uint32_t *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_get_timestamp(uint64_t *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_get_public_key(SignalMutPointerKyberPublicKey *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_get_secret_key(SignalMutPointerKyberSecretKey *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_kyber_pre_key_record_get_key_pair(SignalMutPointerKyberKeyPair *out, SignalConstPointerKyberPreKeyRecord obj); - -SignalFfiError *signal_signed_pre_key_record_new(SignalMutPointerSignedPreKeyRecord *out, uint32_t id, uint64_t timestamp, SignalConstPointerPublicKey pub_key, SignalConstPointerPrivateKey priv_key, SignalBorrowedBuffer signature); - -SignalFfiError *signal_kyber_pre_key_record_new(SignalMutPointerKyberPreKeyRecord *out, uint32_t id, uint64_t timestamp, SignalConstPointerKyberKeyPair key_pair, SignalBorrowedBuffer signature); - -SignalFfiError *signal_pre_key_record_deserialize(SignalMutPointerPreKeyRecord *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerPreKeyRecord obj); - -SignalFfiError *signal_pre_key_record_get_id(uint32_t *out, SignalConstPointerPreKeyRecord obj); - -SignalFfiError *signal_pre_key_record_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyRecord obj); - -SignalFfiError *signal_pre_key_record_get_private_key(SignalMutPointerPrivateKey *out, SignalConstPointerPreKeyRecord obj); - -SignalFfiError *signal_pre_key_record_new(SignalMutPointerPreKeyRecord *out, uint32_t id, SignalConstPointerPublicKey pub_key, SignalConstPointerPrivateKey priv_key); - -SignalFfiError *signal_sender_key_record_deserialize(SignalMutPointerSenderKeyRecord *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_sender_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyRecord obj); - -SignalFfiError *signal_server_certificate_deserialize(SignalMutPointerServerCertificate *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_server_certificate_get_serialized(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); - -SignalFfiError *signal_server_certificate_get_certificate(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); - -SignalFfiError *signal_server_certificate_get_signature(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); - -SignalFfiError *signal_server_certificate_get_key_id(uint32_t *out, SignalConstPointerServerCertificate obj); - -SignalFfiError *signal_server_certificate_get_key(SignalMutPointerPublicKey *out, SignalConstPointerServerCertificate obj); - -SignalFfiError *signal_server_certificate_new(SignalMutPointerServerCertificate *out, uint32_t key_id, SignalConstPointerPublicKey server_key, SignalConstPointerPrivateKey trust_root); - -SignalFfiError *signal_sender_certificate_deserialize(SignalMutPointerSenderCertificate *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_sender_certificate_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_certificate(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_signature(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_sender_uuid(const char **out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_sender_e164(const char **out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_expiration(uint64_t *out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_device_id(uint32_t *out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_get_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderCertificate obj); - -SignalFfiError *signal_sender_certificate_validate(bool *out, SignalConstPointerSenderCertificate cert, SignalConstPointerPublicKey key, uint64_t time); - -SignalFfiError *signal_sender_certificate_get_server_certificate(SignalMutPointerServerCertificate *out, SignalConstPointerSenderCertificate cert); - -SignalFfiError *signal_sender_certificate_new(SignalMutPointerSenderCertificate *out, const char *sender_uuid, const char *sender_e164, uint32_t sender_device_id, SignalConstPointerPublicKey sender_key, uint64_t expiration, SignalConstPointerServerCertificate signer_cert, SignalConstPointerPrivateKey signer_key); - -SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_unidentified_sender_message_content_serialize(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent obj); - -SignalFfiError *signal_unidentified_sender_message_content_get_contents(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent obj); - -SignalFfiError *signal_unidentified_sender_message_content_get_group_id_or_empty(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent m); - -SignalFfiError *signal_unidentified_sender_message_content_get_sender_cert(SignalMutPointerSenderCertificate *out, SignalConstPointerUnidentifiedSenderMessageContent m); - -SignalFfiError *signal_unidentified_sender_message_content_get_msg_type(uint8_t *out, SignalConstPointerUnidentifiedSenderMessageContent m); - -SignalFfiError *signal_unidentified_sender_message_content_get_content_hint(uint32_t *out, SignalConstPointerUnidentifiedSenderMessageContent m); - -SignalFfiError *signal_unidentified_sender_message_content_new(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalConstPointerCiphertextMessage message, SignalConstPointerSenderCertificate sender, uint32_t content_hint, SignalBorrowedBuffer group_id); - -SignalFfiError *signal_ciphertext_message_type(uint8_t *out, SignalConstPointerCiphertextMessage msg); - -SignalFfiError *signal_ciphertext_message_serialize(SignalOwnedBuffer *out, SignalConstPointerCiphertextMessage obj); - -SignalFfiError *signal_ciphertext_message_from_plaintext_content(SignalMutPointerCiphertextMessage *out, SignalConstPointerPlaintextContent m); - -SignalFfiError *signal_session_record_archive_current_state(SignalMutPointerSessionRecord session_record); - -SignalFfiError *signal_session_record_has_usable_sender_chain(bool *out, SignalConstPointerSessionRecord s, uint64_t now); - -SignalFfiError *signal_session_record_current_ratchet_key_matches(bool *out, SignalConstPointerSessionRecord s, SignalConstPointerPublicKey key); - -SignalFfiError *signal_session_record_deserialize(SignalMutPointerSessionRecord *out, SignalBorrowedBuffer data); - -SignalFfiError *signal_session_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSessionRecord obj); - -SignalFfiError *signal_session_record_get_local_registration_id(uint32_t *out, SignalConstPointerSessionRecord obj); - -SignalFfiError *signal_session_record_get_remote_registration_id(uint32_t *out, SignalConstPointerSessionRecord obj); - -SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); - -SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); - -SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); - -SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); - -SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress destination, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); - -SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfConstPointerProtocolAddress recipients, SignalBorrowedSliceOfConstPointerSessionRecord recipient_sessions, SignalBorrowedBuffer excluded_recipients, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); - -SignalFfiError *signal_sealed_sender_multi_recipient_message_for_single_recipient(SignalOwnedBuffer *out, SignalBorrowedBuffer encoded_multi_recipient_message); - -SignalFfiError *signal_sealed_session_cipher_decrypt_to_usmc(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer ctext, SignalConstPointerFfiIdentityKeyStoreStruct identity_store); - -SignalFfiError *signal_sender_key_distribution_message_create(SignalMutPointerSenderKeyDistributionMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalConstPointerFfiSenderKeyStoreStruct store); - -SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); - -SignalFfiError *signal_group_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); - -SignalFfiError *signal_group_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress sender, SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); - -SignalFfiError *signal_device_transfer_generate_private_key(SignalOwnedBuffer *out); - -SignalFfiError *signal_device_transfer_generate_private_key_with_format(SignalOwnedBuffer *out, uint8_t key_format); - -SignalFfiError *signal_device_transfer_generate_certificate(SignalOwnedBuffer *out, SignalBorrowedBuffer private_key, const char *name, uint32_t days_to_expire); - -SignalFfiError *signal_cds2_client_state_new(SignalMutPointerSgxClientState *out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); - -SignalFfiError *signal_hsm_enclave_client_destroy(SignalMutPointerHsmEnclaveClient p); - -SignalFfiError *signal_hsm_enclave_client_new(SignalMutPointerHsmEnclaveClient *out, SignalBorrowedBuffer trusted_public_key, SignalBorrowedBuffer trusted_code_hashes); - -SignalFfiError *signal_hsm_enclave_client_complete_handshake(SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer handshake_received); - -SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *out, SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer plaintext_to_send); - -SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer received_ciphertext); - -SignalFfiError *signal_hsm_enclave_client_initial_request(SignalOwnedBuffer *out, SignalConstPointerHsmEnclaveClient obj); - -SignalFfiError *signal_sgx_client_state_destroy(SignalMutPointerSgxClientState p); - -SignalFfiError *signal_sgx_client_state_initial_request(SignalOwnedBuffer *out, SignalConstPointerSgxClientState obj); - -SignalFfiError *signal_sgx_client_state_complete_handshake(SignalMutPointerSgxClientState cli, SignalBorrowedBuffer handshake_received); - -SignalFfiError *signal_sgx_client_state_established_send(SignalOwnedBuffer *out, SignalMutPointerSgxClientState cli, SignalBorrowedBuffer plaintext_to_send); - -SignalFfiError *signal_sgx_client_state_established_recv(SignalOwnedBuffer *out, SignalMutPointerSgxClientState cli, SignalBorrowedBuffer received_ciphertext); - -SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_expiring_profile_key_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_group_master_key_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_group_public_params_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_group_secret_params_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_profile_key_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_profile_key_ciphertext_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_profile_key_commitment_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_profile_key_credential_request_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_profile_key_credential_request_context_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_receipt_credential_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_receipt_credential_presentation_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_receipt_credential_request_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_receipt_credential_request_context_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_receipt_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_uuid_ciphertext_check_valid_contents(SignalBorrowedBuffer buffer); - -SignalFfiError *signal_server_public_params_destroy(SignalMutPointerServerPublicParams p); - -SignalFfiError *signal_server_public_params_deserialize(SignalMutPointerServerPublicParams *out, SignalBorrowedBuffer buffer); - -SignalFfiError *signal_server_public_params_serialize(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams handle); - -SignalFfiError *signal_server_secret_params_destroy(SignalMutPointerServerSecretParams p); - -SignalFfiError *signal_server_secret_params_deserialize(SignalMutPointerServerSecretParams *out, SignalBorrowedBuffer buffer); - -SignalFfiError *signal_server_secret_params_serialize(SignalOwnedBuffer *out, SignalConstPointerServerSecretParams handle); - -SignalFfiError *signal_profile_key_get_commitment(unsigned char (*out)[SignalPROFILE_KEY_COMMITMENT_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); - -SignalFfiError *signal_profile_key_get_profile_key_version(uint8_t (*out)[SignalPROFILE_KEY_VERSION_ENCODED_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); - -SignalFfiError *signal_profile_key_derive_access_key(uint8_t (*out)[SignalACCESS_KEY_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); - -SignalFfiError *signal_group_secret_params_generate_deterministic(unsigned char (*out)[SignalGROUP_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_group_secret_params_derive_from_master_key(unsigned char (*out)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*master_key)[SignalGROUP_MASTER_KEY_LEN]); - -SignalFfiError *signal_group_secret_params_get_master_key(unsigned char (*out)[SignalGROUP_MASTER_KEY_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN]); - -SignalFfiError *signal_group_secret_params_get_public_params(unsigned char (*out)[SignalGROUP_PUBLIC_PARAMS_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN]); - -SignalFfiError *signal_group_secret_params_encrypt_service_id(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *service_id); - -SignalFfiError *signal_group_secret_params_decrypt_service_id(SignalServiceIdFixedWidthBinaryBytes *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*ciphertext)[SignalUUID_CIPHERTEXT_LEN]); - -SignalFfiError *signal_group_secret_params_encrypt_profile_key(unsigned char (*out)[SignalPROFILE_KEY_CIPHERTEXT_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); - -SignalFfiError *signal_group_secret_params_decrypt_profile_key(unsigned char (*out)[SignalPROFILE_KEY_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_CIPHERTEXT_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); - -SignalFfiError *signal_group_secret_params_encrypt_blob_with_padding_deterministic(SignalOwnedBuffer *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer plaintext, uint32_t padding_len); - -SignalFfiError *signal_group_secret_params_decrypt_blob_with_padding(SignalOwnedBuffer *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer ciphertext); - -SignalFfiError *signal_server_secret_params_generate_deterministic(SignalMutPointerServerSecretParams *out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_server_secret_params_get_public_params(SignalMutPointerServerPublicParams *out, SignalConstPointerServerSecretParams params); - -SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], SignalConstPointerServerSecretParams params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); - -SignalFfiError *signal_server_public_params_get_endorsement_public_key(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params); - -SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params, const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); - -SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); - -SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); - -SignalFfiError *signal_server_public_params_receive_expiring_profile_key_credential(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN], SignalConstPointerServerPublicParams server_public_params, const unsigned char (*request_context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], uint64_t current_time_in_seconds); - -SignalFfiError *signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key_credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); - -SignalFfiError *signal_server_public_params_create_receipt_credential_request_context_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const uint8_t (*receipt_serial)[SignalRECEIPT_SERIAL_LEN]); - -SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_LEN], SignalConstPointerServerPublicParams server_public_params, const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN]); - -SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); - -SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); - -SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorrowedBuffer bytes); - -SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer bytes); - -SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); - -SignalFfiError *signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*commitment)[SignalPROFILE_KEY_COMMITMENT_LEN], uint64_t expiration_in_seconds); - -SignalFfiError *signal_server_secret_params_verify_profile_key_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); - -SignalFfiError *signal_server_secret_params_issue_receipt_credential_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN], SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], uint64_t receipt_expiration_time, uint64_t receipt_level); - -SignalFfiError *signal_server_secret_params_verify_receipt_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); - -SignalFfiError *signal_group_public_params_get_group_identifier(uint8_t (*out)[SignalGROUP_IDENTIFIER_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN]); - -SignalFfiError *signal_server_public_params_verify_signature(SignalConstPointerServerPublicParams server_public_params, SignalBorrowedBuffer message, const uint8_t (*notary_signature)[SignalSIGNATURE_LEN]); +SignalFfiError *signal_aes256_gcm_siv_new(SignalMutPointerAes256GcmSiv *out, SignalBorrowedBuffer key); SignalFfiError *signal_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); -SignalFfiError *signal_auth_credential_presentation_get_uuid_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); - SignalFfiError *signal_auth_credential_presentation_get_pni_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); SignalFfiError *signal_auth_credential_presentation_get_redemption_time(uint64_t *out, SignalBorrowedBuffer presentation_bytes); -SignalFfiError *signal_profile_key_credential_request_context_get_request(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const unsigned char (*context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]); +SignalFfiError *signal_auth_credential_presentation_get_uuid_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); -SignalFfiError *signal_expiring_profile_key_credential_get_expiration_time(uint64_t *out, const unsigned char (*credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); +SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_profile_key_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); +SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_profile_key_credential_presentation_get_uuid_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); +SignalFfiError *signal_authenticated_chat_connection_connect(SignalCPromiseMutPointerAuthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); -SignalFfiError *signal_profile_key_credential_presentation_get_profile_key_ciphertext(unsigned char (*out)[SignalPROFILE_KEY_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); +SignalFfiError *signal_authenticated_chat_connection_destroy(SignalMutPointerAuthenticatedChatConnection p); -SignalFfiError *signal_receipt_credential_request_context_get_request(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN]); +SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat); -SignalFfiError *signal_receipt_credential_get_receipt_expiration_time(uint64_t *out, const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); +SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat); -SignalFfiError *signal_receipt_credential_get_receipt_level(uint64_t *out, const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); +SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); -SignalFfiError *signal_receipt_credential_presentation_get_receipt_expiration_time(uint64_t *out, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); +SignalFfiError *signal_authenticated_chat_connection_preconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); -SignalFfiError *signal_receipt_credential_presentation_get_receipt_level(uint64_t *out, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); - -SignalFfiError *signal_receipt_credential_presentation_get_receipt_serial(uint8_t (*out)[SignalRECEIPT_SERIAL_LEN], const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); - -SignalFfiError *signal_generic_server_secret_params_check_valid_contents(SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_generic_server_secret_params_generate_deterministic(SignalOwnedBuffer *out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_generic_server_secret_params_get_public_params(SignalOwnedBuffer *out, SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_generic_server_public_params_check_valid_contents(SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_call_link_secret_params_check_valid_contents(SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_call_link_secret_params_derive_from_root_key(SignalOwnedBuffer *out, SignalBorrowedBuffer root_key); - -SignalFfiError *signal_call_link_secret_params_get_public_params(SignalOwnedBuffer *out, SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_call_link_secret_params_decrypt_user_id(SignalServiceIdFixedWidthBinaryBytes *out, SignalBorrowedBuffer params_bytes, const unsigned char (*user_id)[SignalUUID_CIPHERTEXT_LEN]); - -SignalFfiError *signal_call_link_public_params_check_valid_contents(SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_create_call_link_credential_request_context_check_valid_contents(SignalBorrowedBuffer context_bytes); - -SignalFfiError *signal_create_call_link_credential_request_context_new_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer room_id, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_create_call_link_credential_request_context_get_request(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes); - -SignalFfiError *signal_create_call_link_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes); - -SignalFfiError *signal_create_call_link_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t timestamp, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_create_call_link_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); - -SignalFfiError *signal_create_call_link_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_create_call_link_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_create_call_link_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, SignalBorrowedBuffer room_id, const SignalServiceIdFixedWidthBinaryBytes *user_id, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_create_call_link_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); - -SignalFfiError *signal_create_call_link_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, SignalBorrowedBuffer room_id, uint64_t now, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes); - -SignalFfiError *signal_call_link_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); - -SignalFfiError *signal_call_link_auth_credential_response_issue_deterministic(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t redemption_time, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_call_link_auth_credential_response_receive(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t redemption_time, SignalBorrowedBuffer params_bytes); - -SignalFfiError *signal_call_link_auth_credential_check_valid_contents(SignalBorrowedBuffer credential_bytes); - -SignalFfiError *signal_call_link_auth_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t redemption_time, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_call_link_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); - -SignalFfiError *signal_call_link_auth_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, uint64_t now, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes); - -SignalFfiError *signal_call_link_auth_credential_presentation_get_user_id(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); - -SignalFfiError *signal_backup_auth_credential_request_context_new(SignalOwnedBuffer *out, const uint8_t (*backup_key)[32], const uint8_t (*uuid)[16]); - -SignalFfiError *signal_backup_auth_credential_request_context_check_valid_contents(SignalBorrowedBuffer context_bytes); - -SignalFfiError *signal_backup_auth_credential_request_context_get_request(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes); - -SignalFfiError *signal_backup_auth_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes); - -SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint8_t backup_level, uint8_t credential_type, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_backup_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); - -SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, uint64_t expected_redemption_time, SignalBorrowedBuffer params_bytes); +SignalFfiError *signal_authenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); SignalFfiError *signal_backup_auth_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); @@ -1821,19 +1177,261 @@ SignalFfiError *signal_backup_auth_credential_presentation_check_valid_contents( SignalFfiError *signal_backup_auth_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, uint64_t now, SignalBorrowedBuffer server_params_bytes); +SignalFfiError *signal_backup_auth_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes); + +SignalFfiError *signal_backup_auth_credential_request_context_check_valid_contents(SignalBorrowedBuffer context_bytes); + +SignalFfiError *signal_backup_auth_credential_request_context_get_request(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes); + +SignalFfiError *signal_backup_auth_credential_request_context_new(SignalOwnedBuffer *out, const uint8_t (*backup_key)[32], const uint8_t (*uuid)[16]); + +SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, uint64_t expected_redemption_time, SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint8_t backup_level, uint8_t credential_type, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_backup_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); + +SignalFfiError *signal_backup_key_derive_backup_id(uint8_t (*out)[16], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_backup_key_derive_ec_key(SignalMutPointerPrivateKey *out, const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_backup_key_derive_local_backup_metadata_key(uint8_t (*out)[SignalLOCAL_BACKUP_METADATA_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN]); + +SignalFfiError *signal_backup_key_derive_media_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); + +SignalFfiError *signal_backup_key_derive_media_id(uint8_t (*out)[SignalMEDIA_ID_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const char *media_name); + +SignalFfiError *signal_backup_key_derive_thumbnail_transit_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); + +SignalFfiError *signal_bridged_string_map_clone(SignalMutPointerBridgedStringMap *new_obj, SignalConstPointerBridgedStringMap obj); + +SignalFfiError *signal_bridged_string_map_destroy(SignalMutPointerBridgedStringMap p); + +SignalFfiError *signal_bridged_string_map_insert(SignalMutPointerBridgedStringMap map, const char *key, const char *value); + +SignalFfiError *signal_bridged_string_map_new(SignalMutPointerBridgedStringMap *out, uint32_t initial_capacity); + +SignalFfiError *signal_call_link_auth_credential_check_valid_contents(SignalBorrowedBuffer credential_bytes); + +SignalFfiError *signal_call_link_auth_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t redemption_time, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_call_link_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_call_link_auth_credential_presentation_get_user_id(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_call_link_auth_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, uint64_t now, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes); + +SignalFfiError *signal_call_link_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); + +SignalFfiError *signal_call_link_auth_credential_response_issue_deterministic(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t redemption_time, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_call_link_auth_credential_response_receive(SignalOwnedBuffer *out, SignalBorrowedBuffer response_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t redemption_time, SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_call_link_public_params_check_valid_contents(SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_call_link_secret_params_check_valid_contents(SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_call_link_secret_params_decrypt_user_id(SignalServiceIdFixedWidthBinaryBytes *out, SignalBorrowedBuffer params_bytes, const unsigned char (*user_id)[SignalUUID_CIPHERTEXT_LEN]); + +SignalFfiError *signal_call_link_secret_params_derive_from_root_key(SignalOwnedBuffer *out, SignalBorrowedBuffer root_key); + +SignalFfiError *signal_call_link_secret_params_encrypt_user_id(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer params_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id); + +SignalFfiError *signal_call_link_secret_params_get_public_params(SignalOwnedBuffer *out, SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_cds2_client_state_new(SignalMutPointerSgxClientState *out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); + +SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerCdsiLookup lookup); + +SignalFfiError *signal_cdsi_lookup_destroy(SignalMutPointerCdsiLookup p); + +SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseMutPointerCdsiLookup *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, SignalConstPointerLookupRequest request); + +SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, SignalConstPointerCdsiLookup lookup); + +SignalFfiError *signal_chat_connection_info_description(const char **out, SignalConstPointerChatConnectionInfo connection_info); + +SignalFfiError *signal_chat_connection_info_ip_version(uint8_t *out, SignalConstPointerChatConnectionInfo connection_info); + +SignalFfiError *signal_chat_connection_info_local_port(uint16_t *out, SignalConstPointerChatConnectionInfo connection_info); + +SignalFfiError *signal_ciphertext_message_destroy(SignalMutPointerCiphertextMessage p); + +SignalFfiError *signal_ciphertext_message_from_plaintext_content(SignalMutPointerCiphertextMessage *out, SignalConstPointerPlaintextContent m); + +SignalFfiError *signal_ciphertext_message_serialize(SignalOwnedBuffer *out, SignalConstPointerCiphertextMessage obj); + +SignalFfiError *signal_ciphertext_message_type(uint8_t *out, SignalConstPointerCiphertextMessage msg); + +SignalFfiError *signal_connection_info_destroy(SignalMutPointerConnectionInfo p); + +SignalFfiError *signal_connection_manager_clear_proxy(SignalConstPointerConnectionManager connection_manager); + +SignalFfiError *signal_connection_manager_destroy(SignalMutPointerConnectionManager p); + +SignalFfiError *signal_connection_manager_new(SignalMutPointerConnectionManager *out, uint8_t environment, const char *user_agent, SignalMutPointerBridgedStringMap remote_config); + +SignalFfiError *signal_connection_manager_on_network_change(SignalConstPointerConnectionManager connection_manager); + +SignalFfiError *signal_connection_manager_set_censorship_circumvention_enabled(SignalConstPointerConnectionManager connection_manager, bool enabled); + +SignalFfiError *signal_connection_manager_set_invalid_proxy(SignalConstPointerConnectionManager connection_manager); + +SignalFfiError *signal_connection_manager_set_proxy(SignalConstPointerConnectionManager connection_manager, SignalConstPointerConnectionProxyConfig proxy); + +SignalFfiError *signal_connection_manager_set_remote_config(SignalConstPointerConnectionManager connection_manager, SignalMutPointerBridgedStringMap remote_config); + +SignalFfiError *signal_connection_proxy_config_clone(SignalMutPointerConnectionProxyConfig *new_obj, SignalConstPointerConnectionProxyConfig obj); + +SignalFfiError *signal_connection_proxy_config_destroy(SignalMutPointerConnectionProxyConfig p); + +SignalFfiError *signal_connection_proxy_config_new(SignalMutPointerConnectionProxyConfig *out, const char *scheme, const char *host, int32_t port, const char *username, const char *password); + +SignalFfiError *signal_create_call_link_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_create_call_link_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, SignalBorrowedBuffer room_id, const SignalServiceIdFixedWidthBinaryBytes *user_id, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_create_call_link_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_create_call_link_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, SignalBorrowedBuffer room_id, uint64_t now, SignalBorrowedBuffer server_params_bytes, SignalBorrowedBuffer call_link_params_bytes); + +SignalFfiError *signal_create_call_link_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes); + +SignalFfiError *signal_create_call_link_credential_request_context_check_valid_contents(SignalBorrowedBuffer context_bytes); + +SignalFfiError *signal_create_call_link_credential_request_context_get_request(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes); + +SignalFfiError *signal_create_call_link_credential_request_context_new_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer room_id, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_create_call_link_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_create_call_link_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, const SignalServiceIdFixedWidthBinaryBytes *user_id, uint64_t timestamp, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_create_call_link_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); + +SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); + +SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); + +SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); + +SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); + +SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); + +SignalFfiError *signal_decryption_error_message_deserialize(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_decryption_error_message_destroy(SignalMutPointerDecryptionErrorMessage p); + +SignalFfiError *signal_decryption_error_message_extract_from_serialized_content(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer bytes); + +SignalFfiError *signal_decryption_error_message_for_original_message(SignalMutPointerDecryptionErrorMessage *out, SignalBorrowedBuffer original_bytes, uint8_t original_type, uint64_t original_timestamp, uint32_t original_sender_device_id); + +SignalFfiError *signal_decryption_error_message_get_device_id(uint32_t *out, SignalConstPointerDecryptionErrorMessage obj); + +SignalFfiError *signal_decryption_error_message_get_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerDecryptionErrorMessage m); + +SignalFfiError *signal_decryption_error_message_get_timestamp(uint64_t *out, SignalConstPointerDecryptionErrorMessage obj); + +SignalFfiError *signal_decryption_error_message_serialize(SignalOwnedBuffer *out, SignalConstPointerDecryptionErrorMessage obj); + +SignalFfiError *signal_device_transfer_generate_certificate(SignalOwnedBuffer *out, SignalBorrowedBuffer private_key, const char *name, uint32_t days_to_expire); + +SignalFfiError *signal_device_transfer_generate_private_key(SignalOwnedBuffer *out); + +SignalFfiError *signal_device_transfer_generate_private_key_with_format(SignalOwnedBuffer *out, uint8_t key_format); + +SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); + +void signal_error_free(SignalFfiError *err); + +SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalMutPointerProtocolAddress *out); + +SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); + +SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); + +SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); + +uint32_t signal_error_get_type(const SignalFfiError *err); + +SignalFfiError *signal_error_get_unknown_fields(const SignalFfiError *err, SignalStringArray *out); + +SignalFfiError *signal_error_get_uuid(const SignalFfiError *err, uint8_t (*out)[16]); + +SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_expiring_profile_key_credential_get_expiration_time(uint64_t *out, const unsigned char (*credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); + +SignalFfiError *signal_expiring_profile_key_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_fingerprint_clone(SignalMutPointerFingerprint *new_obj, SignalConstPointerFingerprint obj); + +SignalFfiError *signal_fingerprint_compare(bool *out, SignalBorrowedBuffer fprint1, SignalBorrowedBuffer fprint2); + +SignalFfiError *signal_fingerprint_destroy(SignalMutPointerFingerprint p); + +SignalFfiError *signal_fingerprint_display_string(const char **out, SignalConstPointerFingerprint obj); + +SignalFfiError *signal_fingerprint_new(SignalMutPointerFingerprint *out, uint32_t iterations, uint32_t version, SignalBorrowedBuffer local_identifier, SignalConstPointerPublicKey local_key, SignalBorrowedBuffer remote_identifier, SignalConstPointerPublicKey remote_key); + +SignalFfiError *signal_fingerprint_scannable_encoding(SignalOwnedBuffer *out, SignalConstPointerFingerprint obj); + +void signal_free_buffer(const unsigned char *buf, size_t buf_len); + +void signal_free_bytestring_array(SignalBytestringArray array); + +void signal_free_list_of_strings(SignalOwnedBufferOfCStringPtr buffer); + +void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); + +void signal_free_string(const char *buf); + +SignalFfiError *signal_generic_server_public_params_check_valid_contents(SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_generic_server_secret_params_check_valid_contents(SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_generic_server_secret_params_generate_deterministic(SignalOwnedBuffer *out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_generic_server_secret_params_get_public_params(SignalOwnedBuffer *out, SignalBorrowedBuffer params_bytes); + +SignalFfiError *signal_group_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress sender, SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); + +SignalFfiError *signal_group_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); + +SignalFfiError *signal_group_master_key_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_group_public_params_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_group_public_params_get_group_identifier(uint8_t (*out)[SignalGROUP_IDENTIFIER_LEN], const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN]); + +SignalFfiError *signal_group_secret_params_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_group_secret_params_decrypt_blob_with_padding(SignalOwnedBuffer *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer ciphertext); + +SignalFfiError *signal_group_secret_params_decrypt_profile_key(unsigned char (*out)[SignalPROFILE_KEY_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_CIPHERTEXT_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); + +SignalFfiError *signal_group_secret_params_decrypt_service_id(SignalServiceIdFixedWidthBinaryBytes *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*ciphertext)[SignalUUID_CIPHERTEXT_LEN]); + +SignalFfiError *signal_group_secret_params_derive_from_master_key(unsigned char (*out)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*master_key)[SignalGROUP_MASTER_KEY_LEN]); + +SignalFfiError *signal_group_secret_params_encrypt_blob_with_padding_deterministic(SignalOwnedBuffer *out, const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer plaintext, uint32_t padding_len); + +SignalFfiError *signal_group_secret_params_encrypt_profile_key(unsigned char (*out)[SignalPROFILE_KEY_CIPHERTEXT_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); + +SignalFfiError *signal_group_secret_params_encrypt_service_id(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN], const SignalServiceIdFixedWidthBinaryBytes *service_id); + +SignalFfiError *signal_group_secret_params_generate_deterministic(unsigned char (*out)[SignalGROUP_SECRET_PARAMS_LEN], const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_group_secret_params_get_master_key(unsigned char (*out)[SignalGROUP_MASTER_KEY_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN]); + +SignalFfiError *signal_group_secret_params_get_public_params(unsigned char (*out)[SignalGROUP_PUBLIC_PARAMS_LEN], const unsigned char (*params)[SignalGROUP_SECRET_PARAMS_LEN]); + SignalFfiError *signal_group_send_derived_key_pair_check_valid_contents(SignalBorrowedBuffer bytes); SignalFfiError *signal_group_send_derived_key_pair_for_expiration(SignalOwnedBuffer *out, uint64_t expiration, SignalConstPointerServerSecretParams server_params); -SignalFfiError *signal_group_send_endorsements_response_check_valid_contents(SignalBorrowedBuffer bytes); - -SignalFfiError *signal_group_send_endorsements_response_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer key_pair, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); - -SignalFfiError *signal_group_send_endorsements_response_get_expiration(uint64_t *out, SignalBorrowedBuffer response_bytes); - -SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalConstPointerServerPublicParams server_params); - -SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, SignalConstPointerServerPublicParams server_params); +SignalFfiError *signal_group_send_endorsement_call_link_params_to_token(SignalOwnedBuffer *out, SignalBorrowedBuffer endorsement, SignalBorrowedBuffer call_link_secret_params_serialized); SignalFfiError *signal_group_send_endorsement_check_valid_contents(SignalBorrowedBuffer bytes); @@ -1843,9 +1441,15 @@ SignalFfiError *signal_group_send_endorsement_remove(SignalOwnedBuffer *out, Sig SignalFfiError *signal_group_send_endorsement_to_token(SignalOwnedBuffer *out, SignalBorrowedBuffer endorsement, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN]); -SignalFfiError *signal_group_send_token_check_valid_contents(SignalBorrowedBuffer bytes); +SignalFfiError *signal_group_send_endorsements_response_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_group_send_token_to_full_token(SignalOwnedBuffer *out, SignalBorrowedBuffer token, uint64_t expiration); +SignalFfiError *signal_group_send_endorsements_response_get_expiration(uint64_t *out, SignalBorrowedBuffer response_bytes); + +SignalFfiError *signal_group_send_endorsements_response_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer key_pair, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer concatenated_group_member_ciphertexts, SignalBorrowedBuffer local_user_ciphertext, uint64_t now, SignalConstPointerServerPublicParams server_params); + +SignalFfiError *signal_group_send_endorsements_response_receive_and_combine_with_service_ids(SignalBytestringArray *out, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer group_members, const SignalServiceIdFixedWidthBinaryBytes *local_user, uint64_t now, const unsigned char (*group_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalConstPointerServerPublicParams server_params); SignalFfiError *signal_group_send_full_token_check_valid_contents(SignalBorrowedBuffer bytes); @@ -1853,111 +1457,173 @@ SignalFfiError *signal_group_send_full_token_get_expiration(uint64_t *out, Signa SignalFfiError *signal_group_send_full_token_verify(SignalBorrowedBuffer token, SignalBorrowedBuffer user_ids, uint64_t now, SignalBorrowedBuffer key_pair); -SignalFfiError *signal_connection_info_destroy(SignalMutPointerConnectionInfo p); +SignalFfiError *signal_group_send_token_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_connection_proxy_config_destroy(SignalMutPointerConnectionProxyConfig p); +SignalFfiError *signal_group_send_token_to_full_token(SignalOwnedBuffer *out, SignalBorrowedBuffer token, uint64_t expiration); -SignalFfiError *signal_connection_proxy_config_clone(SignalMutPointerConnectionProxyConfig *new_obj, SignalConstPointerConnectionProxyConfig obj); +SignalFfiError *signal_hex_encode(char *output, size_t output_len, const uint8_t *input, size_t input_len); -SignalFfiError *signal_connection_proxy_config_new(SignalMutPointerConnectionProxyConfig *out, const char *scheme, const char *host, int32_t port, const char *username, const char *password); +SignalFfiError *signal_hkdf_derive(SignalBorrowedMutableBuffer output, SignalBorrowedBuffer ikm, SignalBorrowedBuffer label, SignalBorrowedBuffer salt); -SignalFfiError *signal_connection_manager_destroy(SignalMutPointerConnectionManager p); +SignalFfiError *signal_hsm_enclave_client_complete_handshake(SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer handshake_received); -SignalFfiError *signal_connection_manager_new(SignalMutPointerConnectionManager *out, uint8_t environment, const char *user_agent); +SignalFfiError *signal_hsm_enclave_client_destroy(SignalMutPointerHsmEnclaveClient p); -SignalFfiError *signal_connection_manager_set_proxy(SignalConstPointerConnectionManager connection_manager, SignalConstPointerConnectionProxyConfig proxy); +SignalFfiError *signal_hsm_enclave_client_established_recv(SignalOwnedBuffer *out, SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer received_ciphertext); -SignalFfiError *signal_connection_manager_set_invalid_proxy(SignalConstPointerConnectionManager connection_manager); +SignalFfiError *signal_hsm_enclave_client_established_send(SignalOwnedBuffer *out, SignalMutPointerHsmEnclaveClient cli, SignalBorrowedBuffer plaintext_to_send); -SignalFfiError *signal_connection_manager_clear_proxy(SignalConstPointerConnectionManager connection_manager); +SignalFfiError *signal_hsm_enclave_client_initial_request(SignalOwnedBuffer *out, SignalConstPointerHsmEnclaveClient obj); -SignalFfiError *signal_connection_manager_set_censorship_circumvention_enabled(SignalConstPointerConnectionManager connection_manager, bool enabled); +SignalFfiError *signal_hsm_enclave_client_new(SignalMutPointerHsmEnclaveClient *out, SignalBorrowedBuffer trusted_public_key, SignalBorrowedBuffer trusted_code_hashes); -SignalFfiError *signal_connection_manager_on_network_change(SignalConstPointerConnectionManager connection_manager); - -SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); - -SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); - -SignalFfiError *signal_lookup_request_destroy(SignalMutPointerLookupRequest p); - -SignalFfiError *signal_lookup_request_new(SignalMutPointerLookupRequest *out); - -SignalFfiError *signal_lookup_request_add_e164(SignalConstPointerLookupRequest request, const char *e164); - -SignalFfiError *signal_lookup_request_add_previous_e164(SignalConstPointerLookupRequest request, const char *e164); - -SignalFfiError *signal_lookup_request_set_token(SignalConstPointerLookupRequest request, SignalBorrowedBuffer token); - -SignalFfiError *signal_lookup_request_add_aci_and_access_key(SignalConstPointerLookupRequest request, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer access_key); - -SignalFfiError *signal_cdsi_lookup_destroy(SignalMutPointerCdsiLookup p); - -SignalFfiError *signal_cdsi_lookup_new(SignalCPromiseMutPointerCdsiLookup *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, SignalConstPointerLookupRequest request); - -SignalFfiError *signal_cdsi_lookup_new_routes(SignalCPromiseMutPointerCdsiLookup *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, SignalConstPointerLookupRequest request); - -SignalFfiError *signal_cdsi_lookup_token(SignalOwnedBuffer *out, SignalConstPointerCdsiLookup lookup); - -SignalFfiError *signal_cdsi_lookup_complete(SignalCPromiseFfiCdsiLookupResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerCdsiLookup lookup); +SignalFfiError *signal_http_request_add_header(SignalConstPointerHttpRequest request, const char *name, const char *value); SignalFfiError *signal_http_request_destroy(SignalMutPointerHttpRequest p); -SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); - -SignalFfiError *signal_authenticated_chat_connection_destroy(SignalMutPointerAuthenticatedChatConnection p); - SignalFfiError *signal_http_request_new_with_body(SignalMutPointerHttpRequest *out, const char *method, const char *path, SignalBorrowedBuffer body_as_slice); SignalFfiError *signal_http_request_new_without_body(SignalMutPointerHttpRequest *out, const char *method, const char *path); -SignalFfiError *signal_http_request_add_header(SignalConstPointerHttpRequest request, const char *name, const char *value); +SignalFfiError *signal_identitykey_verify_alternate_identity(bool *out, SignalConstPointerPublicKey public_key, SignalConstPointerPublicKey other_identity, SignalBorrowedBuffer signature); -SignalFfiError *signal_chat_connection_info_local_port(uint16_t *out, SignalConstPointerChatConnectionInfo connection_info); +SignalFfiError *signal_identitykeypair_deserialize(SignalMutPointerPrivateKey *private_key, SignalMutPointerPublicKey *public_key, SignalBorrowedBuffer input); -SignalFfiError *signal_chat_connection_info_ip_version(uint8_t *out, SignalConstPointerChatConnectionInfo connection_info); +SignalFfiError *signal_identitykeypair_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key); -SignalFfiError *signal_chat_connection_info_description(const char **out, SignalConstPointerChatConnectionInfo connection_info); +SignalFfiError *signal_identitykeypair_sign_alternate_identity(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key, SignalConstPointerPublicKey other_identity); -SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); +SignalFfiError *signal_incremental_mac_calculate_chunk_size(uint32_t *out, uint32_t data_size); -SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); +SignalFfiError *signal_incremental_mac_destroy(SignalMutPointerIncrementalMac p); -SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); +SignalFfiError *signal_incremental_mac_finalize(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac); -SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat); +SignalFfiError *signal_incremental_mac_initialize(SignalMutPointerIncrementalMac *out, SignalBorrowedBuffer key, uint32_t chunk_size); -SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); +SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); -SignalFfiError *signal_authenticated_chat_connection_preconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); +bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); -SignalFfiError *signal_authenticated_chat_connection_connect(SignalCPromiseMutPointerAuthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); +SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj); -SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); +SignalFfiError *signal_kyber_key_pair_destroy(SignalMutPointerKyberKeyPair p); -SignalFfiError *signal_authenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); +SignalFfiError *signal_kyber_key_pair_generate(SignalMutPointerKyberKeyPair *out); -SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat); +SignalFfiError *signal_kyber_key_pair_get_public_key(SignalMutPointerKyberPublicKey *out, SignalConstPointerKyberKeyPair key_pair); -SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat); +SignalFfiError *signal_kyber_key_pair_get_secret_key(SignalMutPointerKyberSecretKey *out, SignalConstPointerKyberKeyPair key_pair); -SignalFfiError *signal_server_message_ack_destroy(SignalMutPointerServerMessageAck p); +SignalFfiError *signal_kyber_pre_key_record_clone(SignalMutPointerKyberPreKeyRecord *new_obj, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_server_message_ack_send(SignalConstPointerServerMessageAck ack); +SignalFfiError *signal_kyber_pre_key_record_deserialize(SignalMutPointerKyberPreKeyRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_tokio_async_context_destroy(SignalMutPointerTokioAsyncContext p); +SignalFfiError *signal_kyber_pre_key_record_destroy(SignalMutPointerKyberPreKeyRecord p); -SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext *out); +SignalFfiError *signal_kyber_pre_key_record_get_id(uint32_t *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_tokio_async_context_cancel(SignalConstPointerTokioAsyncContext context, uint64_t raw_cancellation_id); +SignalFfiError *signal_kyber_pre_key_record_get_key_pair(SignalMutPointerKyberKeyPair *out, SignalConstPointerKyberPreKeyRecord obj); -SignalFfiError *signal_pin_hash_destroy(SignalMutPointerPinHash p); +SignalFfiError *signal_kyber_pre_key_record_get_public_key(SignalMutPointerKyberPublicKey *out, SignalConstPointerKyberPreKeyRecord obj); + +SignalFfiError *signal_kyber_pre_key_record_get_secret_key(SignalMutPointerKyberSecretKey *out, SignalConstPointerKyberPreKeyRecord obj); + +SignalFfiError *signal_kyber_pre_key_record_get_signature(SignalOwnedBuffer *out, SignalConstPointerKyberPreKeyRecord obj); + +SignalFfiError *signal_kyber_pre_key_record_get_timestamp(uint64_t *out, SignalConstPointerKyberPreKeyRecord obj); + +SignalFfiError *signal_kyber_pre_key_record_new(SignalMutPointerKyberPreKeyRecord *out, uint32_t id, uint64_t timestamp, SignalConstPointerKyberKeyPair key_pair, SignalBorrowedBuffer signature); + +SignalFfiError *signal_kyber_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberPreKeyRecord obj); + +SignalFfiError *signal_kyber_public_key_clone(SignalMutPointerKyberPublicKey *new_obj, SignalConstPointerKyberPublicKey obj); + +SignalFfiError *signal_kyber_public_key_deserialize(SignalMutPointerKyberPublicKey *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_kyber_public_key_destroy(SignalMutPointerKyberPublicKey p); + +SignalFfiError *signal_kyber_public_key_equals(bool *out, SignalConstPointerKyberPublicKey lhs, SignalConstPointerKyberPublicKey rhs); + +SignalFfiError *signal_kyber_public_key_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberPublicKey obj); + +SignalFfiError *signal_kyber_secret_key_clone(SignalMutPointerKyberSecretKey *new_obj, SignalConstPointerKyberSecretKey obj); + +SignalFfiError *signal_kyber_secret_key_deserialize(SignalMutPointerKyberSecretKey *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_kyber_secret_key_destroy(SignalMutPointerKyberSecretKey p); + +SignalFfiError *signal_kyber_secret_key_serialize(SignalOwnedBuffer *out, SignalConstPointerKyberSecretKey obj); + +SignalFfiError *signal_lookup_request_add_aci_and_access_key(SignalConstPointerLookupRequest request, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer access_key); + +SignalFfiError *signal_lookup_request_add_e164(SignalConstPointerLookupRequest request, const char *e164); + +SignalFfiError *signal_lookup_request_add_previous_e164(SignalConstPointerLookupRequest request, const char *e164); + +SignalFfiError *signal_lookup_request_destroy(SignalMutPointerLookupRequest p); + +SignalFfiError *signal_lookup_request_new(SignalMutPointerLookupRequest *out); + +SignalFfiError *signal_lookup_request_set_token(SignalConstPointerLookupRequest request, SignalBorrowedBuffer token); + +SignalFfiError *signal_message_backup_key_destroy(SignalMutPointerMessageBackupKey p); + +SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMutPointerMessageBackupKey *out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMutPointerMessageBackupKey *out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16]); + +SignalFfiError *signal_message_backup_key_get_aes_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); + +SignalFfiError *signal_message_backup_key_get_hmac_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); + +SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMutPointerMessageBackupValidationOutcome p); + +SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, SignalConstPointerMessageBackupValidationOutcome outcome); + +SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, SignalConstPointerMessageBackupValidationOutcome outcome); + +SignalFfiError *signal_message_backup_validator_validate(SignalMutPointerMessageBackupValidationOutcome *out, SignalConstPointerMessageBackupKey key, SignalConstPointerFfiInputStreamStruct first_stream, SignalConstPointerFfiInputStreamStruct second_stream, uint64_t len, uint8_t purpose); + +SignalFfiError *signal_message_clone(SignalMutPointerSignalMessage *new_obj, SignalConstPointerSignalMessage obj); + +SignalFfiError *signal_message_deserialize(SignalMutPointerSignalMessage *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_message_destroy(SignalMutPointerSignalMessage p); + +SignalFfiError *signal_message_get_body(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); + +SignalFfiError *signal_message_get_counter(uint32_t *out, SignalConstPointerSignalMessage obj); + +SignalFfiError *signal_message_get_message_version(uint32_t *out, SignalConstPointerSignalMessage obj); + +SignalFfiError *signal_message_get_sender_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerSignalMessage m); + +SignalFfiError *signal_message_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); + +SignalFfiError *signal_message_new(SignalMutPointerSignalMessage *out, uint8_t message_version, SignalBorrowedBuffer mac_key, SignalConstPointerPublicKey sender_ratchet_key, uint32_t counter, uint32_t previous_counter, SignalBorrowedBuffer ciphertext, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key); + +SignalFfiError *signal_message_verify_mac(bool *out, SignalConstPointerSignalMessage msg, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key, SignalBorrowedBuffer mac_key); + +#if defined(SIGNAL_MEDIA_SUPPORTED) +SignalFfiError *signal_mp4_sanitizer_sanitize(SignalMutPointerSanitizedMetadata *out, SignalConstPointerFfiInputStreamStruct input, uint64_t len); +#endif + +SignalFfiError *signal_online_backup_validator_add_frame(SignalMutPointerOnlineBackupValidator backup, SignalBorrowedBuffer frame); + +SignalFfiError *signal_online_backup_validator_destroy(SignalMutPointerOnlineBackupValidator p); + +SignalFfiError *signal_online_backup_validator_finalize(SignalMutPointerOnlineBackupValidator backup); + +SignalFfiError *signal_online_backup_validator_new(SignalMutPointerOnlineBackupValidator *out, SignalBorrowedBuffer backup_info_frame, uint8_t purpose); + +SignalFfiError *signal_pin_hash_access_key(uint8_t (*out)[32], SignalConstPointerPinHash ph); SignalFfiError *signal_pin_hash_clone(SignalMutPointerPinHash *new_obj, SignalConstPointerPinHash obj); -SignalFfiError *signal_pin_hash_encryption_key(uint8_t (*out)[32], SignalConstPointerPinHash ph); +SignalFfiError *signal_pin_hash_destroy(SignalMutPointerPinHash p); -SignalFfiError *signal_pin_hash_access_key(uint8_t (*out)[32], SignalConstPointerPinHash ph); +SignalFfiError *signal_pin_hash_encryption_key(uint8_t (*out)[32], SignalConstPointerPinHash ph); SignalFfiError *signal_pin_hash_from_salt(SignalMutPointerPinHash *out, SignalBorrowedBuffer pin, const uint8_t (*salt)[32]); @@ -1967,110 +1633,180 @@ SignalFfiError *signal_pin_local_hash(const char **out, SignalBorrowedBuffer pin SignalFfiError *signal_pin_verify_local_hash(bool *out, const char *encoded_hash, SignalBorrowedBuffer pin); -SignalFfiError *signal_account_entropy_pool_generate(const char **out); +SignalFfiError *signal_plaintext_content_clone(SignalMutPointerPlaintextContent *new_obj, SignalConstPointerPlaintextContent obj); -SignalFfiError *signal_account_entropy_pool_is_valid(bool *out, const char *account_entropy); +SignalFfiError *signal_plaintext_content_deserialize(SignalMutPointerPlaintextContent *out, SignalBorrowedBuffer data); -SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy); +SignalFfiError *signal_plaintext_content_destroy(SignalMutPointerPlaintextContent p); -SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy); +SignalFfiError *signal_plaintext_content_from_decryption_error_message(SignalMutPointerPlaintextContent *out, SignalConstPointerDecryptionErrorMessage m); -SignalFfiError *signal_backup_key_derive_backup_id(uint8_t (*out)[16], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_plaintext_content_get_body(SignalOwnedBuffer *out, SignalConstPointerPlaintextContent obj); -SignalFfiError *signal_backup_key_derive_ec_key(SignalMutPointerPrivateKey *out, const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_plaintext_content_serialize(SignalOwnedBuffer *out, SignalConstPointerPlaintextContent obj); -SignalFfiError *signal_backup_key_derive_local_backup_metadata_key(uint8_t (*out)[SignalLOCAL_BACKUP_METADATA_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN]); +SignalFfiError *signal_pre_key_bundle_clone(SignalMutPointerPreKeyBundle *new_obj, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_backup_key_derive_media_id(uint8_t (*out)[SignalMEDIA_ID_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const char *media_name); +SignalFfiError *signal_pre_key_bundle_destroy(SignalMutPointerPreKeyBundle p); -SignalFfiError *signal_backup_key_derive_media_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); +SignalFfiError *signal_pre_key_bundle_get_device_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_backup_key_derive_thumbnail_transit_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); +SignalFfiError *signal_pre_key_bundle_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle p); -SignalFfiError *signal_svr2_client_new(SignalMutPointerSgxClientState *out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_incremental_mac_destroy(SignalMutPointerIncrementalMac p); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalMutPointerKyberPublicKey *out, SignalConstPointerPreKeyBundle bundle); -SignalFfiError *signal_incremental_mac_calculate_chunk_size(uint32_t *out, uint32_t data_size); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle bundle); -SignalFfiError *signal_incremental_mac_initialize(SignalMutPointerIncrementalMac *out, SignalBorrowedBuffer key, uint32_t chunk_size); +SignalFfiError *signal_pre_key_bundle_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); +SignalFfiError *signal_pre_key_bundle_get_pre_key_public(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_incremental_mac_finalize(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac); +SignalFfiError *signal_pre_key_bundle_get_registration_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_validating_mac_destroy(SignalMutPointerValidatingMac p); +SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_validating_mac_initialize(SignalMutPointerValidatingMac *out, SignalBorrowedBuffer key, uint32_t chunk_size, SignalBorrowedBuffer digests); +SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_public(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_validating_mac_update(int32_t *out, SignalMutPointerValidatingMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); +SignalFfiError *signal_pre_key_bundle_get_signed_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle obj); -SignalFfiError *signal_validating_mac_finalize(int32_t *out, SignalMutPointerValidatingMac mac); +SignalFfiError *signal_pre_key_bundle_new(SignalMutPointerPreKeyBundle *out, uint32_t registration_id, uint32_t device_id, uint32_t prekey_id, SignalConstPointerPublicKey prekey, uint32_t signed_prekey_id, SignalConstPointerPublicKey signed_prekey, SignalBorrowedBuffer signed_prekey_signature, SignalConstPointerPublicKey identity_key, uint32_t kyber_prekey_id, SignalConstPointerKyberPublicKey kyber_prekey, SignalBorrowedBuffer kyber_prekey_signature); -SignalFfiError *signal_message_backup_key_destroy(SignalMutPointerMessageBackupKey p); +SignalFfiError *signal_pre_key_record_clone(SignalMutPointerPreKeyRecord *new_obj, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_message_backup_validation_outcome_destroy(SignalMutPointerMessageBackupValidationOutcome p); +SignalFfiError *signal_pre_key_record_deserialize(SignalMutPointerPreKeyRecord *out, SignalBorrowedBuffer data); -SignalFfiError *signal_message_backup_key_from_master_key(SignalMutPointerMessageBackupKey *out, const uint8_t (*master_key)[32], const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_pre_key_record_destroy(SignalMutPointerPreKeyRecord p); -SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMutPointerMessageBackupKey *out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_pre_key_record_get_id(uint32_t *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMutPointerMessageBackupKey *out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16]); +SignalFfiError *signal_pre_key_record_get_private_key(SignalMutPointerPrivateKey *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_message_backup_key_get_hmac_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); +SignalFfiError *signal_pre_key_record_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_message_backup_key_get_aes_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); +SignalFfiError *signal_pre_key_record_new(SignalMutPointerPreKeyRecord *out, uint32_t id, SignalConstPointerPublicKey pub_key, SignalConstPointerPrivateKey priv_key); -SignalFfiError *signal_message_backup_validation_outcome_get_error_message(const char **out, SignalConstPointerMessageBackupValidationOutcome outcome); +SignalFfiError *signal_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerPreKeyRecord obj); -SignalFfiError *signal_message_backup_validation_outcome_get_unknown_fields(SignalStringArray *out, SignalConstPointerMessageBackupValidationOutcome outcome); +SignalFfiError *signal_pre_key_signal_message_clone(SignalMutPointerPreKeySignalMessage *new_obj, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_message_backup_validator_validate(SignalMutPointerMessageBackupValidationOutcome *out, SignalConstPointerMessageBackupKey key, SignalConstPointerFfiInputStreamStruct first_stream, SignalConstPointerFfiInputStreamStruct second_stream, uint64_t len, uint8_t purpose); +SignalFfiError *signal_pre_key_signal_message_deserialize(SignalMutPointerPreKeySignalMessage *out, SignalBorrowedBuffer data); -SignalFfiError *signal_online_backup_validator_destroy(SignalMutPointerOnlineBackupValidator p); +SignalFfiError *signal_pre_key_signal_message_destroy(SignalMutPointerPreKeySignalMessage p); -SignalFfiError *signal_online_backup_validator_new(SignalMutPointerOnlineBackupValidator *out, SignalBorrowedBuffer backup_info_frame, uint8_t purpose); +SignalFfiError *signal_pre_key_signal_message_get_base_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeySignalMessage m); -SignalFfiError *signal_online_backup_validator_add_frame(SignalMutPointerOnlineBackupValidator backup, SignalBorrowedBuffer frame); +SignalFfiError *signal_pre_key_signal_message_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeySignalMessage m); -SignalFfiError *signal_online_backup_validator_finalize(SignalMutPointerOnlineBackupValidator backup); +SignalFfiError *signal_pre_key_signal_message_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); +SignalFfiError *signal_pre_key_signal_message_get_registration_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_username_proof(SignalOwnedBuffer *out, const char *username, const uint8_t (*randomness)[32]); +SignalFfiError *signal_pre_key_signal_message_get_signal_message(SignalMutPointerSignalMessage *out, SignalConstPointerPreKeySignalMessage m); -SignalFfiError *signal_username_verify(SignalBorrowedBuffer proof, SignalBorrowedBuffer hash); +SignalFfiError *signal_pre_key_signal_message_get_signed_pre_key_id(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_username_candidates_from(SignalStringArray *out, const char *nickname, uint32_t min_len, uint32_t max_len); +SignalFfiError *signal_pre_key_signal_message_get_version(uint32_t *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_username_hash_from_parts(uint8_t (*out)[32], const char *nickname, const char *discriminator, uint32_t min_len, uint32_t max_len); +SignalFfiError *signal_pre_key_signal_message_new(SignalMutPointerPreKeySignalMessage *out, uint8_t message_version, uint32_t registration_id, uint32_t pre_key_id, uint32_t signed_pre_key_id, SignalConstPointerPublicKey base_key, SignalConstPointerPublicKey identity_key, SignalConstPointerSignalMessage signal_message); -SignalFfiError *signal_username_link_create(SignalOwnedBuffer *out, const char *username, SignalBorrowedBuffer entropy); +SignalFfiError *signal_pre_key_signal_message_serialize(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage obj); -SignalFfiError *signal_username_link_decrypt_username(const char **out, SignalBorrowedBuffer entropy, SignalBorrowedBuffer encrypted_username); +void signal_print_ptr(const void *p); -#if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_destroy(SignalMutPointerSanitizedMetadata p); -#endif +SignalFfiError *signal_privatekey_agree(SignalOwnedBuffer *out, SignalConstPointerPrivateKey private_key, SignalConstPointerPublicKey public_key); + +SignalFfiError *signal_privatekey_clone(SignalMutPointerPrivateKey *new_obj, SignalConstPointerPrivateKey obj); + +SignalFfiError *signal_privatekey_deserialize(SignalMutPointerPrivateKey *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_privatekey_destroy(SignalMutPointerPrivateKey p); + +SignalFfiError *signal_privatekey_generate(SignalMutPointerPrivateKey *out); + +SignalFfiError *signal_privatekey_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPrivateKey k); + +SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstPointerPrivateKey obj); + +SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); + +SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); + +SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); + +SignalFfiError *signal_profile_key_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_profile_key_ciphertext_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_profile_key_commitment_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_profile_key_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_profile_key_credential_presentation_get_profile_key_ciphertext(unsigned char (*out)[SignalPROFILE_KEY_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_profile_key_credential_presentation_get_uuid_ciphertext(unsigned char (*out)[SignalUUID_CIPHERTEXT_LEN], SignalBorrowedBuffer presentation_bytes); + +SignalFfiError *signal_profile_key_credential_request_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_profile_key_credential_request_context_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_profile_key_credential_request_context_get_request(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const unsigned char (*context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]); + +SignalFfiError *signal_profile_key_derive_access_key(uint8_t (*out)[SignalACCESS_KEY_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); + +SignalFfiError *signal_profile_key_get_commitment(unsigned char (*out)[SignalPROFILE_KEY_COMMITMENT_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); + +SignalFfiError *signal_profile_key_get_profile_key_version(uint8_t (*out)[SignalPROFILE_KEY_VERSION_ENCODED_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); + +SignalFfiError *signal_publickey_clone(SignalMutPointerPublicKey *new_obj, SignalConstPointerPublicKey obj); + +SignalFfiError *signal_publickey_compare(int32_t *out, SignalConstPointerPublicKey key1, SignalConstPointerPublicKey key2); + +SignalFfiError *signal_publickey_deserialize(SignalMutPointerPublicKey *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_publickey_destroy(SignalMutPointerPublicKey p); + +SignalFfiError *signal_publickey_equals(bool *out, SignalConstPointerPublicKey lhs, SignalConstPointerPublicKey rhs); + +SignalFfiError *signal_publickey_get_public_key_bytes(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); + +SignalFfiError *signal_publickey_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); + +SignalFfiError *signal_publickey_verify(bool *out, SignalConstPointerPublicKey key, SignalBorrowedBuffer message, SignalBorrowedBuffer signature); + +SignalFfiError *signal_receipt_credential_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_receipt_credential_get_receipt_expiration_time(uint64_t *out, const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); + +SignalFfiError *signal_receipt_credential_get_receipt_level(uint64_t *out, const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); + +SignalFfiError *signal_receipt_credential_presentation_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_receipt_credential_presentation_get_receipt_expiration_time(uint64_t *out, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); + +SignalFfiError *signal_receipt_credential_presentation_get_receipt_level(uint64_t *out, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); + +SignalFfiError *signal_receipt_credential_presentation_get_receipt_serial(uint8_t (*out)[SignalRECEIPT_SERIAL_LEN], const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); + +SignalFfiError *signal_receipt_credential_request_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_receipt_credential_request_context_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_receipt_credential_request_context_get_request(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN]); + +SignalFfiError *signal_receipt_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); #if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_clone(SignalMutPointerSanitizedMetadata *new_obj, SignalConstPointerSanitizedMetadata obj); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_signal_media_check_available(void); +SignalFfiError *signal_sanitized_metadata_destroy(SignalMutPointerSanitizedMetadata p); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_mp4_sanitizer_sanitize(SignalMutPointerSanitizedMetadata *out, SignalConstPointerFfiInputStreamStruct input, uint64_t len); -#endif - -#if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_webp_sanitizer_sanitize(SignalConstPointerFfiSyncInputStreamStruct input); -#endif - -#if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_get_metadata(SignalOwnedBuffer *out, SignalConstPointerSanitizedMetadata sanitized); +SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, SignalConstPointerSanitizedMetadata sanitized); #endif #if defined(SIGNAL_MEDIA_SUPPORTED) @@ -2078,7 +1814,297 @@ SignalFfiError *signal_sanitized_metadata_get_data_offset(uint64_t *out, SignalC #endif #if defined(SIGNAL_MEDIA_SUPPORTED) -SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, SignalConstPointerSanitizedMetadata sanitized); +SignalFfiError *signal_sanitized_metadata_get_metadata(SignalOwnedBuffer *out, SignalConstPointerSanitizedMetadata sanitized); +#endif + +SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfConstPointerProtocolAddress recipients, SignalBorrowedSliceOfConstPointerSessionRecord recipient_sessions, SignalBorrowedBuffer excluded_recipients, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); + +SignalFfiError *signal_sealed_sender_multi_recipient_message_for_single_recipient(SignalOwnedBuffer *out, SignalBorrowedBuffer encoded_multi_recipient_message); + +SignalFfiError *signal_sealed_session_cipher_decrypt(SignalOwnedBuffer *out, const char **sender_e164, const char **sender_uuid, uint32_t *sender_device_id, SignalBorrowedBuffer ctext, SignalConstPointerPublicKey trust_root, uint64_t timestamp, const char *local_e164, const char *local_uuid, unsigned int local_device_id, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store); + +SignalFfiError *signal_sealed_session_cipher_decrypt_to_usmc(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer ctext, SignalConstPointerFfiIdentityKeyStoreStruct identity_store); + +SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress destination, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); + +SignalFfiError *signal_sender_certificate_clone(SignalMutPointerSenderCertificate *new_obj, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_deserialize(SignalMutPointerSenderCertificate *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_sender_certificate_destroy(SignalMutPointerSenderCertificate p); + +SignalFfiError *signal_sender_certificate_get_certificate(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_device_id(uint32_t *out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_expiration(uint64_t *out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_sender_e164(const char **out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_sender_uuid(const char **out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_get_server_certificate(SignalMutPointerServerCertificate *out, SignalConstPointerSenderCertificate cert); + +SignalFfiError *signal_sender_certificate_get_signature(SignalOwnedBuffer *out, SignalConstPointerSenderCertificate obj); + +SignalFfiError *signal_sender_certificate_new(SignalMutPointerSenderCertificate *out, const char *sender_uuid, const char *sender_e164, uint32_t sender_device_id, SignalConstPointerPublicKey sender_key, uint64_t expiration, SignalConstPointerServerCertificate signer_cert, SignalConstPointerPrivateKey signer_key); + +SignalFfiError *signal_sender_certificate_validate(bool *out, SignalConstPointerSenderCertificate cert, SignalConstPointerPublicKey key, uint64_t time); + +SignalFfiError *signal_sender_key_distribution_message_clone(SignalMutPointerSenderKeyDistributionMessage *new_obj, SignalConstPointerSenderKeyDistributionMessage obj); + +SignalFfiError *signal_sender_key_distribution_message_create(SignalMutPointerSenderKeyDistributionMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalConstPointerFfiSenderKeyStoreStruct store); + +SignalFfiError *signal_sender_key_distribution_message_deserialize(SignalMutPointerSenderKeyDistributionMessage *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_sender_key_distribution_message_destroy(SignalMutPointerSenderKeyDistributionMessage p); + +SignalFfiError *signal_sender_key_distribution_message_get_chain_id(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); + +SignalFfiError *signal_sender_key_distribution_message_get_chain_key(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); + +SignalFfiError *signal_sender_key_distribution_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyDistributionMessage obj); + +SignalFfiError *signal_sender_key_distribution_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); + +SignalFfiError *signal_sender_key_distribution_message_get_signature_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderKeyDistributionMessage m); + +SignalFfiError *signal_sender_key_distribution_message_new(SignalMutPointerSenderKeyDistributionMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer chainkey, SignalConstPointerPublicKey pk); + +SignalFfiError *signal_sender_key_distribution_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); + +SignalFfiError *signal_sender_key_message_clone(SignalMutPointerSenderKeyMessage *new_obj, SignalConstPointerSenderKeyMessage obj); + +SignalFfiError *signal_sender_key_message_deserialize(SignalMutPointerSenderKeyMessage *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_sender_key_message_destroy(SignalMutPointerSenderKeyMessage p); + +SignalFfiError *signal_sender_key_message_get_chain_id(uint32_t *out, SignalConstPointerSenderKeyMessage obj); + +SignalFfiError *signal_sender_key_message_get_cipher_text(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); + +SignalFfiError *signal_sender_key_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyMessage obj); + +SignalFfiError *signal_sender_key_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyMessage obj); + +SignalFfiError *signal_sender_key_message_new(SignalMutPointerSenderKeyMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer ciphertext, SignalConstPointerPrivateKey pk); + +SignalFfiError *signal_sender_key_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); + +SignalFfiError *signal_sender_key_message_verify_signature(bool *out, SignalConstPointerSenderKeyMessage skm, SignalConstPointerPublicKey pubkey); + +SignalFfiError *signal_sender_key_record_clone(SignalMutPointerSenderKeyRecord *new_obj, SignalConstPointerSenderKeyRecord obj); + +SignalFfiError *signal_sender_key_record_deserialize(SignalMutPointerSenderKeyRecord *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_sender_key_record_destroy(SignalMutPointerSenderKeyRecord p); + +SignalFfiError *signal_sender_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyRecord obj); + +SignalFfiError *signal_server_certificate_clone(SignalMutPointerServerCertificate *new_obj, SignalConstPointerServerCertificate obj); + +SignalFfiError *signal_server_certificate_deserialize(SignalMutPointerServerCertificate *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_server_certificate_destroy(SignalMutPointerServerCertificate p); + +SignalFfiError *signal_server_certificate_get_certificate(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); + +SignalFfiError *signal_server_certificate_get_key(SignalMutPointerPublicKey *out, SignalConstPointerServerCertificate obj); + +SignalFfiError *signal_server_certificate_get_key_id(uint32_t *out, SignalConstPointerServerCertificate obj); + +SignalFfiError *signal_server_certificate_get_serialized(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); + +SignalFfiError *signal_server_certificate_get_signature(SignalOwnedBuffer *out, SignalConstPointerServerCertificate obj); + +SignalFfiError *signal_server_certificate_new(SignalMutPointerServerCertificate *out, uint32_t key_id, SignalConstPointerPublicKey server_key, SignalConstPointerPrivateKey trust_root); + +SignalFfiError *signal_server_message_ack_destroy(SignalMutPointerServerMessageAck p); + +SignalFfiError *signal_server_message_ack_send(SignalConstPointerServerMessageAck ack); + +SignalFfiError *signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], SignalBorrowedBuffer auth_credential_with_pni_bytes); + +SignalFfiError *signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*group_secret_params)[SignalGROUP_SECRET_PARAMS_LEN], const unsigned char (*profile_key_credential)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]); + +SignalFfiError *signal_server_public_params_create_profile_key_credential_request_context_deterministic(unsigned char (*out)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN]); + +SignalFfiError *signal_server_public_params_create_receipt_credential_presentation_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*receipt_credential)[SignalRECEIPT_CREDENTIAL_LEN]); + +SignalFfiError *signal_server_public_params_create_receipt_credential_request_context_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], SignalConstPointerServerPublicParams server_public_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const uint8_t (*receipt_serial)[SignalRECEIPT_SERIAL_LEN]); + +SignalFfiError *signal_server_public_params_deserialize(SignalMutPointerServerPublicParams *out, SignalBorrowedBuffer buffer); + +SignalFfiError *signal_server_public_params_destroy(SignalMutPointerServerPublicParams p); + +SignalFfiError *signal_server_public_params_get_endorsement_public_key(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params); + +SignalFfiError *signal_server_public_params_receive_auth_credential_with_pni_as_service_id(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams params, const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time, SignalBorrowedBuffer auth_credential_with_pni_response_bytes); + +SignalFfiError *signal_server_public_params_receive_expiring_profile_key_credential(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN], SignalConstPointerServerPublicParams server_public_params, const unsigned char (*request_context)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], uint64_t current_time_in_seconds); + +SignalFfiError *signal_server_public_params_receive_receipt_credential(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_LEN], SignalConstPointerServerPublicParams server_public_params, const unsigned char (*request_context)[SignalRECEIPT_CREDENTIAL_REQUEST_CONTEXT_LEN], const unsigned char (*response)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN]); + +SignalFfiError *signal_server_public_params_serialize(SignalOwnedBuffer *out, SignalConstPointerServerPublicParams handle); + +SignalFfiError *signal_server_public_params_verify_signature(SignalConstPointerServerPublicParams server_public_params, SignalBorrowedBuffer message, const uint8_t (*notary_signature)[SignalSIGNATURE_LEN]); + +SignalFfiError *signal_server_secret_params_deserialize(SignalMutPointerServerSecretParams *out, SignalBorrowedBuffer buffer); + +SignalFfiError *signal_server_secret_params_destroy(SignalMutPointerServerSecretParams p); + +SignalFfiError *signal_server_secret_params_generate_deterministic(SignalMutPointerServerSecretParams *out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]); + +SignalFfiError *signal_server_secret_params_get_public_params(SignalMutPointerServerPublicParams *out, SignalConstPointerServerSecretParams params); + +SignalFfiError *signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(SignalOwnedBuffer *out, SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const SignalServiceIdFixedWidthBinaryBytes *aci, const SignalServiceIdFixedWidthBinaryBytes *pni, uint64_t redemption_time); + +SignalFfiError *signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(unsigned char (*out)[SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN], SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id, const unsigned char (*commitment)[SignalPROFILE_KEY_COMMITMENT_LEN], uint64_t expiration_in_seconds); + +SignalFfiError *signal_server_secret_params_issue_receipt_credential_deterministic(unsigned char (*out)[SignalRECEIPT_CREDENTIAL_RESPONSE_LEN], SignalConstPointerServerSecretParams server_secret_params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], const unsigned char (*request)[SignalRECEIPT_CREDENTIAL_REQUEST_LEN], uint64_t receipt_expiration_time, uint64_t receipt_level); + +SignalFfiError *signal_server_secret_params_serialize(SignalOwnedBuffer *out, SignalConstPointerServerSecretParams handle); + +SignalFfiError *signal_server_secret_params_sign_deterministic(uint8_t (*out)[SignalSIGNATURE_LEN], SignalConstPointerServerSecretParams params, const uint8_t (*randomness)[SignalRANDOMNESS_LEN], SignalBorrowedBuffer message); + +SignalFfiError *signal_server_secret_params_verify_auth_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); + +SignalFfiError *signal_server_secret_params_verify_profile_key_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*group_public_params)[SignalGROUP_PUBLIC_PARAMS_LEN], SignalBorrowedBuffer presentation_bytes, uint64_t current_time_in_seconds); + +SignalFfiError *signal_server_secret_params_verify_receipt_credential_presentation(SignalConstPointerServerSecretParams server_secret_params, const unsigned char (*presentation)[SignalRECEIPT_CREDENTIAL_PRESENTATION_LEN]); + +SignalFfiError *signal_service_id_parse_from_service_id_binary(SignalServiceIdFixedWidthBinaryBytes *out, SignalBorrowedBuffer input); + +SignalFfiError *signal_service_id_parse_from_service_id_string(SignalServiceIdFixedWidthBinaryBytes *out, const char *input); + +SignalFfiError *signal_service_id_service_id_binary(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *value); + +SignalFfiError *signal_service_id_service_id_log(const char **out, const SignalServiceIdFixedWidthBinaryBytes *value); + +SignalFfiError *signal_service_id_service_id_string(const char **out, const SignalServiceIdFixedWidthBinaryBytes *value); + +SignalFfiError *signal_session_record_archive_current_state(SignalMutPointerSessionRecord session_record); + +SignalFfiError *signal_session_record_clone(SignalMutPointerSessionRecord *new_obj, SignalConstPointerSessionRecord obj); + +SignalFfiError *signal_session_record_current_ratchet_key_matches(bool *out, SignalConstPointerSessionRecord s, SignalConstPointerPublicKey key); + +SignalFfiError *signal_session_record_deserialize(SignalMutPointerSessionRecord *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_session_record_destroy(SignalMutPointerSessionRecord p); + +SignalFfiError *signal_session_record_get_local_registration_id(uint32_t *out, SignalConstPointerSessionRecord obj); + +SignalFfiError *signal_session_record_get_remote_registration_id(uint32_t *out, SignalConstPointerSessionRecord obj); + +SignalFfiError *signal_session_record_has_usable_sender_chain(bool *out, SignalConstPointerSessionRecord s, uint64_t now); + +SignalFfiError *signal_session_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSessionRecord obj); + +SignalFfiError *signal_sgx_client_state_complete_handshake(SignalMutPointerSgxClientState cli, SignalBorrowedBuffer handshake_received); + +SignalFfiError *signal_sgx_client_state_destroy(SignalMutPointerSgxClientState p); + +SignalFfiError *signal_sgx_client_state_established_recv(SignalOwnedBuffer *out, SignalMutPointerSgxClientState cli, SignalBorrowedBuffer received_ciphertext); + +SignalFfiError *signal_sgx_client_state_established_send(SignalOwnedBuffer *out, SignalMutPointerSgxClientState cli, SignalBorrowedBuffer plaintext_to_send); + +SignalFfiError *signal_sgx_client_state_initial_request(SignalOwnedBuffer *out, SignalConstPointerSgxClientState obj); + +#if defined(SIGNAL_MEDIA_SUPPORTED) +SignalFfiError *signal_signal_media_check_available(void); +#endif + +SignalFfiError *signal_signed_pre_key_record_clone(SignalMutPointerSignedPreKeyRecord *new_obj, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_signed_pre_key_record_deserialize(SignalMutPointerSignedPreKeyRecord *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_signed_pre_key_record_destroy(SignalMutPointerSignedPreKeyRecord p); + +SignalFfiError *signal_signed_pre_key_record_get_id(uint32_t *out, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_signed_pre_key_record_get_private_key(SignalMutPointerPrivateKey *out, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_signed_pre_key_record_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_signed_pre_key_record_get_signature(SignalOwnedBuffer *out, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_signed_pre_key_record_get_timestamp(uint64_t *out, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_signed_pre_key_record_new(SignalMutPointerSignedPreKeyRecord *out, uint32_t id, uint64_t timestamp, SignalConstPointerPublicKey pub_key, SignalConstPointerPrivateKey priv_key, SignalBorrowedBuffer signature); + +SignalFfiError *signal_signed_pre_key_record_serialize(SignalOwnedBuffer *out, SignalConstPointerSignedPreKeyRecord obj); + +SignalFfiError *signal_svr2_client_new(SignalMutPointerSgxClientState *out, SignalBorrowedBuffer mrenclave, SignalBorrowedBuffer attestation_msg, uint64_t current_timestamp); + +SignalFfiError *signal_tokio_async_context_cancel(SignalConstPointerTokioAsyncContext context, uint64_t raw_cancellation_id); + +SignalFfiError *signal_tokio_async_context_destroy(SignalMutPointerTokioAsyncContext p); + +SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext *out); + +SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); + +SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); + +SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat); + +SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); + +SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); + +SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); + +SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); + +SignalFfiError *signal_unidentified_sender_message_content_destroy(SignalMutPointerUnidentifiedSenderMessageContent p); + +SignalFfiError *signal_unidentified_sender_message_content_get_content_hint(uint32_t *out, SignalConstPointerUnidentifiedSenderMessageContent m); + +SignalFfiError *signal_unidentified_sender_message_content_get_contents(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent obj); + +SignalFfiError *signal_unidentified_sender_message_content_get_group_id_or_empty(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent m); + +SignalFfiError *signal_unidentified_sender_message_content_get_msg_type(uint8_t *out, SignalConstPointerUnidentifiedSenderMessageContent m); + +SignalFfiError *signal_unidentified_sender_message_content_get_sender_cert(SignalMutPointerSenderCertificate *out, SignalConstPointerUnidentifiedSenderMessageContent m); + +SignalFfiError *signal_unidentified_sender_message_content_new(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalConstPointerCiphertextMessage message, SignalConstPointerSenderCertificate sender, uint32_t content_hint, SignalBorrowedBuffer group_id); + +SignalFfiError *signal_unidentified_sender_message_content_new_from_content_and_type(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer message_content, uint8_t message_type, SignalConstPointerSenderCertificate sender, uint32_t content_hint, SignalBorrowedBuffer group_id); + +SignalFfiError *signal_unidentified_sender_message_content_serialize(SignalOwnedBuffer *out, SignalConstPointerUnidentifiedSenderMessageContent obj); + +SignalFfiError *signal_username_candidates_from(SignalStringArray *out, const char *nickname, uint32_t min_len, uint32_t max_len); + +SignalFfiError *signal_username_hash(uint8_t (*out)[32], const char *username); + +SignalFfiError *signal_username_hash_from_parts(uint8_t (*out)[32], const char *nickname, const char *discriminator, uint32_t min_len, uint32_t max_len); + +SignalFfiError *signal_username_link_create(SignalOwnedBuffer *out, const char *username, SignalBorrowedBuffer entropy); + +SignalFfiError *signal_username_link_decrypt_username(const char **out, SignalBorrowedBuffer entropy, SignalBorrowedBuffer encrypted_username); + +SignalFfiError *signal_username_proof(SignalOwnedBuffer *out, const char *username, const uint8_t (*randomness)[32]); + +SignalFfiError *signal_username_verify(SignalBorrowedBuffer proof, SignalBorrowedBuffer hash); + +SignalFfiError *signal_uuid_ciphertext_check_valid_contents(SignalBorrowedBuffer buffer); + +SignalFfiError *signal_validating_mac_destroy(SignalMutPointerValidatingMac p); + +SignalFfiError *signal_validating_mac_finalize(int32_t *out, SignalMutPointerValidatingMac mac); + +SignalFfiError *signal_validating_mac_initialize(SignalMutPointerValidatingMac *out, SignalBorrowedBuffer key, uint32_t chunk_size, SignalBorrowedBuffer digests); + +SignalFfiError *signal_validating_mac_update(int32_t *out, SignalMutPointerValidatingMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); + +#if defined(SIGNAL_MEDIA_SUPPORTED) +SignalFfiError *signal_webp_sanitizer_sanitize(SignalConstPointerFfiSyncInputStreamStruct input); #endif #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 30d8666..631a0a2 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.67.4" +const Version = "v0.70.0" From e9dbb9640157abb9c5a0eb243a9ff0f339ed5259 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 15 Apr 2025 15:22:31 +0300 Subject: [PATCH 455/718] signalmeow: update protobufs --- pkg/msgconv/from-signal-backup.go | 20 +- pkg/msgconv/from-signal.go | 4 +- pkg/signalmeow/contact.go | 9 +- pkg/signalmeow/protobuf/SignalService.pb.go | 3696 +++++++++-------- pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19370 -> 19700 bytes pkg/signalmeow/protobuf/SignalService.proto | 1093 ++--- pkg/signalmeow/protobuf/StorageService.pb.go | 635 ++- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 6238 -> 7611 bytes pkg/signalmeow/protobuf/StorageService.proto | 66 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 939 +++-- .../protobuf/backuppb/Backup.pb.raw | Bin 31259 -> 31810 bytes pkg/signalmeow/protobuf/backuppb/Backup.proto | 35 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- pkg/signalmeow/receiving.go | 8 +- pkg/signalmeow/sending.go | 22 +- 15 files changed, 3652 insertions(+), 2879 deletions(-) diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index ccb4e50..d5532cd 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -189,16 +189,16 @@ func backupToSignalAttachment( atts map[uuid.UUID]*backuppb.FilePointer_BackupLocator, ) *signalpb.AttachmentPointer { sig := &signalpb.AttachmentPointer{ - ContentType: fp.ContentType, - IncrementalMac: fp.IncrementalMac, - IncrementalMacChunkSize: fp.IncrementalMacChunkSize, - FileName: fp.FileName, - Flags: ptr.NonZero(uint32(backupToSignalAttachmentFlag(flag))), - Width: fp.Width, - Height: fp.Height, - Caption: nil, // is this field deprecated or something? - BlurHash: fp.BlurHash, - Uuid: clientUUID[:], + //IncrementalMacChunkSize: fp.IncrementalMacChunkSize, + ContentType: fp.ContentType, + IncrementalMac: fp.IncrementalMac, + FileName: fp.FileName, + Flags: ptr.NonZero(uint32(backupToSignalAttachmentFlag(flag))), + Width: fp.Width, + Height: fp.Height, + Caption: nil, // is this field deprecated or something? + BlurHash: fp.BlurHash, + ClientUuid: clientUUID[:], } switch loc := fp.Locator.(type) { case *backuppb.FilePointer_AttachmentLocator_: diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 7ee29b7..fb80394 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -465,10 +465,10 @@ func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *sig func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) ([]byte, error) { if att.AttachmentIdentifier == nil { - if len(att.GetUuid()) != 16 { + if len(att.GetClientUuid()) != 16 { return nil, fmt.Errorf("no attachment identifier found") } - target, ok := attMap[uuid.UUID(att.GetUuid())] + target, ok := attMap[uuid.UUID(att.GetClientUuid())] if !ok { return nil, fmt.Errorf("no attachment identifier and attachment not found in map") } else if target == nil { diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index fdea194..9e7eec2 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -30,7 +30,6 @@ import ( "github.com/rs/zerolog" "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/types" ) @@ -49,10 +48,10 @@ func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDeta recipient.E164 = contactDetails.GetNumber() } recipient.ContactName = contactDetails.GetName() - if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { - profileKey := libsignalgo.ProfileKey(profileKeyString) - recipient.Profile.Key = profileKey - } + //if profileKeyString := contactDetails.GetProfileKey(); profileKeyString != nil { + // profileKey := libsignalgo.ProfileKey(profileKeyString) + // recipient.Profile.Key = profileKey + //} if avatar != nil && *avatar != nil && len(*avatar) > 0 { rawHash := sha256.Sum256(*avatar) avatarHash := hex.EncodeToString(rawHash[:]) diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index aed9592..2e8d5b0 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -1,7 +1,6 @@ -//* -// Copyright (C) 2014-2016 Open Whisper Systems // -// Licensed according to the LICENSE file in this repository. +// Copyright 2020-2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only // Code generated by protoc-gen-go. DO NOT EDIT. // versions: @@ -30,13 +29,13 @@ const ( type Envelope_Type int32 const ( - Envelope_UNKNOWN Envelope_Type = 0 - Envelope_CIPHERTEXT Envelope_Type = 1 - Envelope_KEY_EXCHANGE Envelope_Type = 2 - Envelope_PREKEY_BUNDLE Envelope_Type = 3 - Envelope_RECEIPT Envelope_Type = 5 - Envelope_UNIDENTIFIED_SENDER Envelope_Type = 6 - Envelope_PLAINTEXT_CONTENT Envelope_Type = 8 + Envelope_UNKNOWN Envelope_Type = 0 + Envelope_CIPHERTEXT Envelope_Type = 1 // content => (version byte | SignalMessage{Content}) + Envelope_PREKEY_BUNDLE Envelope_Type = 3 // content => (version byte | PreKeySignalMessage{Content}) + Envelope_SERVER_DELIVERY_RECEIPT Envelope_Type = 5 // legacyMessage => [] AND content => [] + Envelope_UNIDENTIFIED_SENDER Envelope_Type = 6 // legacyMessage => [] AND content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) + Envelope_SENDERKEY_MESSAGE Envelope_Type = 7 // legacyMessage => [] AND content => (version byte | SenderKeyMessage) + Envelope_PLAINTEXT_CONTENT Envelope_Type = 8 // legacyMessage => [] AND content => (marker byte | Content) ) // Enum value maps for Envelope_Type. @@ -44,20 +43,20 @@ var ( Envelope_Type_name = map[int32]string{ 0: "UNKNOWN", 1: "CIPHERTEXT", - 2: "KEY_EXCHANGE", 3: "PREKEY_BUNDLE", - 5: "RECEIPT", + 5: "SERVER_DELIVERY_RECEIPT", 6: "UNIDENTIFIED_SENDER", + 7: "SENDERKEY_MESSAGE", 8: "PLAINTEXT_CONTENT", } Envelope_Type_value = map[string]int32{ - "UNKNOWN": 0, - "CIPHERTEXT": 1, - "KEY_EXCHANGE": 2, - "PREKEY_BUNDLE": 3, - "RECEIPT": 5, - "UNIDENTIFIED_SENDER": 6, - "PLAINTEXT_CONTENT": 8, + "UNKNOWN": 0, + "CIPHERTEXT": 1, + "PREKEY_BUNDLE": 3, + "SERVER_DELIVERY_RECEIPT": 5, + "UNIDENTIFIED_SENDER": 6, + "SENDERKEY_MESSAGE": 7, + "PLAINTEXT_CONTENT": 8, } ) @@ -275,80 +274,13 @@ func (CallMessage_Opaque_Urgency) EnumDescriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{2, 5, 0} } -type BodyRange_Style int32 - -const ( - BodyRange_NONE BodyRange_Style = 0 - BodyRange_BOLD BodyRange_Style = 1 - BodyRange_ITALIC BodyRange_Style = 2 - BodyRange_SPOILER BodyRange_Style = 3 - BodyRange_STRIKETHROUGH BodyRange_Style = 4 - BodyRange_MONOSPACE BodyRange_Style = 5 -) - -// Enum value maps for BodyRange_Style. -var ( - BodyRange_Style_name = map[int32]string{ - 0: "NONE", - 1: "BOLD", - 2: "ITALIC", - 3: "SPOILER", - 4: "STRIKETHROUGH", - 5: "MONOSPACE", - } - BodyRange_Style_value = map[string]int32{ - "NONE": 0, - "BOLD": 1, - "ITALIC": 2, - "SPOILER": 3, - "STRIKETHROUGH": 4, - "MONOSPACE": 5, - } -) - -func (x BodyRange_Style) Enum() *BodyRange_Style { - p := new(BodyRange_Style) - *p = x - return p -} - -func (x BodyRange_Style) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (BodyRange_Style) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[4].Descriptor() -} - -func (BodyRange_Style) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[4] -} - -func (x BodyRange_Style) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Do not use. -func (x *BodyRange_Style) UnmarshalJSON(b []byte) error { - num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) - if err != nil { - return err - } - *x = BodyRange_Style(num) - return nil -} - -// Deprecated: Use BodyRange_Style.Descriptor instead. -func (BodyRange_Style) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{3, 0} -} - type DataMessage_Flags int32 const ( DataMessage_END_SESSION DataMessage_Flags = 1 DataMessage_EXPIRATION_TIMER_UPDATE DataMessage_Flags = 2 DataMessage_PROFILE_KEY_UPDATE DataMessage_Flags = 4 + DataMessage_FORWARD DataMessage_Flags = 8 ) // Enum value maps for DataMessage_Flags. @@ -357,11 +289,13 @@ var ( 1: "END_SESSION", 2: "EXPIRATION_TIMER_UPDATE", 4: "PROFILE_KEY_UPDATE", + 8: "FORWARD", } DataMessage_Flags_value = map[string]int32{ "END_SESSION": 1, "EXPIRATION_TIMER_UPDATE": 2, "PROFILE_KEY_UPDATE": 4, + "FORWARD": 8, } ) @@ -376,11 +310,11 @@ func (x DataMessage_Flags) String() string { } func (DataMessage_Flags) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[5].Descriptor() + return file_SignalService_proto_enumTypes[4].Descriptor() } func (DataMessage_Flags) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[5] + return &file_SignalService_proto_enumTypes[4] } func (x DataMessage_Flags) Number() protoreflect.EnumNumber { @@ -399,7 +333,7 @@ func (x *DataMessage_Flags) UnmarshalJSON(b []byte) error { // Deprecated: Use DataMessage_Flags.Descriptor instead. func (DataMessage_Flags) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 0} } type DataMessage_ProtocolVersion int32 @@ -453,11 +387,11 @@ func (x DataMessage_ProtocolVersion) String() string { } func (DataMessage_ProtocolVersion) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[6].Descriptor() + return file_SignalService_proto_enumTypes[5].Descriptor() } func (DataMessage_ProtocolVersion) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[6] + return &file_SignalService_proto_enumTypes[5] } func (x DataMessage_ProtocolVersion) Number() protoreflect.EnumNumber { @@ -476,7 +410,63 @@ func (x *DataMessage_ProtocolVersion) UnmarshalJSON(b []byte) error { // Deprecated: Use DataMessage_ProtocolVersion.Descriptor instead. func (DataMessage_ProtocolVersion) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1} + return file_SignalService_proto_rawDescGZIP(), []int{3, 1} +} + +type DataMessage_Payment_Activation_Type int32 + +const ( + DataMessage_Payment_Activation_REQUEST DataMessage_Payment_Activation_Type = 0 + DataMessage_Payment_Activation_ACTIVATED DataMessage_Payment_Activation_Type = 1 +) + +// Enum value maps for DataMessage_Payment_Activation_Type. +var ( + DataMessage_Payment_Activation_Type_name = map[int32]string{ + 0: "REQUEST", + 1: "ACTIVATED", + } + DataMessage_Payment_Activation_Type_value = map[string]int32{ + "REQUEST": 0, + "ACTIVATED": 1, + } +) + +func (x DataMessage_Payment_Activation_Type) Enum() *DataMessage_Payment_Activation_Type { + p := new(DataMessage_Payment_Activation_Type) + *p = x + return p +} + +func (x DataMessage_Payment_Activation_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DataMessage_Payment_Activation_Type) Descriptor() protoreflect.EnumDescriptor { + return file_SignalService_proto_enumTypes[6].Descriptor() +} + +func (DataMessage_Payment_Activation_Type) Type() protoreflect.EnumType { + return &file_SignalService_proto_enumTypes[6] +} + +func (x DataMessage_Payment_Activation_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *DataMessage_Payment_Activation_Type) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = DataMessage_Payment_Activation_Type(num) + return nil +} + +// Deprecated: Use DataMessage_Payment_Activation_Type.Descriptor instead. +func (DataMessage_Payment_Activation_Type) EnumDescriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0, 2, 0} } type DataMessage_Quote_Type int32 @@ -532,7 +522,7 @@ func (x *DataMessage_Quote_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use DataMessage_Quote_Type.Descriptor instead. func (DataMessage_Quote_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 0, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 1, 0} } type DataMessage_Contact_Phone_Type int32 @@ -594,7 +584,7 @@ func (x *DataMessage_Contact_Phone_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use DataMessage_Contact_Phone_Type.Descriptor instead. func (DataMessage_Contact_Phone_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 1, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 1, 0} } type DataMessage_Contact_Email_Type int32 @@ -656,7 +646,7 @@ func (x *DataMessage_Contact_Email_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use DataMessage_Contact_Email_Type.Descriptor instead. func (DataMessage_Contact_Email_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 2, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 2, 0} } type DataMessage_Contact_PostalAddress_Type int32 @@ -715,63 +705,7 @@ func (x *DataMessage_Contact_PostalAddress_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use DataMessage_Contact_PostalAddress_Type.Descriptor instead. func (DataMessage_Contact_PostalAddress_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 3, 0} -} - -type DataMessage_Payment_Activation_Type int32 - -const ( - DataMessage_Payment_Activation_REQUEST DataMessage_Payment_Activation_Type = 0 - DataMessage_Payment_Activation_ACTIVATED DataMessage_Payment_Activation_Type = 1 -) - -// Enum value maps for DataMessage_Payment_Activation_Type. -var ( - DataMessage_Payment_Activation_Type_name = map[int32]string{ - 0: "REQUEST", - 1: "ACTIVATED", - } - DataMessage_Payment_Activation_Type_value = map[string]int32{ - "REQUEST": 0, - "ACTIVATED": 1, - } -) - -func (x DataMessage_Payment_Activation_Type) Enum() *DataMessage_Payment_Activation_Type { - p := new(DataMessage_Payment_Activation_Type) - *p = x - return p -} - -func (x DataMessage_Payment_Activation_Type) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (DataMessage_Payment_Activation_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[11].Descriptor() -} - -func (DataMessage_Payment_Activation_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[11] -} - -func (x DataMessage_Payment_Activation_Type) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Do not use. -func (x *DataMessage_Payment_Activation_Type) UnmarshalJSON(b []byte) error { - num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) - if err != nil { - return err - } - *x = DataMessage_Payment_Activation_Type(num) - return nil -} - -// Deprecated: Use DataMessage_Payment_Activation_Type.Descriptor instead. -func (DataMessage_Payment_Activation_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 2, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 3, 0} } type ReceiptMessage_Type int32 @@ -807,11 +741,11 @@ func (x ReceiptMessage_Type) String() string { } func (ReceiptMessage_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[12].Descriptor() + return file_SignalService_proto_enumTypes[11].Descriptor() } func (ReceiptMessage_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[12] + return &file_SignalService_proto_enumTypes[11] } func (x ReceiptMessage_Type) Number() protoreflect.EnumNumber { @@ -830,7 +764,7 @@ func (x *ReceiptMessage_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use ReceiptMessage_Type.Descriptor instead. func (ReceiptMessage_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{6, 0} + return file_SignalService_proto_rawDescGZIP(), []int{5, 0} } type TypingMessage_Action int32 @@ -863,11 +797,11 @@ func (x TypingMessage_Action) String() string { } func (TypingMessage_Action) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[13].Descriptor() + return file_SignalService_proto_enumTypes[12].Descriptor() } func (TypingMessage_Action) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[13] + return &file_SignalService_proto_enumTypes[12] } func (x TypingMessage_Action) Number() protoreflect.EnumNumber { @@ -886,7 +820,7 @@ func (x *TypingMessage_Action) UnmarshalJSON(b []byte) error { // Deprecated: Use TypingMessage_Action.Descriptor instead. func (TypingMessage_Action) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{7, 0} + return file_SignalService_proto_rawDescGZIP(), []int{6, 0} } type TextAttachment_Style int32 @@ -931,11 +865,11 @@ func (x TextAttachment_Style) String() string { } func (TextAttachment_Style) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[14].Descriptor() + return file_SignalService_proto_enumTypes[13].Descriptor() } func (TextAttachment_Style) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[14] + return &file_SignalService_proto_enumTypes[13] } func (x TextAttachment_Style) Number() protoreflect.EnumNumber { @@ -954,7 +888,7 @@ func (x *TextAttachment_Style) UnmarshalJSON(b []byte) error { // Deprecated: Use TextAttachment_Style.Descriptor instead. func (TextAttachment_Style) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{10, 0} + return file_SignalService_proto_rawDescGZIP(), []int{9, 0} } type Verified_State int32 @@ -990,11 +924,11 @@ func (x Verified_State) String() string { } func (Verified_State) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[15].Descriptor() + return file_SignalService_proto_enumTypes[14].Descriptor() } func (Verified_State) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[15] + return &file_SignalService_proto_enumTypes[14] } func (x Verified_State) Number() protoreflect.EnumNumber { @@ -1013,19 +947,17 @@ func (x *Verified_State) UnmarshalJSON(b []byte) error { // Deprecated: Use Verified_State.Descriptor instead. func (Verified_State) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{11, 0} + return file_SignalService_proto_rawDescGZIP(), []int{10, 0} } type SyncMessage_Request_Type int32 const ( - SyncMessage_Request_UNKNOWN SyncMessage_Request_Type = 0 - SyncMessage_Request_CONTACTS SyncMessage_Request_Type = 1 - // GROUPS = 2; + SyncMessage_Request_UNKNOWN SyncMessage_Request_Type = 0 + SyncMessage_Request_CONTACTS SyncMessage_Request_Type = 1 SyncMessage_Request_BLOCKED SyncMessage_Request_Type = 3 SyncMessage_Request_CONFIGURATION SyncMessage_Request_Type = 4 SyncMessage_Request_KEYS SyncMessage_Request_Type = 5 - SyncMessage_Request_PNI_IDENTITY SyncMessage_Request_Type = 6 ) // Enum value maps for SyncMessage_Request_Type. @@ -1036,7 +968,6 @@ var ( 3: "BLOCKED", 4: "CONFIGURATION", 5: "KEYS", - 6: "PNI_IDENTITY", } SyncMessage_Request_Type_value = map[string]int32{ "UNKNOWN": 0, @@ -1044,7 +975,6 @@ var ( "BLOCKED": 3, "CONFIGURATION": 4, "KEYS": 5, - "PNI_IDENTITY": 6, } ) @@ -1059,11 +989,11 @@ func (x SyncMessage_Request_Type) String() string { } func (SyncMessage_Request_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[16].Descriptor() + return file_SignalService_proto_enumTypes[15].Descriptor() } func (SyncMessage_Request_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[16] + return &file_SignalService_proto_enumTypes[15] } func (x SyncMessage_Request_Type) Number() protoreflect.EnumNumber { @@ -1082,7 +1012,7 @@ func (x *SyncMessage_Request_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_Request_Type.Descriptor instead. func (SyncMessage_Request_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 3, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 3, 0} } type SyncMessage_StickerPackOperation_Type int32 @@ -1115,11 +1045,11 @@ func (x SyncMessage_StickerPackOperation_Type) String() string { } func (SyncMessage_StickerPackOperation_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[17].Descriptor() + return file_SignalService_proto_enumTypes[16].Descriptor() } func (SyncMessage_StickerPackOperation_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[17] + return &file_SignalService_proto_enumTypes[16] } func (x SyncMessage_StickerPackOperation_Type) Number() protoreflect.EnumNumber { @@ -1138,7 +1068,7 @@ func (x *SyncMessage_StickerPackOperation_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_StickerPackOperation_Type.Descriptor instead. func (SyncMessage_StickerPackOperation_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 7, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 7, 0} } type SyncMessage_FetchLatest_Type int32 @@ -1177,11 +1107,11 @@ func (x SyncMessage_FetchLatest_Type) String() string { } func (SyncMessage_FetchLatest_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[18].Descriptor() + return file_SignalService_proto_enumTypes[17].Descriptor() } func (SyncMessage_FetchLatest_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[18] + return &file_SignalService_proto_enumTypes[17] } func (x SyncMessage_FetchLatest_Type) Number() protoreflect.EnumNumber { @@ -1200,7 +1130,7 @@ func (x *SyncMessage_FetchLatest_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_FetchLatest_Type.Descriptor instead. func (SyncMessage_FetchLatest_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 9, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 9, 0} } type SyncMessage_MessageRequestResponse_Type int32 @@ -1248,11 +1178,11 @@ func (x SyncMessage_MessageRequestResponse_Type) String() string { } func (SyncMessage_MessageRequestResponse_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[19].Descriptor() + return file_SignalService_proto_enumTypes[18].Descriptor() } func (SyncMessage_MessageRequestResponse_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[19] + return &file_SignalService_proto_enumTypes[18] } func (x SyncMessage_MessageRequestResponse_Type) Number() protoreflect.EnumNumber { @@ -1271,7 +1201,7 @@ func (x *SyncMessage_MessageRequestResponse_Type) UnmarshalJSON(b []byte) error // Deprecated: Use SyncMessage_MessageRequestResponse_Type.Descriptor instead. func (SyncMessage_MessageRequestResponse_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 11, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 12, 0} } type SyncMessage_CallEvent_Type int32 @@ -1313,11 +1243,11 @@ func (x SyncMessage_CallEvent_Type) String() string { } func (SyncMessage_CallEvent_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[20].Descriptor() + return file_SignalService_proto_enumTypes[19].Descriptor() } func (SyncMessage_CallEvent_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[20] + return &file_SignalService_proto_enumTypes[19] } func (x SyncMessage_CallEvent_Type) Number() protoreflect.EnumNumber { @@ -1336,7 +1266,7 @@ func (x *SyncMessage_CallEvent_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_CallEvent_Type.Descriptor instead. func (SyncMessage_CallEvent_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 14, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 15, 0} } type SyncMessage_CallEvent_Direction int32 @@ -1372,11 +1302,11 @@ func (x SyncMessage_CallEvent_Direction) String() string { } func (SyncMessage_CallEvent_Direction) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[21].Descriptor() + return file_SignalService_proto_enumTypes[20].Descriptor() } func (SyncMessage_CallEvent_Direction) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[21] + return &file_SignalService_proto_enumTypes[20] } func (x SyncMessage_CallEvent_Direction) Number() protoreflect.EnumNumber { @@ -1395,34 +1325,34 @@ func (x *SyncMessage_CallEvent_Direction) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_CallEvent_Direction.Descriptor instead. func (SyncMessage_CallEvent_Direction) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 14, 1} + return file_SignalService_proto_rawDescGZIP(), []int{11, 15, 1} } type SyncMessage_CallEvent_Event int32 const ( - SyncMessage_CallEvent_UNKNOWN_ACTION SyncMessage_CallEvent_Event = 0 - SyncMessage_CallEvent_ACCEPTED SyncMessage_CallEvent_Event = 1 - SyncMessage_CallEvent_NOT_ACCEPTED SyncMessage_CallEvent_Event = 2 - SyncMessage_CallEvent_DELETE SyncMessage_CallEvent_Event = 3 - SyncMessage_CallEvent_OBSERVED SyncMessage_CallEvent_Event = 4 + SyncMessage_CallEvent_UNKNOWN_EVENT SyncMessage_CallEvent_Event = 0 + SyncMessage_CallEvent_ACCEPTED SyncMessage_CallEvent_Event = 1 + SyncMessage_CallEvent_NOT_ACCEPTED SyncMessage_CallEvent_Event = 2 + SyncMessage_CallEvent_DELETE SyncMessage_CallEvent_Event = 3 + SyncMessage_CallEvent_OBSERVED SyncMessage_CallEvent_Event = 4 ) // Enum value maps for SyncMessage_CallEvent_Event. var ( SyncMessage_CallEvent_Event_name = map[int32]string{ - 0: "UNKNOWN_ACTION", + 0: "UNKNOWN_EVENT", 1: "ACCEPTED", 2: "NOT_ACCEPTED", 3: "DELETE", 4: "OBSERVED", } SyncMessage_CallEvent_Event_value = map[string]int32{ - "UNKNOWN_ACTION": 0, - "ACCEPTED": 1, - "NOT_ACCEPTED": 2, - "DELETE": 3, - "OBSERVED": 4, + "UNKNOWN_EVENT": 0, + "ACCEPTED": 1, + "NOT_ACCEPTED": 2, + "DELETE": 3, + "OBSERVED": 4, } ) @@ -1437,11 +1367,11 @@ func (x SyncMessage_CallEvent_Event) String() string { } func (SyncMessage_CallEvent_Event) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[22].Descriptor() + return file_SignalService_proto_enumTypes[21].Descriptor() } func (SyncMessage_CallEvent_Event) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[22] + return &file_SignalService_proto_enumTypes[21] } func (x SyncMessage_CallEvent_Event) Number() protoreflect.EnumNumber { @@ -1460,7 +1390,7 @@ func (x *SyncMessage_CallEvent_Event) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_CallEvent_Event.Descriptor instead. func (SyncMessage_CallEvent_Event) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 14, 2} + return file_SignalService_proto_rawDescGZIP(), []int{11, 15, 2} } type SyncMessage_CallLinkUpdate_Type int32 @@ -1490,11 +1420,11 @@ func (x SyncMessage_CallLinkUpdate_Type) String() string { } func (SyncMessage_CallLinkUpdate_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[23].Descriptor() + return file_SignalService_proto_enumTypes[22].Descriptor() } func (SyncMessage_CallLinkUpdate_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[23] + return &file_SignalService_proto_enumTypes[22] } func (x SyncMessage_CallLinkUpdate_Type) Number() protoreflect.EnumNumber { @@ -1513,7 +1443,7 @@ func (x *SyncMessage_CallLinkUpdate_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_CallLinkUpdate_Type.Descriptor instead. func (SyncMessage_CallLinkUpdate_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 15, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 16, 0} } type SyncMessage_CallLogEvent_Type int32 @@ -1522,6 +1452,7 @@ const ( SyncMessage_CallLogEvent_CLEAR SyncMessage_CallLogEvent_Type = 0 SyncMessage_CallLogEvent_MARKED_AS_READ SyncMessage_CallLogEvent_Type = 1 SyncMessage_CallLogEvent_MARKED_AS_READ_IN_CONVERSATION SyncMessage_CallLogEvent_Type = 2 + SyncMessage_CallLogEvent_CLEAR_IN_CONVERSATION SyncMessage_CallLogEvent_Type = 3 ) // Enum value maps for SyncMessage_CallLogEvent_Type. @@ -1530,11 +1461,13 @@ var ( 0: "CLEAR", 1: "MARKED_AS_READ", 2: "MARKED_AS_READ_IN_CONVERSATION", + 3: "CLEAR_IN_CONVERSATION", } SyncMessage_CallLogEvent_Type_value = map[string]int32{ "CLEAR": 0, "MARKED_AS_READ": 1, "MARKED_AS_READ_IN_CONVERSATION": 2, + "CLEAR_IN_CONVERSATION": 3, } ) @@ -1549,11 +1482,11 @@ func (x SyncMessage_CallLogEvent_Type) String() string { } func (SyncMessage_CallLogEvent_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[24].Descriptor() + return file_SignalService_proto_enumTypes[23].Descriptor() } func (SyncMessage_CallLogEvent_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[24] + return &file_SignalService_proto_enumTypes[23] } func (x SyncMessage_CallLogEvent_Type) Number() protoreflect.EnumNumber { @@ -1572,7 +1505,116 @@ func (x *SyncMessage_CallLogEvent_Type) UnmarshalJSON(b []byte) error { // Deprecated: Use SyncMessage_CallLogEvent_Type.Descriptor instead. func (SyncMessage_CallLogEvent_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 16, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 17, 0} +} + +type SyncMessage_AttachmentBackfillResponse_Error int32 + +const ( + SyncMessage_AttachmentBackfillResponse_MESSAGE_NOT_FOUND SyncMessage_AttachmentBackfillResponse_Error = 0 +) + +// Enum value maps for SyncMessage_AttachmentBackfillResponse_Error. +var ( + SyncMessage_AttachmentBackfillResponse_Error_name = map[int32]string{ + 0: "MESSAGE_NOT_FOUND", + } + SyncMessage_AttachmentBackfillResponse_Error_value = map[string]int32{ + "MESSAGE_NOT_FOUND": 0, + } +) + +func (x SyncMessage_AttachmentBackfillResponse_Error) Enum() *SyncMessage_AttachmentBackfillResponse_Error { + p := new(SyncMessage_AttachmentBackfillResponse_Error) + *p = x + return p +} + +func (x SyncMessage_AttachmentBackfillResponse_Error) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SyncMessage_AttachmentBackfillResponse_Error) Descriptor() protoreflect.EnumDescriptor { + return file_SignalService_proto_enumTypes[24].Descriptor() +} + +func (SyncMessage_AttachmentBackfillResponse_Error) Type() protoreflect.EnumType { + return &file_SignalService_proto_enumTypes[24] +} + +func (x SyncMessage_AttachmentBackfillResponse_Error) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *SyncMessage_AttachmentBackfillResponse_Error) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = SyncMessage_AttachmentBackfillResponse_Error(num) + return nil +} + +// Deprecated: Use SyncMessage_AttachmentBackfillResponse_Error.Descriptor instead. +func (SyncMessage_AttachmentBackfillResponse_Error) EnumDescriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 21, 0} +} + +type SyncMessage_AttachmentBackfillResponse_AttachmentData_Status int32 + +const ( + SyncMessage_AttachmentBackfillResponse_AttachmentData_PENDING SyncMessage_AttachmentBackfillResponse_AttachmentData_Status = 0 + SyncMessage_AttachmentBackfillResponse_AttachmentData_TERMINAL_ERROR SyncMessage_AttachmentBackfillResponse_AttachmentData_Status = 1 +) + +// Enum value maps for SyncMessage_AttachmentBackfillResponse_AttachmentData_Status. +var ( + SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_name = map[int32]string{ + 0: "PENDING", + 1: "TERMINAL_ERROR", + } + SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_value = map[string]int32{ + "PENDING": 0, + "TERMINAL_ERROR": 1, + } +) + +func (x SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) Enum() *SyncMessage_AttachmentBackfillResponse_AttachmentData_Status { + p := new(SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) + *p = x + return p +} + +func (x SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) Descriptor() protoreflect.EnumDescriptor { + return file_SignalService_proto_enumTypes[25].Descriptor() +} + +func (SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) Type() protoreflect.EnumType { + return &file_SignalService_proto_enumTypes[25] +} + +func (x SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = SyncMessage_AttachmentBackfillResponse_AttachmentData_Status(num) + return nil +} + +// Deprecated: Use SyncMessage_AttachmentBackfillResponse_AttachmentData_Status.Descriptor instead. +func (SyncMessage_AttachmentBackfillResponse_AttachmentData_Status) EnumDescriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 21, 0, 0} } type AttachmentPointer_Flags int32 @@ -1580,7 +1622,7 @@ type AttachmentPointer_Flags int32 const ( AttachmentPointer_VOICE_MESSAGE AttachmentPointer_Flags = 1 AttachmentPointer_BORDERLESS AttachmentPointer_Flags = 2 - AttachmentPointer_GIF AttachmentPointer_Flags = 4 + AttachmentPointer_GIF AttachmentPointer_Flags = 8 ) // Enum value maps for AttachmentPointer_Flags. @@ -1588,12 +1630,12 @@ var ( AttachmentPointer_Flags_name = map[int32]string{ 1: "VOICE_MESSAGE", 2: "BORDERLESS", - 4: "GIF", + 8: "GIF", } AttachmentPointer_Flags_value = map[string]int32{ "VOICE_MESSAGE": 1, "BORDERLESS": 2, - "GIF": 4, + "GIF": 8, } ) @@ -1608,11 +1650,11 @@ func (x AttachmentPointer_Flags) String() string { } func (AttachmentPointer_Flags) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[25].Descriptor() + return file_SignalService_proto_enumTypes[26].Descriptor() } func (AttachmentPointer_Flags) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[25] + return &file_SignalService_proto_enumTypes[26] } func (x AttachmentPointer_Flags) Number() protoreflect.EnumNumber { @@ -1631,72 +1673,75 @@ func (x *AttachmentPointer_Flags) UnmarshalJSON(b []byte) error { // Deprecated: Use AttachmentPointer_Flags.Descriptor instead. func (AttachmentPointer_Flags) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{13, 0} + return file_SignalService_proto_rawDescGZIP(), []int{12, 0} } -type GroupContext_Type int32 +type BodyRange_Style int32 const ( - GroupContext_UNKNOWN GroupContext_Type = 0 - GroupContext_UPDATE GroupContext_Type = 1 - GroupContext_DELIVER GroupContext_Type = 2 - GroupContext_QUIT GroupContext_Type = 3 - GroupContext_REQUEST_INFO GroupContext_Type = 4 + BodyRange_NONE BodyRange_Style = 0 + BodyRange_BOLD BodyRange_Style = 1 + BodyRange_ITALIC BodyRange_Style = 2 + BodyRange_SPOILER BodyRange_Style = 3 + BodyRange_STRIKETHROUGH BodyRange_Style = 4 + BodyRange_MONOSPACE BodyRange_Style = 5 ) -// Enum value maps for GroupContext_Type. +// Enum value maps for BodyRange_Style. var ( - GroupContext_Type_name = map[int32]string{ - 0: "UNKNOWN", - 1: "UPDATE", - 2: "DELIVER", - 3: "QUIT", - 4: "REQUEST_INFO", + BodyRange_Style_name = map[int32]string{ + 0: "NONE", + 1: "BOLD", + 2: "ITALIC", + 3: "SPOILER", + 4: "STRIKETHROUGH", + 5: "MONOSPACE", } - GroupContext_Type_value = map[string]int32{ - "UNKNOWN": 0, - "UPDATE": 1, - "DELIVER": 2, - "QUIT": 3, - "REQUEST_INFO": 4, + BodyRange_Style_value = map[string]int32{ + "NONE": 0, + "BOLD": 1, + "ITALIC": 2, + "SPOILER": 3, + "STRIKETHROUGH": 4, + "MONOSPACE": 5, } ) -func (x GroupContext_Type) Enum() *GroupContext_Type { - p := new(GroupContext_Type) +func (x BodyRange_Style) Enum() *BodyRange_Style { + p := new(BodyRange_Style) *p = x return p } -func (x GroupContext_Type) String() string { +func (x BodyRange_Style) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (GroupContext_Type) Descriptor() protoreflect.EnumDescriptor { - return file_SignalService_proto_enumTypes[26].Descriptor() +func (BodyRange_Style) Descriptor() protoreflect.EnumDescriptor { + return file_SignalService_proto_enumTypes[27].Descriptor() } -func (GroupContext_Type) Type() protoreflect.EnumType { - return &file_SignalService_proto_enumTypes[26] +func (BodyRange_Style) Type() protoreflect.EnumType { + return &file_SignalService_proto_enumTypes[27] } -func (x GroupContext_Type) Number() protoreflect.EnumNumber { +func (x BodyRange_Style) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Do not use. -func (x *GroupContext_Type) UnmarshalJSON(b []byte) error { +func (x *BodyRange_Style) UnmarshalJSON(b []byte) error { num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = GroupContext_Type(num) + *x = BodyRange_Style(num) return nil } -// Deprecated: Use GroupContext_Type.Descriptor instead. -func (GroupContext_Type) EnumDescriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{14, 0} +// Deprecated: Use BodyRange_Style.Descriptor instead. +func (BodyRange_Style) EnumDescriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{19, 0} } type Envelope struct { @@ -1709,9 +1754,11 @@ type Envelope struct { Content []byte `protobuf:"bytes,8,opt,name=content" json:"content,omitempty"` // Contains an encrypted Content ServerGuid *string `protobuf:"bytes,9,opt,name=serverGuid" json:"serverGuid,omitempty"` ServerTimestamp *uint64 `protobuf:"varint,10,opt,name=serverTimestamp" json:"serverTimestamp,omitempty"` - Urgent *bool `protobuf:"varint,14,opt,name=urgent,def=1" json:"urgent,omitempty"` - Story *bool `protobuf:"varint,16,opt,name=story" json:"story,omitempty"` - ReportingToken []byte `protobuf:"bytes,17,opt,name=reportingToken" json:"reportingToken,omitempty"` + Ephemeral *bool `protobuf:"varint,12,opt,name=ephemeral" json:"ephemeral,omitempty"` // indicates that the message should not be persisted if the recipient is offline + Urgent *bool `protobuf:"varint,14,opt,name=urgent,def=1" json:"urgent,omitempty"` // indicates that the content is considered timely by the sender; defaults to true so senders have to opt-out to say something isn't time critical + UpdatedPni *string `protobuf:"bytes,15,opt,name=updatedPni" json:"updatedPni,omitempty"` // for number-change synchronization messages, provides the new server-assigned phone number identifier associated with the changed number + Story *bool `protobuf:"varint,16,opt,name=story" json:"story,omitempty"` // indicates that the content is a story. + ReportSpamToken []byte `protobuf:"bytes,17,opt,name=report_spam_token,json=reportSpamToken" json:"report_spam_token,omitempty"` // token sent when reporting spam unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1807,6 +1854,13 @@ func (x *Envelope) GetServerTimestamp() uint64 { return 0 } +func (x *Envelope) GetEphemeral() bool { + if x != nil && x.Ephemeral != nil { + return *x.Ephemeral + } + return false +} + func (x *Envelope) GetUrgent() bool { if x != nil && x.Urgent != nil { return *x.Urgent @@ -1814,6 +1868,13 @@ func (x *Envelope) GetUrgent() bool { return Default_Envelope_Urgent } +func (x *Envelope) GetUpdatedPni() string { + if x != nil && x.UpdatedPni != nil { + return *x.UpdatedPni + } + return "" +} + func (x *Envelope) GetStory() bool { if x != nil && x.Story != nil { return *x.Story @@ -1821,9 +1882,9 @@ func (x *Envelope) GetStory() bool { return false } -func (x *Envelope) GetReportingToken() []byte { +func (x *Envelope) GetReportSpamToken() []byte { if x != nil { - return x.ReportingToken + return x.ReportSpamToken } return nil } @@ -2044,104 +2105,6 @@ func (x *CallMessage) GetOpaque() *CallMessage_Opaque { return nil } -type BodyRange struct { - state protoimpl.MessageState `protogen:"open.v1"` - Start *uint32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` - // Types that are valid to be assigned to AssociatedValue: - // - // *BodyRange_MentionAci - // *BodyRange_Style_ - AssociatedValue isBodyRange_AssociatedValue `protobuf_oneof:"associatedValue"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *BodyRange) Reset() { - *x = BodyRange{} - mi := &file_SignalService_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *BodyRange) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BodyRange) ProtoMessage() {} - -func (x *BodyRange) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_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 BodyRange.ProtoReflect.Descriptor instead. -func (*BodyRange) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{3} -} - -func (x *BodyRange) GetStart() uint32 { - if x != nil && x.Start != nil { - return *x.Start - } - return 0 -} - -func (x *BodyRange) GetLength() uint32 { - if x != nil && x.Length != nil { - return *x.Length - } - return 0 -} - -func (x *BodyRange) GetAssociatedValue() isBodyRange_AssociatedValue { - if x != nil { - return x.AssociatedValue - } - return nil -} - -func (x *BodyRange) GetMentionAci() string { - if x != nil { - if x, ok := x.AssociatedValue.(*BodyRange_MentionAci); ok { - return x.MentionAci - } - } - return "" -} - -func (x *BodyRange) GetStyle() BodyRange_Style { - if x != nil { - if x, ok := x.AssociatedValue.(*BodyRange_Style_); ok { - return x.Style - } - } - return BodyRange_NONE -} - -type isBodyRange_AssociatedValue interface { - isBodyRange_AssociatedValue() -} - -type BodyRange_MentionAci struct { - MentionAci string `protobuf:"bytes,3,opt,name=mentionAci,oneof"` -} - -type BodyRange_Style_ struct { - Style BodyRange_Style `protobuf:"varint,4,opt,name=style,enum=signalservice.BodyRange_Style,oneof"` -} - -func (*BodyRange_MentionAci) isBodyRange_AssociatedValue() {} - -func (*BodyRange_Style_) isBodyRange_AssociatedValue() {} - type DataMessage struct { state protoimpl.MessageState `protogen:"open.v1"` Body *string `protobuf:"bytes,1,opt,name=body" json:"body,omitempty"` @@ -2164,14 +2127,14 @@ type DataMessage struct { GroupCallUpdate *DataMessage_GroupCallUpdate `protobuf:"bytes,19,opt,name=groupCallUpdate" json:"groupCallUpdate,omitempty"` Payment *DataMessage_Payment `protobuf:"bytes,20,opt,name=payment" json:"payment,omitempty"` StoryContext *DataMessage_StoryContext `protobuf:"bytes,21,opt,name=storyContext" json:"storyContext,omitempty"` - GiftBadge *DataMessage_GiftBadge `protobuf:"bytes,22,opt,name=giftBadge" json:"giftBadge,omitempty"` + GiftBadge *DataMessage_GiftBadge `protobuf:"bytes,22,opt,name=giftBadge" json:"giftBadge,omitempty"` // NEXT ID: 24 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *DataMessage) Reset() { *x = DataMessage{} - mi := &file_SignalService_proto_msgTypes[4] + mi := &file_SignalService_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2183,7 +2146,7 @@ func (x *DataMessage) String() string { func (*DataMessage) ProtoMessage() {} func (x *DataMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[4] + mi := &file_SignalService_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2196,7 +2159,7 @@ func (x *DataMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage.ProtoReflect.Descriptor instead. func (*DataMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4} + return file_SignalService_proto_rawDescGZIP(), []int{3} } func (x *DataMessage) GetBody() string { @@ -2355,7 +2318,7 @@ type NullMessage struct { func (x *NullMessage) Reset() { *x = NullMessage{} - mi := &file_SignalService_proto_msgTypes[5] + mi := &file_SignalService_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2367,7 +2330,7 @@ func (x *NullMessage) String() string { func (*NullMessage) ProtoMessage() {} func (x *NullMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[5] + mi := &file_SignalService_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2380,7 +2343,7 @@ func (x *NullMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NullMessage.ProtoReflect.Descriptor instead. func (*NullMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{5} + return file_SignalService_proto_rawDescGZIP(), []int{4} } func (x *NullMessage) GetPadding() []byte { @@ -2400,7 +2363,7 @@ type ReceiptMessage struct { func (x *ReceiptMessage) Reset() { *x = ReceiptMessage{} - mi := &file_SignalService_proto_msgTypes[6] + mi := &file_SignalService_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2412,7 +2375,7 @@ func (x *ReceiptMessage) String() string { func (*ReceiptMessage) ProtoMessage() {} func (x *ReceiptMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[6] + mi := &file_SignalService_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2425,7 +2388,7 @@ func (x *ReceiptMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ReceiptMessage.ProtoReflect.Descriptor instead. func (*ReceiptMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{6} + return file_SignalService_proto_rawDescGZIP(), []int{5} } func (x *ReceiptMessage) GetType() ReceiptMessage_Type { @@ -2453,7 +2416,7 @@ type TypingMessage struct { func (x *TypingMessage) Reset() { *x = TypingMessage{} - mi := &file_SignalService_proto_msgTypes[7] + mi := &file_SignalService_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2465,7 +2428,7 @@ func (x *TypingMessage) String() string { func (*TypingMessage) ProtoMessage() {} func (x *TypingMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[7] + mi := &file_SignalService_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2478,7 +2441,7 @@ func (x *TypingMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use TypingMessage.ProtoReflect.Descriptor instead. func (*TypingMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{7} + return file_SignalService_proto_rawDescGZIP(), []int{6} } func (x *TypingMessage) GetTimestamp() uint64 { @@ -2519,7 +2482,7 @@ type StoryMessage struct { func (x *StoryMessage) Reset() { *x = StoryMessage{} - mi := &file_SignalService_proto_msgTypes[8] + mi := &file_SignalService_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2531,7 +2494,7 @@ func (x *StoryMessage) String() string { func (*StoryMessage) ProtoMessage() {} func (x *StoryMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[8] + mi := &file_SignalService_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2544,7 +2507,7 @@ func (x *StoryMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use StoryMessage.ProtoReflect.Descriptor instead. func (*StoryMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{8} + return file_SignalService_proto_rawDescGZIP(), []int{7} } func (x *StoryMessage) GetProfileKey() []byte { @@ -2629,7 +2592,7 @@ type Preview struct { func (x *Preview) Reset() { *x = Preview{} - mi := &file_SignalService_proto_msgTypes[9] + mi := &file_SignalService_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2641,7 +2604,7 @@ func (x *Preview) String() string { func (*Preview) ProtoMessage() {} func (x *Preview) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[9] + mi := &file_SignalService_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2654,7 +2617,7 @@ func (x *Preview) ProtoReflect() protoreflect.Message { // Deprecated: Use Preview.ProtoReflect.Descriptor instead. func (*Preview) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{9} + return file_SignalService_proto_rawDescGZIP(), []int{8} } func (x *Preview) GetUrl() string { @@ -2710,7 +2673,7 @@ type TextAttachment struct { func (x *TextAttachment) Reset() { *x = TextAttachment{} - mi := &file_SignalService_proto_msgTypes[10] + mi := &file_SignalService_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2722,7 +2685,7 @@ func (x *TextAttachment) String() string { func (*TextAttachment) ProtoMessage() {} func (x *TextAttachment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[10] + mi := &file_SignalService_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2735,7 +2698,7 @@ func (x *TextAttachment) ProtoReflect() protoreflect.Message { // Deprecated: Use TextAttachment.ProtoReflect.Descriptor instead. func (*TextAttachment) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{10} + return file_SignalService_proto_rawDescGZIP(), []int{9} } func (x *TextAttachment) GetText() string { @@ -2826,7 +2789,7 @@ type Verified struct { func (x *Verified) Reset() { *x = Verified{} - mi := &file_SignalService_proto_msgTypes[11] + mi := &file_SignalService_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2838,7 +2801,7 @@ func (x *Verified) String() string { func (*Verified) ProtoMessage() {} func (x *Verified) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[11] + mi := &file_SignalService_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2851,7 +2814,7 @@ func (x *Verified) ProtoReflect() protoreflect.Message { // Deprecated: Use Verified.ProtoReflect.Descriptor instead. func (*Verified) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{11} + return file_SignalService_proto_rawDescGZIP(), []int{10} } func (x *Verified) GetDestinationAci() string { @@ -2883,35 +2846,37 @@ func (x *Verified) GetNullMessage() []byte { } type SyncMessage struct { - state protoimpl.MessageState `protogen:"open.v1"` - Sent *SyncMessage_Sent `protobuf:"bytes,1,opt,name=sent" json:"sent,omitempty"` - Contacts *SyncMessage_Contacts `protobuf:"bytes,2,opt,name=contacts" json:"contacts,omitempty"` - Request *SyncMessage_Request `protobuf:"bytes,4,opt,name=request" json:"request,omitempty"` - Read []*SyncMessage_Read `protobuf:"bytes,5,rep,name=read" json:"read,omitempty"` - Blocked *SyncMessage_Blocked `protobuf:"bytes,6,opt,name=blocked" json:"blocked,omitempty"` - Verified *Verified `protobuf:"bytes,7,opt,name=verified" json:"verified,omitempty"` - Configuration *SyncMessage_Configuration `protobuf:"bytes,9,opt,name=configuration" json:"configuration,omitempty"` - Padding []byte `protobuf:"bytes,8,opt,name=padding" json:"padding,omitempty"` - StickerPackOperation []*SyncMessage_StickerPackOperation `protobuf:"bytes,10,rep,name=stickerPackOperation" json:"stickerPackOperation,omitempty"` - ViewOnceOpen *SyncMessage_ViewOnceOpen `protobuf:"bytes,11,opt,name=viewOnceOpen" json:"viewOnceOpen,omitempty"` - FetchLatest *SyncMessage_FetchLatest `protobuf:"bytes,12,opt,name=fetchLatest" json:"fetchLatest,omitempty"` - Keys *SyncMessage_Keys `protobuf:"bytes,13,opt,name=keys" json:"keys,omitempty"` - MessageRequestResponse *SyncMessage_MessageRequestResponse `protobuf:"bytes,14,opt,name=messageRequestResponse" json:"messageRequestResponse,omitempty"` - OutgoingPayment *SyncMessage_OutgoingPayment `protobuf:"bytes,15,opt,name=outgoingPayment" json:"outgoingPayment,omitempty"` - Viewed []*SyncMessage_Viewed `protobuf:"bytes,16,rep,name=viewed" json:"viewed,omitempty"` - PniChangeNumber *SyncMessage_PniChangeNumber `protobuf:"bytes,18,opt,name=pniChangeNumber" json:"pniChangeNumber,omitempty"` - CallEvent *SyncMessage_CallEvent `protobuf:"bytes,19,opt,name=callEvent" json:"callEvent,omitempty"` - CallLinkUpdate *SyncMessage_CallLinkUpdate `protobuf:"bytes,20,opt,name=callLinkUpdate" json:"callLinkUpdate,omitempty"` - CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent" json:"callLogEvent,omitempty"` - DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe" json:"deleteForMe,omitempty"` - DeviceNameChange *SyncMessage_DeviceNameChange `protobuf:"bytes,23,opt,name=deviceNameChange" json:"deviceNameChange,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Sent *SyncMessage_Sent `protobuf:"bytes,1,opt,name=sent" json:"sent,omitempty"` + Contacts *SyncMessage_Contacts `protobuf:"bytes,2,opt,name=contacts" json:"contacts,omitempty"` + Request *SyncMessage_Request `protobuf:"bytes,4,opt,name=request" json:"request,omitempty"` + Read []*SyncMessage_Read `protobuf:"bytes,5,rep,name=read" json:"read,omitempty"` + Blocked *SyncMessage_Blocked `protobuf:"bytes,6,opt,name=blocked" json:"blocked,omitempty"` + Verified *Verified `protobuf:"bytes,7,opt,name=verified" json:"verified,omitempty"` + Configuration *SyncMessage_Configuration `protobuf:"bytes,9,opt,name=configuration" json:"configuration,omitempty"` + Padding []byte `protobuf:"bytes,8,opt,name=padding" json:"padding,omitempty"` + StickerPackOperation []*SyncMessage_StickerPackOperation `protobuf:"bytes,10,rep,name=stickerPackOperation" json:"stickerPackOperation,omitempty"` + ViewOnceOpen *SyncMessage_ViewOnceOpen `protobuf:"bytes,11,opt,name=viewOnceOpen" json:"viewOnceOpen,omitempty"` + FetchLatest *SyncMessage_FetchLatest `protobuf:"bytes,12,opt,name=fetchLatest" json:"fetchLatest,omitempty"` + Keys *SyncMessage_Keys `protobuf:"bytes,13,opt,name=keys" json:"keys,omitempty"` + MessageRequestResponse *SyncMessage_MessageRequestResponse `protobuf:"bytes,14,opt,name=messageRequestResponse" json:"messageRequestResponse,omitempty"` + OutgoingPayment *SyncMessage_OutgoingPayment `protobuf:"bytes,15,opt,name=outgoingPayment" json:"outgoingPayment,omitempty"` + Viewed []*SyncMessage_Viewed `protobuf:"bytes,16,rep,name=viewed" json:"viewed,omitempty"` + PniChangeNumber *SyncMessage_PniChangeNumber `protobuf:"bytes,18,opt,name=pniChangeNumber" json:"pniChangeNumber,omitempty"` + CallEvent *SyncMessage_CallEvent `protobuf:"bytes,19,opt,name=callEvent" json:"callEvent,omitempty"` + CallLinkUpdate *SyncMessage_CallLinkUpdate `protobuf:"bytes,20,opt,name=callLinkUpdate" json:"callLinkUpdate,omitempty"` + CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent" json:"callLogEvent,omitempty"` + DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe" json:"deleteForMe,omitempty"` + DeviceNameChange *SyncMessage_DeviceNameChange `protobuf:"bytes,23,opt,name=deviceNameChange" json:"deviceNameChange,omitempty"` + AttachmentBackfillRequest *SyncMessage_AttachmentBackfillRequest `protobuf:"bytes,24,opt,name=attachmentBackfillRequest" json:"attachmentBackfillRequest,omitempty"` + AttachmentBackfillResponse *SyncMessage_AttachmentBackfillResponse `protobuf:"bytes,25,opt,name=attachmentBackfillResponse" json:"attachmentBackfillResponse,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage) Reset() { *x = SyncMessage{} - mi := &file_SignalService_proto_msgTypes[12] + mi := &file_SignalService_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2923,7 +2888,7 @@ func (x *SyncMessage) String() string { func (*SyncMessage) ProtoMessage() {} func (x *SyncMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[12] + mi := &file_SignalService_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2936,7 +2901,7 @@ func (x *SyncMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage.ProtoReflect.Descriptor instead. func (*SyncMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12} + return file_SignalService_proto_rawDescGZIP(), []int{11} } func (x *SyncMessage) GetSent() *SyncMessage_Sent { @@ -3086,36 +3051,52 @@ func (x *SyncMessage) GetDeviceNameChange() *SyncMessage_DeviceNameChange { return nil } +func (x *SyncMessage) GetAttachmentBackfillRequest() *SyncMessage_AttachmentBackfillRequest { + if x != nil { + return x.AttachmentBackfillRequest + } + return nil +} + +func (x *SyncMessage) GetAttachmentBackfillResponse() *SyncMessage_AttachmentBackfillResponse { + if x != nil { + return x.AttachmentBackfillResponse + } + return nil +} + type AttachmentPointer struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to AttachmentIdentifier: // // *AttachmentPointer_CdnId // *AttachmentPointer_CdnKey - AttachmentIdentifier isAttachmentPointer_AttachmentIdentifier `protobuf_oneof:"attachment_identifier"` - ContentType *string `protobuf:"bytes,2,opt,name=contentType" json:"contentType,omitempty"` - Key []byte `protobuf:"bytes,3,opt,name=key" json:"key,omitempty"` - Size *uint32 `protobuf:"varint,4,opt,name=size" json:"size,omitempty"` - Thumbnail []byte `protobuf:"bytes,5,opt,name=thumbnail" json:"thumbnail,omitempty"` - Digest []byte `protobuf:"bytes,6,opt,name=digest" json:"digest,omitempty"` - IncrementalMac []byte `protobuf:"bytes,19,opt,name=incrementalMac" json:"incrementalMac,omitempty"` - IncrementalMacChunkSize *uint32 `protobuf:"varint,17,opt,name=incrementalMacChunkSize" json:"incrementalMacChunkSize,omitempty"` - FileName *string `protobuf:"bytes,7,opt,name=fileName" json:"fileName,omitempty"` - Flags *uint32 `protobuf:"varint,8,opt,name=flags" json:"flags,omitempty"` - Width *uint32 `protobuf:"varint,9,opt,name=width" json:"width,omitempty"` - Height *uint32 `protobuf:"varint,10,opt,name=height" json:"height,omitempty"` - Caption *string `protobuf:"bytes,11,opt,name=caption" json:"caption,omitempty"` - BlurHash *string `protobuf:"bytes,12,opt,name=blurHash" json:"blurHash,omitempty"` - UploadTimestamp *uint64 `protobuf:"varint,13,opt,name=uploadTimestamp" json:"uploadTimestamp,omitempty"` - CdnNumber *uint32 `protobuf:"varint,14,opt,name=cdnNumber" json:"cdnNumber,omitempty"` - Uuid []byte `protobuf:"bytes,20,opt,name=uuid" json:"uuid,omitempty"` // Next ID: 21 - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + AttachmentIdentifier isAttachmentPointer_AttachmentIdentifier `protobuf_oneof:"attachment_identifier"` + // Cross-client identifier for this attachment among all attachments on the + // owning message. + ClientUuid []byte `protobuf:"bytes,20,opt,name=clientUuid" json:"clientUuid,omitempty"` + ContentType *string `protobuf:"bytes,2,opt,name=contentType" json:"contentType,omitempty"` + Key []byte `protobuf:"bytes,3,opt,name=key" json:"key,omitempty"` + Size *uint32 `protobuf:"varint,4,opt,name=size" json:"size,omitempty"` + Thumbnail []byte `protobuf:"bytes,5,opt,name=thumbnail" json:"thumbnail,omitempty"` + Digest []byte `protobuf:"bytes,6,opt,name=digest" json:"digest,omitempty"` + IncrementalMac []byte `protobuf:"bytes,19,opt,name=incrementalMac" json:"incrementalMac,omitempty"` + ChunkSize *uint32 `protobuf:"varint,17,opt,name=chunkSize" json:"chunkSize,omitempty"` + FileName *string `protobuf:"bytes,7,opt,name=fileName" json:"fileName,omitempty"` + Flags *uint32 `protobuf:"varint,8,opt,name=flags" json:"flags,omitempty"` + Width *uint32 `protobuf:"varint,9,opt,name=width" json:"width,omitempty"` + Height *uint32 `protobuf:"varint,10,opt,name=height" json:"height,omitempty"` + Caption *string `protobuf:"bytes,11,opt,name=caption" json:"caption,omitempty"` + BlurHash *string `protobuf:"bytes,12,opt,name=blurHash" json:"blurHash,omitempty"` + UploadTimestamp *uint64 `protobuf:"varint,13,opt,name=uploadTimestamp" json:"uploadTimestamp,omitempty"` + CdnNumber *uint32 `protobuf:"varint,14,opt,name=cdnNumber" json:"cdnNumber,omitempty"` // Next ID: 21 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AttachmentPointer) Reset() { *x = AttachmentPointer{} - mi := &file_SignalService_proto_msgTypes[13] + mi := &file_SignalService_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3127,7 +3108,7 @@ func (x *AttachmentPointer) String() string { func (*AttachmentPointer) ProtoMessage() {} func (x *AttachmentPointer) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[13] + mi := &file_SignalService_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3140,7 +3121,7 @@ func (x *AttachmentPointer) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachmentPointer.ProtoReflect.Descriptor instead. func (*AttachmentPointer) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{13} + return file_SignalService_proto_rawDescGZIP(), []int{12} } func (x *AttachmentPointer) GetAttachmentIdentifier() isAttachmentPointer_AttachmentIdentifier { @@ -3168,6 +3149,13 @@ func (x *AttachmentPointer) GetCdnKey() string { return "" } +func (x *AttachmentPointer) GetClientUuid() []byte { + if x != nil { + return x.ClientUuid + } + return nil +} + func (x *AttachmentPointer) GetContentType() string { if x != nil && x.ContentType != nil { return *x.ContentType @@ -3210,9 +3198,9 @@ func (x *AttachmentPointer) GetIncrementalMac() []byte { return nil } -func (x *AttachmentPointer) GetIncrementalMacChunkSize() uint32 { - if x != nil && x.IncrementalMacChunkSize != nil { - return *x.IncrementalMacChunkSize +func (x *AttachmentPointer) GetChunkSize() uint32 { + if x != nil && x.ChunkSize != nil { + return *x.ChunkSize } return 0 } @@ -3273,13 +3261,6 @@ func (x *AttachmentPointer) GetCdnNumber() uint32 { return 0 } -func (x *AttachmentPointer) GetUuid() []byte { - if x != nil { - return x.Uuid - } - return nil -} - type isAttachmentPointer_AttachmentIdentifier interface { isAttachmentPointer_AttachmentIdentifier() } @@ -3296,90 +3277,6 @@ func (*AttachmentPointer_CdnId) isAttachmentPointer_AttachmentIdentifier() {} func (*AttachmentPointer_CdnKey) isAttachmentPointer_AttachmentIdentifier() {} -type GroupContext struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Type *GroupContext_Type `protobuf:"varint,2,opt,name=type,enum=signalservice.GroupContext_Type" json:"type,omitempty"` - Name *string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` - MembersE164 []string `protobuf:"bytes,4,rep,name=membersE164" json:"membersE164,omitempty"` - Members []*GroupContext_Member `protobuf:"bytes,6,rep,name=members" json:"members,omitempty"` - Avatar *AttachmentPointer `protobuf:"bytes,5,opt,name=avatar" json:"avatar,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupContext) Reset() { - *x = GroupContext{} - mi := &file_SignalService_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupContext) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupContext) ProtoMessage() {} - -func (x *GroupContext) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[14] - 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 GroupContext.ProtoReflect.Descriptor instead. -func (*GroupContext) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{14} -} - -func (x *GroupContext) GetId() []byte { - if x != nil { - return x.Id - } - return nil -} - -func (x *GroupContext) GetType() GroupContext_Type { - if x != nil && x.Type != nil { - return *x.Type - } - return GroupContext_UNKNOWN -} - -func (x *GroupContext) GetName() string { - if x != nil && x.Name != nil { - return *x.Name - } - return "" -} - -func (x *GroupContext) GetMembersE164() []string { - if x != nil { - return x.MembersE164 - } - return nil -} - -func (x *GroupContext) GetMembers() []*GroupContext_Member { - if x != nil { - return x.Members - } - return nil -} - -func (x *GroupContext) GetAvatar() *AttachmentPointer { - if x != nil { - return x.Avatar - } - return nil -} - type GroupContextV2 struct { state protoimpl.MessageState `protogen:"open.v1"` MasterKey []byte `protobuf:"bytes,1,opt,name=masterKey" json:"masterKey,omitempty"` @@ -3391,7 +3288,7 @@ type GroupContextV2 struct { func (x *GroupContextV2) Reset() { *x = GroupContextV2{} - mi := &file_SignalService_proto_msgTypes[15] + mi := &file_SignalService_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3403,7 +3300,7 @@ func (x *GroupContextV2) String() string { func (*GroupContextV2) ProtoMessage() {} func (x *GroupContextV2) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[15] + mi := &file_SignalService_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3416,7 +3313,7 @@ func (x *GroupContextV2) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupContextV2.ProtoReflect.Descriptor instead. func (*GroupContextV2) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{15} + return file_SignalService_proto_rawDescGZIP(), []int{13} } func (x *GroupContextV2) GetMasterKey() []byte { @@ -3446,20 +3343,16 @@ type ContactDetails struct { Aci *string `protobuf:"bytes,9,opt,name=aci" json:"aci,omitempty"` Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` Avatar *ContactDetails_Avatar `protobuf:"bytes,3,opt,name=avatar" json:"avatar,omitempty"` - Color *string `protobuf:"bytes,4,opt,name=color" json:"color,omitempty"` - Verified *Verified `protobuf:"bytes,5,opt,name=verified" json:"verified,omitempty"` - ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` ExpireTimer *uint32 `protobuf:"varint,8,opt,name=expireTimer" json:"expireTimer,omitempty"` ExpireTimerVersion *uint32 `protobuf:"varint,12,opt,name=expireTimerVersion" json:"expireTimerVersion,omitempty"` InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` - Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *ContactDetails) Reset() { *x = ContactDetails{} - mi := &file_SignalService_proto_msgTypes[16] + mi := &file_SignalService_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3471,7 +3364,7 @@ func (x *ContactDetails) String() string { func (*ContactDetails) ProtoMessage() {} func (x *ContactDetails) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[16] + mi := &file_SignalService_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3484,7 +3377,7 @@ func (x *ContactDetails) ProtoReflect() protoreflect.Message { // Deprecated: Use ContactDetails.ProtoReflect.Descriptor instead. func (*ContactDetails) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{16} + return file_SignalService_proto_rawDescGZIP(), []int{14} } func (x *ContactDetails) GetNumber() string { @@ -3515,27 +3408,6 @@ func (x *ContactDetails) GetAvatar() *ContactDetails_Avatar { return nil } -func (x *ContactDetails) GetColor() string { - if x != nil && x.Color != nil { - return *x.Color - } - return "" -} - -func (x *ContactDetails) GetVerified() *Verified { - if x != nil { - return x.Verified - } - return nil -} - -func (x *ContactDetails) GetProfileKey() []byte { - if x != nil { - return x.ProfileKey - } - return nil -} - func (x *ContactDetails) GetExpireTimer() uint32 { if x != nil && x.ExpireTimer != nil { return *x.ExpireTimer @@ -3557,147 +3429,11 @@ func (x *ContactDetails) GetInboxPosition() uint32 { return 0 } -func (x *ContactDetails) GetArchived() bool { - if x != nil && x.Archived != nil { - return *x.Archived - } - return false -} - -type GroupDetails struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - MembersE164 []string `protobuf:"bytes,3,rep,name=membersE164" json:"membersE164,omitempty"` - Members []*GroupDetails_Member `protobuf:"bytes,9,rep,name=members" json:"members,omitempty"` - Avatar *GroupDetails_Avatar `protobuf:"bytes,4,opt,name=avatar" json:"avatar,omitempty"` - Active *bool `protobuf:"varint,5,opt,name=active,def=1" json:"active,omitempty"` - ExpireTimer *uint32 `protobuf:"varint,6,opt,name=expireTimer" json:"expireTimer,omitempty"` - Color *string `protobuf:"bytes,7,opt,name=color" json:"color,omitempty"` - Blocked *bool `protobuf:"varint,8,opt,name=blocked" json:"blocked,omitempty"` - InboxPosition *uint32 `protobuf:"varint,10,opt,name=inboxPosition" json:"inboxPosition,omitempty"` - Archived *bool `protobuf:"varint,11,opt,name=archived" json:"archived,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -// Default values for GroupDetails fields. -const ( - Default_GroupDetails_Active = bool(true) -) - -func (x *GroupDetails) Reset() { - *x = GroupDetails{} - mi := &file_SignalService_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupDetails) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupDetails) ProtoMessage() {} - -func (x *GroupDetails) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[17] - 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 GroupDetails.ProtoReflect.Descriptor instead. -func (*GroupDetails) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{17} -} - -func (x *GroupDetails) GetId() []byte { - if x != nil { - return x.Id - } - return nil -} - -func (x *GroupDetails) GetName() string { - if x != nil && x.Name != nil { - return *x.Name - } - return "" -} - -func (x *GroupDetails) GetMembersE164() []string { - if x != nil { - return x.MembersE164 - } - return nil -} - -func (x *GroupDetails) GetMembers() []*GroupDetails_Member { - if x != nil { - return x.Members - } - return nil -} - -func (x *GroupDetails) GetAvatar() *GroupDetails_Avatar { - if x != nil { - return x.Avatar - } - return nil -} - -func (x *GroupDetails) GetActive() bool { - if x != nil && x.Active != nil { - return *x.Active - } - return Default_GroupDetails_Active -} - -func (x *GroupDetails) GetExpireTimer() uint32 { - if x != nil && x.ExpireTimer != nil { - return *x.ExpireTimer - } - return 0 -} - -func (x *GroupDetails) GetColor() string { - if x != nil && x.Color != nil { - return *x.Color - } - return "" -} - -func (x *GroupDetails) GetBlocked() bool { - if x != nil && x.Blocked != nil { - return *x.Blocked - } - return false -} - -func (x *GroupDetails) GetInboxPosition() uint32 { - if x != nil && x.InboxPosition != nil { - return *x.InboxPosition - } - return 0 -} - -func (x *GroupDetails) GetArchived() bool { - if x != nil && x.Archived != nil { - return *x.Archived - } - return false -} - type PaymentAddress struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Address: // - // *PaymentAddress_MobileCoinAddress_ + // *PaymentAddress_MobileCoin_ Address isPaymentAddress_Address `protobuf_oneof:"Address"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -3705,7 +3441,7 @@ type PaymentAddress struct { func (x *PaymentAddress) Reset() { *x = PaymentAddress{} - mi := &file_SignalService_proto_msgTypes[18] + mi := &file_SignalService_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3717,7 +3453,7 @@ func (x *PaymentAddress) String() string { func (*PaymentAddress) ProtoMessage() {} func (x *PaymentAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[18] + mi := &file_SignalService_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3730,7 +3466,7 @@ func (x *PaymentAddress) ProtoReflect() protoreflect.Message { // Deprecated: Use PaymentAddress.ProtoReflect.Descriptor instead. func (*PaymentAddress) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{18} + return file_SignalService_proto_rawDescGZIP(), []int{15} } func (x *PaymentAddress) GetAddress() isPaymentAddress_Address { @@ -3740,10 +3476,10 @@ func (x *PaymentAddress) GetAddress() isPaymentAddress_Address { return nil } -func (x *PaymentAddress) GetMobileCoinAddress() *PaymentAddress_MobileCoinAddress { +func (x *PaymentAddress) GetMobileCoin() *PaymentAddress_MobileCoin { if x != nil { - if x, ok := x.Address.(*PaymentAddress_MobileCoinAddress_); ok { - return x.MobileCoinAddress + if x, ok := x.Address.(*PaymentAddress_MobileCoin_); ok { + return x.MobileCoin } } return nil @@ -3753,15 +3489,15 @@ type isPaymentAddress_Address interface { isPaymentAddress_Address() } -type PaymentAddress_MobileCoinAddress_ struct { - MobileCoinAddress *PaymentAddress_MobileCoinAddress `protobuf:"bytes,1,opt,name=mobileCoinAddress,oneof"` +type PaymentAddress_MobileCoin_ struct { + MobileCoin *PaymentAddress_MobileCoin `protobuf:"bytes,1,opt,name=mobileCoin,oneof"` } -func (*PaymentAddress_MobileCoinAddress_) isPaymentAddress_Address() {} +func (*PaymentAddress_MobileCoin_) isPaymentAddress_Address() {} type DecryptionErrorMessage struct { state protoimpl.MessageState `protogen:"open.v1"` - RatchetKey []byte `protobuf:"bytes,1,opt,name=ratchetKey" json:"ratchetKey,omitempty"` + RatchetKey []byte `protobuf:"bytes,1,opt,name=ratchetKey" json:"ratchetKey,omitempty"` // set to the public ratchet key from the SignalMessage if a 1-1 payload fails to decrypt Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` DeviceId *uint32 `protobuf:"varint,3,opt,name=deviceId" json:"deviceId,omitempty"` unknownFields protoimpl.UnknownFields @@ -3770,7 +3506,7 @@ type DecryptionErrorMessage struct { func (x *DecryptionErrorMessage) Reset() { *x = DecryptionErrorMessage{} - mi := &file_SignalService_proto_msgTypes[19] + mi := &file_SignalService_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3782,7 +3518,7 @@ func (x *DecryptionErrorMessage) String() string { func (*DecryptionErrorMessage) ProtoMessage() {} func (x *DecryptionErrorMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[19] + mi := &file_SignalService_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3795,7 +3531,7 @@ func (x *DecryptionErrorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use DecryptionErrorMessage.ProtoReflect.Descriptor instead. func (*DecryptionErrorMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{19} + return file_SignalService_proto_rawDescGZIP(), []int{16} } func (x *DecryptionErrorMessage) GetRatchetKey() []byte { @@ -3820,16 +3556,17 @@ func (x *DecryptionErrorMessage) GetDeviceId() uint32 { } type PniSignatureMessage struct { - state protoimpl.MessageState `protogen:"open.v1"` - Pni []byte `protobuf:"bytes,1,opt,name=pni" json:"pni,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Pni []byte `protobuf:"bytes,1,opt,name=pni" json:"pni,omitempty"` + // Signature *by* the PNI identity key *of* the ACI identity key + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *PniSignatureMessage) Reset() { *x = PniSignatureMessage{} - mi := &file_SignalService_proto_msgTypes[20] + mi := &file_SignalService_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3841,7 +3578,7 @@ func (x *PniSignatureMessage) String() string { func (*PniSignatureMessage) ProtoMessage() {} func (x *PniSignatureMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[20] + mi := &file_SignalService_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3854,7 +3591,7 @@ func (x *PniSignatureMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use PniSignatureMessage.ProtoReflect.Descriptor instead. func (*PniSignatureMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{20} + return file_SignalService_proto_rawDescGZIP(), []int{17} } func (x *PniSignatureMessage) GetPni() []byte { @@ -3881,7 +3618,7 @@ type EditMessage struct { func (x *EditMessage) Reset() { *x = EditMessage{} - mi := &file_SignalService_proto_msgTypes[21] + mi := &file_SignalService_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3893,7 +3630,7 @@ func (x *EditMessage) String() string { func (*EditMessage) ProtoMessage() {} func (x *EditMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[21] + mi := &file_SignalService_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3906,7 +3643,7 @@ func (x *EditMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use EditMessage.ProtoReflect.Descriptor instead. func (*EditMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{21} + return file_SignalService_proto_rawDescGZIP(), []int{18} } func (x *EditMessage) GetTargetSentTimestamp() uint64 { @@ -3923,6 +3660,292 @@ func (x *EditMessage) GetDataMessage() *DataMessage { return nil } +type BodyRange struct { + state protoimpl.MessageState `protogen:"open.v1"` + Start *uint32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` // Starting index in UTF-16 code units/raw string representation + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` // Length of range in UTF-16 code units/raw string representation + // Types that are valid to be assigned to AssociatedValue: + // + // *BodyRange_MentionAci + // *BodyRange_Style_ + AssociatedValue isBodyRange_AssociatedValue `protobuf_oneof:"associatedValue"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BodyRange) Reset() { + *x = BodyRange{} + mi := &file_SignalService_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BodyRange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BodyRange) ProtoMessage() {} + +func (x *BodyRange) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[19] + 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 BodyRange.ProtoReflect.Descriptor instead. +func (*BodyRange) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{19} +} + +func (x *BodyRange) GetStart() uint32 { + if x != nil && x.Start != nil { + return *x.Start + } + return 0 +} + +func (x *BodyRange) GetLength() uint32 { + if x != nil && x.Length != nil { + return *x.Length + } + return 0 +} + +func (x *BodyRange) GetAssociatedValue() isBodyRange_AssociatedValue { + if x != nil { + return x.AssociatedValue + } + return nil +} + +func (x *BodyRange) GetMentionAci() string { + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_MentionAci); ok { + return x.MentionAci + } + } + return "" +} + +func (x *BodyRange) GetStyle() BodyRange_Style { + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_Style_); ok { + return x.Style + } + } + return BodyRange_NONE +} + +type isBodyRange_AssociatedValue interface { + isBodyRange_AssociatedValue() +} + +type BodyRange_MentionAci struct { + MentionAci string `protobuf:"bytes,3,opt,name=mentionAci,oneof"` +} + +type BodyRange_Style_ struct { + Style BodyRange_Style `protobuf:"varint,4,opt,name=style,enum=signalservice.BodyRange_Style,oneof"` +} + +func (*BodyRange_MentionAci) isBodyRange_AssociatedValue() {} + +func (*BodyRange_Style_) isBodyRange_AssociatedValue() {} + +type AddressableMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Author: + // + // *AddressableMessage_AuthorServiceId + // *AddressableMessage_AuthorE164 + Author isAddressableMessage_Author `protobuf_oneof:"author"` + SentTimestamp *uint64 `protobuf:"varint,3,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddressableMessage) Reset() { + *x = AddressableMessage{} + mi := &file_SignalService_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddressableMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddressableMessage) ProtoMessage() {} + +func (x *AddressableMessage) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[20] + 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 AddressableMessage.ProtoReflect.Descriptor instead. +func (*AddressableMessage) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{20} +} + +func (x *AddressableMessage) GetAuthor() isAddressableMessage_Author { + if x != nil { + return x.Author + } + return nil +} + +func (x *AddressableMessage) GetAuthorServiceId() string { + if x != nil { + if x, ok := x.Author.(*AddressableMessage_AuthorServiceId); ok { + return x.AuthorServiceId + } + } + return "" +} + +func (x *AddressableMessage) GetAuthorE164() string { + if x != nil { + if x, ok := x.Author.(*AddressableMessage_AuthorE164); ok { + return x.AuthorE164 + } + } + return "" +} + +func (x *AddressableMessage) GetSentTimestamp() uint64 { + if x != nil && x.SentTimestamp != nil { + return *x.SentTimestamp + } + return 0 +} + +type isAddressableMessage_Author interface { + isAddressableMessage_Author() +} + +type AddressableMessage_AuthorServiceId struct { + AuthorServiceId string `protobuf:"bytes,1,opt,name=authorServiceId,oneof"` +} + +type AddressableMessage_AuthorE164 struct { + AuthorE164 string `protobuf:"bytes,2,opt,name=authorE164,oneof"` +} + +func (*AddressableMessage_AuthorServiceId) isAddressableMessage_Author() {} + +func (*AddressableMessage_AuthorE164) isAddressableMessage_Author() {} + +type ConversationIdentifier struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Identifier: + // + // *ConversationIdentifier_ThreadServiceId + // *ConversationIdentifier_ThreadGroupId + // *ConversationIdentifier_ThreadE164 + Identifier isConversationIdentifier_Identifier `protobuf_oneof:"identifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConversationIdentifier) Reset() { + *x = ConversationIdentifier{} + mi := &file_SignalService_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConversationIdentifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConversationIdentifier) ProtoMessage() {} + +func (x *ConversationIdentifier) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[21] + 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 ConversationIdentifier.ProtoReflect.Descriptor instead. +func (*ConversationIdentifier) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{21} +} + +func (x *ConversationIdentifier) GetIdentifier() isConversationIdentifier_Identifier { + if x != nil { + return x.Identifier + } + return nil +} + +func (x *ConversationIdentifier) GetThreadServiceId() string { + if x != nil { + if x, ok := x.Identifier.(*ConversationIdentifier_ThreadServiceId); ok { + return x.ThreadServiceId + } + } + return "" +} + +func (x *ConversationIdentifier) GetThreadGroupId() []byte { + if x != nil { + if x, ok := x.Identifier.(*ConversationIdentifier_ThreadGroupId); ok { + return x.ThreadGroupId + } + } + return nil +} + +func (x *ConversationIdentifier) GetThreadE164() string { + if x != nil { + if x, ok := x.Identifier.(*ConversationIdentifier_ThreadE164); ok { + return x.ThreadE164 + } + } + return "" +} + +type isConversationIdentifier_Identifier interface { + isConversationIdentifier_Identifier() +} + +type ConversationIdentifier_ThreadServiceId struct { + ThreadServiceId string `protobuf:"bytes,1,opt,name=threadServiceId,oneof"` +} + +type ConversationIdentifier_ThreadGroupId struct { + ThreadGroupId []byte `protobuf:"bytes,2,opt,name=threadGroupId,oneof"` +} + +type ConversationIdentifier_ThreadE164 struct { + ThreadE164 string `protobuf:"bytes,3,opt,name=threadE164,oneof"` +} + +func (*ConversationIdentifier_ThreadServiceId) isConversationIdentifier_Identifier() {} + +func (*ConversationIdentifier_ThreadGroupId) isConversationIdentifier_Identifier() {} + +func (*ConversationIdentifier_ThreadE164) isConversationIdentifier_Identifier() {} + type CallMessage_Offer struct { state protoimpl.MessageState `protogen:"open.v1"` Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` @@ -4194,7 +4217,7 @@ func (x *CallMessage_Hangup) GetDeviceId() uint32 { type CallMessage_Opaque struct { state protoimpl.MessageState `protogen:"open.v1"` Data []byte `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"` - Urgency *CallMessage_Opaque_Urgency `protobuf:"varint,2,opt,name=urgency,enum=signalservice.CallMessage_Opaque_Urgency" json:"urgency,omitempty"` + Urgency *CallMessage_Opaque_Urgency `protobuf:"varint,2,opt,name=urgency,enum=signalservice.CallMessage_Opaque_Urgency" json:"urgency,omitempty"` // If missing, treat as DROPPABLE. unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4243,6 +4266,88 @@ func (x *CallMessage_Opaque) GetUrgency() CallMessage_Opaque_Urgency { return CallMessage_Opaque_DROPPABLE } +type DataMessage_Payment struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Item: + // + // *DataMessage_Payment_Notification_ + // *DataMessage_Payment_Activation_ + Item isDataMessage_Payment_Item `protobuf_oneof:"Item"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_Payment) Reset() { + *x = DataMessage_Payment{} + mi := &file_SignalService_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_Payment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_Payment) ProtoMessage() {} + +func (x *DataMessage_Payment) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[28] + 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 DataMessage_Payment.ProtoReflect.Descriptor instead. +func (*DataMessage_Payment) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *DataMessage_Payment) GetItem() isDataMessage_Payment_Item { + if x != nil { + return x.Item + } + return nil +} + +func (x *DataMessage_Payment) GetNotification() *DataMessage_Payment_Notification { + if x != nil { + if x, ok := x.Item.(*DataMessage_Payment_Notification_); ok { + return x.Notification + } + } + return nil +} + +func (x *DataMessage_Payment) GetActivation() *DataMessage_Payment_Activation { + if x != nil { + if x, ok := x.Item.(*DataMessage_Payment_Activation_); ok { + return x.Activation + } + } + return nil +} + +type isDataMessage_Payment_Item interface { + isDataMessage_Payment_Item() +} + +type DataMessage_Payment_Notification_ struct { + Notification *DataMessage_Payment_Notification `protobuf:"bytes,1,opt,name=notification,oneof"` +} + +type DataMessage_Payment_Activation_ struct { + Activation *DataMessage_Payment_Activation `protobuf:"bytes,2,opt,name=activation,oneof"` +} + +func (*DataMessage_Payment_Notification_) isDataMessage_Payment_Item() {} + +func (*DataMessage_Payment_Activation_) isDataMessage_Payment_Item() {} + type DataMessage_Quote struct { state protoimpl.MessageState `protogen:"open.v1"` Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` @@ -4257,7 +4362,7 @@ type DataMessage_Quote struct { func (x *DataMessage_Quote) Reset() { *x = DataMessage_Quote{} - mi := &file_SignalService_proto_msgTypes[28] + mi := &file_SignalService_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4269,7 +4374,7 @@ func (x *DataMessage_Quote) String() string { func (*DataMessage_Quote) ProtoMessage() {} func (x *DataMessage_Quote) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[28] + mi := &file_SignalService_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4282,7 +4387,7 @@ func (x *DataMessage_Quote) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Quote.ProtoReflect.Descriptor instead. func (*DataMessage_Quote) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 1} } func (x *DataMessage_Quote) GetId() uint64 { @@ -4341,7 +4446,7 @@ type DataMessage_Contact struct { func (x *DataMessage_Contact) Reset() { *x = DataMessage_Contact{} - mi := &file_SignalService_proto_msgTypes[29] + mi := &file_SignalService_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4353,7 +4458,7 @@ func (x *DataMessage_Contact) String() string { func (*DataMessage_Contact) ProtoMessage() {} func (x *DataMessage_Contact) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[29] + mi := &file_SignalService_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4366,7 +4471,7 @@ func (x *DataMessage_Contact) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Contact.ProtoReflect.Descriptor instead. func (*DataMessage_Contact) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2} } func (x *DataMessage_Contact) GetName() *DataMessage_Contact_Name { @@ -4424,7 +4529,7 @@ type DataMessage_Sticker struct { func (x *DataMessage_Sticker) Reset() { *x = DataMessage_Sticker{} - mi := &file_SignalService_proto_msgTypes[30] + mi := &file_SignalService_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4436,7 +4541,7 @@ func (x *DataMessage_Sticker) String() string { func (*DataMessage_Sticker) ProtoMessage() {} func (x *DataMessage_Sticker) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[30] + mi := &file_SignalService_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4449,7 +4554,7 @@ func (x *DataMessage_Sticker) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Sticker.ProtoReflect.Descriptor instead. func (*DataMessage_Sticker) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 2} + return file_SignalService_proto_rawDescGZIP(), []int{3, 3} } func (x *DataMessage_Sticker) GetPackId() []byte { @@ -4499,7 +4604,7 @@ type DataMessage_Reaction struct { func (x *DataMessage_Reaction) Reset() { *x = DataMessage_Reaction{} - mi := &file_SignalService_proto_msgTypes[31] + mi := &file_SignalService_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4511,7 +4616,7 @@ func (x *DataMessage_Reaction) String() string { func (*DataMessage_Reaction) ProtoMessage() {} func (x *DataMessage_Reaction) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[31] + mi := &file_SignalService_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4524,7 +4629,7 @@ func (x *DataMessage_Reaction) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Reaction.ProtoReflect.Descriptor instead. func (*DataMessage_Reaction) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 3} + return file_SignalService_proto_rawDescGZIP(), []int{3, 4} } func (x *DataMessage_Reaction) GetEmoji() string { @@ -4564,7 +4669,7 @@ type DataMessage_Delete struct { func (x *DataMessage_Delete) Reset() { *x = DataMessage_Delete{} - mi := &file_SignalService_proto_msgTypes[32] + mi := &file_SignalService_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4576,7 +4681,7 @@ func (x *DataMessage_Delete) String() string { func (*DataMessage_Delete) ProtoMessage() {} func (x *DataMessage_Delete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[32] + mi := &file_SignalService_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4589,7 +4694,7 @@ func (x *DataMessage_Delete) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Delete.ProtoReflect.Descriptor instead. func (*DataMessage_Delete) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 4} + return file_SignalService_proto_rawDescGZIP(), []int{3, 5} } func (x *DataMessage_Delete) GetTargetSentTimestamp() uint64 { @@ -4608,7 +4713,7 @@ type DataMessage_GroupCallUpdate struct { func (x *DataMessage_GroupCallUpdate) Reset() { *x = DataMessage_GroupCallUpdate{} - mi := &file_SignalService_proto_msgTypes[33] + mi := &file_SignalService_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4620,7 +4725,7 @@ func (x *DataMessage_GroupCallUpdate) String() string { func (*DataMessage_GroupCallUpdate) ProtoMessage() {} func (x *DataMessage_GroupCallUpdate) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[33] + mi := &file_SignalService_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4633,7 +4738,7 @@ func (x *DataMessage_GroupCallUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_GroupCallUpdate.ProtoReflect.Descriptor instead. func (*DataMessage_GroupCallUpdate) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 5} + return file_SignalService_proto_rawDescGZIP(), []int{3, 6} } func (x *DataMessage_GroupCallUpdate) GetEraId() string { @@ -4653,7 +4758,7 @@ type DataMessage_StoryContext struct { func (x *DataMessage_StoryContext) Reset() { *x = DataMessage_StoryContext{} - mi := &file_SignalService_proto_msgTypes[34] + mi := &file_SignalService_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4665,7 +4770,7 @@ func (x *DataMessage_StoryContext) String() string { func (*DataMessage_StoryContext) ProtoMessage() {} func (x *DataMessage_StoryContext) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[34] + mi := &file_SignalService_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4678,7 +4783,7 @@ func (x *DataMessage_StoryContext) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_StoryContext.ProtoReflect.Descriptor instead. func (*DataMessage_StoryContext) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 6} + return file_SignalService_proto_rawDescGZIP(), []int{3, 7} } func (x *DataMessage_StoryContext) GetAuthorAci() string { @@ -4695,88 +4800,6 @@ func (x *DataMessage_StoryContext) GetSentTimestamp() uint64 { return 0 } -type DataMessage_Payment struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Item: - // - // *DataMessage_Payment_Notification_ - // *DataMessage_Payment_Activation_ - Item isDataMessage_Payment_Item `protobuf_oneof:"Item"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DataMessage_Payment) Reset() { - *x = DataMessage_Payment{} - mi := &file_SignalService_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DataMessage_Payment) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataMessage_Payment) ProtoMessage() {} - -func (x *DataMessage_Payment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[35] - 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 DataMessage_Payment.ProtoReflect.Descriptor instead. -func (*DataMessage_Payment) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7} -} - -func (x *DataMessage_Payment) GetItem() isDataMessage_Payment_Item { - if x != nil { - return x.Item - } - return nil -} - -func (x *DataMessage_Payment) GetNotification() *DataMessage_Payment_Notification { - if x != nil { - if x, ok := x.Item.(*DataMessage_Payment_Notification_); ok { - return x.Notification - } - } - return nil -} - -func (x *DataMessage_Payment) GetActivation() *DataMessage_Payment_Activation { - if x != nil { - if x, ok := x.Item.(*DataMessage_Payment_Activation_); ok { - return x.Activation - } - } - return nil -} - -type isDataMessage_Payment_Item interface { - isDataMessage_Payment_Item() -} - -type DataMessage_Payment_Notification_ struct { - Notification *DataMessage_Payment_Notification `protobuf:"bytes,1,opt,name=notification,oneof"` -} - -type DataMessage_Payment_Activation_ struct { - Activation *DataMessage_Payment_Activation `protobuf:"bytes,2,opt,name=activation,oneof"` -} - -func (*DataMessage_Payment_Notification_) isDataMessage_Payment_Item() {} - -func (*DataMessage_Payment_Activation_) isDataMessage_Payment_Item() {} - type DataMessage_GiftBadge struct { state protoimpl.MessageState `protogen:"open.v1"` ReceiptCredentialPresentation []byte `protobuf:"bytes,1,opt,name=receiptCredentialPresentation" json:"receiptCredentialPresentation,omitempty"` @@ -4811,7 +4834,7 @@ func (x *DataMessage_GiftBadge) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_GiftBadge.ProtoReflect.Descriptor instead. func (*DataMessage_GiftBadge) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 8} + return file_SignalService_proto_rawDescGZIP(), []int{3, 8} } func (x *DataMessage_GiftBadge) GetReceiptCredentialPresentation() []byte { @@ -4821,6 +4844,280 @@ func (x *DataMessage_GiftBadge) GetReceiptCredentialPresentation() []byte { return nil } +type DataMessage_Payment_Amount struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Amount: + // + // *DataMessage_Payment_Amount_MobileCoin_ + Amount isDataMessage_Payment_Amount_Amount `protobuf_oneof:"Amount"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_Payment_Amount) Reset() { + *x = DataMessage_Payment_Amount{} + mi := &file_SignalService_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_Payment_Amount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_Payment_Amount) ProtoMessage() {} + +func (x *DataMessage_Payment_Amount) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[37] + 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 DataMessage_Payment_Amount.ProtoReflect.Descriptor instead. +func (*DataMessage_Payment_Amount) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0, 0} +} + +func (x *DataMessage_Payment_Amount) GetAmount() isDataMessage_Payment_Amount_Amount { + if x != nil { + return x.Amount + } + return nil +} + +func (x *DataMessage_Payment_Amount) GetMobileCoin() *DataMessage_Payment_Amount_MobileCoin { + if x != nil { + if x, ok := x.Amount.(*DataMessage_Payment_Amount_MobileCoin_); ok { + return x.MobileCoin + } + } + return nil +} + +type isDataMessage_Payment_Amount_Amount interface { + isDataMessage_Payment_Amount_Amount() +} + +type DataMessage_Payment_Amount_MobileCoin_ struct { + MobileCoin *DataMessage_Payment_Amount_MobileCoin `protobuf:"bytes,1,opt,name=mobileCoin,oneof"` +} + +func (*DataMessage_Payment_Amount_MobileCoin_) isDataMessage_Payment_Amount_Amount() {} + +type DataMessage_Payment_Notification struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Transaction: + // + // *DataMessage_Payment_Notification_MobileCoin_ + Transaction isDataMessage_Payment_Notification_Transaction `protobuf_oneof:"Transaction"` + // Optional, Refers to the PaymentRequest message, if any. + Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_Payment_Notification) Reset() { + *x = DataMessage_Payment_Notification{} + mi := &file_SignalService_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_Payment_Notification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_Payment_Notification) ProtoMessage() {} + +func (x *DataMessage_Payment_Notification) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DataMessage_Payment_Notification.ProtoReflect.Descriptor instead. +func (*DataMessage_Payment_Notification) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0, 1} +} + +func (x *DataMessage_Payment_Notification) GetTransaction() isDataMessage_Payment_Notification_Transaction { + if x != nil { + return x.Transaction + } + return nil +} + +func (x *DataMessage_Payment_Notification) GetMobileCoin() *DataMessage_Payment_Notification_MobileCoin { + if x != nil { + if x, ok := x.Transaction.(*DataMessage_Payment_Notification_MobileCoin_); ok { + return x.MobileCoin + } + } + return nil +} + +func (x *DataMessage_Payment_Notification) GetNote() string { + if x != nil && x.Note != nil { + return *x.Note + } + return "" +} + +type isDataMessage_Payment_Notification_Transaction interface { + isDataMessage_Payment_Notification_Transaction() +} + +type DataMessage_Payment_Notification_MobileCoin_ struct { + MobileCoin *DataMessage_Payment_Notification_MobileCoin `protobuf:"bytes,1,opt,name=mobileCoin,oneof"` +} + +func (*DataMessage_Payment_Notification_MobileCoin_) isDataMessage_Payment_Notification_Transaction() { +} + +type DataMessage_Payment_Activation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type *DataMessage_Payment_Activation_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.DataMessage_Payment_Activation_Type" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_Payment_Activation) Reset() { + *x = DataMessage_Payment_Activation{} + mi := &file_SignalService_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_Payment_Activation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_Payment_Activation) ProtoMessage() {} + +func (x *DataMessage_Payment_Activation) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[39] + 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 DataMessage_Payment_Activation.ProtoReflect.Descriptor instead. +func (*DataMessage_Payment_Activation) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0, 2} +} + +func (x *DataMessage_Payment_Activation) GetType() DataMessage_Payment_Activation_Type { + if x != nil && x.Type != nil { + return *x.Type + } + return DataMessage_Payment_Activation_REQUEST +} + +type DataMessage_Payment_Amount_MobileCoin struct { + state protoimpl.MessageState `protogen:"open.v1"` + PicoMob *uint64 `protobuf:"varint,1,opt,name=picoMob" json:"picoMob,omitempty"` // 1,000,000,000,000 picoMob per Mob + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { + *x = DataMessage_Payment_Amount_MobileCoin{} + mi := &file_SignalService_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_Payment_Amount_MobileCoin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_Payment_Amount_MobileCoin) ProtoMessage() {} + +func (x *DataMessage_Payment_Amount_MobileCoin) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[40] + 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 DataMessage_Payment_Amount_MobileCoin.ProtoReflect.Descriptor instead. +func (*DataMessage_Payment_Amount_MobileCoin) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0, 0, 0} +} + +func (x *DataMessage_Payment_Amount_MobileCoin) GetPicoMob() uint64 { + if x != nil && x.PicoMob != nil { + return *x.PicoMob + } + return 0 +} + +type DataMessage_Payment_Notification_MobileCoin struct { + state protoimpl.MessageState `protogen:"open.v1"` + Receipt []byte `protobuf:"bytes,1,opt,name=receipt" json:"receipt,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { + *x = DataMessage_Payment_Notification_MobileCoin{} + mi := &file_SignalService_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_Payment_Notification_MobileCoin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_Payment_Notification_MobileCoin) ProtoMessage() {} + +func (x *DataMessage_Payment_Notification_MobileCoin) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DataMessage_Payment_Notification_MobileCoin.ProtoReflect.Descriptor instead. +func (*DataMessage_Payment_Notification_MobileCoin) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 0, 1, 0} +} + +func (x *DataMessage_Payment_Notification_MobileCoin) GetReceipt() []byte { + if x != nil { + return x.Receipt + } + return nil +} + type DataMessage_Quote_QuotedAttachment struct { state protoimpl.MessageState `protogen:"open.v1"` ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` @@ -4832,7 +5129,7 @@ type DataMessage_Quote_QuotedAttachment struct { func (x *DataMessage_Quote_QuotedAttachment) Reset() { *x = DataMessage_Quote_QuotedAttachment{} - mi := &file_SignalService_proto_msgTypes[37] + mi := &file_SignalService_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4844,7 +5141,7 @@ func (x *DataMessage_Quote_QuotedAttachment) String() string { func (*DataMessage_Quote_QuotedAttachment) ProtoMessage() {} func (x *DataMessage_Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[37] + mi := &file_SignalService_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4857,7 +5154,7 @@ func (x *DataMessage_Quote_QuotedAttachment) ProtoReflect() protoreflect.Message // Deprecated: Use DataMessage_Quote_QuotedAttachment.ProtoReflect.Descriptor instead. func (*DataMessage_Quote_QuotedAttachment) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 0, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 1, 0} } func (x *DataMessage_Quote_QuotedAttachment) GetContentType() string { @@ -4895,7 +5192,7 @@ type DataMessage_Contact_Name struct { func (x *DataMessage_Contact_Name) Reset() { *x = DataMessage_Contact_Name{} - mi := &file_SignalService_proto_msgTypes[38] + mi := &file_SignalService_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4907,7 +5204,7 @@ func (x *DataMessage_Contact_Name) String() string { func (*DataMessage_Contact_Name) ProtoMessage() {} func (x *DataMessage_Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[38] + mi := &file_SignalService_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4920,7 +5217,7 @@ func (x *DataMessage_Contact_Name) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Contact_Name.ProtoReflect.Descriptor instead. func (*DataMessage_Contact_Name) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 0} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 0} } func (x *DataMessage_Contact_Name) GetGivenName() string { @@ -4976,7 +5273,7 @@ type DataMessage_Contact_Phone struct { func (x *DataMessage_Contact_Phone) Reset() { *x = DataMessage_Contact_Phone{} - mi := &file_SignalService_proto_msgTypes[39] + mi := &file_SignalService_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4988,7 +5285,7 @@ func (x *DataMessage_Contact_Phone) String() string { func (*DataMessage_Contact_Phone) ProtoMessage() {} func (x *DataMessage_Contact_Phone) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[39] + mi := &file_SignalService_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5001,7 +5298,7 @@ func (x *DataMessage_Contact_Phone) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Contact_Phone.ProtoReflect.Descriptor instead. func (*DataMessage_Contact_Phone) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 1} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 1} } func (x *DataMessage_Contact_Phone) GetValue() string { @@ -5036,7 +5333,7 @@ type DataMessage_Contact_Email struct { func (x *DataMessage_Contact_Email) Reset() { *x = DataMessage_Contact_Email{} - mi := &file_SignalService_proto_msgTypes[40] + mi := &file_SignalService_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5048,7 +5345,7 @@ func (x *DataMessage_Contact_Email) String() string { func (*DataMessage_Contact_Email) ProtoMessage() {} func (x *DataMessage_Contact_Email) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[40] + mi := &file_SignalService_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5061,7 +5358,7 @@ func (x *DataMessage_Contact_Email) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Contact_Email.ProtoReflect.Descriptor instead. func (*DataMessage_Contact_Email) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 2} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 2} } func (x *DataMessage_Contact_Email) GetValue() string { @@ -5102,7 +5399,7 @@ type DataMessage_Contact_PostalAddress struct { func (x *DataMessage_Contact_PostalAddress) Reset() { *x = DataMessage_Contact_PostalAddress{} - mi := &file_SignalService_proto_msgTypes[41] + mi := &file_SignalService_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5114,7 +5411,7 @@ func (x *DataMessage_Contact_PostalAddress) String() string { func (*DataMessage_Contact_PostalAddress) ProtoMessage() {} func (x *DataMessage_Contact_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[41] + mi := &file_SignalService_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5127,7 +5424,7 @@ func (x *DataMessage_Contact_PostalAddress) ProtoReflect() protoreflect.Message // Deprecated: Use DataMessage_Contact_PostalAddress.ProtoReflect.Descriptor instead. func (*DataMessage_Contact_PostalAddress) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 3} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 3} } func (x *DataMessage_Contact_PostalAddress) GetType() DataMessage_Contact_PostalAddress_Type { @@ -5203,7 +5500,7 @@ type DataMessage_Contact_Avatar struct { func (x *DataMessage_Contact_Avatar) Reset() { *x = DataMessage_Contact_Avatar{} - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5215,7 +5512,7 @@ func (x *DataMessage_Contact_Avatar) String() string { func (*DataMessage_Contact_Avatar) ProtoMessage() {} func (x *DataMessage_Contact_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5228,7 +5525,7 @@ func (x *DataMessage_Contact_Avatar) ProtoReflect() protoreflect.Message { // Deprecated: Use DataMessage_Contact_Avatar.ProtoReflect.Descriptor instead. func (*DataMessage_Contact_Avatar) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 1, 4} + return file_SignalService_proto_rawDescGZIP(), []int{3, 2, 4} } func (x *DataMessage_Contact_Avatar) GetAvatar() *AttachmentPointer { @@ -5245,279 +5542,6 @@ func (x *DataMessage_Contact_Avatar) GetIsProfile() bool { return false } -type DataMessage_Payment_Amount struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Amount: - // - // *DataMessage_Payment_Amount_MobileCoin_ - Amount isDataMessage_Payment_Amount_Amount `protobuf_oneof:"Amount"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DataMessage_Payment_Amount) Reset() { - *x = DataMessage_Payment_Amount{} - mi := &file_SignalService_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DataMessage_Payment_Amount) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataMessage_Payment_Amount) ProtoMessage() {} - -func (x *DataMessage_Payment_Amount) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[43] - 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 DataMessage_Payment_Amount.ProtoReflect.Descriptor instead. -func (*DataMessage_Payment_Amount) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 0} -} - -func (x *DataMessage_Payment_Amount) GetAmount() isDataMessage_Payment_Amount_Amount { - if x != nil { - return x.Amount - } - return nil -} - -func (x *DataMessage_Payment_Amount) GetMobileCoin() *DataMessage_Payment_Amount_MobileCoin { - if x != nil { - if x, ok := x.Amount.(*DataMessage_Payment_Amount_MobileCoin_); ok { - return x.MobileCoin - } - } - return nil -} - -type isDataMessage_Payment_Amount_Amount interface { - isDataMessage_Payment_Amount_Amount() -} - -type DataMessage_Payment_Amount_MobileCoin_ struct { - MobileCoin *DataMessage_Payment_Amount_MobileCoin `protobuf:"bytes,1,opt,name=mobileCoin,oneof"` -} - -func (*DataMessage_Payment_Amount_MobileCoin_) isDataMessage_Payment_Amount_Amount() {} - -type DataMessage_Payment_Notification struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Transaction: - // - // *DataMessage_Payment_Notification_MobileCoin_ - Transaction isDataMessage_Payment_Notification_Transaction `protobuf_oneof:"Transaction"` - Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DataMessage_Payment_Notification) Reset() { - *x = DataMessage_Payment_Notification{} - mi := &file_SignalService_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DataMessage_Payment_Notification) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataMessage_Payment_Notification) ProtoMessage() {} - -func (x *DataMessage_Payment_Notification) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[44] - 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 DataMessage_Payment_Notification.ProtoReflect.Descriptor instead. -func (*DataMessage_Payment_Notification) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 1} -} - -func (x *DataMessage_Payment_Notification) GetTransaction() isDataMessage_Payment_Notification_Transaction { - if x != nil { - return x.Transaction - } - return nil -} - -func (x *DataMessage_Payment_Notification) GetMobileCoin() *DataMessage_Payment_Notification_MobileCoin { - if x != nil { - if x, ok := x.Transaction.(*DataMessage_Payment_Notification_MobileCoin_); ok { - return x.MobileCoin - } - } - return nil -} - -func (x *DataMessage_Payment_Notification) GetNote() string { - if x != nil && x.Note != nil { - return *x.Note - } - return "" -} - -type isDataMessage_Payment_Notification_Transaction interface { - isDataMessage_Payment_Notification_Transaction() -} - -type DataMessage_Payment_Notification_MobileCoin_ struct { - MobileCoin *DataMessage_Payment_Notification_MobileCoin `protobuf:"bytes,1,opt,name=mobileCoin,oneof"` -} - -func (*DataMessage_Payment_Notification_MobileCoin_) isDataMessage_Payment_Notification_Transaction() { -} - -type DataMessage_Payment_Activation struct { - state protoimpl.MessageState `protogen:"open.v1"` - Type *DataMessage_Payment_Activation_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.DataMessage_Payment_Activation_Type" json:"type,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DataMessage_Payment_Activation) Reset() { - *x = DataMessage_Payment_Activation{} - mi := &file_SignalService_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DataMessage_Payment_Activation) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataMessage_Payment_Activation) ProtoMessage() {} - -func (x *DataMessage_Payment_Activation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[45] - 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 DataMessage_Payment_Activation.ProtoReflect.Descriptor instead. -func (*DataMessage_Payment_Activation) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 2} -} - -func (x *DataMessage_Payment_Activation) GetType() DataMessage_Payment_Activation_Type { - if x != nil && x.Type != nil { - return *x.Type - } - return DataMessage_Payment_Activation_REQUEST -} - -type DataMessage_Payment_Amount_MobileCoin struct { - state protoimpl.MessageState `protogen:"open.v1"` - PicoMob *uint64 `protobuf:"varint,1,opt,name=picoMob" json:"picoMob,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { - *x = DataMessage_Payment_Amount_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DataMessage_Payment_Amount_MobileCoin) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataMessage_Payment_Amount_MobileCoin) ProtoMessage() {} - -func (x *DataMessage_Payment_Amount_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[46] - 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 DataMessage_Payment_Amount_MobileCoin.ProtoReflect.Descriptor instead. -func (*DataMessage_Payment_Amount_MobileCoin) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 0, 0} -} - -func (x *DataMessage_Payment_Amount_MobileCoin) GetPicoMob() uint64 { - if x != nil && x.PicoMob != nil { - return *x.PicoMob - } - return 0 -} - -type DataMessage_Payment_Notification_MobileCoin struct { - state protoimpl.MessageState `protogen:"open.v1"` - Receipt []byte `protobuf:"bytes,1,opt,name=receipt" json:"receipt,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { - *x = DataMessage_Payment_Notification_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[47] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DataMessage_Payment_Notification_MobileCoin) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataMessage_Payment_Notification_MobileCoin) ProtoMessage() {} - -func (x *DataMessage_Payment_Notification_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[47] - 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 DataMessage_Payment_Notification_MobileCoin.ProtoReflect.Descriptor instead. -func (*DataMessage_Payment_Notification_MobileCoin) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{4, 7, 1, 0} -} - -func (x *DataMessage_Payment_Notification_MobileCoin) GetReceipt() []byte { - if x != nil { - return x.Receipt - } - return nil -} - type TextAttachment_Gradient struct { state protoimpl.MessageState `protogen:"open.v1"` StartColor *uint32 `protobuf:"varint,1,opt,name=startColor" json:"startColor,omitempty"` // deprecated: this field will be removed in a future release. @@ -5556,7 +5580,7 @@ func (x *TextAttachment_Gradient) ProtoReflect() protoreflect.Message { // Deprecated: Use TextAttachment_Gradient.ProtoReflect.Descriptor instead. func (*TextAttachment_Gradient) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{10, 0} + return file_SignalService_proto_rawDescGZIP(), []int{9, 0} } func (x *TextAttachment_Gradient) GetStartColor() uint32 { @@ -5642,7 +5666,7 @@ func (x *SyncMessage_Sent) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Sent.ProtoReflect.Descriptor instead. func (*SyncMessage_Sent) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 0} } func (x *SyncMessage_Sent) GetDestinationE164() string { @@ -5755,7 +5779,7 @@ func (x *SyncMessage_Contacts) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Contacts.ProtoReflect.Descriptor instead. func (*SyncMessage_Contacts) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 1} + return file_SignalService_proto_rawDescGZIP(), []int{11, 1} } func (x *SyncMessage_Contacts) GetBlob() *AttachmentPointer { @@ -5808,7 +5832,7 @@ func (x *SyncMessage_Blocked) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Blocked.ProtoReflect.Descriptor instead. func (*SyncMessage_Blocked) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 2} + return file_SignalService_proto_rawDescGZIP(), []int{11, 2} } func (x *SyncMessage_Blocked) GetNumbers() []string { @@ -5866,7 +5890,7 @@ func (x *SyncMessage_Request) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Request.ProtoReflect.Descriptor instead. func (*SyncMessage_Request) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 3} + return file_SignalService_proto_rawDescGZIP(), []int{11, 3} } func (x *SyncMessage_Request) GetType() SyncMessage_Request_Type { @@ -5911,7 +5935,7 @@ func (x *SyncMessage_Read) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Read.ProtoReflect.Descriptor instead. func (*SyncMessage_Read) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 4} + return file_SignalService_proto_rawDescGZIP(), []int{11, 4} } func (x *SyncMessage_Read) GetSenderAci() string { @@ -5963,7 +5987,7 @@ func (x *SyncMessage_Viewed) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Viewed.ProtoReflect.Descriptor instead. func (*SyncMessage_Viewed) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 5} + return file_SignalService_proto_rawDescGZIP(), []int{11, 5} } func (x *SyncMessage_Viewed) GetSenderAci() string { @@ -6018,7 +6042,7 @@ func (x *SyncMessage_Configuration) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Configuration.ProtoReflect.Descriptor instead. func (*SyncMessage_Configuration) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 6} + return file_SignalService_proto_rawDescGZIP(), []int{11, 6} } func (x *SyncMessage_Configuration) GetReadReceipts() bool { @@ -6092,7 +6116,7 @@ func (x *SyncMessage_StickerPackOperation) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_StickerPackOperation.ProtoReflect.Descriptor instead. func (*SyncMessage_StickerPackOperation) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 7} + return file_SignalService_proto_rawDescGZIP(), []int{11, 7} } func (x *SyncMessage_StickerPackOperation) GetPackId() []byte { @@ -6151,7 +6175,7 @@ func (x *SyncMessage_ViewOnceOpen) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_ViewOnceOpen.ProtoReflect.Descriptor instead. func (*SyncMessage_ViewOnceOpen) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 8} + return file_SignalService_proto_rawDescGZIP(), []int{11, 8} } func (x *SyncMessage_ViewOnceOpen) GetSenderAci() string { @@ -6202,7 +6226,7 @@ func (x *SyncMessage_FetchLatest) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_FetchLatest.ProtoReflect.Descriptor instead. func (*SyncMessage_FetchLatest) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 9} + return file_SignalService_proto_rawDescGZIP(), []int{11, 9} } func (x *SyncMessage_FetchLatest) GetType() SyncMessage_FetchLatest_Type { @@ -6213,13 +6237,10 @@ func (x *SyncMessage_FetchLatest) GetType() SyncMessage_FetchLatest_Type { } type SyncMessage_Keys struct { - state protoimpl.MessageState `protogen:"open.v1"` - // @deprecated - StorageService []byte `protobuf:"bytes,1,opt,name=storageService" json:"storageService,omitempty"` - // @deprecated - Master []byte `protobuf:"bytes,2,opt,name=master" json:"master,omitempty"` - AccountEntropyPool *string `protobuf:"bytes,3,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` - MediaRootBackupKey []byte `protobuf:"bytes,4,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Master []byte `protobuf:"bytes,2,opt,name=master" json:"master,omitempty"` // deprecated: this field will be removed in a future release. + AccountEntropyPool *string `protobuf:"bytes,3,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` + MediaRootBackupKey []byte `protobuf:"bytes,4,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -6251,14 +6272,7 @@ func (x *SyncMessage_Keys) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_Keys.ProtoReflect.Descriptor instead. func (*SyncMessage_Keys) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 10} -} - -func (x *SyncMessage_Keys) GetStorageService() []byte { - if x != nil { - return x.StorageService - } - return nil + return file_SignalService_proto_rawDescGZIP(), []int{11, 10} } func (x *SyncMessage_Keys) GetMaster() []byte { @@ -6282,6 +6296,58 @@ func (x *SyncMessage_Keys) GetMediaRootBackupKey() []byte { return nil } +type SyncMessage_PniIdentity struct { + state protoimpl.MessageState `protogen:"open.v1"` + PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"` + PrivateKey []byte `protobuf:"bytes,2,opt,name=privateKey" json:"privateKey,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SyncMessage_PniIdentity) Reset() { + *x = SyncMessage_PniIdentity{} + mi := &file_SignalService_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SyncMessage_PniIdentity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_PniIdentity) ProtoMessage() {} + +func (x *SyncMessage_PniIdentity) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[60] + 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 SyncMessage_PniIdentity.ProtoReflect.Descriptor instead. +func (*SyncMessage_PniIdentity) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 11} +} + +func (x *SyncMessage_PniIdentity) GetPublicKey() []byte { + if x != nil { + return x.PublicKey + } + return nil +} + +func (x *SyncMessage_PniIdentity) GetPrivateKey() []byte { + if x != nil { + return x.PrivateKey + } + return nil +} + type SyncMessage_MessageRequestResponse struct { state protoimpl.MessageState `protogen:"open.v1"` ThreadAci *string `protobuf:"bytes,2,opt,name=threadAci" json:"threadAci,omitempty"` @@ -6293,7 +6359,7 @@ type SyncMessage_MessageRequestResponse struct { func (x *SyncMessage_MessageRequestResponse) Reset() { *x = SyncMessage_MessageRequestResponse{} - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6305,7 +6371,7 @@ func (x *SyncMessage_MessageRequestResponse) String() string { func (*SyncMessage_MessageRequestResponse) ProtoMessage() {} func (x *SyncMessage_MessageRequestResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6318,7 +6384,7 @@ func (x *SyncMessage_MessageRequestResponse) ProtoReflect() protoreflect.Message // Deprecated: Use SyncMessage_MessageRequestResponse.ProtoReflect.Descriptor instead. func (*SyncMessage_MessageRequestResponse) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 11} + return file_SignalService_proto_rawDescGZIP(), []int{11, 12} } func (x *SyncMessage_MessageRequestResponse) GetThreadAci() string { @@ -6346,17 +6412,17 @@ type SyncMessage_OutgoingPayment struct { state protoimpl.MessageState `protogen:"open.v1"` RecipientServiceId *string `protobuf:"bytes,1,opt,name=recipientServiceId" json:"recipientServiceId,omitempty"` Note *string `protobuf:"bytes,2,opt,name=note" json:"note,omitempty"` - // Types that are valid to be assigned to PaymentDetail: + // Types that are valid to be assigned to AttachmentIdentifier: // // *SyncMessage_OutgoingPayment_MobileCoin_ - PaymentDetail isSyncMessage_OutgoingPayment_PaymentDetail `protobuf_oneof:"paymentDetail"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + AttachmentIdentifier isSyncMessage_OutgoingPayment_AttachmentIdentifier `protobuf_oneof:"attachment_identifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_OutgoingPayment) Reset() { *x = SyncMessage_OutgoingPayment{} - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6368,7 +6434,7 @@ func (x *SyncMessage_OutgoingPayment) String() string { func (*SyncMessage_OutgoingPayment) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6381,7 +6447,7 @@ func (x *SyncMessage_OutgoingPayment) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_OutgoingPayment.ProtoReflect.Descriptor instead. func (*SyncMessage_OutgoingPayment) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 12} + return file_SignalService_proto_rawDescGZIP(), []int{11, 13} } func (x *SyncMessage_OutgoingPayment) GetRecipientServiceId() string { @@ -6398,31 +6464,32 @@ func (x *SyncMessage_OutgoingPayment) GetNote() string { return "" } -func (x *SyncMessage_OutgoingPayment) GetPaymentDetail() isSyncMessage_OutgoingPayment_PaymentDetail { +func (x *SyncMessage_OutgoingPayment) GetAttachmentIdentifier() isSyncMessage_OutgoingPayment_AttachmentIdentifier { if x != nil { - return x.PaymentDetail + return x.AttachmentIdentifier } return nil } func (x *SyncMessage_OutgoingPayment) GetMobileCoin() *SyncMessage_OutgoingPayment_MobileCoin { if x != nil { - if x, ok := x.PaymentDetail.(*SyncMessage_OutgoingPayment_MobileCoin_); ok { + if x, ok := x.AttachmentIdentifier.(*SyncMessage_OutgoingPayment_MobileCoin_); ok { return x.MobileCoin } } return nil } -type isSyncMessage_OutgoingPayment_PaymentDetail interface { - isSyncMessage_OutgoingPayment_PaymentDetail() +type isSyncMessage_OutgoingPayment_AttachmentIdentifier interface { + isSyncMessage_OutgoingPayment_AttachmentIdentifier() } type SyncMessage_OutgoingPayment_MobileCoin_ struct { MobileCoin *SyncMessage_OutgoingPayment_MobileCoin `protobuf:"bytes,3,opt,name=mobileCoin,oneof"` } -func (*SyncMessage_OutgoingPayment_MobileCoin_) isSyncMessage_OutgoingPayment_PaymentDetail() {} +func (*SyncMessage_OutgoingPayment_MobileCoin_) isSyncMessage_OutgoingPayment_AttachmentIdentifier() { +} type SyncMessage_PniChangeNumber struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -6437,7 +6504,7 @@ type SyncMessage_PniChangeNumber struct { func (x *SyncMessage_PniChangeNumber) Reset() { *x = SyncMessage_PniChangeNumber{} - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6449,7 +6516,7 @@ func (x *SyncMessage_PniChangeNumber) String() string { func (*SyncMessage_PniChangeNumber) ProtoMessage() {} func (x *SyncMessage_PniChangeNumber) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6462,7 +6529,7 @@ func (x *SyncMessage_PniChangeNumber) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_PniChangeNumber.ProtoReflect.Descriptor instead. func (*SyncMessage_PniChangeNumber) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 13} + return file_SignalService_proto_rawDescGZIP(), []int{11, 14} } func (x *SyncMessage_PniChangeNumber) GetIdentityKeyPair() []byte { @@ -6501,20 +6568,25 @@ func (x *SyncMessage_PniChangeNumber) GetNewE164() string { } type SyncMessage_CallEvent struct { - state protoimpl.MessageState `protogen:"open.v1"` - ConversationId []byte `protobuf:"bytes,1,opt,name=conversationId" json:"conversationId,omitempty"` - Id *uint64 `protobuf:"varint,2,opt,name=id" json:"id,omitempty"` - Timestamp *uint64 `protobuf:"varint,3,opt,name=timestamp" json:"timestamp,omitempty"` - Type *SyncMessage_CallEvent_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_CallEvent_Type" json:"type,omitempty"` - Direction *SyncMessage_CallEvent_Direction `protobuf:"varint,5,opt,name=direction,enum=signalservice.SyncMessage_CallEvent_Direction" json:"direction,omitempty"` - Event *SyncMessage_CallEvent_Event `protobuf:"varint,6,opt,name=event,enum=signalservice.SyncMessage_CallEvent_Event" json:"event,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // Data identifying a conversation. The service ID for 1:1, the group ID for + // group, or the room ID for an ad-hoc call. See also + // `CallLogEvent/conversationId`. + ConversationId []byte `protobuf:"bytes,1,opt,name=conversationId" json:"conversationId,omitempty"` + // An identifier for a call. Generated directly for 1:1, or derived from + // the era ID for group and ad-hoc calls. See also `CallLogEvent/callId`. + CallId *uint64 `protobuf:"varint,2,opt,name=callId" json:"callId,omitempty"` + Timestamp *uint64 `protobuf:"varint,3,opt,name=timestamp" json:"timestamp,omitempty"` + Type *SyncMessage_CallEvent_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_CallEvent_Type" json:"type,omitempty"` + Direction *SyncMessage_CallEvent_Direction `protobuf:"varint,5,opt,name=direction,enum=signalservice.SyncMessage_CallEvent_Direction" json:"direction,omitempty"` + Event *SyncMessage_CallEvent_Event `protobuf:"varint,6,opt,name=event,enum=signalservice.SyncMessage_CallEvent_Event" json:"event,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_CallEvent) Reset() { *x = SyncMessage_CallEvent{} - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6526,7 +6598,7 @@ func (x *SyncMessage_CallEvent) String() string { func (*SyncMessage_CallEvent) ProtoMessage() {} func (x *SyncMessage_CallEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6539,7 +6611,7 @@ func (x *SyncMessage_CallEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_CallEvent.ProtoReflect.Descriptor instead. func (*SyncMessage_CallEvent) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 14} + return file_SignalService_proto_rawDescGZIP(), []int{11, 15} } func (x *SyncMessage_CallEvent) GetConversationId() []byte { @@ -6549,9 +6621,9 @@ func (x *SyncMessage_CallEvent) GetConversationId() []byte { return nil } -func (x *SyncMessage_CallEvent) GetId() uint64 { - if x != nil && x.Id != nil { - return *x.Id +func (x *SyncMessage_CallEvent) GetCallId() uint64 { + if x != nil && x.CallId != nil { + return *x.CallId } return 0 } @@ -6581,21 +6653,21 @@ func (x *SyncMessage_CallEvent) GetEvent() SyncMessage_CallEvent_Event { if x != nil && x.Event != nil { return *x.Event } - return SyncMessage_CallEvent_UNKNOWN_ACTION + return SyncMessage_CallEvent_UNKNOWN_EVENT } type SyncMessage_CallLinkUpdate struct { state protoimpl.MessageState `protogen:"open.v1"` RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` - AdminPassKey []byte `protobuf:"bytes,2,opt,name=adminPassKey" json:"adminPassKey,omitempty"` - Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` + AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey" json:"adminPasskey,omitempty"` + Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` // defaults to UPDATE unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_CallLinkUpdate) Reset() { *x = SyncMessage_CallLinkUpdate{} - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6607,7 +6679,7 @@ func (x *SyncMessage_CallLinkUpdate) String() string { func (*SyncMessage_CallLinkUpdate) ProtoMessage() {} func (x *SyncMessage_CallLinkUpdate) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6620,7 +6692,7 @@ func (x *SyncMessage_CallLinkUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_CallLinkUpdate.ProtoReflect.Descriptor instead. func (*SyncMessage_CallLinkUpdate) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 15} + return file_SignalService_proto_rawDescGZIP(), []int{11, 16} } func (x *SyncMessage_CallLinkUpdate) GetRootKey() []byte { @@ -6630,9 +6702,9 @@ func (x *SyncMessage_CallLinkUpdate) GetRootKey() []byte { return nil } -func (x *SyncMessage_CallLinkUpdate) GetAdminPassKey() []byte { +func (x *SyncMessage_CallLinkUpdate) GetAdminPasskey() []byte { if x != nil { - return x.AdminPassKey + return x.AdminPasskey } return nil } @@ -6661,7 +6733,7 @@ type SyncMessage_CallLogEvent struct { func (x *SyncMessage_CallLogEvent) Reset() { *x = SyncMessage_CallLogEvent{} - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6673,7 +6745,7 @@ func (x *SyncMessage_CallLogEvent) String() string { func (*SyncMessage_CallLogEvent) ProtoMessage() {} func (x *SyncMessage_CallLogEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6686,7 +6758,7 @@ func (x *SyncMessage_CallLogEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_CallLogEvent.ProtoReflect.Descriptor instead. func (*SyncMessage_CallLogEvent) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 16} + return file_SignalService_proto_rawDescGZIP(), []int{11, 17} } func (x *SyncMessage_CallLogEvent) GetType() SyncMessage_CallLogEvent_Type { @@ -6729,7 +6801,7 @@ type SyncMessage_DeleteForMe struct { func (x *SyncMessage_DeleteForMe) Reset() { *x = SyncMessage_DeleteForMe{} - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6741,7 +6813,7 @@ func (x *SyncMessage_DeleteForMe) String() string { func (*SyncMessage_DeleteForMe) ProtoMessage() {} func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6754,7 +6826,7 @@ func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_DeleteForMe.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17} + return file_SignalService_proto_rawDescGZIP(), []int{11, 18} } func (x *SyncMessage_DeleteForMe) GetMessageDeletes() []*SyncMessage_DeleteForMe_MessageDeletes { @@ -6794,7 +6866,7 @@ type SyncMessage_DeviceNameChange struct { func (x *SyncMessage_DeviceNameChange) Reset() { *x = SyncMessage_DeviceNameChange{} - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6806,7 +6878,7 @@ func (x *SyncMessage_DeviceNameChange) String() string { func (*SyncMessage_DeviceNameChange) ProtoMessage() {} func (x *SyncMessage_DeviceNameChange) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6819,7 +6891,7 @@ func (x *SyncMessage_DeviceNameChange) ProtoReflect() protoreflect.Message { // Deprecated: Use SyncMessage_DeviceNameChange.ProtoReflect.Descriptor instead. func (*SyncMessage_DeviceNameChange) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 18} + return file_SignalService_proto_rawDescGZIP(), []int{11, 19} } func (x *SyncMessage_DeviceNameChange) GetDeviceId() uint32 { @@ -6829,18 +6901,170 @@ func (x *SyncMessage_DeviceNameChange) GetDeviceId() uint32 { return 0 } +type SyncMessage_AttachmentBackfillRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetMessage *AddressableMessage `protobuf:"bytes,1,opt,name=targetMessage" json:"targetMessage,omitempty"` + TargetConversation *ConversationIdentifier `protobuf:"bytes,2,opt,name=targetConversation" json:"targetConversation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SyncMessage_AttachmentBackfillRequest) Reset() { + *x = SyncMessage_AttachmentBackfillRequest{} + mi := &file_SignalService_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SyncMessage_AttachmentBackfillRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_AttachmentBackfillRequest) ProtoMessage() {} + +func (x *SyncMessage_AttachmentBackfillRequest) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[69] + 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 SyncMessage_AttachmentBackfillRequest.ProtoReflect.Descriptor instead. +func (*SyncMessage_AttachmentBackfillRequest) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 20} +} + +func (x *SyncMessage_AttachmentBackfillRequest) GetTargetMessage() *AddressableMessage { + if x != nil { + return x.TargetMessage + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillRequest) GetTargetConversation() *ConversationIdentifier { + if x != nil { + return x.TargetConversation + } + return nil +} + +type SyncMessage_AttachmentBackfillResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetMessage *AddressableMessage `protobuf:"bytes,1,opt,name=targetMessage" json:"targetMessage,omitempty"` + TargetConversation *ConversationIdentifier `protobuf:"bytes,2,opt,name=targetConversation" json:"targetConversation,omitempty"` + // Types that are valid to be assigned to Data: + // + // *SyncMessage_AttachmentBackfillResponse_Attachments + // *SyncMessage_AttachmentBackfillResponse_Error_ + Data isSyncMessage_AttachmentBackfillResponse_Data `protobuf_oneof:"data"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SyncMessage_AttachmentBackfillResponse) Reset() { + *x = SyncMessage_AttachmentBackfillResponse{} + mi := &file_SignalService_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SyncMessage_AttachmentBackfillResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_AttachmentBackfillResponse) ProtoMessage() {} + +func (x *SyncMessage_AttachmentBackfillResponse) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[70] + 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 SyncMessage_AttachmentBackfillResponse.ProtoReflect.Descriptor instead. +func (*SyncMessage_AttachmentBackfillResponse) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 21} +} + +func (x *SyncMessage_AttachmentBackfillResponse) GetTargetMessage() *AddressableMessage { + if x != nil { + return x.TargetMessage + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse) GetTargetConversation() *ConversationIdentifier { + if x != nil { + return x.TargetConversation + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse) GetData() isSyncMessage_AttachmentBackfillResponse_Data { + if x != nil { + return x.Data + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse) GetAttachments() *SyncMessage_AttachmentBackfillResponse_AttachmentDataList { + if x != nil { + if x, ok := x.Data.(*SyncMessage_AttachmentBackfillResponse_Attachments); ok { + return x.Attachments + } + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse) GetError() SyncMessage_AttachmentBackfillResponse_Error { + if x != nil { + if x, ok := x.Data.(*SyncMessage_AttachmentBackfillResponse_Error_); ok { + return x.Error + } + } + return SyncMessage_AttachmentBackfillResponse_MESSAGE_NOT_FOUND +} + +type isSyncMessage_AttachmentBackfillResponse_Data interface { + isSyncMessage_AttachmentBackfillResponse_Data() +} + +type SyncMessage_AttachmentBackfillResponse_Attachments struct { + Attachments *SyncMessage_AttachmentBackfillResponse_AttachmentDataList `protobuf:"bytes,3,opt,name=attachments,oneof"` +} + +type SyncMessage_AttachmentBackfillResponse_Error_ struct { + Error SyncMessage_AttachmentBackfillResponse_Error `protobuf:"varint,4,opt,name=error,enum=signalservice.SyncMessage_AttachmentBackfillResponse_Error,oneof"` +} + +func (*SyncMessage_AttachmentBackfillResponse_Attachments) isSyncMessage_AttachmentBackfillResponse_Data() { +} + +func (*SyncMessage_AttachmentBackfillResponse_Error_) isSyncMessage_AttachmentBackfillResponse_Data() { +} + type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { - state protoimpl.MessageState `protogen:"open.v1"` - DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` - DestinationIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationIdentityKey" json:"destinationIdentityKey,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` + DestinationPniIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationPniIdentityKey" json:"destinationPniIdentityKey,omitempty"` // Only set for PNI destinations + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6852,7 +7076,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6865,7 +7089,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflec // Deprecated: Use SyncMessage_Sent_UnidentifiedDeliveryStatus.ProtoReflect.Descriptor instead. func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 0, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 0, 0} } func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationServiceId() string { @@ -6882,9 +7106,9 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetUnidentified() bool { return false } -func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationIdentityKey() []byte { +func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationPniIdentityKey() []byte { if x != nil { - return x.DestinationIdentityKey + return x.DestinationPniIdentityKey } return nil } @@ -6900,7 +7124,7 @@ type SyncMessage_Sent_StoryMessageRecipient struct { func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6912,7 +7136,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6925,7 +7149,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Mes // Deprecated: Use SyncMessage_Sent_StoryMessageRecipient.ProtoReflect.Descriptor instead. func (*SyncMessage_Sent_StoryMessageRecipient) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 0, 1} + return file_SignalService_proto_rawDescGZIP(), []int{11, 0, 1} } func (x *SyncMessage_Sent_StoryMessageRecipient) GetDestinationServiceId() string { @@ -6950,25 +7174,22 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) GetIsAllowedToReply() bool { } type SyncMessage_OutgoingPayment_MobileCoin struct { - state protoimpl.MessageState `protogen:"open.v1"` - RecipientAddress []byte `protobuf:"bytes,1,opt,name=recipientAddress" json:"recipientAddress,omitempty"` - // @required - AmountPicoMob *uint64 `protobuf:"varint,2,opt,name=amountPicoMob" json:"amountPicoMob,omitempty"` - // @required - FeePicoMob *uint64 `protobuf:"varint,3,opt,name=feePicoMob" json:"feePicoMob,omitempty"` - Receipt []byte `protobuf:"bytes,4,opt,name=receipt" json:"receipt,omitempty"` - LedgerBlockTimestamp *uint64 `protobuf:"varint,5,opt,name=ledgerBlockTimestamp" json:"ledgerBlockTimestamp,omitempty"` - // @required - LedgerBlockIndex *uint64 `protobuf:"varint,6,opt,name=ledgerBlockIndex" json:"ledgerBlockIndex,omitempty"` - SpentKeyImages [][]byte `protobuf:"bytes,7,rep,name=spentKeyImages" json:"spentKeyImages,omitempty"` - OutputPublicKeys [][]byte `protobuf:"bytes,8,rep,name=outputPublicKeys" json:"outputPublicKeys,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + RecipientAddress []byte `protobuf:"bytes,1,opt,name=recipientAddress" json:"recipientAddress,omitempty"` + AmountPicoMob *uint64 `protobuf:"varint,2,opt,name=amountPicoMob" json:"amountPicoMob,omitempty"` + FeePicoMob *uint64 `protobuf:"varint,3,opt,name=feePicoMob" json:"feePicoMob,omitempty"` + Receipt []byte `protobuf:"bytes,4,opt,name=receipt" json:"receipt,omitempty"` + LedgerBlockTimestamp *uint64 `protobuf:"varint,5,opt,name=ledgerBlockTimestamp" json:"ledgerBlockTimestamp,omitempty"` + LedgerBlockIndex *uint64 `protobuf:"varint,6,opt,name=ledgerBlockIndex" json:"ledgerBlockIndex,omitempty"` + SpentKeyImages [][]byte `protobuf:"bytes,7,rep,name=spentKeyImages" json:"spentKeyImages,omitempty"` + OutputPublicKeys [][]byte `protobuf:"bytes,8,rep,name=outputPublicKeys" json:"outputPublicKeys,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6980,7 +7201,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6993,7 +7214,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Mes // Deprecated: Use SyncMessage_OutgoingPayment_MobileCoin.ProtoReflect.Descriptor instead. func (*SyncMessage_OutgoingPayment_MobileCoin) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 12, 0} + return file_SignalService_proto_rawDescGZIP(), []int{11, 13, 0} } func (x *SyncMessage_OutgoingPayment_MobileCoin) GetRecipientAddress() []byte { @@ -7052,210 +7273,17 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) GetOutputPublicKeys() [][]byte return nil } -type SyncMessage_DeleteForMe_ConversationIdentifier struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Identifier: - // - // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId - // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId - // *SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 - Identifier isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier `protobuf_oneof:"identifier"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) Reset() { - *x = SyncMessage_DeleteForMe_ConversationIdentifier{} - mi := &file_SignalService_proto_msgTypes[71] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SyncMessage_DeleteForMe_ConversationIdentifier) ProtoMessage() {} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[71] - 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 SyncMessage_DeleteForMe_ConversationIdentifier.ProtoReflect.Descriptor instead. -func (*SyncMessage_DeleteForMe_ConversationIdentifier) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 0} -} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetIdentifier() isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier { - if x != nil { - return x.Identifier - } - return nil -} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadServiceId() string { - if x != nil { - if x, ok := x.Identifier.(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId); ok { - return x.ThreadServiceId - } - } - return "" -} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadGroupId() []byte { - if x != nil { - if x, ok := x.Identifier.(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId); ok { - return x.ThreadGroupId - } - } - return nil -} - -func (x *SyncMessage_DeleteForMe_ConversationIdentifier) GetThreadE164() string { - if x != nil { - if x, ok := x.Identifier.(*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164); ok { - return x.ThreadE164 - } - } - return "" -} - -type isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier interface { - isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() -} - -type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId struct { - ThreadServiceId string `protobuf:"bytes,1,opt,name=threadServiceId,oneof"` -} - -type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId struct { - ThreadGroupId []byte `protobuf:"bytes,2,opt,name=threadGroupId,oneof"` -} - -type SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164 struct { - ThreadE164 string `protobuf:"bytes,3,opt,name=threadE164,oneof"` -} - -func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { -} - -func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { -} - -func (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164) isSyncMessage_DeleteForMe_ConversationIdentifier_Identifier() { -} - -type SyncMessage_DeleteForMe_AddressableMessage struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Author: - // - // *SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId - // *SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 - Author isSyncMessage_DeleteForMe_AddressableMessage_Author `protobuf_oneof:"author"` - SentTimestamp *uint64 `protobuf:"varint,3,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) Reset() { - *x = SyncMessage_DeleteForMe_AddressableMessage{} - mi := &file_SignalService_proto_msgTypes[72] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SyncMessage_DeleteForMe_AddressableMessage) ProtoMessage() {} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[72] - 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 SyncMessage_DeleteForMe_AddressableMessage.ProtoReflect.Descriptor instead. -func (*SyncMessage_DeleteForMe_AddressableMessage) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 1} -} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthor() isSyncMessage_DeleteForMe_AddressableMessage_Author { - if x != nil { - return x.Author - } - return nil -} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorServiceId() string { - if x != nil { - if x, ok := x.Author.(*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId); ok { - return x.AuthorServiceId - } - } - return "" -} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) GetAuthorE164() string { - if x != nil { - if x, ok := x.Author.(*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164); ok { - return x.AuthorE164 - } - } - return "" -} - -func (x *SyncMessage_DeleteForMe_AddressableMessage) GetSentTimestamp() uint64 { - if x != nil && x.SentTimestamp != nil { - return *x.SentTimestamp - } - return 0 -} - -type isSyncMessage_DeleteForMe_AddressableMessage_Author interface { - isSyncMessage_DeleteForMe_AddressableMessage_Author() -} - -type SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId struct { - AuthorServiceId string `protobuf:"bytes,1,opt,name=authorServiceId,oneof"` -} - -type SyncMessage_DeleteForMe_AddressableMessage_AuthorE164 struct { - AuthorE164 string `protobuf:"bytes,2,opt,name=authorE164,oneof"` -} - -func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId) isSyncMessage_DeleteForMe_AddressableMessage_Author() { -} - -func (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164) isSyncMessage_DeleteForMe_AddressableMessage_Author() { -} - type SyncMessage_DeleteForMe_MessageDeletes struct { - state protoimpl.MessageState `protogen:"open.v1"` - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` - Messages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=messages" json:"messages,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Conversation *ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + Messages []*AddressableMessage `protobuf:"bytes,2,rep,name=messages" json:"messages,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { *x = SyncMessage_DeleteForMe_MessageDeletes{} - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7267,7 +7295,7 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7280,17 +7308,17 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Mes // Deprecated: Use SyncMessage_DeleteForMe_MessageDeletes.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe_MessageDeletes) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 2} + return file_SignalService_proto_rawDescGZIP(), []int{11, 18, 0} } -func (x *SyncMessage_DeleteForMe_MessageDeletes) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { +func (x *SyncMessage_DeleteForMe_MessageDeletes) GetConversation() *ConversationIdentifier { if x != nil { return x.Conversation } return nil } -func (x *SyncMessage_DeleteForMe_MessageDeletes) GetMessages() []*SyncMessage_DeleteForMe_AddressableMessage { +func (x *SyncMessage_DeleteForMe_MessageDeletes) GetMessages() []*AddressableMessage { if x != nil { return x.Messages } @@ -7298,19 +7326,22 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) GetMessages() []*SyncMessage_De } type SyncMessage_DeleteForMe_AttachmentDelete struct { - state protoimpl.MessageState `protogen:"open.v1"` - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` - TargetMessage *SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,opt,name=targetMessage" json:"targetMessage,omitempty"` - Uuid []byte `protobuf:"bytes,3,opt,name=uuid" json:"uuid,omitempty"` // The `uuid` from the `Attachment`. - FallbackDigest []byte `protobuf:"bytes,4,opt,name=fallbackDigest" json:"fallbackDigest,omitempty"` - FallbackPlaintextHash []byte `protobuf:"bytes,5,opt,name=fallbackPlaintextHash" json:"fallbackPlaintextHash,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Conversation *ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + TargetMessage *AddressableMessage `protobuf:"bytes,2,opt,name=targetMessage" json:"targetMessage,omitempty"` + // The `clientUuid` from `AttachmentPointer`. + ClientUuid []byte `protobuf:"bytes,3,opt,name=clientUuid" json:"clientUuid,omitempty"` + // SHA256 hash of the (encrypted, padded, etc.) attachment blob on the CDN. + FallbackDigest []byte `protobuf:"bytes,4,opt,name=fallbackDigest" json:"fallbackDigest,omitempty"` + // SHA256 hash of the plaintext content of the attachment. + FallbackPlaintextHash []byte `protobuf:"bytes,5,opt,name=fallbackPlaintextHash" json:"fallbackPlaintextHash,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { *x = SyncMessage_DeleteForMe_AttachmentDelete{} - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7322,7 +7353,7 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7335,26 +7366,26 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.M // Deprecated: Use SyncMessage_DeleteForMe_AttachmentDelete.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe_AttachmentDelete) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 3} + return file_SignalService_proto_rawDescGZIP(), []int{11, 18, 1} } -func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetConversation() *ConversationIdentifier { if x != nil { return x.Conversation } return nil } -func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetTargetMessage() *SyncMessage_DeleteForMe_AddressableMessage { +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetTargetMessage() *AddressableMessage { if x != nil { return x.TargetMessage } return nil } -func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetUuid() []byte { +func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetClientUuid() []byte { if x != nil { - return x.Uuid + return x.ClientUuid } return nil } @@ -7374,18 +7405,18 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) GetFallbackPlaintextHash() [] } type SyncMessage_DeleteForMe_ConversationDelete struct { - state protoimpl.MessageState `protogen:"open.v1"` - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` - MostRecentMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,2,rep,name=mostRecentMessages" json:"mostRecentMessages,omitempty"` - MostRecentNonExpiringMessages []*SyncMessage_DeleteForMe_AddressableMessage `protobuf:"bytes,4,rep,name=mostRecentNonExpiringMessages" json:"mostRecentNonExpiringMessages,omitempty"` - IsFullDelete *bool `protobuf:"varint,3,opt,name=isFullDelete" json:"isFullDelete,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Conversation *ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + MostRecentMessages []*AddressableMessage `protobuf:"bytes,2,rep,name=mostRecentMessages" json:"mostRecentMessages,omitempty"` + IsFullDelete *bool `protobuf:"varint,3,opt,name=isFullDelete" json:"isFullDelete,omitempty"` + MostRecentNonExpiringMessages []*AddressableMessage `protobuf:"bytes,4,rep,name=mostRecentNonExpiringMessages" json:"mostRecentNonExpiringMessages,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7397,7 +7428,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7410,30 +7441,23 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect // Deprecated: Use SyncMessage_DeleteForMe_ConversationDelete.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe_ConversationDelete) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 4} + return file_SignalService_proto_rawDescGZIP(), []int{11, 18, 2} } -func (x *SyncMessage_DeleteForMe_ConversationDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetConversation() *ConversationIdentifier { if x != nil { return x.Conversation } return nil } -func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentMessages() []*SyncMessage_DeleteForMe_AddressableMessage { +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentMessages() []*AddressableMessage { if x != nil { return x.MostRecentMessages } return nil } -func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentNonExpiringMessages() []*SyncMessage_DeleteForMe_AddressableMessage { - if x != nil { - return x.MostRecentNonExpiringMessages - } - return nil -} - func (x *SyncMessage_DeleteForMe_ConversationDelete) GetIsFullDelete() bool { if x != nil && x.IsFullDelete != nil { return *x.IsFullDelete @@ -7441,16 +7465,23 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) GetIsFullDelete() bool { return false } +func (x *SyncMessage_DeleteForMe_ConversationDelete) GetMostRecentNonExpiringMessages() []*AddressableMessage { + if x != nil { + return x.MostRecentNonExpiringMessages + } + return nil +} + type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { - state protoimpl.MessageState `protogen:"open.v1"` - Conversation *SyncMessage_DeleteForMe_ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Conversation *ConversationIdentifier `protobuf:"bytes,1,opt,name=conversation" json:"conversation,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7462,7 +7493,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7475,38 +7506,42 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() pro // Deprecated: Use SyncMessage_DeleteForMe_LocalOnlyConversationDelete.ProtoReflect.Descriptor instead. func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{12, 17, 5} + return file_SignalService_proto_rawDescGZIP(), []int{11, 18, 3} } -func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) GetConversation() *SyncMessage_DeleteForMe_ConversationIdentifier { +func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) GetConversation() *ConversationIdentifier { if x != nil { return x.Conversation } return nil } -type GroupContext_Member struct { - state protoimpl.MessageState `protogen:"open.v1"` - E164 *string `protobuf:"bytes,2,opt,name=e164" json:"e164,omitempty"` +type SyncMessage_AttachmentBackfillResponse_AttachmentData struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Data: + // + // *SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment + // *SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_ + Data isSyncMessage_AttachmentBackfillResponse_AttachmentData_Data `protobuf_oneof:"data"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupContext_Member) Reset() { - *x = GroupContext_Member{} - mi := &file_SignalService_proto_msgTypes[77] +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) Reset() { + *x = SyncMessage_AttachmentBackfillResponse_AttachmentData{} + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupContext_Member) String() string { +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupContext_Member) ProtoMessage() {} +func (*SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoMessage() {} -func (x *GroupContext_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[77] +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7517,16 +7552,104 @@ func (x *GroupContext_Member) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GroupContext_Member.ProtoReflect.Descriptor instead. -func (*GroupContext_Member) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{14, 0} +// Deprecated: Use SyncMessage_AttachmentBackfillResponse_AttachmentData.ProtoReflect.Descriptor instead. +func (*SyncMessage_AttachmentBackfillResponse_AttachmentData) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 21, 0} } -func (x *GroupContext_Member) GetE164() string { - if x != nil && x.E164 != nil { - return *x.E164 +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) GetData() isSyncMessage_AttachmentBackfillResponse_AttachmentData_Data { + if x != nil { + return x.Data } - return "" + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) GetAttachment() *AttachmentPointer { + if x != nil { + if x, ok := x.Data.(*SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment); ok { + return x.Attachment + } + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) GetStatus() SyncMessage_AttachmentBackfillResponse_AttachmentData_Status { + if x != nil { + if x, ok := x.Data.(*SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_); ok { + return x.Status + } + } + return SyncMessage_AttachmentBackfillResponse_AttachmentData_PENDING +} + +type isSyncMessage_AttachmentBackfillResponse_AttachmentData_Data interface { + isSyncMessage_AttachmentBackfillResponse_AttachmentData_Data() +} + +type SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment struct { + Attachment *AttachmentPointer `protobuf:"bytes,1,opt,name=attachment,oneof"` +} + +type SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_ struct { + Status SyncMessage_AttachmentBackfillResponse_AttachmentData_Status `protobuf:"varint,2,opt,name=status,enum=signalservice.SyncMessage_AttachmentBackfillResponse_AttachmentData_Status,oneof"` +} + +func (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment) isSyncMessage_AttachmentBackfillResponse_AttachmentData_Data() { +} + +func (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_) isSyncMessage_AttachmentBackfillResponse_AttachmentData_Data() { +} + +type SyncMessage_AttachmentBackfillResponse_AttachmentDataList struct { + state protoimpl.MessageState `protogen:"open.v1"` + Attachments []*SyncMessage_AttachmentBackfillResponse_AttachmentData `protobuf:"bytes,1,rep,name=attachments" json:"attachments,omitempty"` + LongText *SyncMessage_AttachmentBackfillResponse_AttachmentData `protobuf:"bytes,2,opt,name=longText" json:"longText,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) Reset() { + *x = SyncMessage_AttachmentBackfillResponse_AttachmentDataList{} + mi := &file_SignalService_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoMessage() {} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[79] + 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 SyncMessage_AttachmentBackfillResponse_AttachmentDataList.ProtoReflect.Descriptor instead. +func (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{11, 21, 1} +} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) GetAttachments() []*SyncMessage_AttachmentBackfillResponse_AttachmentData { + if x != nil { + return x.Attachments + } + return nil +} + +func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) GetLongText() *SyncMessage_AttachmentBackfillResponse_AttachmentData { + if x != nil { + return x.LongText + } + return nil } type ContactDetails_Avatar struct { @@ -7539,7 +7662,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7551,7 +7674,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7564,7 +7687,7 @@ func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { // Deprecated: Use ContactDetails_Avatar.ProtoReflect.Descriptor instead. func (*ContactDetails_Avatar) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{16, 0} + return file_SignalService_proto_rawDescGZIP(), []int{14, 0} } func (x *ContactDetails_Avatar) GetContentType() string { @@ -7581,124 +7704,28 @@ func (x *ContactDetails_Avatar) GetLength() uint32 { return 0 } -type GroupDetails_Avatar struct { +type PaymentAddress_MobileCoin struct { state protoimpl.MessageState `protogen:"open.v1"` - ContentType *string `protobuf:"bytes,1,opt,name=contentType" json:"contentType,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupDetails_Avatar) Reset() { - *x = GroupDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[79] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupDetails_Avatar) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupDetails_Avatar) ProtoMessage() {} - -func (x *GroupDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[79] - 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 GroupDetails_Avatar.ProtoReflect.Descriptor instead. -func (*GroupDetails_Avatar) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{17, 0} -} - -func (x *GroupDetails_Avatar) GetContentType() string { - if x != nil && x.ContentType != nil { - return *x.ContentType - } - return "" -} - -func (x *GroupDetails_Avatar) GetLength() uint32 { - if x != nil && x.Length != nil { - return *x.Length - } - return 0 -} - -type GroupDetails_Member struct { - state protoimpl.MessageState `protogen:"open.v1"` - E164 *string `protobuf:"bytes,2,opt,name=e164" json:"e164,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupDetails_Member) Reset() { - *x = GroupDetails_Member{} - mi := &file_SignalService_proto_msgTypes[80] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupDetails_Member) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupDetails_Member) ProtoMessage() {} - -func (x *GroupDetails_Member) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[80] - 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 GroupDetails_Member.ProtoReflect.Descriptor instead. -func (*GroupDetails_Member) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{17, 1} -} - -func (x *GroupDetails_Member) GetE164() string { - if x != nil && x.E164 != nil { - return *x.E164 - } - return "" -} - -type PaymentAddress_MobileCoinAddress struct { - state protoimpl.MessageState `protogen:"open.v1"` - Address []byte `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + PublicAddress []byte `protobuf:"bytes,1,opt,name=publicAddress" json:"publicAddress,omitempty"` Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PaymentAddress_MobileCoinAddress) Reset() { - *x = PaymentAddress_MobileCoinAddress{} +func (x *PaymentAddress_MobileCoin) Reset() { + *x = PaymentAddress_MobileCoin{} mi := &file_SignalService_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PaymentAddress_MobileCoinAddress) String() string { +func (x *PaymentAddress_MobileCoin) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PaymentAddress_MobileCoinAddress) ProtoMessage() {} +func (*PaymentAddress_MobileCoin) ProtoMessage() {} -func (x *PaymentAddress_MobileCoinAddress) ProtoReflect() protoreflect.Message { +func (x *PaymentAddress_MobileCoin) ProtoReflect() protoreflect.Message { mi := &file_SignalService_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -7710,19 +7737,19 @@ func (x *PaymentAddress_MobileCoinAddress) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PaymentAddress_MobileCoinAddress.ProtoReflect.Descriptor instead. -func (*PaymentAddress_MobileCoinAddress) Descriptor() ([]byte, []int) { - return file_SignalService_proto_rawDescGZIP(), []int{18, 0} +// Deprecated: Use PaymentAddress_MobileCoin.ProtoReflect.Descriptor instead. +func (*PaymentAddress_MobileCoin) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{15, 0} } -func (x *PaymentAddress_MobileCoinAddress) GetAddress() []byte { +func (x *PaymentAddress_MobileCoin) GetPublicAddress() []byte { if x != nil { - return x.Address + return x.PublicAddress } return nil } -func (x *PaymentAddress_MobileCoinAddress) GetSignature() []byte { +func (x *PaymentAddress_MobileCoin) GetSignature() []byte { if x != nil { return x.Signature } @@ -7746,245 +7773,252 @@ func file_SignalService_proto_rawDescGZIP() []byte { return file_SignalService_proto_rawDescData } -var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 27) +var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 28) var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 82) var file_SignalService_proto_goTypes = []any{ - (Envelope_Type)(0), // 0: signalservice.Envelope.Type - (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type - (CallMessage_Hangup_Type)(0), // 2: signalservice.CallMessage.Hangup.Type - (CallMessage_Opaque_Urgency)(0), // 3: signalservice.CallMessage.Opaque.Urgency - (BodyRange_Style)(0), // 4: signalservice.BodyRange.Style - (DataMessage_Flags)(0), // 5: signalservice.DataMessage.Flags - (DataMessage_ProtocolVersion)(0), // 6: signalservice.DataMessage.ProtocolVersion - (DataMessage_Quote_Type)(0), // 7: signalservice.DataMessage.Quote.Type - (DataMessage_Contact_Phone_Type)(0), // 8: signalservice.DataMessage.Contact.Phone.Type - (DataMessage_Contact_Email_Type)(0), // 9: signalservice.DataMessage.Contact.Email.Type - (DataMessage_Contact_PostalAddress_Type)(0), // 10: signalservice.DataMessage.Contact.PostalAddress.Type - (DataMessage_Payment_Activation_Type)(0), // 11: signalservice.DataMessage.Payment.Activation.Type - (ReceiptMessage_Type)(0), // 12: signalservice.ReceiptMessage.Type - (TypingMessage_Action)(0), // 13: signalservice.TypingMessage.Action - (TextAttachment_Style)(0), // 14: signalservice.TextAttachment.Style - (Verified_State)(0), // 15: signalservice.Verified.State - (SyncMessage_Request_Type)(0), // 16: signalservice.SyncMessage.Request.Type - (SyncMessage_StickerPackOperation_Type)(0), // 17: signalservice.SyncMessage.StickerPackOperation.Type - (SyncMessage_FetchLatest_Type)(0), // 18: signalservice.SyncMessage.FetchLatest.Type - (SyncMessage_MessageRequestResponse_Type)(0), // 19: signalservice.SyncMessage.MessageRequestResponse.Type - (SyncMessage_CallEvent_Type)(0), // 20: signalservice.SyncMessage.CallEvent.Type - (SyncMessage_CallEvent_Direction)(0), // 21: signalservice.SyncMessage.CallEvent.Direction - (SyncMessage_CallEvent_Event)(0), // 22: signalservice.SyncMessage.CallEvent.Event - (SyncMessage_CallLinkUpdate_Type)(0), // 23: signalservice.SyncMessage.CallLinkUpdate.Type - (SyncMessage_CallLogEvent_Type)(0), // 24: signalservice.SyncMessage.CallLogEvent.Type - (AttachmentPointer_Flags)(0), // 25: signalservice.AttachmentPointer.Flags - (GroupContext_Type)(0), // 26: signalservice.GroupContext.Type - (*Envelope)(nil), // 27: signalservice.Envelope - (*Content)(nil), // 28: signalservice.Content - (*CallMessage)(nil), // 29: signalservice.CallMessage - (*BodyRange)(nil), // 30: signalservice.BodyRange - (*DataMessage)(nil), // 31: signalservice.DataMessage - (*NullMessage)(nil), // 32: signalservice.NullMessage - (*ReceiptMessage)(nil), // 33: signalservice.ReceiptMessage - (*TypingMessage)(nil), // 34: signalservice.TypingMessage - (*StoryMessage)(nil), // 35: signalservice.StoryMessage - (*Preview)(nil), // 36: signalservice.Preview - (*TextAttachment)(nil), // 37: signalservice.TextAttachment - (*Verified)(nil), // 38: signalservice.Verified - (*SyncMessage)(nil), // 39: signalservice.SyncMessage - (*AttachmentPointer)(nil), // 40: signalservice.AttachmentPointer - (*GroupContext)(nil), // 41: signalservice.GroupContext - (*GroupContextV2)(nil), // 42: signalservice.GroupContextV2 - (*ContactDetails)(nil), // 43: signalservice.ContactDetails - (*GroupDetails)(nil), // 44: signalservice.GroupDetails - (*PaymentAddress)(nil), // 45: signalservice.PaymentAddress - (*DecryptionErrorMessage)(nil), // 46: signalservice.DecryptionErrorMessage - (*PniSignatureMessage)(nil), // 47: signalservice.PniSignatureMessage - (*EditMessage)(nil), // 48: signalservice.EditMessage - (*CallMessage_Offer)(nil), // 49: signalservice.CallMessage.Offer - (*CallMessage_Answer)(nil), // 50: signalservice.CallMessage.Answer - (*CallMessage_IceUpdate)(nil), // 51: signalservice.CallMessage.IceUpdate - (*CallMessage_Busy)(nil), // 52: signalservice.CallMessage.Busy - (*CallMessage_Hangup)(nil), // 53: signalservice.CallMessage.Hangup - (*CallMessage_Opaque)(nil), // 54: signalservice.CallMessage.Opaque - (*DataMessage_Quote)(nil), // 55: signalservice.DataMessage.Quote - (*DataMessage_Contact)(nil), // 56: signalservice.DataMessage.Contact - (*DataMessage_Sticker)(nil), // 57: signalservice.DataMessage.Sticker - (*DataMessage_Reaction)(nil), // 58: signalservice.DataMessage.Reaction - (*DataMessage_Delete)(nil), // 59: signalservice.DataMessage.Delete - (*DataMessage_GroupCallUpdate)(nil), // 60: signalservice.DataMessage.GroupCallUpdate - (*DataMessage_StoryContext)(nil), // 61: signalservice.DataMessage.StoryContext - (*DataMessage_Payment)(nil), // 62: signalservice.DataMessage.Payment - (*DataMessage_GiftBadge)(nil), // 63: signalservice.DataMessage.GiftBadge - (*DataMessage_Quote_QuotedAttachment)(nil), // 64: signalservice.DataMessage.Quote.QuotedAttachment - (*DataMessage_Contact_Name)(nil), // 65: signalservice.DataMessage.Contact.Name - (*DataMessage_Contact_Phone)(nil), // 66: signalservice.DataMessage.Contact.Phone - (*DataMessage_Contact_Email)(nil), // 67: signalservice.DataMessage.Contact.Email - (*DataMessage_Contact_PostalAddress)(nil), // 68: signalservice.DataMessage.Contact.PostalAddress - (*DataMessage_Contact_Avatar)(nil), // 69: signalservice.DataMessage.Contact.Avatar - (*DataMessage_Payment_Amount)(nil), // 70: signalservice.DataMessage.Payment.Amount - (*DataMessage_Payment_Notification)(nil), // 71: signalservice.DataMessage.Payment.Notification - (*DataMessage_Payment_Activation)(nil), // 72: signalservice.DataMessage.Payment.Activation - (*DataMessage_Payment_Amount_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Amount.MobileCoin - (*DataMessage_Payment_Notification_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Notification.MobileCoin - (*TextAttachment_Gradient)(nil), // 75: signalservice.TextAttachment.Gradient - (*SyncMessage_Sent)(nil), // 76: signalservice.SyncMessage.Sent - (*SyncMessage_Contacts)(nil), // 77: signalservice.SyncMessage.Contacts - (*SyncMessage_Blocked)(nil), // 78: signalservice.SyncMessage.Blocked - (*SyncMessage_Request)(nil), // 79: signalservice.SyncMessage.Request - (*SyncMessage_Read)(nil), // 80: signalservice.SyncMessage.Read - (*SyncMessage_Viewed)(nil), // 81: signalservice.SyncMessage.Viewed - (*SyncMessage_Configuration)(nil), // 82: signalservice.SyncMessage.Configuration - (*SyncMessage_StickerPackOperation)(nil), // 83: signalservice.SyncMessage.StickerPackOperation - (*SyncMessage_ViewOnceOpen)(nil), // 84: signalservice.SyncMessage.ViewOnceOpen - (*SyncMessage_FetchLatest)(nil), // 85: signalservice.SyncMessage.FetchLatest - (*SyncMessage_Keys)(nil), // 86: signalservice.SyncMessage.Keys - (*SyncMessage_MessageRequestResponse)(nil), // 87: signalservice.SyncMessage.MessageRequestResponse - (*SyncMessage_OutgoingPayment)(nil), // 88: signalservice.SyncMessage.OutgoingPayment - (*SyncMessage_PniChangeNumber)(nil), // 89: signalservice.SyncMessage.PniChangeNumber - (*SyncMessage_CallEvent)(nil), // 90: signalservice.SyncMessage.CallEvent - (*SyncMessage_CallLinkUpdate)(nil), // 91: signalservice.SyncMessage.CallLinkUpdate - (*SyncMessage_CallLogEvent)(nil), // 92: signalservice.SyncMessage.CallLogEvent - (*SyncMessage_DeleteForMe)(nil), // 93: signalservice.SyncMessage.DeleteForMe - (*SyncMessage_DeviceNameChange)(nil), // 94: signalservice.SyncMessage.DeviceNameChange - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 95: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 96: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 97: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*SyncMessage_DeleteForMe_ConversationIdentifier)(nil), // 98: signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - (*SyncMessage_DeleteForMe_AddressableMessage)(nil), // 99: signalservice.SyncMessage.DeleteForMe.AddressableMessage - (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 100: signalservice.SyncMessage.DeleteForMe.MessageDeletes - (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 101: signalservice.SyncMessage.DeleteForMe.AttachmentDelete - (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 102: signalservice.SyncMessage.DeleteForMe.ConversationDelete - (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 103: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - (*GroupContext_Member)(nil), // 104: signalservice.GroupContext.Member - (*ContactDetails_Avatar)(nil), // 105: signalservice.ContactDetails.Avatar - (*GroupDetails_Avatar)(nil), // 106: signalservice.GroupDetails.Avatar - (*GroupDetails_Member)(nil), // 107: signalservice.GroupDetails.Member - (*PaymentAddress_MobileCoinAddress)(nil), // 108: signalservice.PaymentAddress.MobileCoinAddress + (Envelope_Type)(0), // 0: signalservice.Envelope.Type + (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type + (CallMessage_Hangup_Type)(0), // 2: signalservice.CallMessage.Hangup.Type + (CallMessage_Opaque_Urgency)(0), // 3: signalservice.CallMessage.Opaque.Urgency + (DataMessage_Flags)(0), // 4: signalservice.DataMessage.Flags + (DataMessage_ProtocolVersion)(0), // 5: signalservice.DataMessage.ProtocolVersion + (DataMessage_Payment_Activation_Type)(0), // 6: signalservice.DataMessage.Payment.Activation.Type + (DataMessage_Quote_Type)(0), // 7: signalservice.DataMessage.Quote.Type + (DataMessage_Contact_Phone_Type)(0), // 8: signalservice.DataMessage.Contact.Phone.Type + (DataMessage_Contact_Email_Type)(0), // 9: signalservice.DataMessage.Contact.Email.Type + (DataMessage_Contact_PostalAddress_Type)(0), // 10: signalservice.DataMessage.Contact.PostalAddress.Type + (ReceiptMessage_Type)(0), // 11: signalservice.ReceiptMessage.Type + (TypingMessage_Action)(0), // 12: signalservice.TypingMessage.Action + (TextAttachment_Style)(0), // 13: signalservice.TextAttachment.Style + (Verified_State)(0), // 14: signalservice.Verified.State + (SyncMessage_Request_Type)(0), // 15: signalservice.SyncMessage.Request.Type + (SyncMessage_StickerPackOperation_Type)(0), // 16: signalservice.SyncMessage.StickerPackOperation.Type + (SyncMessage_FetchLatest_Type)(0), // 17: signalservice.SyncMessage.FetchLatest.Type + (SyncMessage_MessageRequestResponse_Type)(0), // 18: signalservice.SyncMessage.MessageRequestResponse.Type + (SyncMessage_CallEvent_Type)(0), // 19: signalservice.SyncMessage.CallEvent.Type + (SyncMessage_CallEvent_Direction)(0), // 20: signalservice.SyncMessage.CallEvent.Direction + (SyncMessage_CallEvent_Event)(0), // 21: signalservice.SyncMessage.CallEvent.Event + (SyncMessage_CallLinkUpdate_Type)(0), // 22: signalservice.SyncMessage.CallLinkUpdate.Type + (SyncMessage_CallLogEvent_Type)(0), // 23: signalservice.SyncMessage.CallLogEvent.Type + (SyncMessage_AttachmentBackfillResponse_Error)(0), // 24: signalservice.SyncMessage.AttachmentBackfillResponse.Error + (SyncMessage_AttachmentBackfillResponse_AttachmentData_Status)(0), // 25: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status + (AttachmentPointer_Flags)(0), // 26: signalservice.AttachmentPointer.Flags + (BodyRange_Style)(0), // 27: signalservice.BodyRange.Style + (*Envelope)(nil), // 28: signalservice.Envelope + (*Content)(nil), // 29: signalservice.Content + (*CallMessage)(nil), // 30: signalservice.CallMessage + (*DataMessage)(nil), // 31: signalservice.DataMessage + (*NullMessage)(nil), // 32: signalservice.NullMessage + (*ReceiptMessage)(nil), // 33: signalservice.ReceiptMessage + (*TypingMessage)(nil), // 34: signalservice.TypingMessage + (*StoryMessage)(nil), // 35: signalservice.StoryMessage + (*Preview)(nil), // 36: signalservice.Preview + (*TextAttachment)(nil), // 37: signalservice.TextAttachment + (*Verified)(nil), // 38: signalservice.Verified + (*SyncMessage)(nil), // 39: signalservice.SyncMessage + (*AttachmentPointer)(nil), // 40: signalservice.AttachmentPointer + (*GroupContextV2)(nil), // 41: signalservice.GroupContextV2 + (*ContactDetails)(nil), // 42: signalservice.ContactDetails + (*PaymentAddress)(nil), // 43: signalservice.PaymentAddress + (*DecryptionErrorMessage)(nil), // 44: signalservice.DecryptionErrorMessage + (*PniSignatureMessage)(nil), // 45: signalservice.PniSignatureMessage + (*EditMessage)(nil), // 46: signalservice.EditMessage + (*BodyRange)(nil), // 47: signalservice.BodyRange + (*AddressableMessage)(nil), // 48: signalservice.AddressableMessage + (*ConversationIdentifier)(nil), // 49: signalservice.ConversationIdentifier + (*CallMessage_Offer)(nil), // 50: signalservice.CallMessage.Offer + (*CallMessage_Answer)(nil), // 51: signalservice.CallMessage.Answer + (*CallMessage_IceUpdate)(nil), // 52: signalservice.CallMessage.IceUpdate + (*CallMessage_Busy)(nil), // 53: signalservice.CallMessage.Busy + (*CallMessage_Hangup)(nil), // 54: signalservice.CallMessage.Hangup + (*CallMessage_Opaque)(nil), // 55: signalservice.CallMessage.Opaque + (*DataMessage_Payment)(nil), // 56: signalservice.DataMessage.Payment + (*DataMessage_Quote)(nil), // 57: signalservice.DataMessage.Quote + (*DataMessage_Contact)(nil), // 58: signalservice.DataMessage.Contact + (*DataMessage_Sticker)(nil), // 59: signalservice.DataMessage.Sticker + (*DataMessage_Reaction)(nil), // 60: signalservice.DataMessage.Reaction + (*DataMessage_Delete)(nil), // 61: signalservice.DataMessage.Delete + (*DataMessage_GroupCallUpdate)(nil), // 62: signalservice.DataMessage.GroupCallUpdate + (*DataMessage_StoryContext)(nil), // 63: signalservice.DataMessage.StoryContext + (*DataMessage_GiftBadge)(nil), // 64: signalservice.DataMessage.GiftBadge + (*DataMessage_Payment_Amount)(nil), // 65: signalservice.DataMessage.Payment.Amount + (*DataMessage_Payment_Notification)(nil), // 66: signalservice.DataMessage.Payment.Notification + (*DataMessage_Payment_Activation)(nil), // 67: signalservice.DataMessage.Payment.Activation + (*DataMessage_Payment_Amount_MobileCoin)(nil), // 68: signalservice.DataMessage.Payment.Amount.MobileCoin + (*DataMessage_Payment_Notification_MobileCoin)(nil), // 69: signalservice.DataMessage.Payment.Notification.MobileCoin + (*DataMessage_Quote_QuotedAttachment)(nil), // 70: signalservice.DataMessage.Quote.QuotedAttachment + (*DataMessage_Contact_Name)(nil), // 71: signalservice.DataMessage.Contact.Name + (*DataMessage_Contact_Phone)(nil), // 72: signalservice.DataMessage.Contact.Phone + (*DataMessage_Contact_Email)(nil), // 73: signalservice.DataMessage.Contact.Email + (*DataMessage_Contact_PostalAddress)(nil), // 74: signalservice.DataMessage.Contact.PostalAddress + (*DataMessage_Contact_Avatar)(nil), // 75: signalservice.DataMessage.Contact.Avatar + (*TextAttachment_Gradient)(nil), // 76: signalservice.TextAttachment.Gradient + (*SyncMessage_Sent)(nil), // 77: signalservice.SyncMessage.Sent + (*SyncMessage_Contacts)(nil), // 78: signalservice.SyncMessage.Contacts + (*SyncMessage_Blocked)(nil), // 79: signalservice.SyncMessage.Blocked + (*SyncMessage_Request)(nil), // 80: signalservice.SyncMessage.Request + (*SyncMessage_Read)(nil), // 81: signalservice.SyncMessage.Read + (*SyncMessage_Viewed)(nil), // 82: signalservice.SyncMessage.Viewed + (*SyncMessage_Configuration)(nil), // 83: signalservice.SyncMessage.Configuration + (*SyncMessage_StickerPackOperation)(nil), // 84: signalservice.SyncMessage.StickerPackOperation + (*SyncMessage_ViewOnceOpen)(nil), // 85: signalservice.SyncMessage.ViewOnceOpen + (*SyncMessage_FetchLatest)(nil), // 86: signalservice.SyncMessage.FetchLatest + (*SyncMessage_Keys)(nil), // 87: signalservice.SyncMessage.Keys + (*SyncMessage_PniIdentity)(nil), // 88: signalservice.SyncMessage.PniIdentity + (*SyncMessage_MessageRequestResponse)(nil), // 89: signalservice.SyncMessage.MessageRequestResponse + (*SyncMessage_OutgoingPayment)(nil), // 90: signalservice.SyncMessage.OutgoingPayment + (*SyncMessage_PniChangeNumber)(nil), // 91: signalservice.SyncMessage.PniChangeNumber + (*SyncMessage_CallEvent)(nil), // 92: signalservice.SyncMessage.CallEvent + (*SyncMessage_CallLinkUpdate)(nil), // 93: signalservice.SyncMessage.CallLinkUpdate + (*SyncMessage_CallLogEvent)(nil), // 94: signalservice.SyncMessage.CallLogEvent + (*SyncMessage_DeleteForMe)(nil), // 95: signalservice.SyncMessage.DeleteForMe + (*SyncMessage_DeviceNameChange)(nil), // 96: signalservice.SyncMessage.DeviceNameChange + (*SyncMessage_AttachmentBackfillRequest)(nil), // 97: signalservice.SyncMessage.AttachmentBackfillRequest + (*SyncMessage_AttachmentBackfillResponse)(nil), // 98: signalservice.SyncMessage.AttachmentBackfillResponse + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 99: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 100: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 101: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 102: signalservice.SyncMessage.DeleteForMe.MessageDeletes + (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 103: signalservice.SyncMessage.DeleteForMe.AttachmentDelete + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 104: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 105: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 106: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 107: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + (*ContactDetails_Avatar)(nil), // 108: signalservice.ContactDetails.Avatar + (*PaymentAddress_MobileCoin)(nil), // 109: signalservice.PaymentAddress.MobileCoin } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type 31, // 1: signalservice.Content.dataMessage:type_name -> signalservice.DataMessage 39, // 2: signalservice.Content.syncMessage:type_name -> signalservice.SyncMessage - 29, // 3: signalservice.Content.callMessage:type_name -> signalservice.CallMessage + 30, // 3: signalservice.Content.callMessage:type_name -> signalservice.CallMessage 32, // 4: signalservice.Content.nullMessage:type_name -> signalservice.NullMessage 33, // 5: signalservice.Content.receiptMessage:type_name -> signalservice.ReceiptMessage 34, // 6: signalservice.Content.typingMessage:type_name -> signalservice.TypingMessage 35, // 7: signalservice.Content.storyMessage:type_name -> signalservice.StoryMessage - 47, // 8: signalservice.Content.pniSignatureMessage:type_name -> signalservice.PniSignatureMessage - 48, // 9: signalservice.Content.editMessage:type_name -> signalservice.EditMessage - 49, // 10: signalservice.CallMessage.offer:type_name -> signalservice.CallMessage.Offer - 50, // 11: signalservice.CallMessage.answer:type_name -> signalservice.CallMessage.Answer - 51, // 12: signalservice.CallMessage.iceUpdate:type_name -> signalservice.CallMessage.IceUpdate - 52, // 13: signalservice.CallMessage.busy:type_name -> signalservice.CallMessage.Busy - 53, // 14: signalservice.CallMessage.hangup:type_name -> signalservice.CallMessage.Hangup - 54, // 15: signalservice.CallMessage.opaque:type_name -> signalservice.CallMessage.Opaque - 4, // 16: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style - 40, // 17: signalservice.DataMessage.attachments:type_name -> signalservice.AttachmentPointer - 42, // 18: signalservice.DataMessage.groupV2:type_name -> signalservice.GroupContextV2 - 55, // 19: signalservice.DataMessage.quote:type_name -> signalservice.DataMessage.Quote - 56, // 20: signalservice.DataMessage.contact:type_name -> signalservice.DataMessage.Contact - 36, // 21: signalservice.DataMessage.preview:type_name -> signalservice.Preview - 57, // 22: signalservice.DataMessage.sticker:type_name -> signalservice.DataMessage.Sticker - 58, // 23: signalservice.DataMessage.reaction:type_name -> signalservice.DataMessage.Reaction - 59, // 24: signalservice.DataMessage.delete:type_name -> signalservice.DataMessage.Delete - 30, // 25: signalservice.DataMessage.bodyRanges:type_name -> signalservice.BodyRange - 60, // 26: signalservice.DataMessage.groupCallUpdate:type_name -> signalservice.DataMessage.GroupCallUpdate - 62, // 27: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment - 61, // 28: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext - 63, // 29: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge - 12, // 30: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type - 13, // 31: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action - 42, // 32: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 - 40, // 33: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer - 37, // 34: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment - 30, // 35: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange - 40, // 36: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer - 14, // 37: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style - 36, // 38: signalservice.TextAttachment.preview:type_name -> signalservice.Preview - 75, // 39: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient - 15, // 40: signalservice.Verified.state:type_name -> signalservice.Verified.State - 76, // 41: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent - 77, // 42: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts - 79, // 43: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request - 80, // 44: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read - 78, // 45: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked - 38, // 46: signalservice.SyncMessage.verified:type_name -> signalservice.Verified - 82, // 47: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration - 83, // 48: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation - 84, // 49: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen - 85, // 50: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest - 86, // 51: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys - 87, // 52: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse - 88, // 53: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment - 81, // 54: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed - 89, // 55: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber - 90, // 56: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent - 91, // 57: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate - 92, // 58: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 93, // 59: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe - 94, // 60: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange - 26, // 61: signalservice.GroupContext.type:type_name -> signalservice.GroupContext.Type - 104, // 62: signalservice.GroupContext.members:type_name -> signalservice.GroupContext.Member - 40, // 63: signalservice.GroupContext.avatar:type_name -> signalservice.AttachmentPointer - 105, // 64: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 38, // 65: signalservice.ContactDetails.verified:type_name -> signalservice.Verified - 107, // 66: signalservice.GroupDetails.members:type_name -> signalservice.GroupDetails.Member - 106, // 67: signalservice.GroupDetails.avatar:type_name -> signalservice.GroupDetails.Avatar - 108, // 68: signalservice.PaymentAddress.mobileCoinAddress:type_name -> signalservice.PaymentAddress.MobileCoinAddress - 31, // 69: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 1, // 70: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 71: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 72: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 64, // 73: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 30, // 74: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 75: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 65, // 76: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 66, // 77: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 67, // 78: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 68, // 79: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 69, // 80: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 40, // 81: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 71, // 82: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 72, // 83: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 40, // 84: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 85: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 86: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 87: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 40, // 88: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 73, // 89: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 74, // 90: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 11, // 91: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 31, // 92: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 95, // 93: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 35, // 94: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 96, // 95: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 48, // 96: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 40, // 97: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 16, // 98: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 17, // 99: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 18, // 100: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 19, // 101: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 97, // 102: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 20, // 103: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 21, // 104: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 22, // 105: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 23, // 106: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type - 24, // 107: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 100, // 108: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes - 102, // 109: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete - 103, // 110: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - 101, // 111: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete - 98, // 112: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 99, // 113: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 98, // 114: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 99, // 115: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 98, // 116: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 99, // 117: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 99, // 118: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.SyncMessage.DeleteForMe.AddressableMessage - 98, // 119: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationIdentifier - 120, // [120:120] is the sub-list for method output_type - 120, // [120:120] is the sub-list for method input_type - 120, // [120:120] is the sub-list for extension type_name - 120, // [120:120] is the sub-list for extension extendee - 0, // [0:120] is the sub-list for field type_name + 45, // 8: signalservice.Content.pniSignatureMessage:type_name -> signalservice.PniSignatureMessage + 46, // 9: signalservice.Content.editMessage:type_name -> signalservice.EditMessage + 50, // 10: signalservice.CallMessage.offer:type_name -> signalservice.CallMessage.Offer + 51, // 11: signalservice.CallMessage.answer:type_name -> signalservice.CallMessage.Answer + 52, // 12: signalservice.CallMessage.iceUpdate:type_name -> signalservice.CallMessage.IceUpdate + 53, // 13: signalservice.CallMessage.busy:type_name -> signalservice.CallMessage.Busy + 54, // 14: signalservice.CallMessage.hangup:type_name -> signalservice.CallMessage.Hangup + 55, // 15: signalservice.CallMessage.opaque:type_name -> signalservice.CallMessage.Opaque + 40, // 16: signalservice.DataMessage.attachments:type_name -> signalservice.AttachmentPointer + 41, // 17: signalservice.DataMessage.groupV2:type_name -> signalservice.GroupContextV2 + 57, // 18: signalservice.DataMessage.quote:type_name -> signalservice.DataMessage.Quote + 58, // 19: signalservice.DataMessage.contact:type_name -> signalservice.DataMessage.Contact + 36, // 20: signalservice.DataMessage.preview:type_name -> signalservice.Preview + 59, // 21: signalservice.DataMessage.sticker:type_name -> signalservice.DataMessage.Sticker + 60, // 22: signalservice.DataMessage.reaction:type_name -> signalservice.DataMessage.Reaction + 61, // 23: signalservice.DataMessage.delete:type_name -> signalservice.DataMessage.Delete + 47, // 24: signalservice.DataMessage.bodyRanges:type_name -> signalservice.BodyRange + 62, // 25: signalservice.DataMessage.groupCallUpdate:type_name -> signalservice.DataMessage.GroupCallUpdate + 56, // 26: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment + 63, // 27: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext + 64, // 28: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge + 11, // 29: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type + 12, // 30: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action + 41, // 31: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 + 40, // 32: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer + 37, // 33: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment + 47, // 34: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange + 40, // 35: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer + 13, // 36: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style + 36, // 37: signalservice.TextAttachment.preview:type_name -> signalservice.Preview + 76, // 38: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient + 14, // 39: signalservice.Verified.state:type_name -> signalservice.Verified.State + 77, // 40: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent + 78, // 41: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts + 80, // 42: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request + 81, // 43: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read + 79, // 44: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked + 38, // 45: signalservice.SyncMessage.verified:type_name -> signalservice.Verified + 83, // 46: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration + 84, // 47: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation + 85, // 48: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen + 86, // 49: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest + 87, // 50: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys + 89, // 51: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse + 90, // 52: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment + 82, // 53: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed + 91, // 54: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber + 92, // 55: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent + 93, // 56: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate + 94, // 57: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent + 95, // 58: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe + 96, // 59: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange + 97, // 60: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest + 98, // 61: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse + 108, // 62: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 109, // 63: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin + 31, // 64: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 27, // 65: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style + 1, // 66: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 67: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 68: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 66, // 69: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 67, // 70: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 70, // 71: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 47, // 72: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 73: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 71, // 74: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 72, // 75: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 73, // 76: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 74, // 77: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 75, // 78: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 79: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 68, // 80: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 69, // 81: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 6, // 82: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 40, // 83: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 84: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 85: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 86: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 40, // 87: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 31, // 88: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 99, // 89: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 90: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 100, // 91: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 46, // 92: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 93: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 15, // 94: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 16, // 95: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 17, // 96: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 18, // 97: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 101, // 98: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 19, // 99: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 20, // 100: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 21, // 101: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 22, // 102: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 23, // 103: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 102, // 104: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes + 104, // 105: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 105, // 106: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 103, // 107: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete + 48, // 108: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 109: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier + 48, // 110: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 111: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier + 107, // 112: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + 24, // 113: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error + 49, // 114: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 115: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage + 49, // 116: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 117: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 118: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 119: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage + 48, // 120: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage + 49, // 121: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 40, // 122: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer + 25, // 123: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status + 106, // 124: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 106, // 125: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 126, // [126:126] is the sub-list for method output_type + 126, // [126:126] is the sub-list for method input_type + 126, // [126:126] is the sub-list for extension type_name + 126, // [126:126] is the sub-list for extension extendee + 0, // [0:126] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -7992,53 +8026,61 @@ func file_SignalService_proto_init() { if File_SignalService_proto != nil { return } - file_SignalService_proto_msgTypes[3].OneofWrappers = []any{ - (*BodyRange_MentionAci)(nil), - (*BodyRange_Style_)(nil), - } - file_SignalService_proto_msgTypes[8].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[7].OneofWrappers = []any{ (*StoryMessage_FileAttachment)(nil), (*StoryMessage_TextAttachment)(nil), } - file_SignalService_proto_msgTypes[10].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[9].OneofWrappers = []any{ (*TextAttachment_Gradient_)(nil), (*TextAttachment_Color)(nil), } - file_SignalService_proto_msgTypes[13].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[12].OneofWrappers = []any{ (*AttachmentPointer_CdnId)(nil), (*AttachmentPointer_CdnKey)(nil), } - file_SignalService_proto_msgTypes[18].OneofWrappers = []any{ - (*PaymentAddress_MobileCoinAddress_)(nil), + file_SignalService_proto_msgTypes[15].OneofWrappers = []any{ + (*PaymentAddress_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[35].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[19].OneofWrappers = []any{ + (*BodyRange_MentionAci)(nil), + (*BodyRange_Style_)(nil), + } + file_SignalService_proto_msgTypes[20].OneofWrappers = []any{ + (*AddressableMessage_AuthorServiceId)(nil), + (*AddressableMessage_AuthorE164)(nil), + } + file_SignalService_proto_msgTypes[21].OneofWrappers = []any{ + (*ConversationIdentifier_ThreadServiceId)(nil), + (*ConversationIdentifier_ThreadGroupId)(nil), + (*ConversationIdentifier_ThreadE164)(nil), + } + file_SignalService_proto_msgTypes[28].OneofWrappers = []any{ (*DataMessage_Payment_Notification_)(nil), (*DataMessage_Payment_Activation_)(nil), } - file_SignalService_proto_msgTypes[43].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[37].OneofWrappers = []any{ (*DataMessage_Payment_Amount_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[44].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[38].OneofWrappers = []any{ (*DataMessage_Payment_Notification_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[61].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[62].OneofWrappers = []any{ (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[71].OneofWrappers = []any{ - (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadServiceId)(nil), - (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadGroupId)(nil), - (*SyncMessage_DeleteForMe_ConversationIdentifier_ThreadE164)(nil), + file_SignalService_proto_msgTypes[70].OneofWrappers = []any{ + (*SyncMessage_AttachmentBackfillResponse_Attachments)(nil), + (*SyncMessage_AttachmentBackfillResponse_Error_)(nil), } - file_SignalService_proto_msgTypes[72].OneofWrappers = []any{ - (*SyncMessage_DeleteForMe_AddressableMessage_AuthorServiceId)(nil), - (*SyncMessage_DeleteForMe_AddressableMessage_AuthorE164)(nil), + file_SignalService_proto_msgTypes[78].OneofWrappers = []any{ + (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment)(nil), + (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_SignalService_proto_rawDesc, - NumEnums: 27, + NumEnums: 28, NumMessages: 82, NumExtensions: 0, NumServices: 0, diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw index ef74a34b022885779472ea55468cec2136898678..befb7053450b2a5831204736297be0cfa084b7e8 100644 GIT binary patch delta 2426 zcmcIm+i%-c7~gU3CvE2*md!~^Te7z6x-Jskwd&S2O}sQs<77^{t{@b=#A{8R%WS8t z2s9yqCLy6Aoel(IzyoN21QYVpKms8RA@L7@GyzYH7c^-S5(05MwzE1Z9UBk494p`D z_g&8Kd|%#w1^oOfcxiyT;`(S;40QR#+LBln6+vd&`oNHvw*`0+^cH&{tk+6{CYG`l ziP=g_e0-AxZG$dVt17DuZF*Zj&@k* CF+3TjO#7qsfKSYbMeMH|1>Qsjs{Z-~Pm z;xE9!U?*(P@@$G-C``?9@mZF3pf0#0$MPpxz7S_;ljOTlz=#^0$gy0UL&Dqo0Y$d}90-mue4(bRC8VauM1O-H!|i%(DiU8WX1;1~T%C^+?T z<}#%ZZGFIpzX|2QBY31M-H!awb3DV(NBKDI)mOWo@KCp7`VZl6T?0sgK|#}m;!;_x zXj4LQ`HUpXym+=Qsv5(P8vUdD@v{S6C!=?>;_nWC>M*n!x>~DNRFMhx0sQA!@8Qj$ zEffA<+(W2go8CjS|KDf)Rd{dBhh`M0RUdsd-weXm>n=+ zH?JU>^_-DJ1xF6t0PkUV@WA%%&|MT{IaxAsoV@i*Pak{%1oP0vu8>N0-%ut2R*`1`|GK?z?ROZK2348&&HC|^i&1``Qy zbJ2V59I;~DcL+0B0#RtcBKt+29|YHpX50 z?s-RSRb0@7SxMEVxA4tCCeN%++opw*3MWW-DvG0)p5|A=X;i~y0G=}bTyFyYjlw_TXf)B=I!m^-%n~wP@P+7=0NDk_rFvyKCp{&a{~6kOUlA9kZsLX5evh%! zowO6L#RlS0|x*A delta 1910 zcma)6U2GIp6z0xMyUX35&R%MF7%Ev7yFjoFEl{DQlx26iUAEnp>8?s5X{NiEc4U9* z?CeTO47>;if0JWkc#sH*O(1EA86Sv7pDT&J7+*B{M2zu?2NR<&dgrI4lqh|f%=x+Z zobS8eIe%P7cRoTN^l+=fXM0iz-a_4@ow%)G){P}ejG?`L)ip>0hYh+|H%z@YU#Op_ zH7UZvL3M*S{xo#YdEc8Hx(A=^Zz+Sgt4tfLan020wQQNzOx;|{(Iu(Pf$$$u z)&mkb_7%i7`8H_JuRv$-*XUFDzIPm*h3>wbNEpuPe0DaQR`P{x;f(cK-xPmf8DW9l z-mp2dnbhX#3^iJMiAu=j>~Sxw_Fu4IfFSgqwS4d&BzEA?qPA3JeWt0Y=@t0u@K5L# zTpv6f4r5L)OB}mKP&wUtFnA5gMck&eSTZ3vT+HY4Q!nLblc_>>Di2qWw07A*?E^tI zsFkaFZCYzIn2(&qg1NLvB_2+{&;zNX2e`iwG>_gzS?C$c^75^)_0G_J1RWDMkPH`d zAMTg$BOIQjjRr%MrWI<^2GMY^RIjzD(Qw#x5C#TD;O3qLj0}fhWmLkXi2YUP7=(uV zA$elkpl8#DyvkuQX_{JT!3AtzyO~?JlUW=xHDjKdUP}(jz`#+b_K6d_MS_K9lhMUH z=!GWS8=337%43pR*Rcy^GZi_a!yCtUK-chI8v}fKypy|xVPteCCkYT4?sdG(gzt_& z$IF)yoE_a6eL6w;@FUSjL=yiKQt1rbNiX*w!BM?dGN?_AR+-dFsfA|k{EU8)I>Q%I zH->>KzjiVixUf4t*o*?mjUDm{aeKCSxH6VF@Q}m7j8ShcGAc}Z!6dG*TzxW$kwcz3 zY~_RpVsHcR$oCbPUQ|alc9EJ^W$Iz^t*Y}+VmMHx)j6gGrGM~{B*b_YTJIvqu+Pho z+Tm{C8Cb!=?!HOqkh&HkM{v8=(%9QdZE*S7#3j`;|$yvE0| zV7F;+7jGEEEd=BC;&eJ$P()-0(#k~kMMY(6$&ZE8#cY9XBR0yaa=NI@6lSyeu_;lA zS8&*&2tFS>$Nj)Vcjn!FY&n+dmAb*e*@az$9K?P$0s1+emYtmv7>L5RyP|M+cK~_= zF}R(1y_?9`uNkEUy~UCO?6hBfWJ7E`Lw%w@{u}Q-i#zy@C!S@Eb`Q7x1RH7R|BrT9 z2}BbPDzCy5ZK?{17 z8d5t$98%Z2$RjR&>$#M$Z>~}=oo6ihV?mpyH5>lUB%VfNdSX)|`GzgBX?MjY%VmS@ zCbmr?)%u)Xp{crF^PF%q9EC5&w=14KzD0d9NzUQO (version byte | SignalMessage{Content}) + reserved 2; + reserved "KEY_EXCHANGE"; + PREKEY_BUNDLE = 3; // content => (version byte | PreKeySignalMessage{Content}) + SERVER_DELIVERY_RECEIPT = 5; // legacyMessage => [] AND content => [] + UNIDENTIFIED_SENDER = 6; // legacyMessage => [] AND content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) + SENDERKEY_MESSAGE = 7; // legacyMessage => [] AND content => (version byte | SenderKeyMessage) + PLAINTEXT_CONTENT = 8; // legacyMessage => [] AND content => (marker byte | Content) } - optional Type type = 1; - reserved /*sourceE164*/ 2; - optional string sourceServiceId = 11; - optional uint32 sourceDevice = 7; + optional Type type = 1; + reserved 2; // formerly optional string sourceE164 = 2; + optional string sourceServiceId = 11; + optional uint32 sourceDevice = 7; optional string destinationServiceId = 13; - reserved /*relay*/ 3; - optional uint64 timestamp = 5; - reserved /*legacyMessage*/ 6; - optional bytes content = 8; // Contains an encrypted Content - optional string serverGuid = 9; - optional uint64 serverTimestamp = 10; - optional bool urgent = 14 [default = true]; - reserved /*updatedPni*/ 15; // Not used presently, may be used in the future - optional bool story = 16; - optional bytes reportingToken = 17; - reserved 18; // internal server use - // NEXT ID: 19 + reserved 3; // formerly optional string relay = 3; + optional uint64 timestamp = 5; + reserved 6; // formerly optional bytes legacyMessage = 6; // Contains an encrypted DataMessage; this field could have been set historically for type 1 or 3 messages; no longer in use + optional bytes content = 8; // Contains an encrypted Content + optional string serverGuid = 9; + optional uint64 serverTimestamp = 10; + optional bool ephemeral = 12; // indicates that the message should not be persisted if the recipient is offline + optional bool urgent = 14 [default = true]; // indicates that the content is considered timely by the sender; defaults to true so senders have to opt-out to say something isn't time critical + optional string updatedPni = 15; // for number-change synchronization messages, provides the new server-assigned phone number identifier associated with the changed number + optional bool story = 16; // indicates that the content is a story. + optional bytes report_spam_token = 17; // token sent when reporting spam + reserved 18; // internal server use + // next: 19 } message Content { - optional DataMessage dataMessage = 1; - optional SyncMessage syncMessage = 2; - optional CallMessage callMessage = 3; - optional NullMessage nullMessage = 4; - optional ReceiptMessage receiptMessage = 5; - optional TypingMessage typingMessage = 6; - optional bytes senderKeyDistributionMessage = 7; - optional bytes decryptionErrorMessage = 8; - optional StoryMessage storyMessage = 9; - optional PniSignatureMessage pniSignatureMessage = 10; - optional EditMessage editMessage = 11; + optional DataMessage dataMessage = 1; + optional SyncMessage syncMessage = 2; + optional CallMessage callMessage = 3; + optional NullMessage nullMessage = 4; + optional ReceiptMessage receiptMessage = 5; + optional TypingMessage typingMessage = 6; + optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7; + optional bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8; + optional StoryMessage storyMessage = 9; + optional PniSignatureMessage pniSignatureMessage = 10; + optional EditMessage editMessage = 11; } message CallMessage { message Offer { enum Type { - OFFER_AUDIO_CALL = 0; - OFFER_VIDEO_CALL = 1; - reserved /* OFFER_NEED_PERMISSION */ 2; // removed + OFFER_AUDIO_CALL = 0; + OFFER_VIDEO_CALL = 1; + reserved /* OFFER_NEED_PERMISSION */ 2; // removed } - - optional uint64 id = 1; - reserved /* sdp */ 2; - optional Type type = 3; - optional bytes opaque = 4; + optional uint64 id = 1; + reserved /* sdp */ 2; + optional Type type = 3; + optional bytes opaque = 4; } message Answer { - optional uint64 id = 1; - reserved /* sdp */ 2; - optional bytes opaque = 3; + optional uint64 id = 1; + reserved /* sdp */ 2; + optional bytes opaque = 3; } message IceUpdate { - optional uint64 id = 1; - reserved /* mid */ 2; - reserved /* line */ 3; - reserved /* sdp */ 4; - optional bytes opaque = 5; + optional uint64 id = 1; + reserved /* mid */ 2; + reserved /* line */ 3; + reserved /* sdp */ 4; + optional bytes opaque = 5; } message Busy { @@ -89,188 +90,50 @@ message CallMessage { message Hangup { enum Type { - HANGUP_NORMAL = 0; - HANGUP_ACCEPTED = 1; - HANGUP_DECLINED = 2; - HANGUP_BUSY = 3; + HANGUP_NORMAL = 0; + HANGUP_ACCEPTED = 1; + HANGUP_DECLINED = 2; + HANGUP_BUSY = 3; HANGUP_NEED_PERMISSION = 4; } - - optional uint64 id = 1; - optional Type type = 2; + optional uint64 id = 1; + optional Type type = 2; optional uint32 deviceId = 3; } message Opaque { enum Urgency { - DROPPABLE = 0; + DROPPABLE = 0; HANDLE_IMMEDIATELY = 1; } - - optional bytes data = 1; - optional Urgency urgency = 2; + optional bytes data = 1; + optional Urgency urgency = 2; // If missing, treat as DROPPABLE. } - optional Offer offer = 1; - optional Answer answer = 2; - repeated IceUpdate iceUpdate = 3; - reserved /* legacyHangup */ 4; - optional Busy busy = 5; - reserved /* profileKey */ 6; - optional Hangup hangup = 7; - reserved /* multiRing */ 8; - optional uint32 destinationDeviceId = 9; - optional Opaque opaque = 10; -} - -message BodyRange { - enum Style { - NONE = 0; - BOLD = 1; - ITALIC = 2; - SPOILER = 3; - STRIKETHROUGH = 4; - MONOSPACE = 5; - } - - optional uint32 start = 1; - optional uint32 length = 2; - - oneof associatedValue { - string mentionAci = 3; - Style style = 4; - } + optional Offer offer = 1; + optional Answer answer = 2; + repeated IceUpdate iceUpdate = 3; + reserved /* legacyHangup */ 4; + optional Busy busy = 5; + reserved /* profileKey */ 6; + optional Hangup hangup = 7; + reserved /* multiRing */ 8; + optional uint32 destinationDeviceId = 9; + optional Opaque opaque = 10; } message DataMessage { enum Flags { - END_SESSION = 1; + END_SESSION = 1; EXPIRATION_TIMER_UPDATE = 2; - PROFILE_KEY_UPDATE = 4; - } - - message Quote { - enum Type { - NORMAL = 0; - GIFT_BADGE = 1; - } - - message QuotedAttachment { - optional string contentType = 1; - optional string fileName = 2; - optional AttachmentPointer thumbnail = 3; - } - - optional uint64 id = 1; - reserved /*authorE164*/ 2; - optional string authorAci = 5; - optional string text = 3; - repeated QuotedAttachment attachments = 4; - repeated BodyRange bodyRanges = 6; - optional Type type = 7; - } - - message Contact { - message Name { - optional string givenName = 1; - optional string familyName = 2; - optional string prefix = 3; - optional string suffix = 4; - optional string middleName = 5; - reserved /*displayName*/ 6; - optional string nickname = 7; - } - - message Phone { - enum Type { - HOME = 1; - MOBILE = 2; - WORK = 3; - CUSTOM = 4; - } - - optional string value = 1; - optional Type type = 2; - optional string label = 3; - } - - message Email { - enum Type { - HOME = 1; - MOBILE = 2; - WORK = 3; - CUSTOM = 4; - } - - optional string value = 1; - optional Type type = 2; - optional string label = 3; - } - - message PostalAddress { - enum Type { - HOME = 1; - WORK = 2; - CUSTOM = 3; - } - - optional Type type = 1; - optional string label = 2; - optional string street = 3; - optional string pobox = 4; - optional string neighborhood = 5; - optional string city = 6; - optional string region = 7; - optional string postcode = 8; - optional string country = 9; - } - - message Avatar { - optional AttachmentPointer avatar = 1; - optional bool isProfile = 2; - } - - optional Name name = 1; - repeated Phone number = 3; - repeated Email email = 4; - repeated PostalAddress address = 5; - optional Avatar avatar = 6; - optional string organization = 7; - } - - message Sticker { - optional bytes packId = 1; - optional bytes packKey = 2; - optional uint32 stickerId = 3; - optional AttachmentPointer data = 4; - optional string emoji = 5; - } - - message Reaction { - optional string emoji = 1; - optional bool remove = 2; - reserved /*targetAuthorE164*/ 3; - optional string targetAuthorAci = 4; - optional uint64 targetSentTimestamp = 5; - } - - message Delete { - optional uint64 targetSentTimestamp = 1; - } - - message GroupCallUpdate { - optional string eraId = 1; - } - - message StoryContext { - optional string authorAci = 1; - optional uint64 sentTimestamp = 2; + PROFILE_KEY_UPDATE = 4; + FORWARD = 8; } message Payment { message Amount { message MobileCoin { - optional uint64 picoMob = 1; + optional uint64 picoMob = 1; // 1,000,000,000,000 picoMob per Mob } oneof Amount { @@ -287,13 +150,14 @@ message DataMessage { MobileCoin mobileCoin = 1; } + // Optional, Refers to the PaymentRequest message, if any. optional string note = 2; reserved /*requestId*/ 1003; } message Activation { enum Type { - REQUEST = 0; + REQUEST = 0; ACTIVATED = 1; } @@ -302,53 +166,172 @@ message DataMessage { oneof Item { Notification notification = 1; - Activation activation = 2; + Activation activation = 2; } - reserved /*request*/ 1002; + reserved /*request*/ 1002; reserved /*cancellation*/ 1003; } + message Quote { + enum Type { + NORMAL = 0; + GIFT_BADGE = 1; + } + + message QuotedAttachment { + optional string contentType = 1; + optional string fileName = 2; + optional AttachmentPointer thumbnail = 3; + } + + optional uint64 id = 1; + reserved /*authorE164*/ 2; + optional string authorAci = 5; + optional string text = 3; + repeated QuotedAttachment attachments = 4; + repeated BodyRange bodyRanges = 6; + optional Type type = 7; + } + + message Contact { + message Name { + optional string givenName = 1; + optional string familyName = 2; + optional string prefix = 3; + optional string suffix = 4; + optional string middleName = 5; + reserved /*displayName*/ 6; + optional string nickname = 7; + } + + message Phone { + enum Type { + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + optional string value = 1; + optional Type type = 2; + optional string label = 3; + } + + message Email { + enum Type { + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + optional string value = 1; + optional Type type = 2; + optional string label = 3; + } + + message PostalAddress { + enum Type { + HOME = 1; + WORK = 2; + CUSTOM = 3; + } + + optional Type type = 1; + optional string label = 2; + optional string street = 3; + optional string pobox = 4; + optional string neighborhood = 5; + optional string city = 6; + optional string region = 7; + optional string postcode = 8; + optional string country = 9; + } + + message Avatar { + optional AttachmentPointer avatar = 1; + optional bool isProfile = 2; + } + + optional Name name = 1; + repeated Phone number = 3; + repeated Email email = 4; + repeated PostalAddress address = 5; + optional Avatar avatar = 6; + optional string organization = 7; + } + + message Sticker { + optional bytes packId = 1; + optional bytes packKey = 2; + optional uint32 stickerId = 3; + optional AttachmentPointer data = 4; + optional string emoji = 5; + } + + message Reaction { + optional string emoji = 1; + optional bool remove = 2; + reserved /* targetAuthorE164 */ 3; + optional string targetAuthorAci = 4; + optional uint64 targetSentTimestamp = 5; + } + + message Delete { + optional uint64 targetSentTimestamp = 1; + } + + message GroupCallUpdate { + optional string eraId = 1; + } + + message StoryContext { + optional string authorAci = 1; + optional uint64 sentTimestamp = 2; + } + + enum ProtocolVersion { + option allow_alias = true; + + INITIAL = 0; + MESSAGE_TIMERS = 1; + VIEW_ONCE = 2; + VIEW_ONCE_VIDEO = 3; + REACTIONS = 4; + CDN_SELECTOR_ATTACHMENTS = 5; + MENTIONS = 6; + PAYMENTS = 7; + CURRENT = 7; + } + message GiftBadge { optional bytes receiptCredentialPresentation = 1; } - enum ProtocolVersion { - option allow_alias = true; - - INITIAL = 0; - MESSAGE_TIMERS = 1; - VIEW_ONCE = 2; - VIEW_ONCE_VIDEO = 3; - REACTIONS = 4; - CDN_SELECTOR_ATTACHMENTS = 5; - MENTIONS = 6; - PAYMENTS = 7; - CURRENT = 7; - } - - optional string body = 1; - repeated AttachmentPointer attachments = 2; - reserved /*groupV1*/ 3; - optional GroupContextV2 groupV2 = 15; - optional uint32 flags = 4; - optional uint32 expireTimer = 5; - optional uint32 expireTimerVersion = 23; - optional bytes profileKey = 6; - optional uint64 timestamp = 7; - optional Quote quote = 8; - repeated Contact contact = 9; - repeated Preview preview = 10; - optional Sticker sticker = 11; - optional uint32 requiredProtocolVersion = 12; - optional bool isViewOnce = 14; - optional Reaction reaction = 16; - optional Delete delete = 17; - repeated BodyRange bodyRanges = 18; - optional GroupCallUpdate groupCallUpdate = 19; - optional Payment payment = 20; - optional StoryContext storyContext = 21; - optional GiftBadge giftBadge = 22; + optional string body = 1; + repeated AttachmentPointer attachments = 2; + reserved /*groupV1*/ 3; + optional GroupContextV2 groupV2 = 15; + optional uint32 flags = 4; + optional uint32 expireTimer = 5; + optional uint32 expireTimerVersion = 23; + optional bytes profileKey = 6; + optional uint64 timestamp = 7; + optional Quote quote = 8; + repeated Contact contact = 9; + repeated Preview preview = 10; + optional Sticker sticker = 11; + optional uint32 requiredProtocolVersion = 12; + optional bool isViewOnce = 14; + optional Reaction reaction = 16; + optional Delete delete = 17; + repeated BodyRange bodyRanges = 18; + optional GroupCallUpdate groupCallUpdate = 19; + optional Payment payment = 20; + optional StoryContext storyContext = 21; + optional GiftBadge giftBadge = 22; + // NEXT ID: 24 } message NullMessage { @@ -358,185 +341,186 @@ message NullMessage { message ReceiptMessage { enum Type { DELIVERY = 0; - READ = 1; - VIEWED = 2; + READ = 1; + VIEWED = 2; } - optional Type type = 1; + optional Type type = 1; repeated uint64 timestamp = 2; } message TypingMessage { - enum Action { - STARTED = 0; - STOPPED = 1; - } + enum Action { + STARTED = 0; + STOPPED = 1; + } - optional uint64 timestamp = 1; - optional Action action = 2; - optional bytes groupId = 3; + optional uint64 timestamp = 1; + optional Action action = 2; + optional bytes groupId = 3; } message StoryMessage { - optional bytes profileKey = 1; - optional GroupContextV2 group = 2; + optional bytes profileKey = 1; + optional GroupContextV2 group = 2; oneof attachment { AttachmentPointer fileAttachment = 3; - TextAttachment textAttachment = 4; + TextAttachment textAttachment = 4; } - optional bool allowsReplies = 5; - repeated BodyRange bodyRanges = 6; + optional bool allowsReplies = 5; + repeated BodyRange bodyRanges = 6; } message Preview { - optional string url = 1; - optional string title = 2; - optional AttachmentPointer image = 3; - optional string description = 4; - optional uint64 date = 5; + optional string url = 1; + optional string title = 2; + optional AttachmentPointer image = 3; + optional string description = 4; + optional uint64 date = 5; } message TextAttachment { enum Style { - DEFAULT = 0; - REGULAR = 1; - BOLD = 2; - SERIF = 3; - SCRIPT = 4; + DEFAULT = 0; + REGULAR = 1; + BOLD = 2; + SERIF = 3; + SCRIPT = 4; CONDENSED = 5; } message Gradient { optional uint32 startColor = 1; // deprecated: this field will be removed in a future release. - optional uint32 endColor = 2; // deprecated: this field will be removed in a future release. - optional uint32 angle = 3; // degrees - repeated uint32 colors = 4; - repeated float positions = 5; // percent from 0 to 1 + optional uint32 endColor = 2; // deprecated: this field will be removed in a future release. + optional uint32 angle = 3; // degrees + repeated uint32 colors = 4; + repeated float positions = 5; // percent from 0 to 1 } - optional string text = 1; - optional Style textStyle = 2; - optional uint32 textForegroundColor = 3; // integer representation of hex color - optional uint32 textBackgroundColor = 4; - optional Preview preview = 5; + optional string text = 1; + optional Style textStyle = 2; + optional uint32 textForegroundColor = 3; // integer representation of hex color + optional uint32 textBackgroundColor = 4; + optional Preview preview = 5; oneof background { Gradient gradient = 6; - uint32 color = 7; + uint32 color = 7; } } message Verified { enum State { - DEFAULT = 0; - VERIFIED = 1; + DEFAULT = 0; + VERIFIED = 1; UNVERIFIED = 2; } - reserved /*destinationE164*/ 1; - optional string destinationAci = 5; - optional bytes identityKey = 2; - optional State state = 3; - optional bytes nullMessage = 4; + reserved /*destinationE164*/ 1; + optional string destinationAci = 5; + optional bytes identityKey = 2; + optional State state = 3; + optional bytes nullMessage = 4; } message SyncMessage { message Sent { message UnidentifiedDeliveryStatus { - reserved /*destinationE164*/ 1; - optional string destinationServiceId = 3; - optional bool unidentified = 2; - reserved /*destinationPni*/ 4; - optional bytes destinationIdentityKey = 5; + reserved /*destinationE164*/ 1; + optional string destinationServiceId = 3; + optional bool unidentified = 2; + reserved /*destinationPni */ 4; + optional bytes destinationPniIdentityKey = 5; // Only set for PNI destinations } message StoryMessageRecipient { optional string destinationServiceId = 1; - repeated string distributionListIds = 2; - optional bool isAllowedToReply = 3; + repeated string distributionListIds = 2; + optional bool isAllowedToReply = 3; + reserved /*destinationPni */ 4; } - optional string destinationE164 = 1; - optional string destinationServiceId = 7; - optional uint64 timestamp = 2; - optional DataMessage message = 3; - optional uint64 expirationStartTimestamp = 4; - repeated UnidentifiedDeliveryStatus unidentifiedStatus = 5; - optional bool isRecipientUpdate = 6 [default = false]; - optional StoryMessage storyMessage = 8; - repeated StoryMessageRecipient storyMessageRecipients = 9; - optional EditMessage editMessage = 10; - reserved /*destinationPni*/ 11; - // NEXT ID: 12 + optional string destinationE164 = 1; + optional string destinationServiceId = 7; + optional uint64 timestamp = 2; + optional DataMessage message = 3; + optional uint64 expirationStartTimestamp = 4; + repeated UnidentifiedDeliveryStatus unidentifiedStatus = 5; + optional bool isRecipientUpdate = 6 [default = false]; + optional StoryMessage storyMessage = 8; + repeated StoryMessageRecipient storyMessageRecipients = 9; + optional EditMessage editMessage = 10; + reserved /*destinationPni */ 11; + // Next ID: 12 } message Contacts { - optional AttachmentPointer blob = 1; - optional bool complete = 2 [default = false]; + optional AttachmentPointer blob = 1; + optional bool complete = 2 [default = false]; } message Blocked { - repeated string numbers = 1; - repeated string acis = 3; - repeated bytes groupIds = 2; + repeated string numbers = 1; + repeated string acis = 3; + repeated bytes groupIds = 2; } message Request { enum Type { - UNKNOWN = 0; - CONTACTS = 1; -// GROUPS = 2; - BLOCKED = 3; + UNKNOWN = 0; + CONTACTS = 1; + reserved /*GROUPS*/ 2; + BLOCKED = 3; CONFIGURATION = 4; - KEYS = 5; - PNI_IDENTITY = 6; + KEYS = 5; + reserved /*PNI_IDENTITY*/ 6; } optional Type type = 1; } message Read { - reserved /*senderE164*/ 1; - optional string senderAci = 3; - optional uint64 timestamp = 2; + reserved /*senderE164*/ 1; + optional string senderAci = 3; + optional uint64 timestamp = 2; } message Viewed { - reserved /*senderE164*/ 1; - optional string senderAci = 3; - optional uint64 timestamp = 2; + reserved /*senderE164*/ 1; + optional string senderAci = 3; + optional uint64 timestamp = 2; } message Configuration { - optional bool readReceipts = 1; - optional bool unidentifiedDeliveryIndicators = 2; - optional bool typingIndicators = 3; - reserved /* linkPreviews */ 4; - optional uint32 provisioningVersion = 5; - optional bool linkPreviews = 6; + optional bool readReceipts = 1; + optional bool unidentifiedDeliveryIndicators = 2; + optional bool typingIndicators = 3; + reserved /* linkPreviews */ 4; + optional uint32 provisioningVersion = 5; + optional bool linkPreviews = 6; } message StickerPackOperation { enum Type { INSTALL = 0; - REMOVE = 1; + REMOVE = 1; } - optional bytes packId = 1; + optional bytes packId = 1; optional bytes packKey = 2; - optional Type type = 3; + optional Type type = 3; } message ViewOnceOpen { - reserved /*senderE164*/ 1; - optional string senderAci = 3; - optional uint64 timestamp = 2; + reserved /*senderE164*/ 1; + optional string senderAci = 3; + optional uint64 timestamp = 2; } message FetchLatest { enum Type { - UNKNOWN = 0; - LOCAL_PROFILE = 1; - STORAGE_MANIFEST = 2; + UNKNOWN = 0; + LOCAL_PROFILE = 1; + STORAGE_MANIFEST = 2; SUBSCRIPTION_STATUS = 3; } @@ -544,91 +528,95 @@ message SyncMessage { } message Keys { - // @deprecated - optional bytes storageService = 1; - // @deprecated - optional bytes master = 2; + reserved /* storageService */ 1; + optional bytes master = 2; // deprecated: this field will be removed in a future release. optional string accountEntropyPool = 3; optional bytes mediaRootBackupKey = 4; } + message PniIdentity { + optional bytes publicKey = 1; + optional bytes privateKey = 2; + } + message MessageRequestResponse { enum Type { - UNKNOWN = 0; - ACCEPT = 1; - DELETE = 2; - BLOCK = 3; + UNKNOWN = 0; + ACCEPT = 1; + DELETE = 2; + BLOCK = 3; BLOCK_AND_DELETE = 4; - SPAM = 5; - BLOCK_AND_SPAM = 6; + SPAM = 5; + BLOCK_AND_SPAM = 6; } - reserved /*threadE164*/ 1; - optional string threadAci = 2; - optional bytes groupId = 3; - optional Type type = 4; + reserved /*threadE164*/ 1; + optional string threadAci = 2; + optional bytes groupId = 3; + optional Type type = 4; } message OutgoingPayment { message MobileCoin { - optional bytes recipientAddress = 1; - // @required - optional uint64 amountPicoMob = 2; - // @required - optional uint64 feePicoMob = 3; - optional bytes receipt = 4; + optional bytes recipientAddress = 1; + optional uint64 amountPicoMob = 2; + optional uint64 feePicoMob = 3; + optional bytes receipt = 4; optional uint64 ledgerBlockTimestamp = 5; - // @required - optional uint64 ledgerBlockIndex = 6; - repeated bytes spentKeyImages = 7; - repeated bytes outputPublicKeys = 8; + optional uint64 ledgerBlockIndex = 6; + repeated bytes spentKeyImages = 7; + repeated bytes outputPublicKeys = 8; } optional string recipientServiceId = 1; - optional string note = 2; - - oneof paymentDetail { + optional string note = 2; + oneof attachment_identifier { MobileCoin mobileCoin = 3; } } message PniChangeNumber { - optional bytes identityKeyPair = 1; // Serialized libsignal-client IdentityKeyPair - optional bytes signedPreKey = 2; // Serialized libsignal-client SignedPreKeyRecord - optional bytes lastResortKyberPreKey = 5; // Serialized libsignal-client KyberPreKeyRecord - optional uint32 registrationId = 3; - optional string newE164 = 4; // The e164 we have changed our number to + optional bytes identityKeyPair = 1; // Serialized libsignal-client IdentityKeyPair + optional bytes signedPreKey = 2; // Serialized libsignal-client SignedPreKeyRecord + optional bytes lastResortKyberPreKey = 5; // Serialized libsignal-client KyberPreKeyRecord + optional uint32 registrationId = 3; + optional string newE164 = 4; // The e164 we have changed our number to // Next ID: 6 } message CallEvent { enum Type { UNKNOWN_TYPE = 0; - AUDIO_CALL = 1; - VIDEO_CALL = 2; - GROUP_CALL = 3; - AD_HOC_CALL = 4; + AUDIO_CALL = 1; + VIDEO_CALL = 2; + GROUP_CALL = 3; + AD_HOC_CALL = 4; } enum Direction { UNKNOWN_DIRECTION = 0; - INCOMING = 1; - OUTGOING = 2; + INCOMING = 1; + OUTGOING = 2; } enum Event { - UNKNOWN_ACTION = 0; - ACCEPTED = 1; - NOT_ACCEPTED = 2; - DELETE = 3; - OBSERVED = 4; + UNKNOWN_EVENT = 0; + ACCEPTED = 1; + NOT_ACCEPTED = 2; + DELETE = 3; + OBSERVED = 4; } - optional bytes conversationId = 1; - optional uint64 id = 2; - optional uint64 timestamp = 3; - optional Type type = 4; - optional Direction direction = 5; - optional Event event = 6; + /* Data identifying a conversation. The service ID for 1:1, the group ID for + * group, or the room ID for an ad-hoc call. See also + * `CallLogEvent/conversationId`. */ + optional bytes conversationId = 1; + /* An identifier for a call. Generated directly for 1:1, or derived from + * the era ID for group and ad-hoc calls. See also `CallLogEvent/callId`. */ + optional uint64 callId = 2; + optional uint64 timestamp = 3; + optional Type type = 4; + optional Direction direction = 5; + optional Event event = 6; } message CallLinkUpdate { @@ -637,46 +625,31 @@ message SyncMessage { reserved 1; // was DELETE, superseded by storage service } - optional bytes rootKey = 1; - optional bytes adminPassKey = 2; - optional Type type = 3; + optional bytes rootKey = 1; + optional bytes adminPasskey = 2; + optional Type type = 3; // defaults to UPDATE } message CallLogEvent { enum Type { - CLEAR = 0; - MARKED_AS_READ = 1; + CLEAR = 0; + MARKED_AS_READ = 1; MARKED_AS_READ_IN_CONVERSATION = 2; + CLEAR_IN_CONVERSATION = 3; } - optional Type type = 1; - optional uint64 timestamp = 2; + optional Type type = 1; + optional uint64 timestamp = 2; /* Data identifying a conversation. The service ID for 1:1, the group ID for * group, or the room ID for an ad-hoc call. See also * `CallEvent/conversationId`. */ optional bytes conversationId = 3; /* An identifier for a call. Generated directly for 1:1, or derived from * the era ID for group and ad-hoc calls. See also `CallEvent/callId`. */ - optional uint64 callId = 4; + optional uint64 callId = 4; } message DeleteForMe { - message ConversationIdentifier { - oneof identifier { - string threadServiceId = 1; - bytes threadGroupId = 2; - string threadE164 = 3; - } - } - - message AddressableMessage { - oneof author { - string authorServiceId = 1; - string authorE164 = 2; - } - optional uint64 sentTimestamp = 3; - } - message MessageDeletes { optional ConversationIdentifier conversation = 1; repeated AddressableMessage messages = 2; @@ -685,16 +658,19 @@ message SyncMessage { message AttachmentDelete { optional ConversationIdentifier conversation = 1; optional AddressableMessage targetMessage = 2; - optional bytes uuid = 3; // The `uuid` from the `Attachment`. + // The `clientUuid` from `AttachmentPointer`. + optional bytes clientUuid = 3; + // SHA256 hash of the (encrypted, padded, etc.) attachment blob on the CDN. optional bytes fallbackDigest = 4; + // SHA256 hash of the plaintext content of the attachment. optional bytes fallbackPlaintextHash = 5; } message ConversationDelete { optional ConversationIdentifier conversation = 1; repeated AddressableMessage mostRecentMessages = 2; - repeated AddressableMessage mostRecentNonExpiringMessages = 4; optional bool isFullDelete = 3; + repeated AddressableMessage mostRecentNonExpiringMessages = 4; } message LocalOnlyConversationDelete { @@ -708,163 +684,194 @@ message SyncMessage { } message DeviceNameChange { - reserved /*name*/ 1; + reserved /*name*/ 1; optional uint32 deviceId = 2; } - optional Sent sent = 1; - optional Contacts contacts = 2; - reserved /*groups*/ 3; - optional Request request = 4; - repeated Read read = 5; - optional Blocked blocked = 6; - optional Verified verified = 7; - optional Configuration configuration = 9; - optional bytes padding = 8; - repeated StickerPackOperation stickerPackOperation = 10; - optional ViewOnceOpen viewOnceOpen = 11; - optional FetchLatest fetchLatest = 12; - optional Keys keys = 13; + message AttachmentBackfillRequest { + optional AddressableMessage targetMessage = 1; + optional ConversationIdentifier targetConversation = 2; + } + + message AttachmentBackfillResponse { + message AttachmentData { + enum Status { + PENDING = 0; + TERMINAL_ERROR = 1; + } + + oneof data { + AttachmentPointer attachment = 1; + Status status = 2; + } + } + + enum Error { + MESSAGE_NOT_FOUND = 0; + } + + message AttachmentDataList { + repeated AttachmentData attachments = 1; + optional AttachmentData longText = 2; + } + + optional AddressableMessage targetMessage = 1; + optional ConversationIdentifier targetConversation = 2; + + oneof data { + AttachmentDataList attachments = 3; + Error error = 4; + } + } + + optional Sent sent = 1; + optional Contacts contacts = 2; + reserved /*groups*/ 3; + optional Request request = 4; + repeated Read read = 5; + optional Blocked blocked = 6; + optional Verified verified = 7; + optional Configuration configuration = 9; + optional bytes padding = 8; + repeated StickerPackOperation stickerPackOperation = 10; + optional ViewOnceOpen viewOnceOpen = 11; + optional FetchLatest fetchLatest = 12; + optional Keys keys = 13; optional MessageRequestResponse messageRequestResponse = 14; - optional OutgoingPayment outgoingPayment = 15; - repeated Viewed viewed = 16; - reserved /*pniIdentity*/ 17; - optional PniChangeNumber pniChangeNumber = 18; - optional CallEvent callEvent = 19; - optional CallLinkUpdate callLinkUpdate = 20; - optional CallLogEvent callLogEvent = 21; - optional DeleteForMe deleteForMe = 22; - optional DeviceNameChange deviceNameChange = 23; + optional OutgoingPayment outgoingPayment = 15; + repeated Viewed viewed = 16; + reserved /*pniIdentity*/ 17; + optional PniChangeNumber pniChangeNumber = 18; + optional CallEvent callEvent = 19; + optional CallLinkUpdate callLinkUpdate = 20; + optional CallLogEvent callLogEvent = 21; + optional DeleteForMe deleteForMe = 22; + optional DeviceNameChange deviceNameChange = 23; + optional AttachmentBackfillRequest attachmentBackfillRequest = 24; + optional AttachmentBackfillResponse attachmentBackfillResponse = 25; } message AttachmentPointer { enum Flags { VOICE_MESSAGE = 1; - BORDERLESS = 2; - reserved 3; - GIF = 4; + BORDERLESS = 2; + reserved 4; + GIF = 8; } oneof attachment_identifier { - fixed64 cdnId = 1; - string cdnKey = 15; + fixed64 cdnId = 1; + string cdnKey = 15; } - optional string contentType = 2; - optional bytes key = 3; - optional uint32 size = 4; - optional bytes thumbnail = 5; - optional bytes digest = 6; - reserved 16; - reserved 18; - optional bytes incrementalMac = 19; - optional uint32 incrementalMacChunkSize = 17; - optional string fileName = 7; - optional uint32 flags = 8; - optional uint32 width = 9; - optional uint32 height = 10; - optional string caption = 11; - optional string blurHash = 12; - optional uint64 uploadTimestamp = 13; - optional uint32 cdnNumber = 14; - optional bytes uuid = 20; + // Cross-client identifier for this attachment among all attachments on the + // owning message. + optional bytes clientUuid = 20; + optional string contentType = 2; + optional bytes key = 3; + optional uint32 size = 4; + optional bytes thumbnail = 5; + optional bytes digest = 6; + reserved /* incrementalMac with implicit chunk sizing */ 16; + reserved /* incrementalMac for all attachment types */ 18; + optional bytes incrementalMac = 19; + optional uint32 chunkSize = 17; + optional string fileName = 7; + optional uint32 flags = 8; + optional uint32 width = 9; + optional uint32 height = 10; + optional string caption = 11; + optional string blurHash = 12; + optional uint64 uploadTimestamp = 13; + optional uint32 cdnNumber = 14; // Next ID: 21 } -message GroupContext { - enum Type { - UNKNOWN = 0; - UPDATE = 1; - DELIVER = 2; - QUIT = 3; - REQUEST_INFO = 4; - } - - message Member { - reserved /* uuid */ 1; // removed - optional string e164 = 2; - } - - optional bytes id = 1; - optional Type type = 2; - optional string name = 3; - repeated string membersE164 = 4; - repeated Member members = 6; - optional AttachmentPointer avatar = 5; -} - message GroupContextV2 { - optional bytes masterKey = 1; - optional uint32 revision = 2; - optional bytes groupChange = 3; + optional bytes masterKey = 1; + optional uint32 revision = 2; + optional bytes groupChange = 3; } message ContactDetails { message Avatar { optional string contentType = 1; - optional uint32 length = 2; + optional uint32 length = 2; } - optional string number = 1; - optional string aci = 9; - optional string name = 2; - optional Avatar avatar = 3; - optional string color = 4; - optional Verified verified = 5; - optional bytes profileKey = 6; - reserved /*blocked*/ 7; - optional uint32 expireTimer = 8; - optional uint32 expireTimerVersion = 12; - optional uint32 inboxPosition = 10; - optional bool archived = 11; -} - -message GroupDetails { - message Avatar { - optional string contentType = 1; - optional uint32 length = 2; - } - - message Member { - reserved /* uuid */ 1; // removed - optional string e164 = 2; - } - - optional bytes id = 1; - optional string name = 2; - repeated string membersE164 = 3; - repeated Member members = 9; - optional Avatar avatar = 4; - optional bool active = 5 [default = true]; - optional uint32 expireTimer = 6; - optional string color = 7; - optional bool blocked = 8; - optional uint32 inboxPosition = 10; - optional bool archived = 11; + optional string number = 1; + optional string aci = 9; + optional string name = 2; + optional Avatar avatar = 3; + reserved /* color */ 4; + reserved /* verified */ 5; + reserved /* profileKey */ 6; + reserved /* blocked */ 7; + optional uint32 expireTimer = 8; + optional uint32 expireTimerVersion = 12; + optional uint32 inboxPosition = 10; + reserved /* archived */ 11; + // NEXT ID: 13 } message PaymentAddress { - oneof Address { - MobileCoinAddress mobileCoinAddress = 1; + message MobileCoin { + optional bytes publicAddress = 1; + optional bytes signature = 2; } - message MobileCoinAddress { - optional bytes address = 1; - optional bytes signature = 2; + oneof Address { + MobileCoin mobileCoin = 1; } } message DecryptionErrorMessage { - optional bytes ratchetKey = 1; - optional uint64 timestamp = 2; - optional uint32 deviceId = 3; + optional bytes ratchetKey = 1; // set to the public ratchet key from the SignalMessage if a 1-1 payload fails to decrypt + optional uint64 timestamp = 2; + optional uint32 deviceId = 3; } message PniSignatureMessage { - optional bytes pni = 1; + optional bytes pni = 1; + // Signature *by* the PNI identity key *of* the ACI identity key optional bytes signature = 2; } message EditMessage { - optional uint64 targetSentTimestamp = 1; - optional DataMessage dataMessage = 2; + optional uint64 targetSentTimestamp = 1; + optional DataMessage dataMessage = 2; +} + +message BodyRange { + enum Style { + NONE = 0; + BOLD = 1; + ITALIC = 2; + SPOILER = 3; + STRIKETHROUGH = 4; + MONOSPACE = 5; + } + + optional uint32 start = 1; // Starting index in UTF-16 code units/raw string representation + optional uint32 length = 2; // Length of range in UTF-16 code units/raw string representation + + oneof associatedValue { + string mentionAci = 3; + Style style = 4; + } +} + +message AddressableMessage { + oneof author { + string authorServiceId = 1; + string authorE164 = 2; + } + optional uint64 sentTimestamp = 3; +} + +message ConversationIdentifier { + oneof identifier { + string threadServiceId = 1; + bytes threadGroupId = 2; + string threadE164 = 3; + } } diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index a371ea9..3aad8ab 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -76,6 +76,91 @@ func (OptionalBool) EnumDescriptor() ([]byte, []int) { return file_StorageService_proto_rawDescGZIP(), []int{0} } +// If unset - computed as the value of the first byte of SHA-256(msg=CONTACT_ID) +// modulo the count of colors. Once set the avatar color for a recipient is +// never recomputed or changed. +// +// `CONTACT_ID` is the first available identifier from the list: +// - ServiceIdToBinary(ACI) +// - E164 +// - ServiceIdToBinary(PNI) +// - Group Id +type AvatarColor int32 + +const ( + AvatarColor_A100 AvatarColor = 0 + AvatarColor_A110 AvatarColor = 1 + AvatarColor_A120 AvatarColor = 2 + AvatarColor_A130 AvatarColor = 3 + AvatarColor_A140 AvatarColor = 4 + AvatarColor_A150 AvatarColor = 5 + AvatarColor_A160 AvatarColor = 6 + AvatarColor_A170 AvatarColor = 7 + AvatarColor_A180 AvatarColor = 8 + AvatarColor_A190 AvatarColor = 9 + AvatarColor_A200 AvatarColor = 10 + AvatarColor_A210 AvatarColor = 11 +) + +// Enum value maps for AvatarColor. +var ( + AvatarColor_name = map[int32]string{ + 0: "A100", + 1: "A110", + 2: "A120", + 3: "A130", + 4: "A140", + 5: "A150", + 6: "A160", + 7: "A170", + 8: "A180", + 9: "A190", + 10: "A200", + 11: "A210", + } + AvatarColor_value = map[string]int32{ + "A100": 0, + "A110": 1, + "A120": 2, + "A130": 3, + "A140": 4, + "A150": 5, + "A160": 6, + "A170": 7, + "A180": 8, + "A190": 9, + "A200": 10, + "A210": 11, + } +) + +func (x AvatarColor) Enum() *AvatarColor { + p := new(AvatarColor) + *p = x + return p +} + +func (x AvatarColor) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AvatarColor) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[1].Descriptor() +} + +func (AvatarColor) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[1] +} + +func (x AvatarColor) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AvatarColor.Descriptor instead. +func (AvatarColor) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{1} +} + type ManifestRecord_Identifier_Type int32 const ( @@ -86,6 +171,7 @@ const ( ManifestRecord_Identifier_ACCOUNT ManifestRecord_Identifier_Type = 4 ManifestRecord_Identifier_STORY_DISTRIBUTION_LIST ManifestRecord_Identifier_Type = 5 ManifestRecord_Identifier_CALL_LINK ManifestRecord_Identifier_Type = 7 + ManifestRecord_Identifier_CHAT_FOLDER ManifestRecord_Identifier_Type = 8 ) // Enum value maps for ManifestRecord_Identifier_Type. @@ -98,6 +184,7 @@ var ( 4: "ACCOUNT", 5: "STORY_DISTRIBUTION_LIST", 7: "CALL_LINK", + 8: "CHAT_FOLDER", } ManifestRecord_Identifier_Type_value = map[string]int32{ "UNKNOWN": 0, @@ -107,6 +194,7 @@ var ( "ACCOUNT": 4, "STORY_DISTRIBUTION_LIST": 5, "CALL_LINK": 7, + "CHAT_FOLDER": 8, } ) @@ -121,11 +209,11 @@ func (x ManifestRecord_Identifier_Type) String() string { } func (ManifestRecord_Identifier_Type) Descriptor() protoreflect.EnumDescriptor { - return file_StorageService_proto_enumTypes[1].Descriptor() + return file_StorageService_proto_enumTypes[2].Descriptor() } func (ManifestRecord_Identifier_Type) Type() protoreflect.EnumType { - return &file_StorageService_proto_enumTypes[1] + return &file_StorageService_proto_enumTypes[2] } func (x ManifestRecord_Identifier_Type) Number() protoreflect.EnumNumber { @@ -170,11 +258,11 @@ func (x ContactRecord_IdentityState) String() string { } func (ContactRecord_IdentityState) Descriptor() protoreflect.EnumDescriptor { - return file_StorageService_proto_enumTypes[2].Descriptor() + return file_StorageService_proto_enumTypes[3].Descriptor() } func (ContactRecord_IdentityState) Type() protoreflect.EnumType { - return &file_StorageService_proto_enumTypes[2] + return &file_StorageService_proto_enumTypes[3] } func (x ContactRecord_IdentityState) Number() protoreflect.EnumNumber { @@ -219,11 +307,11 @@ func (x GroupV2Record_StorySendMode) String() string { } func (GroupV2Record_StorySendMode) Descriptor() protoreflect.EnumDescriptor { - return file_StorageService_proto_enumTypes[3].Descriptor() + return file_StorageService_proto_enumTypes[4].Descriptor() } func (GroupV2Record_StorySendMode) Type() protoreflect.EnumType { - return &file_StorageService_proto_enumTypes[3] + return &file_StorageService_proto_enumTypes[4] } func (x GroupV2Record_StorySendMode) Number() protoreflect.EnumNumber { @@ -268,11 +356,11 @@ func (x AccountRecord_PhoneNumberSharingMode) String() string { } func (AccountRecord_PhoneNumberSharingMode) Descriptor() protoreflect.EnumDescriptor { - return file_StorageService_proto_enumTypes[4].Descriptor() + return file_StorageService_proto_enumTypes[5].Descriptor() } func (AccountRecord_PhoneNumberSharingMode) Type() protoreflect.EnumType { - return &file_StorageService_proto_enumTypes[4] + return &file_StorageService_proto_enumTypes[5] } func (x AccountRecord_PhoneNumberSharingMode) Number() protoreflect.EnumNumber { @@ -335,11 +423,11 @@ func (x AccountRecord_UsernameLink_Color) String() string { } func (AccountRecord_UsernameLink_Color) Descriptor() protoreflect.EnumDescriptor { - return file_StorageService_proto_enumTypes[5].Descriptor() + return file_StorageService_proto_enumTypes[6].Descriptor() } func (AccountRecord_UsernameLink_Color) Type() protoreflect.EnumType { - return &file_StorageService_proto_enumTypes[5] + return &file_StorageService_proto_enumTypes[6] } func (x AccountRecord_UsernameLink_Color) Number() protoreflect.EnumNumber { @@ -351,6 +439,56 @@ func (AccountRecord_UsernameLink_Color) EnumDescriptor() ([]byte, []int) { return file_StorageService_proto_rawDescGZIP(), []int{11, 1, 0} } +// Represents the default "All chats" folder record vs all other custom folders +type ChatFolderRecord_FolderType int32 + +const ( + ChatFolderRecord_UNKNOWN ChatFolderRecord_FolderType = 0 + ChatFolderRecord_ALL ChatFolderRecord_FolderType = 1 + ChatFolderRecord_CUSTOM ChatFolderRecord_FolderType = 2 +) + +// Enum value maps for ChatFolderRecord_FolderType. +var ( + ChatFolderRecord_FolderType_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ALL", + 2: "CUSTOM", + } + ChatFolderRecord_FolderType_value = map[string]int32{ + "UNKNOWN": 0, + "ALL": 1, + "CUSTOM": 2, + } +) + +func (x ChatFolderRecord_FolderType) Enum() *ChatFolderRecord_FolderType { + p := new(ChatFolderRecord_FolderType) + *p = x + return p +} + +func (x ChatFolderRecord_FolderType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ChatFolderRecord_FolderType) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[7].Descriptor() +} + +func (ChatFolderRecord_FolderType) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[7] +} + +func (x ChatFolderRecord_FolderType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ChatFolderRecord_FolderType.Descriptor instead. +func (ChatFolderRecord_FolderType) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{14, 0} +} + type StorageManifest struct { state protoimpl.MessageState `protogen:"open.v1"` Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` @@ -689,6 +827,7 @@ type StorageRecord struct { // *StorageRecord_Account // *StorageRecord_StoryDistributionList // *StorageRecord_CallLink + // *StorageRecord_ChatFolder Record isStorageRecord_Record `protobuf_oneof:"record"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -785,6 +924,15 @@ func (x *StorageRecord) GetCallLink() *CallLinkRecord { return nil } +func (x *StorageRecord) GetChatFolder() *ChatFolderRecord { + if x != nil { + if x, ok := x.Record.(*StorageRecord_ChatFolder); ok { + return x.ChatFolder + } + } + return nil +} + type isStorageRecord_Record interface { isStorageRecord_Record() } @@ -813,6 +961,10 @@ type StorageRecord_CallLink struct { CallLink *CallLinkRecord `protobuf:"bytes,7,opt,name=callLink,proto3,oneof"` } +type StorageRecord_ChatFolder struct { + ChatFolder *ChatFolderRecord `protobuf:"bytes,8,opt,name=chatFolder,proto3,oneof"` +} + func (*StorageRecord_Contact) isStorageRecord_Record() {} func (*StorageRecord_GroupV1) isStorageRecord_Record() {} @@ -825,6 +977,8 @@ func (*StorageRecord_StoryDistributionList) isStorageRecord_Record() {} func (*StorageRecord_CallLink) isStorageRecord_Record() {} +func (*StorageRecord_ChatFolder) isStorageRecord_Record() {} + type ContactRecord struct { state protoimpl.MessageState `protogen:"open.v1"` Aci string `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` @@ -849,7 +1003,8 @@ type ContactRecord struct { Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` PniSignatureVerified bool `protobuf:"varint,21,opt,name=pniSignatureVerified,proto3" json:"pniSignatureVerified,omitempty"` Nickname *ContactRecord_Name `protobuf:"bytes,22,opt,name=nickname,proto3" json:"nickname,omitempty"` - Note string `protobuf:"bytes,23,opt,name=note,proto3" json:"note,omitempty"` // NEXT ID: 24 + Note string `protobuf:"bytes,23,opt,name=note,proto3" json:"note,omitempty"` + AvatarColor *AvatarColor `protobuf:"varint,24,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` // Next ID: 25 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1045,6 +1200,13 @@ func (x *ContactRecord) GetNote() string { return "" } +func (x *ContactRecord) GetAvatarColor() AvatarColor { + if x != nil && x.AvatarColor != nil { + return *x.AvatarColor + } + return AvatarColor_A100 +} + type GroupV1Record struct { state protoimpl.MessageState `protogen:"open.v1"` Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -1140,6 +1302,7 @@ type GroupV2Record struct { DontNotifyForMentionsIfMuted bool `protobuf:"varint,7,opt,name=dontNotifyForMentionsIfMuted,proto3" json:"dontNotifyForMentionsIfMuted,omitempty"` HideStory bool `protobuf:"varint,8,opt,name=hideStory,proto3" json:"hideStory,omitempty"` StorySendMode GroupV2Record_StorySendMode `protobuf:"varint,10,opt,name=storySendMode,proto3,enum=signalservice.GroupV2Record_StorySendMode" json:"storySendMode,omitempty"` + AvatarColor *AvatarColor `protobuf:"varint,11,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1237,6 +1400,13 @@ func (x *GroupV2Record) GetStorySendMode() GroupV2Record_StorySendMode { return GroupV2Record_DEFAULT } +func (x *GroupV2Record) GetAvatarColor() AvatarColor { + if x != nil && x.AvatarColor != nil { + return *x.AvatarColor + } + return AvatarColor_A100 +} + type Payments struct { state protoimpl.MessageState `protogen:"open.v1"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` @@ -1326,6 +1496,7 @@ type AccountRecord struct { HasBackup *bool `protobuf:"varint,39,opt,name=hasBackup,proto3,oneof" json:"hasBackup,omitempty"` // Set to true after backups are enabled and one is uploaded. BackupTier *uint64 `protobuf:"varint,40,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` // See zkgroup for integer particular values BackupSubscriberData *AccountRecord_IAPSubscriberData `protobuf:"bytes,41,opt,name=backupSubscriberData,proto3" json:"backupSubscriberData,omitempty"` + AvatarColor *AvatarColor `protobuf:"varint,42,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1605,6 +1776,13 @@ func (x *AccountRecord) GetBackupSubscriberData() *AccountRecord_IAPSubscriberDa return nil } +func (x *AccountRecord) GetAvatarColor() AvatarColor { + if x != nil && x.AvatarColor != nil { + return *x.AvatarColor + } + return AvatarColor_A100 +} + type StoryDistributionListRecord struct { state protoimpl.MessageState `protogen:"open.v1"` Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` @@ -1749,6 +1927,130 @@ func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 { return 0 } +type ChatFolderRecord struct { + state protoimpl.MessageState `protogen:"open.v1"` + Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Position uint32 `protobuf:"varint,3,opt,name=position,proto3" json:"position,omitempty"` + ShowOnlyUnread bool `protobuf:"varint,4,opt,name=showOnlyUnread,proto3" json:"showOnlyUnread,omitempty"` + ShowMutedChats bool `protobuf:"varint,5,opt,name=showMutedChats,proto3" json:"showMutedChats,omitempty"` + IncludeAllIndividualChats bool `protobuf:"varint,6,opt,name=includeAllIndividualChats,proto3" json:"includeAllIndividualChats,omitempty"` // Folder includes all 1:1 chats, unless excluded + IncludeAllGroupChats bool `protobuf:"varint,7,opt,name=includeAllGroupChats,proto3" json:"includeAllGroupChats,omitempty"` // Folder includes all group chats, unless excluded + FolderType ChatFolderRecord_FolderType `protobuf:"varint,8,opt,name=folderType,proto3,enum=signalservice.ChatFolderRecord_FolderType" json:"folderType,omitempty"` + IncludedRecipients []*ChatFolderRecord_Recipient `protobuf:"bytes,9,rep,name=includedRecipients,proto3" json:"includedRecipients,omitempty"` + ExcludedRecipients []*ChatFolderRecord_Recipient `protobuf:"bytes,10,rep,name=excludedRecipients,proto3" json:"excludedRecipients,omitempty"` + DeletedAtTimestampMs uint64 `protobuf:"varint,11,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` // When non-zero, `position` should be set to -1 and includedRecipients should be empty + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatFolderRecord) Reset() { + *x = ChatFolderRecord{} + mi := &file_StorageService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatFolderRecord) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatFolderRecord) ProtoMessage() {} + +func (x *ChatFolderRecord) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[14] + 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 ChatFolderRecord.ProtoReflect.Descriptor instead. +func (*ChatFolderRecord) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{14} +} + +func (x *ChatFolderRecord) GetIdentifier() []byte { + if x != nil { + return x.Identifier + } + return nil +} + +func (x *ChatFolderRecord) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ChatFolderRecord) GetPosition() uint32 { + if x != nil { + return x.Position + } + return 0 +} + +func (x *ChatFolderRecord) GetShowOnlyUnread() bool { + if x != nil { + return x.ShowOnlyUnread + } + return false +} + +func (x *ChatFolderRecord) GetShowMutedChats() bool { + if x != nil { + return x.ShowMutedChats + } + return false +} + +func (x *ChatFolderRecord) GetIncludeAllIndividualChats() bool { + if x != nil { + return x.IncludeAllIndividualChats + } + return false +} + +func (x *ChatFolderRecord) GetIncludeAllGroupChats() bool { + if x != nil { + return x.IncludeAllGroupChats + } + return false +} + +func (x *ChatFolderRecord) GetFolderType() ChatFolderRecord_FolderType { + if x != nil { + return x.FolderType + } + return ChatFolderRecord_UNKNOWN +} + +func (x *ChatFolderRecord) GetIncludedRecipients() []*ChatFolderRecord_Recipient { + if x != nil { + return x.IncludedRecipients + } + return nil +} + +func (x *ChatFolderRecord) GetExcludedRecipients() []*ChatFolderRecord_Recipient { + if x != nil { + return x.ExcludedRecipients + } + return nil +} + +func (x *ChatFolderRecord) GetDeletedAtTimestampMs() uint64 { + if x != nil { + return x.DeletedAtTimestampMs + } + return 0 +} + type ManifestRecord_Identifier struct { state protoimpl.MessageState `protogen:"open.v1"` Raw []byte `protobuf:"bytes,1,opt,name=raw,proto3" json:"raw,omitempty"` @@ -1759,7 +2061,7 @@ type ManifestRecord_Identifier struct { func (x *ManifestRecord_Identifier) Reset() { *x = ManifestRecord_Identifier{} - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1771,7 +2073,7 @@ func (x *ManifestRecord_Identifier) String() string { func (*ManifestRecord_Identifier) ProtoMessage() {} func (x *ManifestRecord_Identifier) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1811,7 +2113,7 @@ type ContactRecord_Name struct { func (x *ContactRecord_Name) Reset() { *x = ContactRecord_Name{} - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1823,7 +2125,7 @@ func (x *ContactRecord_Name) String() string { func (*ContactRecord_Name) ProtoMessage() {} func (x *ContactRecord_Name) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1867,7 +2169,7 @@ type AccountRecord_PinnedConversation struct { func (x *AccountRecord_PinnedConversation) Reset() { *x = AccountRecord_PinnedConversation{} - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1879,7 +2181,7 @@ func (x *AccountRecord_PinnedConversation) String() string { func (*AccountRecord_PinnedConversation) ProtoMessage() {} func (x *AccountRecord_PinnedConversation) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1964,7 +2266,7 @@ type AccountRecord_UsernameLink struct { func (x *AccountRecord_UsernameLink) Reset() { *x = AccountRecord_UsernameLink{} - mi := &file_StorageService_proto_msgTypes[17] + mi := &file_StorageService_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1976,7 +2278,7 @@ func (x *AccountRecord_UsernameLink) String() string { func (*AccountRecord_UsernameLink) ProtoMessage() {} func (x *AccountRecord_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[17] + mi := &file_StorageService_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2027,7 +2329,7 @@ type AccountRecord_IAPSubscriberData struct { func (x *AccountRecord_IAPSubscriberData) Reset() { *x = AccountRecord_IAPSubscriberData{} - mi := &file_StorageService_proto_msgTypes[18] + mi := &file_StorageService_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2039,7 +2341,7 @@ func (x *AccountRecord_IAPSubscriberData) String() string { func (*AccountRecord_IAPSubscriberData) ProtoMessage() {} func (x *AccountRecord_IAPSubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[18] + mi := &file_StorageService_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2117,7 +2419,7 @@ type AccountRecord_PinnedConversation_Contact struct { func (x *AccountRecord_PinnedConversation_Contact) Reset() { *x = AccountRecord_PinnedConversation_Contact{} - mi := &file_StorageService_proto_msgTypes[19] + mi := &file_StorageService_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2129,7 +2431,7 @@ func (x *AccountRecord_PinnedConversation_Contact) String() string { func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[19] + mi := &file_StorageService_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2159,6 +2461,156 @@ func (x *AccountRecord_PinnedConversation_Contact) GetE164() string { return "" } +type ChatFolderRecord_Recipient struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Identifier: + // + // *ChatFolderRecord_Recipient_Contact_ + // *ChatFolderRecord_Recipient_LegacyGroupId + // *ChatFolderRecord_Recipient_GroupMasterKey + Identifier isChatFolderRecord_Recipient_Identifier `protobuf_oneof:"identifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatFolderRecord_Recipient) Reset() { + *x = ChatFolderRecord_Recipient{} + mi := &file_StorageService_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatFolderRecord_Recipient) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatFolderRecord_Recipient) ProtoMessage() {} + +func (x *ChatFolderRecord_Recipient) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[21] + 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 ChatFolderRecord_Recipient.ProtoReflect.Descriptor instead. +func (*ChatFolderRecord_Recipient) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{14, 0} +} + +func (x *ChatFolderRecord_Recipient) GetIdentifier() isChatFolderRecord_Recipient_Identifier { + if x != nil { + return x.Identifier + } + return nil +} + +func (x *ChatFolderRecord_Recipient) GetContact() *ChatFolderRecord_Recipient_Contact { + if x != nil { + if x, ok := x.Identifier.(*ChatFolderRecord_Recipient_Contact_); ok { + return x.Contact + } + } + return nil +} + +func (x *ChatFolderRecord_Recipient) GetLegacyGroupId() []byte { + if x != nil { + if x, ok := x.Identifier.(*ChatFolderRecord_Recipient_LegacyGroupId); ok { + return x.LegacyGroupId + } + } + return nil +} + +func (x *ChatFolderRecord_Recipient) GetGroupMasterKey() []byte { + if x != nil { + if x, ok := x.Identifier.(*ChatFolderRecord_Recipient_GroupMasterKey); ok { + return x.GroupMasterKey + } + } + return nil +} + +type isChatFolderRecord_Recipient_Identifier interface { + isChatFolderRecord_Recipient_Identifier() +} + +type ChatFolderRecord_Recipient_Contact_ struct { + Contact *ChatFolderRecord_Recipient_Contact `protobuf:"bytes,1,opt,name=contact,proto3,oneof"` +} + +type ChatFolderRecord_Recipient_LegacyGroupId struct { + LegacyGroupId []byte `protobuf:"bytes,2,opt,name=legacyGroupId,proto3,oneof"` +} + +type ChatFolderRecord_Recipient_GroupMasterKey struct { + GroupMasterKey []byte `protobuf:"bytes,3,opt,name=groupMasterKey,proto3,oneof"` +} + +func (*ChatFolderRecord_Recipient_Contact_) isChatFolderRecord_Recipient_Identifier() {} + +func (*ChatFolderRecord_Recipient_LegacyGroupId) isChatFolderRecord_Recipient_Identifier() {} + +func (*ChatFolderRecord_Recipient_GroupMasterKey) isChatFolderRecord_Recipient_Identifier() {} + +type ChatFolderRecord_Recipient_Contact struct { + state protoimpl.MessageState `protogen:"open.v1"` + ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` + E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatFolderRecord_Recipient_Contact) Reset() { + *x = ChatFolderRecord_Recipient_Contact{} + mi := &file_StorageService_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatFolderRecord_Recipient_Contact) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatFolderRecord_Recipient_Contact) ProtoMessage() {} + +func (x *ChatFolderRecord_Recipient_Contact) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[22] + 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 ChatFolderRecord_Recipient_Contact.ProtoReflect.Descriptor instead. +func (*ChatFolderRecord_Recipient_Contact) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{14, 0, 0} +} + +func (x *ChatFolderRecord_Recipient_Contact) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *ChatFolderRecord_Recipient_Contact) GetE164() string { + if x != nil { + return x.E164 + } + return "" +} + var File_StorageService_proto protoreflect.FileDescriptor //go:embed StorageService.pb.raw @@ -2176,64 +2628,77 @@ func file_StorageService_proto_rawDescGZIP() []byte { return file_StorageService_proto_rawDescData } -var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 8) +var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 23) var file_StorageService_proto_goTypes = []any{ (OptionalBool)(0), // 0: signalservice.OptionalBool - (ManifestRecord_Identifier_Type)(0), // 1: signalservice.ManifestRecord.Identifier.Type - (ContactRecord_IdentityState)(0), // 2: signalservice.ContactRecord.IdentityState - (GroupV2Record_StorySendMode)(0), // 3: signalservice.GroupV2Record.StorySendMode - (AccountRecord_PhoneNumberSharingMode)(0), // 4: signalservice.AccountRecord.PhoneNumberSharingMode - (AccountRecord_UsernameLink_Color)(0), // 5: signalservice.AccountRecord.UsernameLink.Color - (*StorageManifest)(nil), // 6: signalservice.StorageManifest - (*StorageItem)(nil), // 7: signalservice.StorageItem - (*StorageItems)(nil), // 8: signalservice.StorageItems - (*ReadOperation)(nil), // 9: signalservice.ReadOperation - (*WriteOperation)(nil), // 10: signalservice.WriteOperation - (*ManifestRecord)(nil), // 11: signalservice.ManifestRecord - (*StorageRecord)(nil), // 12: signalservice.StorageRecord - (*ContactRecord)(nil), // 13: signalservice.ContactRecord - (*GroupV1Record)(nil), // 14: signalservice.GroupV1Record - (*GroupV2Record)(nil), // 15: signalservice.GroupV2Record - (*Payments)(nil), // 16: signalservice.Payments - (*AccountRecord)(nil), // 17: signalservice.AccountRecord - (*StoryDistributionListRecord)(nil), // 18: signalservice.StoryDistributionListRecord - (*CallLinkRecord)(nil), // 19: signalservice.CallLinkRecord - (*ManifestRecord_Identifier)(nil), // 20: signalservice.ManifestRecord.Identifier - (*ContactRecord_Name)(nil), // 21: signalservice.ContactRecord.Name - (*AccountRecord_PinnedConversation)(nil), // 22: signalservice.AccountRecord.PinnedConversation - (*AccountRecord_UsernameLink)(nil), // 23: signalservice.AccountRecord.UsernameLink - (*AccountRecord_IAPSubscriberData)(nil), // 24: signalservice.AccountRecord.IAPSubscriberData - (*AccountRecord_PinnedConversation_Contact)(nil), // 25: signalservice.AccountRecord.PinnedConversation.Contact + (AvatarColor)(0), // 1: signalservice.AvatarColor + (ManifestRecord_Identifier_Type)(0), // 2: signalservice.ManifestRecord.Identifier.Type + (ContactRecord_IdentityState)(0), // 3: signalservice.ContactRecord.IdentityState + (GroupV2Record_StorySendMode)(0), // 4: signalservice.GroupV2Record.StorySendMode + (AccountRecord_PhoneNumberSharingMode)(0), // 5: signalservice.AccountRecord.PhoneNumberSharingMode + (AccountRecord_UsernameLink_Color)(0), // 6: signalservice.AccountRecord.UsernameLink.Color + (ChatFolderRecord_FolderType)(0), // 7: signalservice.ChatFolderRecord.FolderType + (*StorageManifest)(nil), // 8: signalservice.StorageManifest + (*StorageItem)(nil), // 9: signalservice.StorageItem + (*StorageItems)(nil), // 10: signalservice.StorageItems + (*ReadOperation)(nil), // 11: signalservice.ReadOperation + (*WriteOperation)(nil), // 12: signalservice.WriteOperation + (*ManifestRecord)(nil), // 13: signalservice.ManifestRecord + (*StorageRecord)(nil), // 14: signalservice.StorageRecord + (*ContactRecord)(nil), // 15: signalservice.ContactRecord + (*GroupV1Record)(nil), // 16: signalservice.GroupV1Record + (*GroupV2Record)(nil), // 17: signalservice.GroupV2Record + (*Payments)(nil), // 18: signalservice.Payments + (*AccountRecord)(nil), // 19: signalservice.AccountRecord + (*StoryDistributionListRecord)(nil), // 20: signalservice.StoryDistributionListRecord + (*CallLinkRecord)(nil), // 21: signalservice.CallLinkRecord + (*ChatFolderRecord)(nil), // 22: signalservice.ChatFolderRecord + (*ManifestRecord_Identifier)(nil), // 23: signalservice.ManifestRecord.Identifier + (*ContactRecord_Name)(nil), // 24: signalservice.ContactRecord.Name + (*AccountRecord_PinnedConversation)(nil), // 25: signalservice.AccountRecord.PinnedConversation + (*AccountRecord_UsernameLink)(nil), // 26: signalservice.AccountRecord.UsernameLink + (*AccountRecord_IAPSubscriberData)(nil), // 27: signalservice.AccountRecord.IAPSubscriberData + (*AccountRecord_PinnedConversation_Contact)(nil), // 28: signalservice.AccountRecord.PinnedConversation.Contact + (*ChatFolderRecord_Recipient)(nil), // 29: signalservice.ChatFolderRecord.Recipient + (*ChatFolderRecord_Recipient_Contact)(nil), // 30: signalservice.ChatFolderRecord.Recipient.Contact } var file_StorageService_proto_depIdxs = []int32{ - 7, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem - 6, // 1: signalservice.WriteOperation.manifest:type_name -> signalservice.StorageManifest - 7, // 2: signalservice.WriteOperation.insertItem:type_name -> signalservice.StorageItem - 20, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier - 13, // 4: signalservice.StorageRecord.contact:type_name -> signalservice.ContactRecord - 14, // 5: signalservice.StorageRecord.groupV1:type_name -> signalservice.GroupV1Record - 15, // 6: signalservice.StorageRecord.groupV2:type_name -> signalservice.GroupV2Record - 17, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord - 18, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord - 19, // 9: signalservice.StorageRecord.callLink:type_name -> signalservice.CallLinkRecord - 2, // 10: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState - 21, // 11: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name - 3, // 12: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode - 4, // 13: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode - 22, // 14: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation - 16, // 15: signalservice.AccountRecord.payments:type_name -> signalservice.Payments - 0, // 16: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool - 23, // 17: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink - 24, // 18: signalservice.AccountRecord.backupSubscriberData:type_name -> signalservice.AccountRecord.IAPSubscriberData - 1, // 19: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type - 25, // 20: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact - 5, // 21: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color - 22, // [22:22] is the sub-list for method output_type - 22, // [22:22] is the sub-list for method input_type - 22, // [22:22] is the sub-list for extension type_name - 22, // [22:22] is the sub-list for extension extendee - 0, // [0:22] is the sub-list for field type_name + 9, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem + 8, // 1: signalservice.WriteOperation.manifest:type_name -> signalservice.StorageManifest + 9, // 2: signalservice.WriteOperation.insertItem:type_name -> signalservice.StorageItem + 23, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier + 15, // 4: signalservice.StorageRecord.contact:type_name -> signalservice.ContactRecord + 16, // 5: signalservice.StorageRecord.groupV1:type_name -> signalservice.GroupV1Record + 17, // 6: signalservice.StorageRecord.groupV2:type_name -> signalservice.GroupV2Record + 19, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord + 20, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord + 21, // 9: signalservice.StorageRecord.callLink:type_name -> signalservice.CallLinkRecord + 22, // 10: signalservice.StorageRecord.chatFolder:type_name -> signalservice.ChatFolderRecord + 3, // 11: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState + 24, // 12: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name + 1, // 13: signalservice.ContactRecord.avatarColor:type_name -> signalservice.AvatarColor + 4, // 14: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode + 1, // 15: signalservice.GroupV2Record.avatarColor:type_name -> signalservice.AvatarColor + 5, // 16: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode + 25, // 17: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation + 18, // 18: signalservice.AccountRecord.payments:type_name -> signalservice.Payments + 0, // 19: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool + 26, // 20: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink + 27, // 21: signalservice.AccountRecord.backupSubscriberData:type_name -> signalservice.AccountRecord.IAPSubscriberData + 1, // 22: signalservice.AccountRecord.avatarColor:type_name -> signalservice.AvatarColor + 7, // 23: signalservice.ChatFolderRecord.folderType:type_name -> signalservice.ChatFolderRecord.FolderType + 29, // 24: signalservice.ChatFolderRecord.includedRecipients:type_name -> signalservice.ChatFolderRecord.Recipient + 29, // 25: signalservice.ChatFolderRecord.excludedRecipients:type_name -> signalservice.ChatFolderRecord.Recipient + 2, // 26: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type + 28, // 27: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact + 6, // 28: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color + 30, // 29: signalservice.ChatFolderRecord.Recipient.contact:type_name -> signalservice.ChatFolderRecord.Recipient.Contact + 30, // [30:30] is the sub-list for method output_type + 30, // [30:30] is the sub-list for method input_type + 30, // [30:30] is the sub-list for extension type_name + 30, // [30:30] is the sub-list for extension extendee + 0, // [0:30] is the sub-list for field type_name } func init() { file_StorageService_proto_init() } @@ -2248,24 +2713,32 @@ func file_StorageService_proto_init() { (*StorageRecord_Account)(nil), (*StorageRecord_StoryDistributionList)(nil), (*StorageRecord_CallLink)(nil), + (*StorageRecord_ChatFolder)(nil), } + file_StorageService_proto_msgTypes[7].OneofWrappers = []any{} + file_StorageService_proto_msgTypes[9].OneofWrappers = []any{} file_StorageService_proto_msgTypes[11].OneofWrappers = []any{} - file_StorageService_proto_msgTypes[16].OneofWrappers = []any{ + file_StorageService_proto_msgTypes[17].OneofWrappers = []any{ (*AccountRecord_PinnedConversation_Contact_)(nil), (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), } - file_StorageService_proto_msgTypes[18].OneofWrappers = []any{ + file_StorageService_proto_msgTypes[19].OneofWrappers = []any{ (*AccountRecord_IAPSubscriberData_PurchaseToken)(nil), (*AccountRecord_IAPSubscriberData_OriginalTransactionId)(nil), } + file_StorageService_proto_msgTypes[21].OneofWrappers = []any{ + (*ChatFolderRecord_Recipient_Contact_)(nil), + (*ChatFolderRecord_Recipient_LegacyGroupId)(nil), + (*ChatFolderRecord_Recipient_GroupMasterKey)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_StorageService_proto_rawDesc, - NumEnums: 6, - NumMessages: 20, + NumEnums: 8, + NumMessages: 23, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw index 9c6689d9adaa8592bc569b23dfe69630c4881315..1e4142f2f966d232fa2d25f4dc748e115b3520bd 100644 GIT binary patch delta 1236 zcmbW0zi-n(9L0Nf5<6eh^mKvN%|aCk)OLuj1`4GtX`n5oZIEdNOqH=sYss=BCn_C+#(4?ZB zE!CZE&v5H@u_S zU&izwGlbqn+EaNVj`VEOzB+n)mH^9&+^^ z|54R*_cp!2HY_#8CuF_n^!MCavte5ud|ge)bMYy;2IG!rx=qV2yY5ZTa(11T)im75 zlL^k%$6G&OVHt zSt%SN$acSmtbt_uUc)dOD&j+mHuKk;uqXL*NMHx~NhGqPyg`d4fcWl+0@CLCt@Y~N zbv#5Q5X-Bp7!iO>W%JHPbqx#b+t_St`Y8e>@oy3tQso&+xhGUJl$%1OQ7lC20>xsa sE>fI|)Fq13k(#AA6RFD-OOd)lu^g#6inF28cm|Mc2d(iCg{kV|FG9n1!~g&Q delta 101 zcmV-r0Gj{1JKiv`(g6XHlhXmZ0oId_0%HMllk);|0wSWbc>|dN4MGSC26AO%Z*pWJ z$_KMz1y}=<{RncCe+kh7&I7Yj3XcJkBn&x|Z45^Nq_edQZwIqy6cPioi5I5 signal.backup.AccountData - 33, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient - 38, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat - 43, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem - 106, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack - 40, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall - 108, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile - 109, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder - 110, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink - 112, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData - 111, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings - 113, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData - 34, // 12: signal.backup.Recipient.contact:type_name -> signal.backup.Contact - 35, // 13: signal.backup.Recipient.group:type_name -> signal.backup.Group - 41, // 14: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem - 36, // 15: signal.backup.Recipient.self:type_name -> signal.backup.Self - 37, // 16: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes - 39, // 17: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink - 4, // 18: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility - 114, // 19: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered - 115, // 20: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered - 3, // 21: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState - 116, // 22: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name - 5, // 23: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode - 117, // 24: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot - 107, // 25: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle - 8, // 26: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions - 9, // 27: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State - 42, // 28: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList - 10, // 29: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode - 43, // 30: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem - 124, // 31: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails - 125, // 32: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails - 126, // 33: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails - 46, // 34: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage - 47, // 35: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage - 53, // 36: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage - 54, // 37: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage - 62, // 38: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage - 49, // 39: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification - 50, // 40: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge - 51, // 41: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage - 48, // 42: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage - 127, // 43: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending - 128, // 44: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent - 129, // 45: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered - 130, // 46: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read - 131, // 47: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed - 132, // 48: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped - 133, // 49: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed - 60, // 50: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange - 59, // 51: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote - 45, // 52: signal.backup.StandardMessage.text:type_name -> signal.backup.Text - 57, // 53: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment - 56, // 54: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview - 58, // 55: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer - 61, // 56: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction - 52, // 57: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment - 61, // 58: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction - 134, // 59: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply - 61, // 60: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction - 135, // 61: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails - 14, // 62: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State - 57, // 63: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment - 61, // 64: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction - 139, // 65: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name - 140, // 66: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone - 141, // 67: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email - 142, // 68: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress - 58, // 69: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer - 55, // 70: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker - 61, // 71: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction - 58, // 72: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer - 58, // 73: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer - 58, // 74: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer - 18, // 75: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag - 143, // 76: signal.backup.FilePointer.backupLocator:type_name -> signal.backup.FilePointer.BackupLocator - 144, // 77: signal.backup.FilePointer.attachmentLocator:type_name -> signal.backup.FilePointer.AttachmentLocator - 145, // 78: signal.backup.FilePointer.invalidAttachmentLocator:type_name -> signal.backup.FilePointer.InvalidAttachmentLocator - 45, // 79: signal.backup.Quote.text:type_name -> signal.backup.Text - 146, // 80: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 19, // 81: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 20, // 82: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 65, // 83: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 71, // 84: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 66, // 85: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 67, // 86: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 69, // 87: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 70, // 88: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 63, // 89: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 64, // 90: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 68, // 91: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 21, // 92: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 22, // 93: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 23, // 94: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 24, // 95: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 25, // 96: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 147, // 97: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 0, // 98: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 0, // 99: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 148, // 100: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 26, // 101: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 58, // 102: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 151, // 103: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 27, // 104: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 28, // 105: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 29, // 106: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 2, // 107: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 1, // 108: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 107, // 109: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 150, // 110: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 118, // 111: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 118, // 112: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 118, // 113: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 123, // 114: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 119, // 115: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 120, // 116: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 121, // 117: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 122, // 118: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 6, // 119: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 119, // 120: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 7, // 121: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 7, // 122: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 7, // 123: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 44, // 124: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 11, // 125: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 45, // 126: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 58, // 127: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 138, // 128: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 137, // 129: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 12, // 130: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 13, // 131: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 136, // 132: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 15, // 133: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 16, // 134: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 17, // 135: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 57, // 136: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 72, // 137: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 73, // 138: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 74, // 139: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 75, // 140: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 76, // 141: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 77, // 142: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 78, // 143: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 79, // 144: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 80, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 81, // 146: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 82, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 83, // 148: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 84, // 149: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 85, // 150: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 86, // 151: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 87, // 152: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 88, // 153: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 89, // 154: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 90, // 155: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 91, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 92, // 157: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 93, // 158: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 94, // 159: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 96, // 160: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 97, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 98, // 162: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 99, // 163: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 100, // 164: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 101, // 165: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 102, // 166: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 103, // 167: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 104, // 168: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 95, // 169: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 105, // 170: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 149, // 171: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 172, // [172:172] is the sub-list for method output_type - 172, // [172:172] is the sub-list for method input_type - 172, // [172:172] is the sub-list for extension type_name - 172, // [172:172] is the sub-list for extension extendee - 0, // [0:172] is the sub-list for field type_name + 33, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData + 34, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient + 39, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat + 44, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem + 107, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack + 41, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall + 109, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile + 110, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder + 111, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink + 113, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData + 112, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings + 114, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData + 35, // 12: signal.backup.Recipient.contact:type_name -> signal.backup.Contact + 36, // 13: signal.backup.Recipient.group:type_name -> signal.backup.Group + 42, // 14: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem + 37, // 15: signal.backup.Recipient.self:type_name -> signal.backup.Self + 38, // 16: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes + 40, // 17: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink + 5, // 18: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility + 115, // 19: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered + 116, // 20: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered + 4, // 21: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState + 117, // 22: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name + 0, // 23: signal.backup.Contact.avatarColor:type_name -> signal.backup.AvatarColor + 6, // 24: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode + 118, // 25: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot + 0, // 26: signal.backup.Group.avatarColor:type_name -> signal.backup.AvatarColor + 0, // 27: signal.backup.Self.avatarColor:type_name -> signal.backup.AvatarColor + 108, // 28: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle + 9, // 29: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions + 10, // 30: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State + 43, // 31: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList + 11, // 32: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode + 44, // 33: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem + 125, // 34: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails + 126, // 35: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails + 127, // 36: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails + 47, // 37: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage + 48, // 38: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage + 54, // 39: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage + 55, // 40: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage + 63, // 41: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage + 50, // 42: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification + 51, // 43: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge + 52, // 44: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage + 49, // 45: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage + 128, // 46: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending + 129, // 47: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent + 130, // 48: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered + 131, // 49: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read + 132, // 50: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed + 133, // 51: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped + 134, // 52: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed + 61, // 53: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange + 60, // 54: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote + 46, // 55: signal.backup.StandardMessage.text:type_name -> signal.backup.Text + 58, // 56: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment + 57, // 57: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview + 59, // 58: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer + 62, // 59: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction + 53, // 60: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment + 62, // 61: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction + 135, // 62: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply + 62, // 63: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction + 136, // 64: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails + 15, // 65: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State + 58, // 66: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment + 62, // 67: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction + 140, // 68: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name + 141, // 69: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone + 142, // 70: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email + 143, // 71: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress + 59, // 72: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer + 56, // 73: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker + 62, // 74: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction + 59, // 75: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer + 59, // 76: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer + 59, // 77: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer + 19, // 78: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag + 144, // 79: signal.backup.FilePointer.backupLocator:type_name -> signal.backup.FilePointer.BackupLocator + 145, // 80: signal.backup.FilePointer.attachmentLocator:type_name -> signal.backup.FilePointer.AttachmentLocator + 146, // 81: signal.backup.FilePointer.invalidAttachmentLocator:type_name -> signal.backup.FilePointer.InvalidAttachmentLocator + 46, // 82: signal.backup.Quote.text:type_name -> signal.backup.Text + 147, // 83: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 20, // 84: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 21, // 85: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 66, // 86: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 72, // 87: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 67, // 88: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 68, // 89: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 70, // 90: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 71, // 91: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 64, // 92: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 65, // 93: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 69, // 94: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 22, // 95: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 23, // 96: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 24, // 97: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 25, // 98: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 26, // 99: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 148, // 100: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 101: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 102: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 149, // 103: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 27, // 104: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 59, // 105: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 152, // 106: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 28, // 107: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 29, // 108: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 30, // 109: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 3, // 110: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 2, // 111: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 108, // 112: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 151, // 113: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 119, // 114: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 115: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 116: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 124, // 117: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 120, // 118: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 121, // 119: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 122, // 120: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 123, // 121: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 7, // 122: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 120, // 123: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 8, // 124: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 125: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 126: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 45, // 127: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 12, // 128: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 46, // 129: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 59, // 130: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 139, // 131: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 138, // 132: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 13, // 133: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 14, // 134: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 137, // 135: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 16, // 136: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 17, // 137: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 18, // 138: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 58, // 139: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 73, // 140: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 74, // 141: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 75, // 142: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 76, // 143: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 77, // 144: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 78, // 145: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 79, // 146: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 80, // 147: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 81, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 82, // 149: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 83, // 150: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 84, // 151: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 85, // 152: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 86, // 153: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 87, // 154: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 88, // 155: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 89, // 156: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 90, // 157: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 91, // 158: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 92, // 159: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 93, // 160: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 94, // 161: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 95, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 97, // 163: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 98, // 164: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 99, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 100, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 101, // 167: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 102, // 168: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 103, // 169: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 104, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 105, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 96, // 172: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 106, // 173: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 150, // 174: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 175, // [175:175] is the sub-list for method output_type + 175, // [175:175] is the sub-list for method input_type + 175, // [175:175] is the sub-list for extension type_name + 175, // [175:175] is the sub-list for extension extendee + 0, // [0:175] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -11408,6 +11561,8 @@ func file_backuppb_Backup_proto_init() { (*Contact_Registered_)(nil), (*Contact_NotRegistered_)(nil), } + file_backuppb_Backup_proto_msgTypes[5].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[6].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[8].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[9].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[11].OneofWrappers = []any{ @@ -11571,7 +11726,7 @@ func file_backuppb_Backup_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_backuppb_Backup_proto_rawDesc, - NumEnums: 30, + NumEnums: 31, NumMessages: 122, NumExtensions: 0, NumServices: 0, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.raw b/pkg/signalmeow/protobuf/backuppb/Backup.pb.raw index 7a030359a9583e852063511073a9fec4c60b91d5..c72802f548667437a91409072bf911376e63bc75 100644 GIT binary patch delta 654 zcmbRJh4Ii2#tk2t7(Z_Q#3aikAtc7dR$NvTkeMgJt-z?k83g5R=4U<1!E~By^EKWN zO!YzQnA#U-h^?wMt&d47qxsS-k9<>83ViZj#m5_9yD5|gt_3-lZj zDm*xYkTrBLGHyO5(8Vb1#K*-Gk7SZkztHAjAx=hTAv7D<3EIGbVMC1YX7+jv8zQ+_ zf>U$S&@Esj-2x1wfu0FU%}GrxPW8(#Ni9~o%*?e}Te>@j@xtcqr0kH7`0ok+i0v!UgCk4d_0{RHE?hWt)v!4-)0Rtku5wkoK2?4W+ j6tf2iA_fWsQ)O&sv!)!MTmitdMtP9|ljnLdlc0N|vA7;a diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 42f3e8d..9fe2079 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -117,6 +117,7 @@ message AccountData { reserved /*backupsSubscriberData*/ 8; // A deprecated format AccountSettings accountSettings = 9; IAPSubscriberData backupsSubscriberData = 10; + string svrPin = 11; } message Recipient { @@ -132,6 +133,30 @@ message Recipient { } } +// If unset - computed as the value of the first byte of SHA-256(msg=CONTACT_ID) +// modulo the count of colors. Once set the avatar color for a recipient is +// never recomputed or changed. +// +// `CONTACT_ID` is the first available identifier from the list: +// - ServiceIdToBinary(ACI) +// - E164 +// - ServiceIdToBinary(PNI) +// - Group Id +enum AvatarColor { + A100 = 0; + A110 = 1; + A120 = 2; + A130 = 3; + A140 = 4; + A150 = 5; + A160 = 6; + A170 = 7; + A180 = 8; + A190 = 9; + A200 = 10; + A210 = 11; +} + message Contact { enum IdentityState { DEFAULT = 0; // A valid value -- indicates unset by the user @@ -177,6 +202,10 @@ message Contact { IdentityState identityState = 15; Name nickname = 16; // absent iff both `given` and `family` are empty string note = 17; + string systemGivenName = 18; + string systemFamilyName = 19; + string systemNickname = 20; + optional AvatarColor avatarColor = 21; } message Group { @@ -192,6 +221,7 @@ message Group { StorySendMode storySendMode = 4; GroupSnapshot snapshot = 5; bool blocked = 6; + optional AvatarColor avatarColor = 7; // These are simply plaintext copies of the groups proto from Groups.proto. // They should be kept completely in-sync with Groups.proto. @@ -271,7 +301,9 @@ message Group { } } -message Self {} +message Self { + optional AvatarColor avatarColor = 1; +} message ReleaseNotes {} @@ -1279,4 +1311,5 @@ message ChatFolder { FolderType folderType = 6; repeated uint64 includedRecipientIds = 7; // generated recipient id of groups, contacts, and/or note to self repeated uint64 excludedRecipientIds = 8; // generated recipient id of groups, contacts, and/or note to self + bytes id = 9; // should be 16 bytes } diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 1699017..1dd2e40 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-aa9c87ee67364a28977a2a5ba3bb7f5e715e19a0} -DESKTOP_GIT_REVISION=${1:-3f0536f5a58b6a20949690afd76093f41931843c} +ANDROID_GIT_REVISION=${1:-68058264729cb237bd8523df404d9455cb3f622f} +DESKTOP_GIT_REVISION=${1:-c861161f22e553ecb81982bc2c7b7d495ee42fcc} update_proto() { case "$1" in diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 34fcd55..6ea9885 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -431,11 +431,11 @@ func (cli *Client) decryptEnvelope( Content: &content, } - case signalpb.Envelope_RECEIPT: - return DecryptionResult{Err: fmt.Errorf("receipt envelopes are not yet supported")} + case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: + return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} - case signalpb.Envelope_KEY_EXCHANGE: - return DecryptionResult{Err: fmt.Errorf("key exchange envelopes are not yet supported")} + case signalpb.Envelope_SENDERKEY_MESSAGE: + return DecryptionResult{Err: fmt.Errorf("senderkey message envelopes are not yet supported")} case signalpb.Envelope_UNKNOWN: return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 555cbc2..7687da8 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -305,10 +305,10 @@ func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *l } type SuccessfulSendResult struct { - Recipient libsignalgo.ServiceID - RecipientE164 *string - Unidentified bool - DestinationIdentityKey *libsignalgo.IdentityKey + Recipient libsignalgo.ServiceID + RecipientE164 *string + Unidentified bool + DestinationPNIIdentityKey *libsignalgo.IdentityKey } type FailedSendResult struct { Recipient libsignalgo.ServiceID @@ -386,9 +386,9 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), - Unidentified: &result.Unidentified, - DestinationIdentityKey: result.DestinationIdentityKey.TrySerialize(), + DestinationServiceId: proto.String(result.Recipient.String()), + Unidentified: &result.Unidentified, + DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, }, }, @@ -407,9 +407,9 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), - Unidentified: &result.Unidentified, - DestinationIdentityKey: result.DestinationIdentityKey.TrySerialize(), + DestinationServiceId: proto.String(result.Recipient.String()), + Unidentified: &result.Unidentified, + DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, }, }, @@ -791,7 +791,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv }, } if recipientID.Type == libsignalgo.ServiceIDTypePNI { - result.DestinationIdentityKey, err = cli.Store.IdentityKeyStore.GetIdentityKey(ctx, recipientID) + result.DestinationPNIIdentityKey, err = cli.Store.IdentityKeyStore.GetIdentityKey(ctx, recipientID) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to add PNI destination identity key to sync message") } From e1cbbc9b9a29e5d85af681291a3484cd58c9f2c3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 16 Apr 2025 12:55:13 +0300 Subject: [PATCH 456/718] Bump version to v0.8.2 --- CHANGELOG.md | 5 ++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 26 ++++++++++---------- go.sum | 49 +++++++++++++++++++------------------- 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01410df..722ed55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v0.8.2 (2025-04-16) + +* Updated libsignal to v0.70.0 +* Fixed panics in some cases when the bridge was under heavy load. + # v0.8.1 (2025-03-16) * Added QR refreshing when logging in. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index c97a5d2..c1689d6 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.1", + Version: "0.8.2", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 7e2044e..28e17e8 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.23.0 -toolchain go1.24.1 +toolchain go1.24.2 require ( github.com/coder/websocket v1.8.13 @@ -10,15 +10,15 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/mattn/go-pointer v0.0.1 - github.com/rs/zerolog v1.33.0 + github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 go.mau.fi/util v0.8.6 - golang.org/x/crypto v0.36.0 - golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 - golang.org/x/net v0.37.0 - google.golang.org/protobuf v1.36.5 - maunium.net/go/mautrix v0.23.3-0.20250320134109-06f200da0d10 + golang.org/x/crypto v0.37.0 + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 + golang.org/x/net v0.39.0 + google.golang.org/protobuf v1.36.6 + maunium.net/go/mautrix v0.23.3 ) require ( @@ -30,8 +30,8 @@ require ( github.com/lib/pq v1.10.9 // 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.24 // indirect - github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 // indirect + github.com/mattn/go-sqlite3 v1.14.27 // indirect + github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -39,11 +39,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.8 // indirect + github.com/yuin/goldmark v1.7.10 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index b049d15..fc57e3c 100644 --- a/go.sum +++ b/go.sum @@ -38,10 +38,10 @@ 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.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= -github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 h1:E7Kmf11E4K7B5hDti2K2NqPb1nlYlGYsu02S1JNd/Bs= -github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= +github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a h1:S+AGcmAESQ0pXCUNnRH7V+bOUIgkSX5qVt2cNKCrm0Q= +github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -49,11 +49,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN 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= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -68,29 +67,29 @@ 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.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= -github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI= +github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= go.mau.fi/util v0.8.6 h1:AEK13rfgtiZJL2YsNK+W4ihhYCuukcRom8WPP/w/L54= go.mau.fi/util v0.8.6/go.mod h1:uNB3UTXFbkpp7xL1M/WvQks90B/L4gvbLpbS0603KOE= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 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= @@ -100,5 +99,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.23.3-0.20250320134109-06f200da0d10 h1:XE2szxSvJVngk+qHqlKO2fiBZwcAp3oYq+9P5jlAm6w= -maunium.net/go/mautrix v0.23.3-0.20250320134109-06f200da0d10/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= +maunium.net/go/mautrix v0.23.3 h1:U+fzdcLhFKLUm5gf2+Q0hEUqWkwDMRfvE+paUH9ogSk= +maunium.net/go/mautrix v0.23.3/go.mod h1:LX+3evXVKSvh/b43BVC3rkvN2qV7b0bkIV4fY7Snn/4= From 6e62a6835fd27767e4c26497e38ea1064a706778 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 24 Apr 2025 19:16:23 +0300 Subject: [PATCH 457/718] signalmeow/protobuf: rebuild without embed-raw --- .../protobuf/ContactDiscovery.pb.go | 30 +- .../protobuf/ContactDiscovery.pb.raw | 15 - pkg/signalmeow/protobuf/DeviceName.pb.go | 24 +- pkg/signalmeow/protobuf/DeviceName.pb.raw | 9 - pkg/signalmeow/protobuf/Groups.pb.go | 213 +++- pkg/signalmeow/protobuf/Groups.pb.raw | Bin 7339 -> 0 bytes pkg/signalmeow/protobuf/Provisioning.pb.go | 47 +- pkg/signalmeow/protobuf/Provisioning.pb.raw | Bin 957 -> 0 bytes pkg/signalmeow/protobuf/SignalService.pb.go | 668 +++++++++- pkg/signalmeow/protobuf/SignalService.pb.raw | Bin 19700 -> 0 bytes .../protobuf/StickerResources.pb.go | 27 +- .../protobuf/StickerResources.pb.raw | 12 - pkg/signalmeow/protobuf/StorageService.pb.go | 278 ++++- pkg/signalmeow/protobuf/StorageService.pb.raw | Bin 7611 -> 0 bytes .../protobuf/UnidentifiedDelivery.pb.go | 58 +- .../protobuf/UnidentifiedDelivery.pb.raw | Bin 1172 -> 0 bytes .../protobuf/WebSocketResources.pb.go | 38 +- .../protobuf/WebSocketResources.pb.raw | Bin 645 -> 0 bytes pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 1083 ++++++++++++++++- pkg/signalmeow/protobuf/build-protos.sh | 2 - 20 files changed, 2376 insertions(+), 128 deletions(-) delete mode 100644 pkg/signalmeow/protobuf/ContactDiscovery.pb.raw delete mode 100644 pkg/signalmeow/protobuf/DeviceName.pb.raw delete mode 100644 pkg/signalmeow/protobuf/Groups.pb.raw delete mode 100644 pkg/signalmeow/protobuf/Provisioning.pb.raw delete mode 100644 pkg/signalmeow/protobuf/SignalService.pb.raw delete mode 100644 pkg/signalmeow/protobuf/StickerResources.pb.raw delete mode 100644 pkg/signalmeow/protobuf/StorageService.pb.raw delete mode 100644 pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.raw delete mode 100644 pkg/signalmeow/protobuf/WebSocketResources.pb.raw diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 020c413..97ac6b4 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: ContactDiscovery.proto @@ -14,10 +14,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -206,17 +205,31 @@ func (x *CDSClientResponse) GetToken() []byte { var File_ContactDiscovery_proto protoreflect.FileDescriptor -//go:embed ContactDiscovery.pb.raw -var file_ContactDiscovery_proto_rawDesc []byte +const file_ContactDiscovery_proto_rawDesc = "" + + "\n" + + "\x16ContactDiscovery.proto\x12\rsignalservice\"\x9e\x02\n" + + "\x10CDSClientRequest\x12\"\n" + + "\raci_uak_pairs\x18\x01 \x01(\fR\vaciUakPairs\x12\x1d\n" + + "\n" + + "prev_e164s\x18\x02 \x01(\fR\tprevE164s\x12\x1b\n" + + "\tnew_e164s\x18\x03 \x01(\fR\bnewE164s\x12#\n" + + "\rdiscard_e164s\x18\x04 \x01(\fR\fdiscardE164s\x12\x19\n" + + "\bhas_more\x18\x05 \x01(\bR\ahasMore\x12\x14\n" + + "\x05token\x18\x06 \x01(\fR\x05token\x12\x1b\n" + + "\ttoken_ack\x18\a \x01(\bR\btokenAck\x127\n" + + "\x18return_acis_without_uaks\x18\b \x01(\bR\x15returnAcisWithoutUaks\"Z\n" + + "\x11CDSClientResponse\x12/\n" + + "\x14e164_pni_aci_triples\x18\x01 \x01(\fR\x11e164PniAciTriples\x12\x14\n" + + "\x05token\x18\x03 \x01(\fR\x05token" var ( file_ContactDiscovery_proto_rawDescOnce sync.Once - file_ContactDiscovery_proto_rawDescData = file_ContactDiscovery_proto_rawDesc + file_ContactDiscovery_proto_rawDescData []byte ) func file_ContactDiscovery_proto_rawDescGZIP() []byte { file_ContactDiscovery_proto_rawDescOnce.Do(func() { - file_ContactDiscovery_proto_rawDescData = protoimpl.X.CompressGZIP(file_ContactDiscovery_proto_rawDescData) + file_ContactDiscovery_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ContactDiscovery_proto_rawDesc), len(file_ContactDiscovery_proto_rawDesc))) }) return file_ContactDiscovery_proto_rawDescData } @@ -243,7 +256,7 @@ func file_ContactDiscovery_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_ContactDiscovery_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_ContactDiscovery_proto_rawDesc), len(file_ContactDiscovery_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -254,7 +267,6 @@ func file_ContactDiscovery_proto_init() { MessageInfos: file_ContactDiscovery_proto_msgTypes, }.Build() File_ContactDiscovery_proto = out.File - file_ContactDiscovery_proto_rawDesc = nil file_ContactDiscovery_proto_goTypes = nil file_ContactDiscovery_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.raw b/pkg/signalmeow/protobuf/ContactDiscovery.pb.raw deleted file mode 100644 index c98f8c4..0000000 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.raw +++ /dev/null @@ -1,15 +0,0 @@ - -ContactDiscovery.proto signalservice"ž -CDSClientRequest" - aci_uak_pairs ( R aciUakPairs - -prev_e164s ( R prevE164s - new_e164s ( RnewE164s# - discard_e164s ( R discardE164s -has_more (RhasMore -token ( Rtoken - token_ack (RtokenAck7 -return_acis_without_uaks (RreturnAcisWithoutUaks"Z -CDSClientResponse/ -e164_pni_aci_triples ( Re164PniAciTriples -token ( Rtoken \ No newline at end of file diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index dbc3df8..e83e374 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: DeviceName.proto @@ -14,10 +14,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -87,17 +86,25 @@ func (x *DeviceName) GetCiphertext() []byte { var File_DeviceName_proto protoreflect.FileDescriptor -//go:embed DeviceName.pb.raw -var file_DeviceName_proto_rawDesc []byte +const file_DeviceName_proto_rawDesc = "" + + "\n" + + "\x10DeviceName.proto\x12\rsignalservice\"x\n" + + "\n" + + "DeviceName\x12(\n" + + "\x0fephemeralPublic\x18\x01 \x01(\fR\x0fephemeralPublic\x12 \n" + + "\vsyntheticIv\x18\x02 \x01(\fR\vsyntheticIv\x12\x1e\n" + + "\n" + + "ciphertext\x18\x03 \x01(\fR\n" + + "ciphertext" var ( file_DeviceName_proto_rawDescOnce sync.Once - file_DeviceName_proto_rawDescData = file_DeviceName_proto_rawDesc + file_DeviceName_proto_rawDescData []byte ) func file_DeviceName_proto_rawDescGZIP() []byte { file_DeviceName_proto_rawDescOnce.Do(func() { - file_DeviceName_proto_rawDescData = protoimpl.X.CompressGZIP(file_DeviceName_proto_rawDescData) + file_DeviceName_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_DeviceName_proto_rawDesc), len(file_DeviceName_proto_rawDesc))) }) return file_DeviceName_proto_rawDescData } @@ -123,7 +130,7 @@ func file_DeviceName_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_DeviceName_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_DeviceName_proto_rawDesc), len(file_DeviceName_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -134,7 +141,6 @@ func file_DeviceName_proto_init() { MessageInfos: file_DeviceName_proto_msgTypes, }.Build() File_DeviceName_proto = out.File - file_DeviceName_proto_rawDesc = nil file_DeviceName_proto_goTypes = nil file_DeviceName_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.raw b/pkg/signalmeow/protobuf/DeviceName.pb.raw deleted file mode 100644 index b8aca07..0000000 --- a/pkg/signalmeow/protobuf/DeviceName.pb.raw +++ /dev/null @@ -1,9 +0,0 @@ - -DeviceName.proto signalservice"x - -DeviceName( -ephemeralPublic ( RephemeralPublic - syntheticIv ( R syntheticIv - -ciphertext ( R -ciphertext \ No newline at end of file diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 212d5a3..7178760 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: Groups.proto @@ -16,10 +16,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -2609,17 +2608,214 @@ func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetInviteLinkPassword() []by var File_Groups_proto protoreflect.FileDescriptor -//go:embed Groups.pb.raw -var file_Groups_proto_rawDesc []byte +const file_Groups_proto_rawDesc = "" + + "\n" + + "\fGroups.proto\"\xc4\x01\n" + + "\x16AvatarUploadAttributes\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x1e\n" + + "\n" + + "credential\x18\x02 \x01(\tR\n" + + "credential\x12\x10\n" + + "\x03acl\x18\x03 \x01(\tR\x03acl\x12\x1c\n" + + "\talgorithm\x18\x04 \x01(\tR\talgorithm\x12\x12\n" + + "\x04date\x18\x05 \x01(\tR\x04date\x12\x16\n" + + "\x06policy\x18\x06 \x01(\tR\x06policy\x12\x1c\n" + + "\tsignature\x18\a \x01(\tR\tsignature\"\xe7\x01\n" + + "\x06Member\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12 \n" + + "\x04role\x18\x02 \x01(\x0e2\f.Member.RoleR\x04role\x12\x1e\n" + + "\n" + + "profileKey\x18\x03 \x01(\fR\n" + + "profileKey\x12\"\n" + + "\fpresentation\x18\x04 \x01(\fR\fpresentation\x12*\n" + + "\x10joinedAtRevision\x18\x05 \x01(\rR\x10joinedAtRevision\"3\n" + + "\x04Role\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\v\n" + + "\aDEFAULT\x10\x01\x12\x11\n" + + "\rADMINISTRATOR\x10\x02\"t\n" + + "\rPendingMember\x12\x1f\n" + + "\x06member\x18\x01 \x01(\v2\a.MemberR\x06member\x12$\n" + + "\raddedByUserId\x18\x02 \x01(\fR\raddedByUserId\x12\x1c\n" + + "\ttimestamp\x18\x03 \x01(\x04R\ttimestamp\"\x8c\x01\n" + + "\x10RequestingMember\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1e\n" + + "\n" + + "profileKey\x18\x02 \x01(\fR\n" + + "profileKey\x12\"\n" + + "\fpresentation\x18\x03 \x01(\fR\fpresentation\x12\x1c\n" + + "\ttimestamp\x18\x04 \x01(\x04R\ttimestamp\"D\n" + + "\fBannedMember\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\xae\x02\n" + + "\rAccessControl\x12=\n" + + "\n" + + "attributes\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\n" + + "attributes\x127\n" + + "\amembers\x18\x02 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\amembers\x12K\n" + + "\x11addFromInviteLink\x18\x03 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + + "\x0eAccessRequired\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\a\n" + + "\x03ANY\x10\x01\x12\n" + + "\n" + + "\x06MEMBER\x10\x02\x12\x11\n" + + "\rADMINISTRATOR\x10\x03\x12\x11\n" + + "\rUNSATISFIABLE\x10\x04\"\xb4\x04\n" + + "\x05Group\x12\x1c\n" + + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + + "\x05title\x18\x02 \x01(\fR\x05title\x12\x16\n" + + "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12<\n" + + "\x19disappearingMessagesTimer\x18\x04 \x01(\fR\x19disappearingMessagesTimer\x124\n" + + "\raccessControl\x18\x05 \x01(\v2\x0e.AccessControlR\raccessControl\x12\x1a\n" + + "\brevision\x18\x06 \x01(\rR\brevision\x12!\n" + + "\amembers\x18\a \x03(\v2\a.MemberR\amembers\x126\n" + + "\x0ependingMembers\x18\b \x03(\v2\x0e.PendingMemberR\x0ependingMembers\x12?\n" + + "\x11requestingMembers\x18\t \x03(\v2\x11.RequestingMemberR\x11requestingMembers\x12.\n" + + "\x12inviteLinkPassword\x18\n" + + " \x01(\fR\x12inviteLinkPassword\x12 \n" + + "\vdescription\x18\v \x01(\fR\vdescription\x12,\n" + + "\x11announcementsOnly\x18\f \x01(\bR\x11announcementsOnly\x123\n" + + "\rbannedMembers\x18\r \x03(\v2\r.BannedMemberR\rbannedMembers\"\xe6!\n" + + "\vGroupChange\x12\x18\n" + + "\aactions\x18\x01 \x01(\fR\aactions\x12(\n" + + "\x0fserverSignature\x18\x02 \x01(\fR\x0fserverSignature\x12 \n" + + "\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xf0 \n" + + "\aActions\x12(\n" + + "\x0fsourceServiceId\x18\x01 \x01(\fR\x0fsourceServiceId\x12\x18\n" + + "\agroupId\x18\x19 \x01(\fR\agroupId\x12\x1a\n" + + "\brevision\x18\x02 \x01(\rR\brevision\x12D\n" + + "\n" + + "addMembers\x18\x03 \x03(\v2$.GroupChange.Actions.AddMemberActionR\n" + + "addMembers\x12M\n" + + "\rdeleteMembers\x18\x04 \x03(\v2'.GroupChange.Actions.DeleteMemberActionR\rdeleteMembers\x12Y\n" + + "\x11modifyMemberRoles\x18\x05 \x03(\v2+.GroupChange.Actions.ModifyMemberRoleActionR\x11modifyMemberRoles\x12k\n" + + "\x17modifyMemberProfileKeys\x18\x06 \x03(\v21.GroupChange.Actions.ModifyMemberProfileKeyActionR\x17modifyMemberProfileKeys\x12Y\n" + + "\x11addPendingMembers\x18\a \x03(\v2+.GroupChange.Actions.AddPendingMemberActionR\x11addPendingMembers\x12b\n" + + "\x14deletePendingMembers\x18\b \x03(\v2..GroupChange.Actions.DeletePendingMemberActionR\x14deletePendingMembers\x12e\n" + + "\x15promotePendingMembers\x18\t \x03(\v2/.GroupChange.Actions.PromotePendingMemberActionR\x15promotePendingMembers\x12H\n" + + "\vmodifyTitle\x18\n" + + " \x01(\v2&.GroupChange.Actions.ModifyTitleActionR\vmodifyTitle\x12K\n" + + "\fmodifyAvatar\x18\v \x01(\v2'.GroupChange.Actions.ModifyAvatarActionR\fmodifyAvatar\x12\x84\x01\n" + + "\x1fmodifyDisappearingMessagesTimer\x18\f \x01(\v2:.GroupChange.Actions.ModifyDisappearingMessagesTimerActionR\x1fmodifyDisappearingMessagesTimer\x12p\n" + + "\x16modifyAttributesAccess\x18\r \x01(\v28.GroupChange.Actions.ModifyAttributesAccessControlActionR\x16modifyAttributesAccess\x12e\n" + + "\x12modifyMemberAccess\x18\x0e \x01(\v25.GroupChange.Actions.ModifyMembersAccessControlActionR\x12modifyMemberAccess\x12\x85\x01\n" + + "\x1dmodifyAddFromInviteLinkAccess\x18\x0f \x01(\v2?.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlActionR\x1dmodifyAddFromInviteLinkAccess\x12b\n" + + "\x14addRequestingMembers\x18\x10 \x03(\v2..GroupChange.Actions.AddRequestingMemberActionR\x14addRequestingMembers\x12k\n" + + "\x17deleteRequestingMembers\x18\x11 \x03(\v21.GroupChange.Actions.DeleteRequestingMemberActionR\x17deleteRequestingMembers\x12n\n" + + "\x18promoteRequestingMembers\x18\x12 \x03(\v22.GroupChange.Actions.PromoteRequestingMemberActionR\x18promoteRequestingMembers\x12o\n" + + "\x18modifyInviteLinkPassword\x18\x13 \x01(\v23.GroupChange.Actions.ModifyInviteLinkPasswordActionR\x18modifyInviteLinkPassword\x12Z\n" + + "\x11modifyDescription\x18\x14 \x01(\v2,.GroupChange.Actions.ModifyDescriptionActionR\x11modifyDescription\x12l\n" + + "\x17modifyAnnouncementsOnly\x18\x15 \x01(\v22.GroupChange.Actions.ModifyAnnouncementsOnlyActionR\x17modifyAnnouncementsOnly\x12V\n" + + "\x10addBannedMembers\x18\x16 \x03(\v2*.GroupChange.Actions.AddBannedMemberActionR\x10addBannedMembers\x12_\n" + + "\x13deleteBannedMembers\x18\x17 \x03(\v2-.GroupChange.Actions.DeleteBannedMemberActionR\x13deleteBannedMembers\x12\x81\x01\n" + + "\x1bpromotePendingPniAciMembers\x18\x18 \x03(\v2?.GroupChange.Actions.PromotePendingPniAciMemberProfileKeyActionR\x1bpromotePendingPniAciMembers\x1a`\n" + + "\x0fAddMemberAction\x12\x1d\n" + + "\x05added\x18\x01 \x01(\v2\a.MemberR\x05added\x12.\n" + + "\x12joinFromInviteLink\x18\x02 \x01(\bR\x12joinFromInviteLink\x1a:\n" + + "\x12DeleteMemberAction\x12$\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1aR\n" + + "\x16ModifyMemberRoleAction\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12 \n" + + "\x04role\x18\x02 \x01(\x0e2\f.Member.RoleR\x04role\x1a|\n" + + "\x1cModifyMemberProfileKeyAction\x12\"\n" + + "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x17\n" + + "\auser_id\x18\x02 \x01(\fR\x06userId\x12\x1f\n" + + "\vprofile_key\x18\x03 \x01(\fR\n" + + "profileKey\x1a>\n" + + "\x16AddPendingMemberAction\x12$\n" + + "\x05added\x18\x01 \x01(\v2\x0e.PendingMemberR\x05added\x1aA\n" + + "\x19DeletePendingMemberAction\x12$\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1az\n" + + "\x1aPromotePendingMemberAction\x12\"\n" + + "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x17\n" + + "\auser_id\x18\x02 \x01(\fR\x06userId\x12\x1f\n" + + "\vprofile_key\x18\x03 \x01(\fR\n" + + "profileKey\x1a\x9a\x01\n" + + "*PromotePendingPniAciMemberProfileKeyAction\x12\"\n" + + "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x16\n" + + "\x06userId\x18\x02 \x01(\fR\x06userId\x12\x10\n" + + "\x03pni\x18\x03 \x01(\fR\x03pni\x12\x1e\n" + + "\n" + + "profileKey\x18\x04 \x01(\fR\n" + + "profileKey\x1aD\n" + + "\x19AddRequestingMemberAction\x12'\n" + + "\x05added\x18\x01 \x01(\v2\x11.RequestingMemberR\x05added\x1aD\n" + + "\x1cDeleteRequestingMemberAction\x12$\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1aY\n" + + "\x1dPromoteRequestingMemberAction\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12 \n" + + "\x04role\x18\x02 \x01(\x0e2\f.Member.RoleR\x04role\x1a<\n" + + "\x15AddBannedMemberAction\x12#\n" + + "\x05added\x18\x01 \x01(\v2\r.BannedMemberR\x05added\x1a@\n" + + "\x18DeleteBannedMemberAction\x12$\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1a)\n" + + "\x11ModifyTitleAction\x12\x14\n" + + "\x05title\x18\x01 \x01(\fR\x05title\x1a;\n" + + "\x17ModifyDescriptionAction\x12 \n" + + "\vdescription\x18\x01 \x01(\fR\vdescription\x1a,\n" + + "\x12ModifyAvatarAction\x12\x16\n" + + "\x06avatar\x18\x01 \x01(\tR\x06avatar\x1a=\n" + + "%ModifyDisappearingMessagesTimerAction\x12\x14\n" + + "\x05timer\x18\x01 \x01(\fR\x05timer\x1ap\n" + + "#ModifyAttributesAccessControlAction\x12I\n" + + "\x10attributesAccess\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x10attributesAccess\x1ag\n" + + " ModifyMembersAccessControlAction\x12C\n" + + "\rmembersAccess\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\rmembersAccess\x1a\x85\x01\n" + + "*ModifyAddFromInviteLinkAccessControlAction\x12W\n" + + "\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1aP\n" + + "\x1eModifyInviteLinkPasswordAction\x12.\n" + + "\x12inviteLinkPassword\x18\x01 \x01(\fR\x12inviteLinkPassword\x1aM\n" + + "\x1dModifyAnnouncementsOnlyAction\x12,\n" + + "\x11announcementsOnly\x18\x01 \x01(\bR\x11announcementsOnly\"s\n" + + "\rGroupResponse\x12\x1c\n" + + "\x05group\x18\x01 \x01(\v2\x06.GroupR\x05group\x12D\n" + + "\x1dgroupSendEndorsementsResponse\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\"\x84\x02\n" + + "\fGroupChanges\x12B\n" + + "\fgroupChanges\x18\x01 \x03(\v2\x1e.GroupChanges.GroupChangeStateR\fgroupChanges\x12D\n" + + "\x1dgroupSendEndorsementsResponse\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\x1aj\n" + + "\x10GroupChangeState\x12.\n" + + "\vgroupChange\x18\x01 \x01(\v2\f.GroupChangeR\vgroupChange\x12&\n" + + "\n" + + "groupState\x18\x02 \x01(\v2\x06.GroupR\n" + + "groupState\"\x8b\x01\n" + + "\x13GroupChangeResponse\x12.\n" + + "\vgroupChange\x18\x01 \x01(\v2\f.GroupChangeR\vgroupChange\x12D\n" + + "\x1dgroupSendEndorsementsResponse\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\"\xbb\x01\n" + + "\x12GroupAttributeBlob\x12\x16\n" + + "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + + "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + + "\x1cdisappearingMessagesDuration\x18\x03 \x01(\rH\x00R\x1cdisappearingMessagesDuration\x12\"\n" + + "\vdescription\x18\x04 \x01(\tH\x00R\vdescriptionB\t\n" + + "\acontent\"\xe0\x01\n" + + "\x0fGroupInviteLink\x12L\n" + + "\n" + + "v1Contents\x18\x01 \x01(\v2*.GroupInviteLink.GroupInviteLinkContentsV1H\x00R\n" + + "v1Contents\x1as\n" + + "\x19GroupInviteLinkContentsV1\x12&\n" + + "\x0egroupMasterKey\x18\x01 \x01(\fR\x0egroupMasterKey\x12.\n" + + "\x12inviteLinkPassword\x18\x02 \x01(\fR\x12inviteLinkPasswordB\n" + + "\n" + + "\bcontents\"\xbc\x02\n" + + "\rGroupJoinInfo\x12\x1c\n" + + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + + "\x05title\x18\x02 \x01(\fR\x05title\x12\x16\n" + + "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12 \n" + + "\vmemberCount\x18\x04 \x01(\rR\vmemberCount\x12K\n" + + "\x11addFromInviteLink\x18\x05 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x11addFromInviteLink\x12\x1a\n" + + "\brevision\x18\x06 \x01(\rR\brevision\x122\n" + + "\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\x12 \n" + + "\vdescription\x18\b \x01(\fR\vdescription\"/\n" + + "\x17GroupExternalCredential\x12\x14\n" + + "\x05token\x18\x01 \x01(\tR\x05tokenB+\n" + + "'org.signal.storageservice.protos.groupsP\x01b\x06proto3" var ( file_Groups_proto_rawDescOnce sync.Once - file_Groups_proto_rawDescData = file_Groups_proto_rawDesc + file_Groups_proto_rawDescData []byte ) func file_Groups_proto_rawDescGZIP() []byte { file_Groups_proto_rawDescOnce.Do(func() { - file_Groups_proto_rawDescData = protoimpl.X.CompressGZIP(file_Groups_proto_rawDescData) + file_Groups_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_Groups_proto_rawDesc), len(file_Groups_proto_rawDesc))) }) return file_Groups_proto_rawDescData } @@ -2744,7 +2940,7 @@ func file_Groups_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_Groups_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_Groups_proto_rawDesc), len(file_Groups_proto_rawDesc)), NumEnums: 2, NumMessages: 40, NumExtensions: 0, @@ -2756,7 +2952,6 @@ func file_Groups_proto_init() { MessageInfos: file_Groups_proto_msgTypes, }.Build() File_Groups_proto = out.File - file_Groups_proto_rawDesc = nil file_Groups_proto_goTypes = nil file_Groups_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/Groups.pb.raw b/pkg/signalmeow/protobuf/Groups.pb.raw deleted file mode 100644 index dceda274eece491e05fbb427b8eb4b191fdc755d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7339 zcmb_hOLH5?5jMmJ$Ob@yBZ*vYM2UtSOOX}01m#tZ9S0z&n2|`amZTl|A}@gvv=*?7 z>@1lul}oCeQ}PS)BXY_uIr@kAG<`+(3yKryWlRw#QfKJT2JWK+=?_5(G z#){a|(|l|vqO zgRrOVy#tE_Wx2Aq)F^7pJiW}`g^J(p@^0(mg#01{SN7~h>E9$6aFO_fp|XA68!y!U zT7as@e|v`eW6je%ZTpe5&GI98+V-P$9GN)QaoSLB`5}7wl9*dkK2XulFkUQ7CeK2{S=B63Zb*?65f=WJ%Ke0(c?H8?1kq+ z!k-4=YZZh`)lc%(egi9X;`EGmf)!z|dGH*Q3$SE%_glM|Rg;M}CznnRj+)1NN00ZK zt*5)y`Px6`VL^2dnJvS!Q!Gr!Ag3WFq z{Na%Mu}Ur>{2mv_n2oWnvFQZtN0{Aa3{|z28Y_0xFxyQc=E72(mZ$796>s#--X2G> zxIK5zsHjoAegZ2)vj~N=q$pSFR&9D2D)tGi#hEG+&az@%t7q%Wo1|rRV8JLu4t*hh z7sXu%Q~+{zu<4b$Ty)}Ks5(|j5t>Wv0j6FUMrUD%53sX|XJP-sDI?vIH@U$cLFLpa zJmFN-;VX5s96g(+_TAf1QfagE$`5;-IZ*UF@;pMPPWs92!78?>a~>a!T0OOo?6Neh zqonN)qs}XpQ5DZza{sdp#U`mya-*}j!;esU(BY%YVO7}6@@zeMKO)7Za#s3jrHnk3 znKEtc8(rOu1Rh3a&AWBOX3R!qaJ`w5(E_%QbV0CvsC0RsC!D&Pz~q;L?&b<=8 z&CQ;}+92u%FE2=(ylMnihZOmKuE_liwH7-mg}sIiQ}p5J))aVaO9c-vRWRn!YNkn) zcA%52!V)+EOt%AlY*D9nOh{p;aDzN<(Wlj1&ozP^Z!u^Exw06Cn>bYrqJ&#KY2AO2 zs|39>!J)O}OJkoxi9&L$Ir`H?^D-4|2U%K`UVe;XQe#2_rvvjy$!YcYB zZBlYbVOy|({^az4HpX9Cl{2V(;@T}kJ$RP9oE`T=VB{7{3BF3nxn2D#rB{T#=z6eD zNkP1Fh9RT=|7X7YN4RCm%(`phnNJ6^pQjs8lpw>4psNfYqYQVTgb|hge<8t>2@t{k z1>!Ba^9jDwEw^Xi613?yVUxURO%vKFS99tgz_qi-3QQK|c(dmJtpN9J<+D=vO0gKj z5cF0^0Ut!8hGC#XAb(~69*HVg0FT>-O^i)`>t=WD@Z`MLbcEV)iy|~d(A9$U9JaKd zridAvO%Y1Xz7*$jKZ2WR=46v%@7N}0UUk~MUxGvC9WB9&SHEmGUiWRycv5C=1@xvX$ zJ6c(0!nDRkwug6BhTv*A(*&E_gKg4CN+A(GGJf2Cw-UA>f z$x|wijQwcr)c#U{>xQz_hySy_Hxrb97J#YKj2@4zesqexM+2iWg_b{kD}_d#5j3i< zFx*JNQM^p@z|r7FOwjl4x1jY$5a%?@pnr9*+bN3@Vf#wGYZC}81j{##NhUQk??qoFlSb$R67j; zIn~|*Ske}X+P@I{S10&2jWa zs4nv8H4jyeEMtbtkJkHeH;Q|8^^aY@E|Msg7(b!0^jD;)tDuX+!s#NOF^L}i7t^s? A+yDRo diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 97c5adc..e2fbf7c 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: Provisioning.proto @@ -16,10 +16,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -348,17 +347,48 @@ func (x *ProvisionMessage) GetMediaRootBackupKey() []byte { var File_Provisioning_proto protoreflect.FileDescriptor -//go:embed Provisioning.pb.raw -var file_Provisioning_proto_rawDesc []byte +const file_Provisioning_proto_rawDesc = "" + + "\n" + + "\x12Provisioning.proto\x12\rsignalservice\"/\n" + + "\x13ProvisioningAddress\x12\x18\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\"E\n" + + "\x11ProvisionEnvelope\x12\x1c\n" + + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x12\n" + + "\x04body\x18\x02 \x01(\fR\x04body\"\x90\x05\n" + + "\x10ProvisionMessage\x122\n" + + "\x14aciIdentityKeyPublic\x18\x01 \x01(\fR\x14aciIdentityKeyPublic\x124\n" + + "\x15aciIdentityKeyPrivate\x18\x02 \x01(\fR\x15aciIdentityKeyPrivate\x122\n" + + "\x14pniIdentityKeyPublic\x18\v \x01(\fR\x14pniIdentityKeyPublic\x124\n" + + "\x15pniIdentityKeyPrivate\x18\f \x01(\fR\x15pniIdentityKeyPrivate\x12\x10\n" + + "\x03aci\x18\b \x01(\tR\x03aci\x12\x10\n" + + "\x03pni\x18\n" + + " \x01(\tR\x03pni\x12\x16\n" + + "\x06number\x18\x03 \x01(\tR\x06number\x12*\n" + + "\x10provisioningCode\x18\x04 \x01(\tR\x10provisioningCode\x12\x1c\n" + + "\tuserAgent\x18\x05 \x01(\tR\tuserAgent\x12\x1e\n" + + "\n" + + "profileKey\x18\x06 \x01(\fR\n" + + "profileKey\x12\"\n" + + "\freadReceipts\x18\a \x01(\bR\freadReceipts\x120\n" + + "\x13provisioningVersion\x18\t \x01(\rR\x13provisioningVersion\x12\x1c\n" + + "\tmasterKey\x18\r \x01(\fR\tmasterKey\x12.\n" + + "\x12ephemeralBackupKey\x18\x0e \x01(\fR\x12ephemeralBackupKey\x12.\n" + + "\x12accountEntropyPool\x18\x0f \x01(\tR\x12accountEntropyPool\x12.\n" + + "\x12mediaRootBackupKey\x18\x10 \x01(\fR\x12mediaRootBackupKey*G\n" + + "\x13ProvisioningVersion\x12\v\n" + + "\aINITIAL\x10\x00\x12\x12\n" + + "\x0eTABLET_SUPPORT\x10\x01\x12\v\n" + + "\aCURRENT\x10\x01\x1a\x02\x10\x01BD\n" + + ".org.whispersystems.signalservice.internal.pushB\x12ProvisioningProtos" var ( file_Provisioning_proto_rawDescOnce sync.Once - file_Provisioning_proto_rawDescData = file_Provisioning_proto_rawDesc + file_Provisioning_proto_rawDescData []byte ) func file_Provisioning_proto_rawDescGZIP() []byte { file_Provisioning_proto_rawDescOnce.Do(func() { - file_Provisioning_proto_rawDescData = protoimpl.X.CompressGZIP(file_Provisioning_proto_rawDescData) + file_Provisioning_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_Provisioning_proto_rawDesc), len(file_Provisioning_proto_rawDesc))) }) return file_Provisioning_proto_rawDescData } @@ -388,7 +418,7 @@ func file_Provisioning_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_Provisioning_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_Provisioning_proto_rawDesc), len(file_Provisioning_proto_rawDesc)), NumEnums: 1, NumMessages: 3, NumExtensions: 0, @@ -400,7 +430,6 @@ func file_Provisioning_proto_init() { MessageInfos: file_Provisioning_proto_msgTypes, }.Build() File_Provisioning_proto = out.File - file_Provisioning_proto_rawDesc = nil file_Provisioning_proto_goTypes = nil file_Provisioning_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.raw b/pkg/signalmeow/protobuf/Provisioning.pb.raw deleted file mode 100644 index 874538c7f1185b2aa7736feabcfdb3e4125f025d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 957 zcmZuw+iuf95GB2(**eAD0$L%2P@Yg93_|^Zq*y4T6l+O&MH_oaR<*sWT|3Bs!6!4j zF}bvUn?2{unemK=(8Q>fv{IF_TtwQaO3|T}i&Eqk%u1#(`amvsMdK_pU@c{&FV-RJ zz3aUn@c++IOfEJFak+wAX`pY&K-cqJreC4)2?5^%l#-*l${KcnP67Av=9V8JnQyU^bCn+Dw3Py% z)J@Wm9Aba$)KAfc4nZGA)(D356*(#EVh)BKda!-bD-z<;HXFQA8L%U-c!IkX)VS2~ z0*A+ry=V*2w}hb6Z<&MJ&!bT%E|hR^U\n" + + "\tthumbnail\x18\x03 \x01(\v2 .signalservice.AttachmentPointerR\tthumbnail\"\"\n" + + "\x04Type\x12\n" + + "\n" + + "\x06NORMAL\x10\x00\x12\x0e\n" + + "\n" + + "GIFT_BADGE\x10\x01J\x04\b\x02\x10\x03\x1a\xbf\n" + + "\n" + + "\aContact\x12;\n" + + "\x04name\x18\x01 \x01(\v2'.signalservice.DataMessage.Contact.NameR\x04name\x12@\n" + + "\x06number\x18\x03 \x03(\v2(.signalservice.DataMessage.Contact.PhoneR\x06number\x12>\n" + + "\x05email\x18\x04 \x03(\v2(.signalservice.DataMessage.Contact.EmailR\x05email\x12J\n" + + "\aaddress\x18\x05 \x03(\v20.signalservice.DataMessage.Contact.PostalAddressR\aaddress\x12A\n" + + "\x06avatar\x18\x06 \x01(\v2).signalservice.DataMessage.Contact.AvatarR\x06avatar\x12\"\n" + + "\forganization\x18\a \x01(\tR\forganization\x1a\xb6\x01\n" + + "\x04Name\x12\x1c\n" + + "\tgivenName\x18\x01 \x01(\tR\tgivenName\x12\x1e\n" + + "\n" + + "familyName\x18\x02 \x01(\tR\n" + + "familyName\x12\x16\n" + + "\x06prefix\x18\x03 \x01(\tR\x06prefix\x12\x16\n" + + "\x06suffix\x18\x04 \x01(\tR\x06suffix\x12\x1e\n" + + "\n" + + "middleName\x18\x05 \x01(\tR\n" + + "middleName\x12\x1a\n" + + "\bnickname\x18\a \x01(\tR\bnicknameJ\x04\b\x06\x10\a\x1a\xaa\x01\n" + + "\x05Phone\x12\x14\n" + + "\x05value\x18\x01 \x01(\tR\x05value\x12A\n" + + "\x04type\x18\x02 \x01(\x0e2-.signalservice.DataMessage.Contact.Phone.TypeR\x04type\x12\x14\n" + + "\x05label\x18\x03 \x01(\tR\x05label\"2\n" + + "\x04Type\x12\b\n" + + "\x04HOME\x10\x01\x12\n" + + "\n" + + "\x06MOBILE\x10\x02\x12\b\n" + + "\x04WORK\x10\x03\x12\n" + + "\n" + + "\x06CUSTOM\x10\x04\x1a\xaa\x01\n" + + "\x05Email\x12\x14\n" + + "\x05value\x18\x01 \x01(\tR\x05value\x12A\n" + + "\x04type\x18\x02 \x01(\x0e2-.signalservice.DataMessage.Contact.Email.TypeR\x04type\x12\x14\n" + + "\x05label\x18\x03 \x01(\tR\x05label\"2\n" + + "\x04Type\x12\b\n" + + "\x04HOME\x10\x01\x12\n" + + "\n" + + "\x06MOBILE\x10\x02\x12\b\n" + + "\x04WORK\x10\x03\x12\n" + + "\n" + + "\x06CUSTOM\x10\x04\x1a\xcc\x02\n" + + "\rPostalAddress\x12I\n" + + "\x04type\x18\x01 \x01(\x0e25.signalservice.DataMessage.Contact.PostalAddress.TypeR\x04type\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\x12\x16\n" + + "\x06street\x18\x03 \x01(\tR\x06street\x12\x14\n" + + "\x05pobox\x18\x04 \x01(\tR\x05pobox\x12\"\n" + + "\fneighborhood\x18\x05 \x01(\tR\fneighborhood\x12\x12\n" + + "\x04city\x18\x06 \x01(\tR\x04city\x12\x16\n" + + "\x06region\x18\a \x01(\tR\x06region\x12\x1a\n" + + "\bpostcode\x18\b \x01(\tR\bpostcode\x12\x18\n" + + "\acountry\x18\t \x01(\tR\acountry\"&\n" + + "\x04Type\x12\b\n" + + "\x04HOME\x10\x01\x12\b\n" + + "\x04WORK\x10\x02\x12\n" + + "\n" + + "\x06CUSTOM\x10\x03\x1a`\n" + + "\x06Avatar\x128\n" + + "\x06avatar\x18\x01 \x01(\v2 .signalservice.AttachmentPointerR\x06avatar\x12\x1c\n" + + "\tisProfile\x18\x02 \x01(\bR\tisProfile\x1a\xa5\x01\n" + + "\aSticker\x12\x16\n" + + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + + "\apackKey\x18\x02 \x01(\fR\apackKey\x12\x1c\n" + + "\tstickerId\x18\x03 \x01(\rR\tstickerId\x124\n" + + "\x04data\x18\x04 \x01(\v2 .signalservice.AttachmentPointerR\x04data\x12\x14\n" + + "\x05emoji\x18\x05 \x01(\tR\x05emoji\x1a\x9a\x01\n" + + "\bReaction\x12\x14\n" + + "\x05emoji\x18\x01 \x01(\tR\x05emoji\x12\x16\n" + + "\x06remove\x18\x02 \x01(\bR\x06remove\x12(\n" + + "\x0ftargetAuthorAci\x18\x04 \x01(\tR\x0ftargetAuthorAci\x120\n" + + "\x13targetSentTimestamp\x18\x05 \x01(\x04R\x13targetSentTimestampJ\x04\b\x03\x10\x04\x1a:\n" + + "\x06Delete\x120\n" + + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x1a'\n" + + "\x0fGroupCallUpdate\x12\x14\n" + + "\x05eraId\x18\x01 \x01(\tR\x05eraId\x1aR\n" + + "\fStoryContext\x12\x1c\n" + + "\tauthorAci\x18\x01 \x01(\tR\tauthorAci\x12$\n" + + "\rsentTimestamp\x18\x02 \x01(\x04R\rsentTimestamp\x1aQ\n" + + "\tGiftBadge\x12D\n" + + "\x1dreceiptCredentialPresentation\x18\x01 \x01(\fR\x1dreceiptCredentialPresentation\"Z\n" + + "\x05Flags\x12\x0f\n" + + "\vEND_SESSION\x10\x01\x12\x1b\n" + + "\x17EXPIRATION_TIMER_UPDATE\x10\x02\x12\x16\n" + + "\x12PROFILE_KEY_UPDATE\x10\x04\x12\v\n" + + "\aFORWARD\x10\b\"\xb0\x01\n" + + "\x0fProtocolVersion\x12\v\n" + + "\aINITIAL\x10\x00\x12\x12\n" + + "\x0eMESSAGE_TIMERS\x10\x01\x12\r\n" + + "\tVIEW_ONCE\x10\x02\x12\x13\n" + + "\x0fVIEW_ONCE_VIDEO\x10\x03\x12\r\n" + + "\tREACTIONS\x10\x04\x12\x1c\n" + + "\x18CDN_SELECTOR_ATTACHMENTS\x10\x05\x12\f\n" + + "\bMENTIONS\x10\x06\x12\f\n" + + "\bPAYMENTS\x10\a\x12\v\n" + + "\aCURRENT\x10\a\x1a\x02\x10\x01J\x04\b\x03\x10\x04\"'\n" + + "\vNullMessage\x12\x18\n" + + "\apadding\x18\x01 \x01(\fR\apadding\"\x92\x01\n" + + "\x0eReceiptMessage\x126\n" + + "\x04type\x18\x01 \x01(\x0e2\".signalservice.ReceiptMessage.TypeR\x04type\x12\x1c\n" + + "\ttimestamp\x18\x02 \x03(\x04R\ttimestamp\"*\n" + + "\x04Type\x12\f\n" + + "\bDELIVERY\x10\x00\x12\b\n" + + "\x04READ\x10\x01\x12\n" + + "\n" + + "\x06VIEWED\x10\x02\"\xa8\x01\n" + + "\rTypingMessage\x12\x1c\n" + + "\ttimestamp\x18\x01 \x01(\x04R\ttimestamp\x12;\n" + + "\x06action\x18\x02 \x01(\x0e2#.signalservice.TypingMessage.ActionR\x06action\x12\x18\n" + + "\agroupId\x18\x03 \x01(\fR\agroupId\"\"\n" + + "\x06Action\x12\v\n" + + "\aSTARTED\x10\x00\x12\v\n" + + "\aSTOPPED\x10\x01\"\xe6\x02\n" + + "\fStoryMessage\x12\x1e\n" + + "\n" + + "profileKey\x18\x01 \x01(\fR\n" + + "profileKey\x123\n" + + "\x05group\x18\x02 \x01(\v2\x1d.signalservice.GroupContextV2R\x05group\x12J\n" + + "\x0efileAttachment\x18\x03 \x01(\v2 .signalservice.AttachmentPointerH\x00R\x0efileAttachment\x12G\n" + + "\x0etextAttachment\x18\x04 \x01(\v2\x1d.signalservice.TextAttachmentH\x00R\x0etextAttachment\x12$\n" + + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x128\n" + + "\n" + + "bodyRanges\x18\x06 \x03(\v2\x18.signalservice.BodyRangeR\n" + + "bodyRangesB\f\n" + + "\n" + + "attachment\"\x9f\x01\n" + + "\aPreview\x12\x10\n" + + "\x03url\x18\x01 \x01(\tR\x03url\x12\x14\n" + + "\x05title\x18\x02 \x01(\tR\x05title\x126\n" + + "\x05image\x18\x03 \x01(\v2 .signalservice.AttachmentPointerR\x05image\x12 \n" + + "\vdescription\x18\x04 \x01(\tR\vdescription\x12\x12\n" + + "\x04date\x18\x05 \x01(\x04R\x04date\"\xd1\x04\n" + + "\x0eTextAttachment\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x12A\n" + + "\ttextStyle\x18\x02 \x01(\x0e2#.signalservice.TextAttachment.StyleR\ttextStyle\x120\n" + + "\x13textForegroundColor\x18\x03 \x01(\rR\x13textForegroundColor\x120\n" + + "\x13textBackgroundColor\x18\x04 \x01(\rR\x13textBackgroundColor\x120\n" + + "\apreview\x18\x05 \x01(\v2\x16.signalservice.PreviewR\apreview\x12D\n" + + "\bgradient\x18\x06 \x01(\v2&.signalservice.TextAttachment.GradientH\x00R\bgradient\x12\x16\n" + + "\x05color\x18\a \x01(\rH\x00R\x05color\x1a\x92\x01\n" + + "\bGradient\x12\x1e\n" + + "\n" + + "startColor\x18\x01 \x01(\rR\n" + + "startColor\x12\x1a\n" + + "\bendColor\x18\x02 \x01(\rR\bendColor\x12\x14\n" + + "\x05angle\x18\x03 \x01(\rR\x05angle\x12\x16\n" + + "\x06colors\x18\x04 \x03(\rR\x06colors\x12\x1c\n" + + "\tpositions\x18\x05 \x03(\x02R\tpositions\"Q\n" + + "\x05Style\x12\v\n" + + "\aDEFAULT\x10\x00\x12\v\n" + + "\aREGULAR\x10\x01\x12\b\n" + + "\x04BOLD\x10\x02\x12\t\n" + + "\x05SERIF\x10\x03\x12\n" + + "\n" + + "\x06SCRIPT\x10\x04\x12\r\n" + + "\tCONDENSED\x10\x05B\f\n" + + "\n" + + "background\"\xe5\x01\n" + + "\bVerified\x12&\n" + + "\x0edestinationAci\x18\x05 \x01(\tR\x0edestinationAci\x12 \n" + + "\videntityKey\x18\x02 \x01(\fR\videntityKey\x123\n" + + "\x05state\x18\x03 \x01(\x0e2\x1d.signalservice.Verified.StateR\x05state\x12 \n" + + "\vnullMessage\x18\x04 \x01(\fR\vnullMessage\"2\n" + + "\x05State\x12\v\n" + + "\aDEFAULT\x10\x00\x12\f\n" + + "\bVERIFIED\x10\x01\x12\x0e\n" + + "\n" + + "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\xf1C\n" + + "\vSyncMessage\x123\n" + + "\x04sent\x18\x01 \x01(\v2\x1f.signalservice.SyncMessage.SentR\x04sent\x12?\n" + + "\bcontacts\x18\x02 \x01(\v2#.signalservice.SyncMessage.ContactsR\bcontacts\x12<\n" + + "\arequest\x18\x04 \x01(\v2\".signalservice.SyncMessage.RequestR\arequest\x123\n" + + "\x04read\x18\x05 \x03(\v2\x1f.signalservice.SyncMessage.ReadR\x04read\x12<\n" + + "\ablocked\x18\x06 \x01(\v2\".signalservice.SyncMessage.BlockedR\ablocked\x123\n" + + "\bverified\x18\a \x01(\v2\x17.signalservice.VerifiedR\bverified\x12N\n" + + "\rconfiguration\x18\t \x01(\v2(.signalservice.SyncMessage.ConfigurationR\rconfiguration\x12\x18\n" + + "\apadding\x18\b \x01(\fR\apadding\x12c\n" + + "\x14stickerPackOperation\x18\n" + + " \x03(\v2/.signalservice.SyncMessage.StickerPackOperationR\x14stickerPackOperation\x12K\n" + + "\fviewOnceOpen\x18\v \x01(\v2'.signalservice.SyncMessage.ViewOnceOpenR\fviewOnceOpen\x12H\n" + + "\vfetchLatest\x18\f \x01(\v2&.signalservice.SyncMessage.FetchLatestR\vfetchLatest\x123\n" + + "\x04keys\x18\r \x01(\v2\x1f.signalservice.SyncMessage.KeysR\x04keys\x12i\n" + + "\x16messageRequestResponse\x18\x0e \x01(\v21.signalservice.SyncMessage.MessageRequestResponseR\x16messageRequestResponse\x12T\n" + + "\x0foutgoingPayment\x18\x0f \x01(\v2*.signalservice.SyncMessage.OutgoingPaymentR\x0foutgoingPayment\x129\n" + + "\x06viewed\x18\x10 \x03(\v2!.signalservice.SyncMessage.ViewedR\x06viewed\x12T\n" + + "\x0fpniChangeNumber\x18\x12 \x01(\v2*.signalservice.SyncMessage.PniChangeNumberR\x0fpniChangeNumber\x12B\n" + + "\tcallEvent\x18\x13 \x01(\v2$.signalservice.SyncMessage.CallEventR\tcallEvent\x12Q\n" + + "\x0ecallLinkUpdate\x18\x14 \x01(\v2).signalservice.SyncMessage.CallLinkUpdateR\x0ecallLinkUpdate\x12K\n" + + "\fcallLogEvent\x18\x15 \x01(\v2'.signalservice.SyncMessage.CallLogEventR\fcallLogEvent\x12H\n" + + "\vdeleteForMe\x18\x16 \x01(\v2&.signalservice.SyncMessage.DeleteForMeR\vdeleteForMe\x12W\n" + + "\x10deviceNameChange\x18\x17 \x01(\v2+.signalservice.SyncMessage.DeviceNameChangeR\x10deviceNameChange\x12r\n" + + "\x19attachmentBackfillRequest\x18\x18 \x01(\v24.signalservice.SyncMessage.AttachmentBackfillRequestR\x19attachmentBackfillRequest\x12u\n" + + "\x1aattachmentBackfillResponse\x18\x19 \x01(\v25.signalservice.SyncMessage.AttachmentBackfillResponseR\x1aattachmentBackfillResponse\x1a\xfc\a\n" + + "\x04Sent\x12(\n" + + "\x0fdestinationE164\x18\x01 \x01(\tR\x0fdestinationE164\x122\n" + + "\x14destinationServiceId\x18\a \x01(\tR\x14destinationServiceId\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x124\n" + + "\amessage\x18\x03 \x01(\v2\x1a.signalservice.DataMessageR\amessage\x12:\n" + + "\x18expirationStartTimestamp\x18\x04 \x01(\x04R\x18expirationStartTimestamp\x12j\n" + + "\x12unidentifiedStatus\x18\x05 \x03(\v2:.signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatusR\x12unidentifiedStatus\x123\n" + + "\x11isRecipientUpdate\x18\x06 \x01(\b:\x05falseR\x11isRecipientUpdate\x12?\n" + + "\fstoryMessage\x18\b \x01(\v2\x1b.signalservice.StoryMessageR\fstoryMessage\x12m\n" + + "\x16storyMessageRecipients\x18\t \x03(\v25.signalservice.SyncMessage.Sent.StoryMessageRecipientR\x16storyMessageRecipients\x12<\n" + + "\veditMessage\x18\n" + + " \x01(\v2\x1a.signalservice.EditMessageR\veditMessage\x1a\xbe\x01\n" + + "\x1aUnidentifiedDeliveryStatus\x122\n" + + "\x14destinationServiceId\x18\x03 \x01(\tR\x14destinationServiceId\x12\"\n" + + "\funidentified\x18\x02 \x01(\bR\funidentified\x12<\n" + + "\x19destinationPniIdentityKey\x18\x05 \x01(\fR\x19destinationPniIdentityKeyJ\x04\b\x01\x10\x02J\x04\b\x04\x10\x05\x1a\xaf\x01\n" + + "\x15StoryMessageRecipient\x122\n" + + "\x14destinationServiceId\x18\x01 \x01(\tR\x14destinationServiceId\x120\n" + + "\x13distributionListIds\x18\x02 \x03(\tR\x13distributionListIds\x12*\n" + + "\x10isAllowedToReply\x18\x03 \x01(\bR\x10isAllowedToReplyJ\x04\b\x04\x10\x05J\x04\b\v\x10\f\x1ac\n" + + "\bContacts\x124\n" + + "\x04blob\x18\x01 \x01(\v2 .signalservice.AttachmentPointerR\x04blob\x12!\n" + + "\bcomplete\x18\x02 \x01(\b:\x05falseR\bcomplete\x1aS\n" + + "\aBlocked\x12\x18\n" + + "\anumbers\x18\x01 \x03(\tR\anumbers\x12\x12\n" + + "\x04acis\x18\x03 \x03(\tR\x04acis\x12\x1a\n" + + "\bgroupIds\x18\x02 \x03(\fR\bgroupIds\x1a\x9f\x01\n" + + "\aRequest\x12;\n" + + "\x04type\x18\x01 \x01(\x0e2'.signalservice.SyncMessage.Request.TypeR\x04type\"W\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\f\n" + + "\bCONTACTS\x10\x01\x12\v\n" + + "\aBLOCKED\x10\x03\x12\x11\n" + + "\rCONFIGURATION\x10\x04\x12\b\n" + + "\x04KEYS\x10\x05\"\x04\b\x02\x10\x02\"\x04\b\x06\x10\x06\x1aH\n" + + "\x04Read\x12\x1c\n" + + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestampJ\x04\b\x01\x10\x02\x1aJ\n" + + "\x06Viewed\x12\x1c\n" + + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestampJ\x04\b\x01\x10\x02\x1a\x83\x02\n" + + "\rConfiguration\x12\"\n" + + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x12F\n" + + "\x1eunidentifiedDeliveryIndicators\x18\x02 \x01(\bR\x1eunidentifiedDeliveryIndicators\x12*\n" + + "\x10typingIndicators\x18\x03 \x01(\bR\x10typingIndicators\x120\n" + + "\x13provisioningVersion\x18\x05 \x01(\rR\x13provisioningVersion\x12\"\n" + + "\flinkPreviews\x18\x06 \x01(\bR\flinkPreviewsJ\x04\b\x04\x10\x05\x1a\xb3\x01\n" + + "\x14StickerPackOperation\x12\x16\n" + + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + + "\apackKey\x18\x02 \x01(\fR\apackKey\x12H\n" + + "\x04type\x18\x03 \x01(\x0e24.signalservice.SyncMessage.StickerPackOperation.TypeR\x04type\"\x1f\n" + + "\x04Type\x12\v\n" + + "\aINSTALL\x10\x00\x12\n" + + "\n" + + "\x06REMOVE\x10\x01\x1aP\n" + + "\fViewOnceOpen\x12\x1c\n" + + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestampJ\x04\b\x01\x10\x02\x1a\xa5\x01\n" + + "\vFetchLatest\x12?\n" + + "\x04type\x18\x01 \x01(\x0e2+.signalservice.SyncMessage.FetchLatest.TypeR\x04type\"U\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\x11\n" + + "\rLOCAL_PROFILE\x10\x01\x12\x14\n" + + "\x10STORAGE_MANIFEST\x10\x02\x12\x17\n" + + "\x13SUBSCRIPTION_STATUS\x10\x03\x1a\x84\x01\n" + + "\x04Keys\x12\x16\n" + + "\x06master\x18\x02 \x01(\fR\x06master\x12.\n" + + "\x12accountEntropyPool\x18\x03 \x01(\tR\x12accountEntropyPool\x12.\n" + + "\x12mediaRootBackupKey\x18\x04 \x01(\fR\x12mediaRootBackupKeyJ\x04\b\x01\x10\x02\x1aK\n" + + "\vPniIdentity\x12\x1c\n" + + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x1e\n" + + "\n" + + "privateKey\x18\x02 \x01(\fR\n" + + "privateKey\x1a\x8e\x02\n" + + "\x16MessageRequestResponse\x12\x1c\n" + + "\tthreadAci\x18\x02 \x01(\tR\tthreadAci\x12\x18\n" + + "\agroupId\x18\x03 \x01(\fR\agroupId\x12J\n" + + "\x04type\x18\x04 \x01(\x0e26.signalservice.SyncMessage.MessageRequestResponse.TypeR\x04type\"j\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\n" + + "\n" + + "\x06ACCEPT\x10\x01\x12\n" + + "\n" + + "\x06DELETE\x10\x02\x12\t\n" + + "\x05BLOCK\x10\x03\x12\x14\n" + + "\x10BLOCK_AND_DELETE\x10\x04\x12\b\n" + + "\x04SPAM\x10\x05\x12\x12\n" + + "\x0eBLOCK_AND_SPAM\x10\x06J\x04\b\x01\x10\x02\x1a\x96\x04\n" + + "\x0fOutgoingPayment\x12.\n" + + "\x12recipientServiceId\x18\x01 \x01(\tR\x12recipientServiceId\x12\x12\n" + + "\x04note\x18\x02 \x01(\tR\x04note\x12W\n" + + "\n" + + "mobileCoin\x18\x03 \x01(\v25.signalservice.SyncMessage.OutgoingPayment.MobileCoinH\x00R\n" + + "mobileCoin\x1a\xcc\x02\n" + + "\n" + + "MobileCoin\x12*\n" + + "\x10recipientAddress\x18\x01 \x01(\fR\x10recipientAddress\x12$\n" + + "\ramountPicoMob\x18\x02 \x01(\x04R\ramountPicoMob\x12\x1e\n" + + "\n" + + "feePicoMob\x18\x03 \x01(\x04R\n" + + "feePicoMob\x12\x18\n" + + "\areceipt\x18\x04 \x01(\fR\areceipt\x122\n" + + "\x14ledgerBlockTimestamp\x18\x05 \x01(\x04R\x14ledgerBlockTimestamp\x12*\n" + + "\x10ledgerBlockIndex\x18\x06 \x01(\x04R\x10ledgerBlockIndex\x12&\n" + + "\x0espentKeyImages\x18\a \x03(\fR\x0espentKeyImages\x12*\n" + + "\x10outputPublicKeys\x18\b \x03(\fR\x10outputPublicKeysB\x17\n" + + "\x15attachment_identifier\x1a\xd7\x01\n" + + "\x0fPniChangeNumber\x12(\n" + + "\x0fidentityKeyPair\x18\x01 \x01(\fR\x0fidentityKeyPair\x12\"\n" + + "\fsignedPreKey\x18\x02 \x01(\fR\fsignedPreKey\x124\n" + + "\x15lastResortKyberPreKey\x18\x05 \x01(\fR\x15lastResortKyberPreKey\x12&\n" + + "\x0eregistrationId\x18\x03 \x01(\rR\x0eregistrationId\x12\x18\n" + + "\anewE164\x18\x04 \x01(\tR\anewE164\x1a\xa9\x04\n" + + "\tCallEvent\x12&\n" + + "\x0econversationId\x18\x01 \x01(\fR\x0econversationId\x12\x16\n" + + "\x06callId\x18\x02 \x01(\x04R\x06callId\x12\x1c\n" + + "\ttimestamp\x18\x03 \x01(\x04R\ttimestamp\x12=\n" + + "\x04type\x18\x04 \x01(\x0e2).signalservice.SyncMessage.CallEvent.TypeR\x04type\x12L\n" + + "\tdirection\x18\x05 \x01(\x0e2..signalservice.SyncMessage.CallEvent.DirectionR\tdirection\x12@\n" + + "\x05event\x18\x06 \x01(\x0e2*.signalservice.SyncMessage.CallEvent.EventR\x05event\"Y\n" + + "\x04Type\x12\x10\n" + + "\fUNKNOWN_TYPE\x10\x00\x12\x0e\n" + + "\n" + + "AUDIO_CALL\x10\x01\x12\x0e\n" + + "\n" + + "VIDEO_CALL\x10\x02\x12\x0e\n" + + "\n" + + "GROUP_CALL\x10\x03\x12\x0f\n" + + "\vAD_HOC_CALL\x10\x04\">\n" + + "\tDirection\x12\x15\n" + + "\x11UNKNOWN_DIRECTION\x10\x00\x12\f\n" + + "\bINCOMING\x10\x01\x12\f\n" + + "\bOUTGOING\x10\x02\"T\n" + + "\x05Event\x12\x11\n" + + "\rUNKNOWN_EVENT\x10\x00\x12\f\n" + + "\bACCEPTED\x10\x01\x12\x10\n" + + "\fNOT_ACCEPTED\x10\x02\x12\n" + + "\n" + + "\x06DELETE\x10\x03\x12\f\n" + + "\bOBSERVED\x10\x04\x1a\xac\x01\n" + + "\x0eCallLinkUpdate\x12\x18\n" + + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x12B\n" + + "\x04type\x18\x03 \x01(\x0e2..signalservice.SyncMessage.CallLinkUpdate.TypeR\x04type\"\x18\n" + + "\x04Type\x12\n" + + "\n" + + "\x06UPDATE\x10\x00\"\x04\b\x01\x10\x01\x1a\x94\x02\n" + + "\fCallLogEvent\x12@\n" + + "\x04type\x18\x01 \x01(\x0e2,.signalservice.SyncMessage.CallLogEvent.TypeR\x04type\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12&\n" + + "\x0econversationId\x18\x03 \x01(\fR\x0econversationId\x12\x16\n" + + "\x06callId\x18\x04 \x01(\x04R\x06callId\"d\n" + + "\x04Type\x12\t\n" + + "\x05CLEAR\x10\x00\x12\x12\n" + + "\x0eMARKED_AS_READ\x10\x01\x12\"\n" + + "\x1eMARKED_AS_READ_IN_CONVERSATION\x10\x02\x12\x19\n" + + "\x15CLEAR_IN_CONVERSATION\x10\x03\x1a\xb9\n" + + "\n" + + "\vDeleteForMe\x12]\n" + + "\x0emessageDeletes\x18\x01 \x03(\v25.signalservice.SyncMessage.DeleteForMe.MessageDeletesR\x0emessageDeletes\x12k\n" + + "\x13conversationDeletes\x18\x02 \x03(\v29.signalservice.SyncMessage.DeleteForMe.ConversationDeleteR\x13conversationDeletes\x12\x86\x01\n" + + "\x1clocalOnlyConversationDeletes\x18\x03 \x03(\v2B.signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDeleteR\x1clocalOnlyConversationDeletes\x12e\n" + + "\x11attachmentDeletes\x18\x04 \x03(\v27.signalservice.SyncMessage.DeleteForMe.AttachmentDeleteR\x11attachmentDeletes\x1a\x9a\x01\n" + + "\x0eMessageDeletes\x12I\n" + + "\fconversation\x18\x01 \x01(\v2%.signalservice.ConversationIdentifierR\fconversation\x12=\n" + + "\bmessages\x18\x02 \x03(\v2!.signalservice.AddressableMessageR\bmessages\x1a\xa4\x02\n" + + "\x10AttachmentDelete\x12I\n" + + "\fconversation\x18\x01 \x01(\v2%.signalservice.ConversationIdentifierR\fconversation\x12G\n" + + "\rtargetMessage\x18\x02 \x01(\v2!.signalservice.AddressableMessageR\rtargetMessage\x12\x1e\n" + + "\n" + + "clientUuid\x18\x03 \x01(\fR\n" + + "clientUuid\x12&\n" + + "\x0efallbackDigest\x18\x04 \x01(\fR\x0efallbackDigest\x124\n" + + "\x15fallbackPlaintextHash\x18\x05 \x01(\fR\x15fallbackPlaintextHash\x1a\xbf\x02\n" + + "\x12ConversationDelete\x12I\n" + + "\fconversation\x18\x01 \x01(\v2%.signalservice.ConversationIdentifierR\fconversation\x12Q\n" + + "\x12mostRecentMessages\x18\x02 \x03(\v2!.signalservice.AddressableMessageR\x12mostRecentMessages\x12\"\n" + + "\fisFullDelete\x18\x03 \x01(\bR\fisFullDelete\x12g\n" + + "\x1dmostRecentNonExpiringMessages\x18\x04 \x03(\v2!.signalservice.AddressableMessageR\x1dmostRecentNonExpiringMessages\x1ah\n" + + "\x1bLocalOnlyConversationDelete\x12I\n" + + "\fconversation\x18\x01 \x01(\v2%.signalservice.ConversationIdentifierR\fconversation\x1a4\n" + + "\x10DeviceNameChange\x12\x1a\n" + + "\bdeviceId\x18\x02 \x01(\rR\bdeviceIdJ\x04\b\x01\x10\x02\x1a\xbb\x01\n" + + "\x19AttachmentBackfillRequest\x12G\n" + + "\rtargetMessage\x18\x01 \x01(\v2!.signalservice.AddressableMessageR\rtargetMessage\x12U\n" + + "\x12targetConversation\x18\x02 \x01(\v2%.signalservice.ConversationIdentifierR\x12targetConversation\x1a\xf9\x06\n" + + "\x1aAttachmentBackfillResponse\x12G\n" + + "\rtargetMessage\x18\x01 \x01(\v2!.signalservice.AddressableMessageR\rtargetMessage\x12U\n" + + "\x12targetConversation\x18\x02 \x01(\v2%.signalservice.ConversationIdentifierR\x12targetConversation\x12l\n" + + "\vattachments\x18\x03 \x01(\v2H.signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataListH\x00R\vattachments\x12S\n" + + "\x05error\x18\x04 \x01(\x0e2;.signalservice.SyncMessage.AttachmentBackfillResponse.ErrorH\x00R\x05error\x1a\xee\x01\n" + + "\x0eAttachmentData\x12B\n" + + "\n" + + "attachment\x18\x01 \x01(\v2 .signalservice.AttachmentPointerH\x00R\n" + + "attachment\x12e\n" + + "\x06status\x18\x02 \x01(\x0e2K.signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.StatusH\x00R\x06status\")\n" + + "\x06Status\x12\v\n" + + "\aPENDING\x10\x00\x12\x12\n" + + "\x0eTERMINAL_ERROR\x10\x01B\x06\n" + + "\x04data\x1a\xde\x01\n" + + "\x12AttachmentDataList\x12f\n" + + "\vattachments\x18\x01 \x03(\v2D.signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataR\vattachments\x12`\n" + + "\blongText\x18\x02 \x01(\v2D.signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataR\blongText\"\x1e\n" + + "\x05Error\x12\x15\n" + + "\x11MESSAGE_NOT_FOUND\x10\x00B\x06\n" + + "\x04dataJ\x04\b\x03\x10\x04J\x04\b\x11\x10\x12\"\xe7\x04\n" + + "\x11AttachmentPointer\x12\x16\n" + + "\x05cdnId\x18\x01 \x01(\x06H\x00R\x05cdnId\x12\x18\n" + + "\x06cdnKey\x18\x0f \x01(\tH\x00R\x06cdnKey\x12\x1e\n" + + "\n" + + "clientUuid\x18\x14 \x01(\fR\n" + + "clientUuid\x12 \n" + + "\vcontentType\x18\x02 \x01(\tR\vcontentType\x12\x10\n" + + "\x03key\x18\x03 \x01(\fR\x03key\x12\x12\n" + + "\x04size\x18\x04 \x01(\rR\x04size\x12\x1c\n" + + "\tthumbnail\x18\x05 \x01(\fR\tthumbnail\x12\x16\n" + + "\x06digest\x18\x06 \x01(\fR\x06digest\x12&\n" + + "\x0eincrementalMac\x18\x13 \x01(\fR\x0eincrementalMac\x12\x1c\n" + + "\tchunkSize\x18\x11 \x01(\rR\tchunkSize\x12\x1a\n" + + "\bfileName\x18\a \x01(\tR\bfileName\x12\x14\n" + + "\x05flags\x18\b \x01(\rR\x05flags\x12\x14\n" + + "\x05width\x18\t \x01(\rR\x05width\x12\x16\n" + + "\x06height\x18\n" + + " \x01(\rR\x06height\x12\x18\n" + + "\acaption\x18\v \x01(\tR\acaption\x12\x1a\n" + + "\bblurHash\x18\f \x01(\tR\bblurHash\x12(\n" + + "\x0fuploadTimestamp\x18\r \x01(\x04R\x0fuploadTimestamp\x12\x1c\n" + + "\tcdnNumber\x18\x0e \x01(\rR\tcdnNumber\"9\n" + + "\x05Flags\x12\x11\n" + + "\rVOICE_MESSAGE\x10\x01\x12\x0e\n" + + "\n" + + "BORDERLESS\x10\x02\x12\a\n" + + "\x03GIF\x10\b\"\x04\b\x04\x10\x04B\x17\n" + + "\x15attachment_identifierJ\x04\b\x10\x10\x11J\x04\b\x12\x10\x13\"l\n" + + "\x0eGroupContextV2\x12\x1c\n" + + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x1a\n" + + "\brevision\x18\x02 \x01(\rR\brevision\x12 \n" + + "\vgroupChange\x18\x03 \x01(\fR\vgroupChange\"\xe6\x02\n" + + "\x0eContactDetails\x12\x16\n" + + "\x06number\x18\x01 \x01(\tR\x06number\x12\x10\n" + + "\x03aci\x18\t \x01(\tR\x03aci\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12<\n" + + "\x06avatar\x18\x03 \x01(\v2$.signalservice.ContactDetails.AvatarR\x06avatar\x12 \n" + + "\vexpireTimer\x18\b \x01(\rR\vexpireTimer\x12.\n" + + "\x12expireTimerVersion\x18\f \x01(\rR\x12expireTimerVersion\x12$\n" + + "\rinboxPosition\x18\n" + + " \x01(\rR\rinboxPosition\x1aB\n" + + "\x06Avatar\x12 \n" + + "\vcontentType\x18\x01 \x01(\tR\vcontentType\x12\x16\n" + + "\x06length\x18\x02 \x01(\rR\x06lengthJ\x04\b\x04\x10\x05J\x04\b\x05\x10\x06J\x04\b\x06\x10\aJ\x04\b\a\x10\bJ\x04\b\v\x10\f\"\xb9\x01\n" + + "\x0ePaymentAddress\x12J\n" + + "\n" + + "mobileCoin\x18\x01 \x01(\v2(.signalservice.PaymentAddress.MobileCoinH\x00R\n" + + "mobileCoin\x1aP\n" + + "\n" + + "MobileCoin\x12$\n" + + "\rpublicAddress\x18\x01 \x01(\fR\rpublicAddress\x12\x1c\n" + + "\tsignature\x18\x02 \x01(\fR\tsignatureB\t\n" + + "\aAddress\"r\n" + + "\x16DecryptionErrorMessage\x12\x1e\n" + + "\n" + + "ratchetKey\x18\x01 \x01(\fR\n" + + "ratchetKey\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12\x1a\n" + + "\bdeviceId\x18\x03 \x01(\rR\bdeviceId\"E\n" + + "\x13PniSignatureMessage\x12\x10\n" + + "\x03pni\x18\x01 \x01(\fR\x03pni\x12\x1c\n" + + "\tsignature\x18\x02 \x01(\fR\tsignature\"}\n" + + "\vEditMessage\x120\n" + + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x12<\n" + + "\vdataMessage\x18\x02 \x01(\v2\x1a.signalservice.DataMessageR\vdataMessage\"\xfe\x01\n" + + "\tBodyRange\x12\x14\n" + + "\x05start\x18\x01 \x01(\rR\x05start\x12\x16\n" + + "\x06length\x18\x02 \x01(\rR\x06length\x12 \n" + + "\n" + + "mentionAci\x18\x03 \x01(\tH\x00R\n" + + "mentionAci\x126\n" + + "\x05style\x18\x04 \x01(\x0e2\x1e.signalservice.BodyRange.StyleH\x00R\x05style\"V\n" + + "\x05Style\x12\b\n" + + "\x04NONE\x10\x00\x12\b\n" + + "\x04BOLD\x10\x01\x12\n" + + "\n" + + "\x06ITALIC\x10\x02\x12\v\n" + + "\aSPOILER\x10\x03\x12\x11\n" + + "\rSTRIKETHROUGH\x10\x04\x12\r\n" + + "\tMONOSPACE\x10\x05B\x11\n" + + "\x0fassociatedValue\"\x92\x01\n" + + "\x12AddressableMessage\x12*\n" + + "\x0fauthorServiceId\x18\x01 \x01(\tH\x00R\x0fauthorServiceId\x12 \n" + + "\n" + + "authorE164\x18\x02 \x01(\tH\x00R\n" + + "authorE164\x12$\n" + + "\rsentTimestamp\x18\x03 \x01(\x04R\rsentTimestampB\b\n" + + "\x06author\"\x9c\x01\n" + + "\x16ConversationIdentifier\x12*\n" + + "\x0fthreadServiceId\x18\x01 \x01(\tH\x00R\x0fthreadServiceId\x12&\n" + + "\rthreadGroupId\x18\x02 \x01(\fH\x00R\rthreadGroupId\x12 \n" + + "\n" + + "threadE164\x18\x03 \x01(\tH\x00R\n" + + "threadE164B\f\n" + + "\n" + + "identifierBE\n" + + ".org.whispersystems.signalservice.internal.pushB\x13SignalServiceProtos" var ( file_SignalService_proto_rawDescOnce sync.Once - file_SignalService_proto_rawDescData = file_SignalService_proto_rawDesc + file_SignalService_proto_rawDescData []byte ) func file_SignalService_proto_rawDescGZIP() []byte { file_SignalService_proto_rawDescOnce.Do(func() { - file_SignalService_proto_rawDescData = protoimpl.X.CompressGZIP(file_SignalService_proto_rawDescData) + file_SignalService_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_SignalService_proto_rawDesc), len(file_SignalService_proto_rawDesc))) }) return file_SignalService_proto_rawDescData } @@ -8079,7 +8730,7 @@ func file_SignalService_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_SignalService_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_SignalService_proto_rawDesc), len(file_SignalService_proto_rawDesc)), NumEnums: 28, NumMessages: 82, NumExtensions: 0, @@ -8091,7 +8742,6 @@ func file_SignalService_proto_init() { MessageInfos: file_SignalService_proto_msgTypes, }.Build() File_SignalService_proto = out.File - file_SignalService_proto_rawDesc = nil file_SignalService_proto_goTypes = nil file_SignalService_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/SignalService.pb.raw b/pkg/signalmeow/protobuf/SignalService.pb.raw deleted file mode 100644 index befb7053450b2a5831204736297be0cfa084b7e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19700 zcmd5^-*0QlUEd^5;*1kt-*b2Gdfn}IYs$7=AhhnXZMQApU&-~}#P*JzY%c<(zV=CS zdL7$6w(o8#@dV-#p@Mj*kaz*{LkN(NkSZkl5AXm_Ji!AJAW?(_F9-=CKA)L6=gc{F ze6!U>;w3pVXTCFYX1??N@%eto;$FwQ81;r7*MI8u-TjF_o{gQosj8gn%Hr>BigbPS z)E$l|uJbvOnq5!a{MzelpUIY9-H$ch51Q?F(MGD4&S%7(>3HtCeGoq40)%o~rQF85TIOW!%Kik+Ev1*+cFB)^Go(H4e~o`1gl1UnR?$1dl#zrJDM!4<_z4)rF-T2 zyY&ta8$<9o2Ii&d0>dow_`&%d=YjsDb~F&Sbq> zZ?wC)P3L8C@1)tN)tlYML8D$f>(raIy3B1kFNwSQnSCACJDu`jJ-5y3_EEXf1i#jz7Se7`>gn~UA5gDj;TEYoQ447|Cw0F!90t@IOR1|-3u!ke z^=KYZr<1?j?Cq7-q8p#BaQxSVO=icZd=w(awl05KW zo2ZS9lc0}Rr|xLr`VZafnm3*K-s3q>ZO|pp_pV&o#(7)ZAGm%0dP2gw?~na}S|8RM z-a0=6S;A8hwC3r}ls=YNgpSn&g2pO2U2$(R@|1X-&3!lMhX*`UDkl2D$xODC%gDL6 z?!XJThJtXBuj)|?X*VzaM_Obow!z|Tj?d3sUrFOk>Gi~{tfu=dwv)QK^JTHs8%;j| zp=Rt)t{^O{hSCsVPj?`iPn1B)Z@j*N>3?bkbt7miBQoa;BK3Gay;h<)Q~JaT@(P+s z)tGa>?2Rtw6Qve1rB!o&pc+a;0G)Nu(ivL0Knsy2_T;ix9Be%4eQWOK^?t7!tfd-C zLs0m`HLTDY@t(M2s>;=Bz1^+XpbewSTD^MIXrgl6xg#>BW#y#v2nw~_#Vfl~Jv&vgt&D>HwK}BP(q~tEtL|t2 zgjPiVS_YKG&q1N-8_MV8u)^VakQ1I4XxN+G7s}moIH1 z=Zj+d!XM8krzK_NENZMnzE$e|!`W#`2CZoToez5#(>%|{p40{Bbx7I|C!X)p3iFk$ z*@HBVs+@h{SjAJ=#QBnV*>}G+$FdLF^d&-N7Zr$2UQ-RFA;4D& zvbls>ai@7lEo441dL?Ket+uct?kJ|FDmF^#pGty^M;^@H=!m`3I(M3at#6B%( zD1GK?7<5%){WB=g1qxocdD(PpSVS* z<&X$nT3r;r1LZ$OC5YaojsS~e1 zMvWRGh5gjUN;;TH;rnZ1*Iowa=a)?Fom))J?&QV^QWIdWT&16&3HZD?Y2%EjNyE1` z#mb(@bbT11`b59GmHxqY?q9bH9|{pIxpNQ$8%npBctmU|{$ermZ)N?xlX|BM4G4u; zu67%z(0ownl`WBK%-k!?v>hc77Tt&E@>+@u=qw)v7Hj$!G}z z3nC&3H(7|S&~yWaao9NMo>j^|gXo-nX@& zC1>r(SY6@Ifi`gsX)j%PPu&p=rDWbMHfQ!c2+v z)A>2;X%6m4Q(}Kt-e6#ukDdwoi)zT4BbYthSLI>u$gr%(FOAL$n`ERACLXZ@pxdQeXNcGzwgboV*r8AXO7~#7c^P* zNiZcc+XUa+9}l!Y0A>ry8jpru0YsMw#SV>mRV==-zz4zJuUmV+QTPT70(~C86dq|U z-=6J~1t%GY)0@JCr?^%M9*A{VQTW|8v2ARBbr5^~C-A8`2HgFLDk*~nPxO_z^3eT! zfg%sSaWO(iJgRWsGS0BZJ)b>e?Ji^A+^g|714XP0h3~G3bl?hbYjqQIYE?mR(bf2A z@RisimI&@c6kfQqa;W3AKuJ~;UeYZ)Fvvs9U-3vvE_(%e0t}?^j@Z(E#!WqNp38eE zd|KQ|cnRwB{GQnc$PUCB8iRrqySDYtwU3Mzy%14_^C__h#Mb%xIX8^Wn%H<1OuD_1uv{+!r6pbt+71#tod3p7l!#u!8W>+OatcLAH6 zbsNV(xlY{u~PA-L|%~xwpO#P@{?Y4l$ zb-U&2gJXm-ItYjCiZmZp+bx#bAf2 zahV8)6@PzC?8U+ZE1EU_(^SCo}nfhOJiSYP`z^v5F@9_l~WM)}!Bpg`D| zBFw@q-IlA|>6Q`Bs$tHm062`cfAOEz%_%V`e*)^^RO3+37sRIOUrqIyNR@62TP;gz z8X2*-wQ}JXCMcalk)=mr^`*sSGRo79HDX6`GM;z<4dV}{(wz)Fpc}M|(lTC|06;#1 zk5So$;~nCD#ovbBFo=_r6B~1XXiO+RQi9FAnb9|pV5-0%hj+ygo(`iuTOsJ?^hSXC z_kBdd$W&T*+f~%q1H@I0q*l+xze$N~e9=NrPD@Me$(6y%SlZ6)+DtdQ07u1p*;h>w zcMhnO&`0553=09s=4enI56AQ*R8)fP60ZV^3e>1g!7oD`gA|EZpa^h1^^v!L|7s$A z;r9j}#J6z+k{Em9yADlj@K#6(xx5MF4_`yGXAiG*k*G;JAmAZ`AL7sScXM_3q*X&B z3DHCSmLdUgeNZN=0F1-h>*dk~>T)$Kq2LX)Hzf)lm{%V8K>JDSGO8%PCpOjQP$tys z2j!C^!UHJC`r*k@SwgNs!c|&Fg!p&RxGoz9+T89`C4=25sseP*8wc?!b9NWUXLS1RW%5$-bUar?czGgtDs;MnkNh{L3}SE(Cak5y5$ABz0SM zn+z`R#sbLjHn1F^h%W~uKH~c-l8^O(UwzUH%j+;`)*$i!y(%(ROq_8(ngQyFFUI+- zmix4vq-so@x34{I#u1j`yf&fnq^2??A~;G2+MUkSnO_9VZF;F&5|>gWoHJl%TKM#) zld;J-X>TA^V-ERvI0j}uFlQ#IZ*97YZYcv244HmvxWmLYUrzWt!B)z!q0UcsDnY9Nr9zu*v zF71q%G=mhx{xQPHgdUP`jNN$$|_R&xW+=v1o4jwkM4>8z80yWHsnl1E21GNmNoXV1hKAPGWwLx&76jOVip z;LaBY1~;*@WO%_IqZOx+$u1Zv;bwrFbLtc%qu+LC+y-|b4FM;FtcfZk^=?x`V~$$8 zRTDz?giRrnT`%MST)&E zL?9C#kZDzy;|o2r<$;ui4o!0zBPP@8@D#NEaS%#L>R!7q?K`U0$X!waD^+mb7dai~ zCUT}1Rz)>4r5{Vkm3Vi|xr<2TLMM(dUWsfuni?=?hlW-2d9}^SxQ9JLWUMA=<;~qX zb5U3}ra4frs6mtP(6a{B#BxQ)h5z0bDJmtx0G7J0fBx;ajK!L)zA-aVBR{vuOw_)% z8b>-swg|sf}s*jY` zbtUfGX;x{8O_bcmoASL1f4L?KH?QiA97lU_ zM=s|$Aer_KD-$a%V|AGHD;Cc~IyWpsROj^E+(6rc_{#*JKUotmEnTo1=dPWs<#T5q zmz73%gy+UUXPfLGk8AN2vS4%Gv`qij9dyTZaj(@;O3Q_MJ!AaMm1E58)u<4XdRdy(SAkDH- zMI0+iN=D6Ng?E8ADf8nw^z};!LBtGXV*d053{=LAAutlFLxB1<`!oeouQ3`he_`xv z7bY#A(TaSEoq`o-QF2MZr^$Mv07yf6>M>gh6z~mH-V)CxP=F<`_$5P_JqCE0Djx-3 zV%M4T`e$q6#bs7IJ!=i?t7W(i$d7GS%%`2xRd&I$0c}qFM8t`WCJ;Q8+X$pl){k4K zh=vu~V%PQto&z@^zLBw<0;nDPB&{-|EGqjOPNHv!P7{s{j!*gM%wX6!Qb^fE08b(# z{_MEiY#cCEVV$Y;os)_N8;F8q5xOTGM6!Pwu~d2<+@Gu76ghQDpkse@i8*e)zKS2! z5m6dXuG`~r5M5mIhV8GApxl$=u>zCk6M_#k8+PTAH|8Kd6d6lPaQ!Fq$3w4AS{|ES zz%44Xxa6Uv$RH&$E@nZ+%@{C{SG|4w zj%?}e6;|-_f$g3A=CYjxH|pF_Y$2Y3jn`Ft0%(zvkdTkqS@n2^tV>>(U;`y0JMHo@ z;sXdmMDJDImRa53Oo=-QpN;$E2c}bW2}Uc=C2y!klBqiI6Rd0_V_~i`e-d-JF)yfq zaIT%X1mPCW)g&Dlu2`s7aI{K`YMWdqE&BI*b|qQp+;xK{lrSme281=_1dPZ#5QcSw zBF&DWi&QmVY2IY8Zs|J;XNv|B+Wk<8(3D)LC%QKUATa~yHwao!f#__2!4tLY6OQ|2 zK5GZ(Vv592wp^&MyewXdT%fbiI`<2I%fMFLcc#B$!G`Ugr!NQK)=#3ET49QNUQE=q zPGYPMw$DpLh!q?_+$4He0o* zAEbb%23|b-1J(t1VjA?Pg-W7U!M`BFc$#ar=$$u|r4hxQG`Cn@*4JXf;aPBi^7Jiv z;2epa0n%M{pp5TjN7M#g=Pl4_Z}Skt!lXE1Wd1YX$w+ z8o2ev$R-AXh1h6TTgQ#&A!H#+t&{Fyi>38qS8S@O(pC&;>!*x*Dmp8>9+Pjjx@TdH z%5N}2b3^r7Q5Vl@2&4ZIf}dQA2&hr#9||l|Kij@8lIeScD{s{9O{Y)7%!F7S&?eh* zdDdn|!&+QX%$r?+GB82u7hwLb!C3i?b+N0aYhWO3xoung_%nFt$dFlsDYa$I%QTU#~EdvY0`UR0S*oUswj!~wxNJCz@Xb2&@Qb$`JOc5|7cch6teb3n{gKbLYp=J`|Cz-*P}YJr6y^XF$_G$t z)jMAkX~P-X`(4cBH%3P9@i4fyCqt6L@2rbl@*|$-^bT=xQsoVq6;Qh9R&$Kg(a7l| zA`fVcw~zIiwQ8sp0h0|GXRLX!Gy+>EQA-^jv}+H0ym<5B>_KmOsUpI=a{0@`_t%B9 z$g0nCq27b5fgCsqLv0jXi2MjUx`de0-J2fZW~}B-wP9>wff#8QMfek#G^aTGxS9$*a@K8_Jfx^23dzZeKH(L-keoH%R&T(6F4W zWFNyZ&&=0Bj}{el6jE_j*nw=DEj|3%hm5#a6fc8q3sx&1u7KjzvSH#@E49yb2;`dwWg-Ui$#C2oL}&=p9a1t`t-fwBGGTq*(B#(z z6~!+HDZKFRPFsyC5KQyi9?I3Mv?PB1;|Nu71h&Nn?&YXo_ekYZHzFM1v|R2k{_@8? zh9Y|yy8+DkXqb}>WpKu@g5S)$tqL4B8Zao6n^eTaM8`GH*i}pk%|c`G#!t zS~2eBBqQ52NKA{^@9Px*XHD#cH>N54p!0p5DG1@G3KVn8_z8zsP!1#f6-EweLqv5< z8J?=lTp}6S(rXE291g6La;ctF^Wv#6nV^VVHd{@CW_VJWp9@I=XW+tj z^!1DcsE;`&UvM3CTZN!1S;KXR>K3nakeQO#Ie33q(-ePeP29K5^vDM1#B`)($;1*b zpe^@wm6F#6j@`xF;??{B-A;V~=eENSi0YU}>xDQ#r7reyyKw)5OAi>kKfOl0>uQ?V YTlK>d_(ik*$$WZQiT}Krx&$))UvGw&JOBUy diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index c194ebc..b1969bc 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: StickerResources.proto @@ -16,10 +16,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -157,17 +156,28 @@ func (x *Pack_Sticker) GetContentType() string { var File_StickerResources_proto protoreflect.FileDescriptor -//go:embed StickerResources.pb.raw -var file_StickerResources_proto_rawDesc []byte +const file_StickerResources_proto_rawDesc = "" + + "\n" + + "\x16StickerResources.proto\x12\rsignalservice\"\xf3\x01\n" + + "\x04Pack\x12\x14\n" + + "\x05title\x18\x01 \x01(\tR\x05title\x12\x16\n" + + "\x06author\x18\x02 \x01(\tR\x06author\x121\n" + + "\x05cover\x18\x03 \x01(\v2\x1b.signalservice.Pack.StickerR\x05cover\x127\n" + + "\bstickers\x18\x04 \x03(\v2\x1b.signalservice.Pack.StickerR\bstickers\x1aQ\n" + + "\aSticker\x12\x0e\n" + + "\x02id\x18\x01 \x01(\rR\x02id\x12\x14\n" + + "\x05emoji\x18\x02 \x01(\tR\x05emoji\x12 \n" + + "\vcontentType\x18\x03 \x01(\tR\vcontentTypeBB\n" + + "1org.whispersystems.signalservice.internal.stickerB\rStickerProtos" var ( file_StickerResources_proto_rawDescOnce sync.Once - file_StickerResources_proto_rawDescData = file_StickerResources_proto_rawDesc + file_StickerResources_proto_rawDescData []byte ) func file_StickerResources_proto_rawDescGZIP() []byte { file_StickerResources_proto_rawDescOnce.Do(func() { - file_StickerResources_proto_rawDescData = protoimpl.X.CompressGZIP(file_StickerResources_proto_rawDescData) + file_StickerResources_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_StickerResources_proto_rawDesc), len(file_StickerResources_proto_rawDesc))) }) return file_StickerResources_proto_rawDescData } @@ -196,7 +206,7 @@ func file_StickerResources_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_StickerResources_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_StickerResources_proto_rawDesc), len(file_StickerResources_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -207,7 +217,6 @@ func file_StickerResources_proto_init() { MessageInfos: file_StickerResources_proto_msgTypes, }.Build() File_StickerResources_proto = out.File - file_StickerResources_proto_rawDesc = nil file_StickerResources_proto_goTypes = nil file_StickerResources_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.raw b/pkg/signalmeow/protobuf/StickerResources.pb.raw deleted file mode 100644 index 03768ca..0000000 --- a/pkg/signalmeow/protobuf/StickerResources.pb.raw +++ /dev/null @@ -1,12 +0,0 @@ - -StickerResources.proto signalservice"ó -Pack -title ( Rtitle -author ( Rauthor1 -cover ( 2.signalservice.Pack.StickerRcover7 -stickers ( 2.signalservice.Pack.StickerRstickersQ -Sticker -id ( Rid -emoji ( Remoji - contentType ( R contentTypeBB -1org.whispersystems.signalservice.internal.stickerB StickerProtos \ No newline at end of file diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 3aad8ab..3826c83 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: StorageService.proto @@ -16,10 +16,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -2613,17 +2612,279 @@ func (x *ChatFolderRecord_Recipient_Contact) GetE164() string { var File_StorageService_proto protoreflect.FileDescriptor -//go:embed StorageService.pb.raw -var file_StorageService_proto_rawDesc []byte +const file_StorageService_proto_rawDesc = "" + + "\n" + + "\x14StorageService.proto\x12\rsignalservice\"A\n" + + "\x0fStorageManifest\x12\x18\n" + + "\aversion\x18\x01 \x01(\x04R\aversion\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value\"5\n" + + "\vStorageItem\x12\x10\n" + + "\x03key\x18\x01 \x01(\fR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value\"@\n" + + "\fStorageItems\x120\n" + + "\x05items\x18\x01 \x03(\v2\x1a.signalservice.StorageItemR\x05items\")\n" + + "\rReadOperation\x12\x18\n" + + "\areadKey\x18\x01 \x03(\fR\areadKey\"\xc2\x01\n" + + "\x0eWriteOperation\x12:\n" + + "\bmanifest\x18\x01 \x01(\v2\x1e.signalservice.StorageManifestR\bmanifest\x12:\n" + + "\n" + + "insertItem\x18\x02 \x03(\v2\x1a.signalservice.StorageItemR\n" + + "insertItem\x12\x1c\n" + + "\tdeleteKey\x18\x03 \x03(\fR\tdeleteKey\x12\x1a\n" + + "\bclearAll\x18\x04 \x01(\bR\bclearAll\"\xa3\x03\n" + + "\x0eManifestRecord\x12\x18\n" + + "\aversion\x18\x01 \x01(\x04R\aversion\x12\"\n" + + "\fsourceDevice\x18\x03 \x01(\rR\fsourceDevice\x12J\n" + + "\videntifiers\x18\x02 \x03(\v2(.signalservice.ManifestRecord.IdentifierR\videntifiers\x12\x1c\n" + + "\trecordIkm\x18\x04 \x01(\fR\trecordIkm\x1a\xe8\x01\n" + + "\n" + + "Identifier\x12\x10\n" + + "\x03raw\x18\x01 \x01(\fR\x03raw\x12A\n" + + "\x04type\x18\x02 \x01(\x0e2-.signalservice.ManifestRecord.Identifier.TypeR\x04type\"\x84\x01\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\v\n" + + "\aCONTACT\x10\x01\x12\v\n" + + "\aGROUPV1\x10\x02\x12\v\n" + + "\aGROUPV2\x10\x03\x12\v\n" + + "\aACCOUNT\x10\x04\x12\x1b\n" + + "\x17STORY_DISTRIBUTION_LIST\x10\x05\x12\r\n" + + "\tCALL_LINK\x10\a\x12\x0f\n" + + "\vCHAT_FOLDER\x10\b\"\xe5\x03\n" + + "\rStorageRecord\x128\n" + + "\acontact\x18\x01 \x01(\v2\x1c.signalservice.ContactRecordH\x00R\acontact\x128\n" + + "\agroupV1\x18\x02 \x01(\v2\x1c.signalservice.GroupV1RecordH\x00R\agroupV1\x128\n" + + "\agroupV2\x18\x03 \x01(\v2\x1c.signalservice.GroupV2RecordH\x00R\agroupV2\x128\n" + + "\aaccount\x18\x04 \x01(\v2\x1c.signalservice.AccountRecordH\x00R\aaccount\x12b\n" + + "\x15storyDistributionList\x18\x05 \x01(\v2*.signalservice.StoryDistributionListRecordH\x00R\x15storyDistributionList\x12;\n" + + "\bcallLink\x18\a \x01(\v2\x1d.signalservice.CallLinkRecordH\x00R\bcallLink\x12A\n" + + "\n" + + "chatFolder\x18\b \x01(\v2\x1f.signalservice.ChatFolderRecordH\x00R\n" + + "chatFolderB\b\n" + + "\x06record\"\x9d\b\n" + + "\rContactRecord\x12\x10\n" + + "\x03aci\x18\x01 \x01(\tR\x03aci\x12\x12\n" + + "\x04e164\x18\x02 \x01(\tR\x04e164\x12\x10\n" + + "\x03pni\x18\x0f \x01(\tR\x03pni\x12\x1e\n" + + "\n" + + "profileKey\x18\x03 \x01(\fR\n" + + "profileKey\x12 \n" + + "\videntityKey\x18\x04 \x01(\fR\videntityKey\x12P\n" + + "\ridentityState\x18\x05 \x01(\x0e2*.signalservice.ContactRecord.IdentityStateR\ridentityState\x12\x1c\n" + + "\tgivenName\x18\x06 \x01(\tR\tgivenName\x12\x1e\n" + + "\n" + + "familyName\x18\a \x01(\tR\n" + + "familyName\x12\x1a\n" + + "\busername\x18\b \x01(\tR\busername\x12\x18\n" + + "\ablocked\x18\t \x01(\bR\ablocked\x12 \n" + + "\vwhitelisted\x18\n" + + " \x01(\bR\vwhitelisted\x12\x1a\n" + + "\barchived\x18\v \x01(\bR\barchived\x12\"\n" + + "\fmarkedUnread\x18\f \x01(\bR\fmarkedUnread\x120\n" + + "\x13mutedUntilTimestamp\x18\r \x01(\x04R\x13mutedUntilTimestamp\x12\x1c\n" + + "\thideStory\x18\x0e \x01(\bR\thideStory\x128\n" + + "\x17unregisteredAtTimestamp\x18\x10 \x01(\x04R\x17unregisteredAtTimestamp\x12(\n" + + "\x0fsystemGivenName\x18\x11 \x01(\tR\x0fsystemGivenName\x12*\n" + + "\x10systemFamilyName\x18\x12 \x01(\tR\x10systemFamilyName\x12&\n" + + "\x0esystemNickname\x18\x13 \x01(\tR\x0esystemNickname\x12\x16\n" + + "\x06hidden\x18\x14 \x01(\bR\x06hidden\x122\n" + + "\x14pniSignatureVerified\x18\x15 \x01(\bR\x14pniSignatureVerified\x12=\n" + + "\bnickname\x18\x16 \x01(\v2!.signalservice.ContactRecord.NameR\bnickname\x12\x12\n" + + "\x04note\x18\x17 \x01(\tR\x04note\x12A\n" + + "\vavatarColor\x18\x18 \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x1a4\n" + + "\x04Name\x12\x14\n" + + "\x05given\x18\x01 \x01(\tR\x05given\x12\x16\n" + + "\x06family\x18\x02 \x01(\tR\x06family\":\n" + + "\rIdentityState\x12\v\n" + + "\aDEFAULT\x10\x00\x12\f\n" + + "\bVERIFIED\x10\x01\x12\x0e\n" + + "\n" + + "UNVERIFIED\x10\x02B\x0e\n" + + "\f_avatarColor\"\xcd\x01\n" + + "\rGroupV1Record\x12\x0e\n" + + "\x02id\x18\x01 \x01(\fR\x02id\x12\x18\n" + + "\ablocked\x18\x02 \x01(\bR\ablocked\x12 \n" + + "\vwhitelisted\x18\x03 \x01(\bR\vwhitelisted\x12\x1a\n" + + "\barchived\x18\x04 \x01(\bR\barchived\x12\"\n" + + "\fmarkedUnread\x18\x05 \x01(\bR\fmarkedUnread\x120\n" + + "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\"\xa1\x04\n" + + "\rGroupV2Record\x12\x1c\n" + + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x18\n" + + "\ablocked\x18\x02 \x01(\bR\ablocked\x12 \n" + + "\vwhitelisted\x18\x03 \x01(\bR\vwhitelisted\x12\x1a\n" + + "\barchived\x18\x04 \x01(\bR\barchived\x12\"\n" + + "\fmarkedUnread\x18\x05 \x01(\bR\fmarkedUnread\x120\n" + + "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\x12B\n" + + "\x1cdontNotifyForMentionsIfMuted\x18\a \x01(\bR\x1cdontNotifyForMentionsIfMuted\x12\x1c\n" + + "\thideStory\x18\b \x01(\bR\thideStory\x12P\n" + + "\rstorySendMode\x18\n" + + " \x01(\x0e2*.signalservice.GroupV2Record.StorySendModeR\rstorySendMode\x12A\n" + + "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\"7\n" + + "\rStorySendMode\x12\v\n" + + "\aDEFAULT\x10\x00\x12\f\n" + + "\bDISABLED\x10\x01\x12\v\n" + + "\aENABLED\x10\x02B\x0e\n" + + "\f_avatarColorJ\x04\b\t\x10\n" + + "\">\n" + + "\bPayments\x12\x18\n" + + "\aenabled\x18\x01 \x01(\bR\aenabled\x12\x18\n" + + "\aentropy\x18\x02 \x01(\fR\aentropy\"\xf7\x15\n" + + "\rAccountRecord\x12\x1e\n" + + "\n" + + "profileKey\x18\x01 \x01(\fR\n" + + "profileKey\x12\x1c\n" + + "\tgivenName\x18\x02 \x01(\tR\tgivenName\x12\x1e\n" + + "\n" + + "familyName\x18\x03 \x01(\tR\n" + + "familyName\x12$\n" + + "\ravatarUrlPath\x18\x04 \x01(\tR\ravatarUrlPath\x12.\n" + + "\x12noteToSelfArchived\x18\x05 \x01(\bR\x12noteToSelfArchived\x12\"\n" + + "\freadReceipts\x18\x06 \x01(\bR\freadReceipts\x126\n" + + "\x16sealedSenderIndicators\x18\a \x01(\bR\x16sealedSenderIndicators\x12*\n" + + "\x10typingIndicators\x18\b \x01(\bR\x10typingIndicators\x126\n" + + "\x16noteToSelfMarkedUnread\x18\n" + + " \x01(\bR\x16noteToSelfMarkedUnread\x12\"\n" + + "\flinkPreviews\x18\v \x01(\bR\flinkPreviews\x12k\n" + + "\x16phoneNumberSharingMode\x18\f \x01(\x0e23.signalservice.AccountRecord.PhoneNumberSharingModeR\x16phoneNumberSharingMode\x120\n" + + "\x13unlistedPhoneNumber\x18\r \x01(\bR\x13unlistedPhoneNumber\x12a\n" + + "\x13pinnedConversations\x18\x0e \x03(\v2/.signalservice.AccountRecord.PinnedConversationR\x13pinnedConversations\x122\n" + + "\x14preferContactAvatars\x18\x0f \x01(\bR\x14preferContactAvatars\x123\n" + + "\bpayments\x18\x10 \x01(\v2\x17.signalservice.PaymentsR\bpayments\x122\n" + + "\x14universalExpireTimer\x18\x11 \x01(\rR\x14universalExpireTimer\x12(\n" + + "\x0fprimarySendsSms\x18\x12 \x01(\bR\x0fprimarySendsSms\x12\x12\n" + + "\x04e164\x18\x13 \x01(\tR\x04e164\x126\n" + + "\x16preferredReactionEmoji\x18\x14 \x03(\tR\x16preferredReactionEmoji\x12\"\n" + + "\fsubscriberId\x18\x15 \x01(\fR\fsubscriberId\x126\n" + + "\x16subscriberCurrencyCode\x18\x16 \x01(\tR\x16subscriberCurrencyCode\x126\n" + + "\x16displayBadgesOnProfile\x18\x17 \x01(\bR\x16displayBadgesOnProfile\x12D\n" + + "\x1dsubscriptionManuallyCancelled\x18\x18 \x01(\bR\x1dsubscriptionManuallyCancelled\x126\n" + + "\x16keepMutedChatsArchived\x18\x19 \x01(\bR\x16keepMutedChatsArchived\x126\n" + + "\x16hasSetMyStoriesPrivacy\x18\x1a \x01(\bR\x16hasSetMyStoriesPrivacy\x12:\n" + + "\x18hasViewedOnboardingStory\x18\x1b \x01(\bR\x18hasViewedOnboardingStory\x12(\n" + + "\x0fstoriesDisabled\x18\x1d \x01(\bR\x0fstoriesDisabled\x12W\n" + + "\x18storyViewReceiptsEnabled\x18\x1e \x01(\x0e2\x1b.signalservice.OptionalBoolR\x18storyViewReceiptsEnabled\x12H\n" + + "\x1fhasSeenGroupStoryEducationSheet\x18 \x01(\bR\x1fhasSeenGroupStoryEducationSheet\x12\x1a\n" + + "\busername\x18! \x01(\tR\busername\x12F\n" + + "\x1ehasCompletedUsernameOnboarding\x18\" \x01(\bR\x1ehasCompletedUsernameOnboarding\x12M\n" + + "\fusernameLink\x18# \x01(\v2).signalservice.AccountRecord.UsernameLinkR\fusernameLink\x12!\n" + + "\thasBackup\x18' \x01(\bH\x00R\thasBackup\x88\x01\x01\x12#\n" + + "\n" + + "backupTier\x18( \x01(\x04H\x01R\n" + + "backupTier\x88\x01\x01\x12b\n" + + "\x14backupSubscriberData\x18) \x01(\v2..signalservice.AccountRecord.IAPSubscriberDataR\x14backupSubscriberData\x12A\n" + + "\vavatarColor\x18* \x01(\x0e2\x1a.signalservice.AvatarColorH\x02R\vavatarColor\x88\x01\x01\x1a\x86\x02\n" + + "\x12PinnedConversation\x12S\n" + + "\acontact\x18\x01 \x01(\v27.signalservice.AccountRecord.PinnedConversation.ContactH\x00R\acontact\x12&\n" + + "\rlegacyGroupId\x18\x03 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + + "\x0egroupMasterKey\x18\x04 \x01(\fH\x00R\x0egroupMasterKey\x1a;\n" + + "\aContact\x12\x1c\n" + + "\tserviceId\x18\x01 \x01(\tR\tserviceId\x12\x12\n" + + "\x04e164\x18\x02 \x01(\tR\x04e164B\f\n" + + "\n" + + "identifier\x1a\xf8\x01\n" + + "\fUsernameLink\x12\x18\n" + + "\aentropy\x18\x01 \x01(\fR\aentropy\x12\x1a\n" + + "\bserverId\x18\x02 \x01(\fR\bserverId\x12E\n" + + "\x05color\x18\x03 \x01(\x0e2/.signalservice.AccountRecord.UsernameLink.ColorR\x05color\"k\n" + + "\x05Color\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\b\n" + + "\x04BLUE\x10\x01\x12\t\n" + + "\x05WHITE\x10\x02\x12\b\n" + + "\x04GREY\x10\x03\x12\t\n" + + "\x05OLIVE\x10\x04\x12\t\n" + + "\x05GREEN\x10\x05\x12\n" + + "\n" + + "\x06ORANGE\x10\x06\x12\b\n" + + "\x04PINK\x10\a\x12\n" + + "\n" + + "\x06PURPLE\x10\b\x1a\xac\x01\n" + + "\x11IAPSubscriberData\x12\"\n" + + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12&\n" + + "\rpurchaseToken\x18\x02 \x01(\tH\x00R\rpurchaseToken\x126\n" + + "\x15originalTransactionId\x18\x03 \x01(\x04H\x00R\x15originalTransactionIdB\x13\n" + + "\x11iapSubscriptionId\"@\n" + + "\x16PhoneNumberSharingMode\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\r\n" + + "\tEVERYBODY\x10\x01\x12\n" + + "\n" + + "\x06NOBODY\x10\x02B\f\n" + + "\n" + + "_hasBackupB\r\n" + + "\v_backupTierB\x0e\n" + + "\f_avatarColorJ\x04\b\t\x10\n" + + "J\x04\b\x1c\x10\x1dJ\x04\b\x1f\x10 J\x04\b$\x10%J\x04\b%\x10&J\x04\b&\x10'\"\xfb\x01\n" + + "\x1bStoryDistributionListRecord\x12\x1e\n" + + "\n" + + "identifier\x18\x01 \x01(\fR\n" + + "identifier\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x120\n" + + "\x13recipientServiceIds\x18\x03 \x03(\tR\x13recipientServiceIds\x12.\n" + + "\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" + + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" + + "\visBlockList\x18\x06 \x01(\bR\visBlockList\"\x82\x01\n" + + "\x0eCallLinkRecord\x12\x18\n" + + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\"\x84\a\n" + + "\x10ChatFolderRecord\x12\x1e\n" + + "\n" + + "identifier\x18\x01 \x01(\fR\n" + + "identifier\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1a\n" + + "\bposition\x18\x03 \x01(\rR\bposition\x12&\n" + + "\x0eshowOnlyUnread\x18\x04 \x01(\bR\x0eshowOnlyUnread\x12&\n" + + "\x0eshowMutedChats\x18\x05 \x01(\bR\x0eshowMutedChats\x12<\n" + + "\x19includeAllIndividualChats\x18\x06 \x01(\bR\x19includeAllIndividualChats\x122\n" + + "\x14includeAllGroupChats\x18\a \x01(\bR\x14includeAllGroupChats\x12J\n" + + "\n" + + "folderType\x18\b \x01(\x0e2*.signalservice.ChatFolderRecord.FolderTypeR\n" + + "folderType\x12Y\n" + + "\x12includedRecipients\x18\t \x03(\v2).signalservice.ChatFolderRecord.RecipientR\x12includedRecipients\x12Y\n" + + "\x12excludedRecipients\x18\n" + + " \x03(\v2).signalservice.ChatFolderRecord.RecipientR\x12excludedRecipients\x122\n" + + "\x14deletedAtTimestampMs\x18\v \x01(\x04R\x14deletedAtTimestampMs\x1a\xf7\x01\n" + + "\tRecipient\x12M\n" + + "\acontact\x18\x01 \x01(\v21.signalservice.ChatFolderRecord.Recipient.ContactH\x00R\acontact\x12&\n" + + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + + "\x0egroupMasterKey\x18\x03 \x01(\fH\x00R\x0egroupMasterKey\x1a;\n" + + "\aContact\x12\x1c\n" + + "\tserviceId\x18\x01 \x01(\tR\tserviceId\x12\x12\n" + + "\x04e164\x18\x02 \x01(\tR\x04e164B\f\n" + + "\n" + + "identifier\".\n" + + "\n" + + "FolderType\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\a\n" + + "\x03ALL\x10\x01\x12\n" + + "\n" + + "\x06CUSTOM\x10\x02*4\n" + + "\fOptionalBool\x12\t\n" + + "\x05UNSET\x10\x00\x12\v\n" + + "\aENABLED\x10\x01\x12\f\n" + + "\bDISABLED\x10\x02*\x85\x01\n" + + "\vAvatarColor\x12\b\n" + + "\x04A100\x10\x00\x12\b\n" + + "\x04A110\x10\x01\x12\b\n" + + "\x04A120\x10\x02\x12\b\n" + + "\x04A130\x10\x03\x12\b\n" + + "\x04A140\x10\x04\x12\b\n" + + "\x04A150\x10\x05\x12\b\n" + + "\x04A160\x10\x06\x12\b\n" + + "\x04A170\x10\a\x12\b\n" + + "\x04A180\x10\b\x12\b\n" + + "\x04A190\x10\t\x12\b\n" + + "\x04A200\x10\n" + + "\x12\b\n" + + "\x04A210\x10\vB<\n" + + "8org.whispersystems.signalservice.internal.storage.protosP\x01b\x06proto3" var ( file_StorageService_proto_rawDescOnce sync.Once - file_StorageService_proto_rawDescData = file_StorageService_proto_rawDesc + file_StorageService_proto_rawDescData []byte ) func file_StorageService_proto_rawDescGZIP() []byte { file_StorageService_proto_rawDescOnce.Do(func() { - file_StorageService_proto_rawDescData = protoimpl.X.CompressGZIP(file_StorageService_proto_rawDescData) + file_StorageService_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_StorageService_proto_rawDesc), len(file_StorageService_proto_rawDesc))) }) return file_StorageService_proto_rawDescData } @@ -2736,7 +2997,7 @@ func file_StorageService_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_StorageService_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_StorageService_proto_rawDesc), len(file_StorageService_proto_rawDesc)), NumEnums: 8, NumMessages: 23, NumExtensions: 0, @@ -2748,7 +3009,6 @@ func file_StorageService_proto_init() { MessageInfos: file_StorageService_proto_msgTypes, }.Build() File_StorageService_proto = out.File - file_StorageService_proto_rawDesc = nil file_StorageService_proto_goTypes = nil file_StorageService_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/StorageService.pb.raw b/pkg/signalmeow/protobuf/StorageService.pb.raw deleted file mode 100644 index 1e4142f2f966d232fa2d25f4dc748e115b3520bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7611 zcmdT}OK%(36%HlJ8eTq3k6#n{%_NR(psYkYwwt6yNQ$x zP!6|6TJ%qJQFPm1(S3hLf&POO=%(kKJDe9u*+J1oH^kiYxX<(W&LO+f_Z?S17JcEK znIlo1xQ_3rMbA98b<2~)N}XK{#13@ZJQAL-YHagNxSr|QTIO!%L6*;l>J_$erdv~? ztpUBj<)HEv%Lh}meKA(cZ2eTsNVUN6bA{S>tPoT4)NQt5g1!fu>ksm^t!iSU)tD@o zf|ZA?$c1inC&JZz*e>qe1;Q&@ejRo=A6EXBVWl@N%pVDV&6II)WZG=Lc6<4f^NZo3 zy!tg`rVUr<fTh@|Sg1 z3O6H0j%%FrRuxw8oT)n!y8>SyR?0jm@&rx&p5;wL*uHsW!h;9rc#yh<n!WfCepG>wO@Sf9;yRS;-p&nF~hPr zRP$_e*m>3IzUh=d!9laz8PuDDas~%4cz4))y;EL`2DS1!4(iQjci0(}v+50Yy+7#k zx9@h_{Q++`hJ$vu^KKsor6!q@hP5l|h3=9i}x$_Z8?XjYCWPjH8bzjhpmlke3vE9Iv0}Y;>0Nwf6JQH?D z9}DdQ?KL9cj*s-QY0Zd@?~vm$3P!Ohghv~d@tSiy9An5jw4BkYFti-76h0r~Ip3c^ zjJCjLfXj#*C*i!hJ34`l8Css$;aG)$H`ZO4c4%V~&+WL9#3KJA;dguV2&Z( z>Enr31ko&C#=?6zfvY83)k-vFL;zp8K84keal@`K>V7n5ndV%@Rv)m7-VC(HFTz{C z1R6P>CaaHFSxW9jH?ETC0$sh&N>a9Cj!xF>^SgBIl%Kv`wcuZ7*)PzMVX}n zufVjh+uExS_Xm(l3QT$3;_bb5YZr1!iLqfP9IrJ>tne&o9Vte6PTps{8eLDGY- zxF;Z>TI~s#yA{6D69Swt_lyNk!0@Z^kMacc^yQvV`Ez!Do*-$UZ;W-cdkfvJ3<4K}gWh#cKfzub(QGK3&q*pEBp#Nb80{kG% ziSJSR1pkZE)Tiv4Cv>?`2m*?+oL60w+i*ltajszqr z!uB#Bc?9efer2+Rr#@!NB=8Rn0YbiZJ++s)`|wZ@7n<6D65te8>xYTy3Pc&MhIpaK zm+}x^Ok5N25P7!Ohq4+mgTm9~5TZ(;AR#Ikj@&+A8ZMx2fk@aIJHIsnF06wKt>B{J zc+*2~1mGV`TEd0`)SNLI8Gbl!PF+{nqgfNdy#AtsaynouElVHo(7)K_p( z??m_d!ao3D?zpD#daik zGun5{m_meuC+MFD;cItkOCJ(TR1)_gp(-}{&onj1wiX*x&twM`@KuSGe zg?Y6?b>(NEm9ITa9X%Pr=8K^MPpGT+pk&a!hCVu-PP8v^2Y^o_5};G{GsX^yKY+%I z_5ftEFEczwL!m=88iCb2q#=Lp6x2@qWmCRNrz1&~OR!39dk*cmwp;VBi(Aef?W zeFNwmQ)9V(dbf*E=s-w4howkMNPU;$Z>U(Rk^ zW|vHT68HiIueMS7j$Mo4h!}WDUKVuvT2SD;{F&bn{Ghp%4d0rWVwYF$$H@ z*lh{S6Kj8jP0*_{Cnmt_zU=q64Uc-xIlhdANLTiz6RiyNoh)C%Q4v2|mh;}@Vq!sN zp}vy>_&H9b{*~9jo)2{cvBrdI){ID%-$8pm*|$UIaUI8xO3V2W%}O`Mrrpy$?-crB z(t#2*#7v6^Il!~yQI_&5KW?%z=62a0{4eeuynEt!CgwU?un1r-7*mJl#ChMfty$2g zlGS_3OHk)>5#R`}mgFL;`Yrp^v`5y|5OvGKn&8Yd0N@Zt2?~$Z0(ec4HpNt_h#ft^ zu*-PxrvW>n1}gU2sk^sW#HO#YD({q<^)YSrEmMOvuv(Iq>Oor&QF=Q6F3cHf@FkPr z)Zz!anE2G}XHUI2$x7qG0(^yWZT*yCxp2dPIOZ*Wa^-w&CzTvmANHftBDuuJq{Vsu z{NJU;N|mwb^^*a1ldZ!)DKfM+hwzunL3!=b6IO_$OiV<>PQQf>xL5}wgWb5WIkEQW z_ZgOtbp$a_)pxeHL5aS0wqX_es%^`RSKoQO4H=JUPqrc9(breoknia0>9)*v^_^$i z@HY?9o^O{G`Sq*qa*n=gum+P~utvV|Eqm^`$5rTKd+@iUY{q)2$2D!}nL#3}BKU?s RXyre%UN3Waf&Qa?{2zQv9oGN= diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index 1d1da9b..adc1e3f 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: UnidentifiedDelivery.proto @@ -14,10 +14,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -527,17 +526,59 @@ func (x *UnidentifiedSenderMessage_Message) GetGroupId() []byte { var File_UnidentifiedDelivery_proto protoreflect.FileDescriptor -//go:embed UnidentifiedDelivery.pb.raw -var file_UnidentifiedDelivery_proto_rawDesc []byte +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\x12\n" + + "\x0ePREKEY_MESSAGE\x10\x01\x12\v\n" + + "\aMESSAGE\x10\x02\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 = file_UnidentifiedDelivery_proto_rawDesc + file_UnidentifiedDelivery_proto_rawDescData []byte ) func file_UnidentifiedDelivery_proto_rawDescGZIP() []byte { file_UnidentifiedDelivery_proto_rawDescOnce.Do(func() { - file_UnidentifiedDelivery_proto_rawDescData = protoimpl.X.CompressGZIP(file_UnidentifiedDelivery_proto_rawDescData) + 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 } @@ -575,7 +616,7 @@ func file_UnidentifiedDelivery_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_UnidentifiedDelivery_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_UnidentifiedDelivery_proto_rawDesc), len(file_UnidentifiedDelivery_proto_rawDesc)), NumEnums: 2, NumMessages: 6, NumExtensions: 0, @@ -587,7 +628,6 @@ func file_UnidentifiedDelivery_proto_init() { MessageInfos: file_UnidentifiedDelivery_proto_msgTypes, }.Build() File_UnidentifiedDelivery_proto = out.File - file_UnidentifiedDelivery_proto_rawDesc = nil file_UnidentifiedDelivery_proto_goTypes = nil file_UnidentifiedDelivery_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.raw b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.raw deleted file mode 100644 index 7d8db350b01354f7b5508c6ea3789823fdc2239c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1172 zcmb_c%Wl&^6eSOm_U2J{B%}}_R9Ql*ShymBstY!G7_gdzXyORiP^I=I9pT#6*eQ6= zZ}9Wxv6DCnERa}v?zyjX@0l^QXFhY$kJ%T7?f^Y@hdePt9>f7@L~P;Dy$Jao zb5Q?Lfa9q+Bkv=Z3C=u5asoAHW3~z>h0{9CL*xk@szULSW2>nA8=!p#wS2iI6q&24 zG^jWc4N6}z$8{6pj#MeK^4D;jAPU)i2@b6GUZZJRpR7QOkYlynuEv%ROC{Tw;l>-t#e{* ziDm2wMYDMQz6_7^qNlqYVHC|5NKWAh!yCLsKKCZeYmYgZq`R<+^c|jrF}l-u9*f9S z+#}qE$#c-wP}WBcT&H_@`&S97D=rq4<0M2ypxJq~GvQxnFtU8Z7RgkVAY(XA<;dMN zMfXpe+qqkGKUGTS1b!?YPBzKPB%j55NImbE@Ji{Lo!9@&y}zj;Uem^qofkYBp#4C9+)&AQFRnxzW6L`JGhcsj&e>>4{Z((U# diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index 45d5396..ff48cda 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: WebSocketResources.proto @@ -16,10 +16,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -300,17 +299,39 @@ func (x *WebSocketMessage) GetResponse() *WebSocketResponseMessage { var File_WebSocketResources_proto protoreflect.FileDescriptor -//go:embed WebSocketResources.pb.raw -var file_WebSocketResources_proto_rawDesc []byte +const file_WebSocketResources_proto_rawDesc = "" + + "\n" + + "\x18WebSocketResources.proto\x12\rsignalservice\"\x7f\n" + + "\x17WebSocketRequestMessage\x12\x12\n" + + "\x04verb\x18\x01 \x01(\tR\x04verb\x12\x12\n" + + "\x04path\x18\x02 \x01(\tR\x04path\x12\x12\n" + + "\x04body\x18\x03 \x01(\fR\x04body\x12\x18\n" + + "\aheaders\x18\x05 \x03(\tR\aheaders\x12\x0e\n" + + "\x02id\x18\x04 \x01(\x04R\x02id\"\x8a\x01\n" + + "\x18WebSocketResponseMessage\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" + + "\x06status\x18\x02 \x01(\rR\x06status\x12\x18\n" + + "\amessage\x18\x03 \x01(\tR\amessage\x12\x18\n" + + "\aheaders\x18\x05 \x03(\tR\aheaders\x12\x12\n" + + "\x04body\x18\x04 \x01(\fR\x04body\"\x83\x02\n" + + "\x10WebSocketMessage\x128\n" + + "\x04type\x18\x01 \x01(\x0e2$.signalservice.WebSocketMessage.TypeR\x04type\x12@\n" + + "\arequest\x18\x02 \x01(\v2&.signalservice.WebSocketRequestMessageR\arequest\x12C\n" + + "\bresponse\x18\x03 \x01(\v2'.signalservice.WebSocketResponseMessageR\bresponse\".\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\v\n" + + "\aREQUEST\x10\x01\x12\f\n" + + "\bRESPONSE\x10\x02BF\n" + + "3org.whispersystems.signalservice.internal.websocketB\x0fWebSocketProtos" var ( file_WebSocketResources_proto_rawDescOnce sync.Once - file_WebSocketResources_proto_rawDescData = file_WebSocketResources_proto_rawDesc + file_WebSocketResources_proto_rawDescData []byte ) func file_WebSocketResources_proto_rawDescGZIP() []byte { file_WebSocketResources_proto_rawDescOnce.Do(func() { - file_WebSocketResources_proto_rawDescData = protoimpl.X.CompressGZIP(file_WebSocketResources_proto_rawDescData) + file_WebSocketResources_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_WebSocketResources_proto_rawDesc), len(file_WebSocketResources_proto_rawDesc))) }) return file_WebSocketResources_proto_rawDescData } @@ -343,7 +364,7 @@ func file_WebSocketResources_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_WebSocketResources_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_WebSocketResources_proto_rawDesc), len(file_WebSocketResources_proto_rawDesc)), NumEnums: 1, NumMessages: 3, NumExtensions: 0, @@ -355,7 +376,6 @@ func file_WebSocketResources_proto_init() { MessageInfos: file_WebSocketResources_proto_msgTypes, }.Build() File_WebSocketResources_proto = out.File - file_WebSocketResources_proto_rawDesc = nil file_WebSocketResources_proto_goTypes = nil file_WebSocketResources_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.raw b/pkg/signalmeow/protobuf/WebSocketResources.pb.raw deleted file mode 100644 index a521defa0604210f4e9dc97d2d2b08983e362deb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 645 zcmaKq%}>HW5XEh&g3E`^9<)c&81>WxUOXC1y%-B_A)H&7K%>yQvp{*VJ`ngOnS%R8uKq|r*MQ;`5TiLz zN~{g=*fF}s-8s{>nq`q#IA$?ZwVK80EO%;h)?&J*4yi97ngK`Wv|E$*s-+!bCNsy9 zT8qib{V~WMY?iJNDuhC;0JNB1k~0*MSfd7Lv$9j`mIbw@kn76!ACL-Lp_JI}w@K_> z92LX^u|%GM&Y{!0_Vxnw4&~lRYMFM>M^fjYGu6D!-pw&HD`e$LR@vwiX>dTDiT<)? z@Ami;g|2#IXLLPcDJa?`^>OeL3?_knq8jGEjs0+B8?;3l%nyfyAoOjs|4i;vKKHhZ h1T*;ua}=<|gSE*@0GD^ diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 4e68cdc..cce9b50 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.1 +// protoc-gen-go v1.36.6 // protoc v3.21.12 // source: backuppb/Backup.proto @@ -11,10 +11,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) -import _ "embed" - const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) @@ -11178,17 +11177,1084 @@ func (*ChatStyle_AutomaticBubbleColor) Descriptor() ([]byte, []int) { var File_backuppb_Backup_proto protoreflect.FileDescriptor -//go:embed Backup.pb.raw -var file_backuppb_Backup_proto_rawDesc []byte +const file_backuppb_Backup_proto_rawDesc = "" + + "\n" + + "\x15backuppb/Backup.proto\x12\rsignal.backup\"\xd2\x01\n" + + "\n" + + "BackupInfo\x12\x18\n" + + "\aversion\x18\x01 \x01(\x04R\aversion\x12\"\n" + + "\fbackupTimeMs\x18\x02 \x01(\x04R\fbackupTimeMs\x12.\n" + + "\x12mediaRootBackupKey\x18\x03 \x01(\fR\x12mediaRootBackupKey\x12,\n" + + "\x11currentAppVersion\x18\x04 \x01(\tR\x11currentAppVersion\x12(\n" + + "\x0ffirstAppVersion\x18\x05 \x01(\tR\x0ffirstAppVersion\"\xf2\x03\n" + + "\x05Frame\x126\n" + + "\aaccount\x18\x01 \x01(\v2\x1a.signal.backup.AccountDataH\x00R\aaccount\x128\n" + + "\trecipient\x18\x02 \x01(\v2\x18.signal.backup.RecipientH\x00R\trecipient\x12)\n" + + "\x04chat\x18\x03 \x01(\v2\x13.signal.backup.ChatH\x00R\x04chat\x125\n" + + "\bchatItem\x18\x04 \x01(\v2\x17.signal.backup.ChatItemH\x00R\bchatItem\x12>\n" + + "\vstickerPack\x18\x05 \x01(\v2\x1a.signal.backup.StickerPackH\x00R\vstickerPack\x128\n" + + "\tadHocCall\x18\x06 \x01(\v2\x18.signal.backup.AdHocCallH\x00R\tadHocCall\x12V\n" + + "\x13notificationProfile\x18\a \x01(\v2\".signal.backup.NotificationProfileH\x00R\x13notificationProfile\x12;\n" + + "\n" + + "chatFolder\x18\b \x01(\v2\x19.signal.backup.ChatFolderH\x00R\n" + + "chatFolderB\x06\n" + + "\x04item\"\xf1\x12\n" + + "\vAccountData\x12\x1e\n" + + "\n" + + "profileKey\x18\x01 \x01(\fR\n" + + "profileKey\x12\x1f\n" + + "\busername\x18\x02 \x01(\tH\x00R\busername\x88\x01\x01\x12K\n" + + "\fusernameLink\x18\x03 \x01(\v2'.signal.backup.AccountData.UsernameLinkR\fusernameLink\x12\x1c\n" + + "\tgivenName\x18\x04 \x01(\tR\tgivenName\x12\x1e\n" + + "\n" + + "familyName\x18\x05 \x01(\tR\n" + + "familyName\x12$\n" + + "\ravatarUrlPath\x18\x06 \x01(\tR\ravatarUrlPath\x12a\n" + + "\x16donationSubscriberData\x18\a \x01(\v2).signal.backup.AccountData.SubscriberDataR\x16donationSubscriberData\x12T\n" + + "\x0faccountSettings\x18\t \x01(\v2*.signal.backup.AccountData.AccountSettingsR\x0faccountSettings\x12b\n" + + "\x15backupsSubscriberData\x18\n" + + " \x01(\v2,.signal.backup.AccountData.IAPSubscriberDataR\x15backupsSubscriberData\x12\x16\n" + + "\x06svrPin\x18\v \x01(\tR\x06svrPin\x1a\xf6\x01\n" + + "\fUsernameLink\x12\x18\n" + + "\aentropy\x18\x01 \x01(\fR\aentropy\x12\x1a\n" + + "\bserverId\x18\x02 \x01(\fR\bserverId\x12C\n" + + "\x05color\x18\x03 \x01(\x0e2-.signal.backup.AccountData.UsernameLink.ColorR\x05color\"k\n" + + "\x05Color\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\b\n" + + "\x04BLUE\x10\x01\x12\t\n" + + "\x05WHITE\x10\x02\x12\b\n" + + "\x04GREY\x10\x03\x12\t\n" + + "\x05OLIVE\x10\x04\x12\t\n" + + "\x05GREEN\x10\x05\x12\n" + + "\n" + + "\x06ORANGE\x10\x06\x12\b\n" + + "\x04PINK\x10\a\x12\n" + + "\n" + + "\x06PURPLE\x10\b\x1a\xb4\t\n" + + "\x0fAccountSettings\x12\"\n" + + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x126\n" + + "\x16sealedSenderIndicators\x18\x02 \x01(\bR\x16sealedSenderIndicators\x12*\n" + + "\x10typingIndicators\x18\x03 \x01(\bR\x10typingIndicators\x12\"\n" + + "\flinkPreviews\x18\x04 \x01(\bR\flinkPreviews\x12B\n" + + "\x1cnotDiscoverableByPhoneNumber\x18\x05 \x01(\bR\x1cnotDiscoverableByPhoneNumber\x122\n" + + "\x14preferContactAvatars\x18\x06 \x01(\bR\x14preferContactAvatars\x12@\n" + + "\x1buniversalExpireTimerSeconds\x18\a \x01(\rR\x1buniversalExpireTimerSeconds\x126\n" + + "\x16preferredReactionEmoji\x18\b \x03(\tR\x16preferredReactionEmoji\x126\n" + + "\x16displayBadgesOnProfile\x18\t \x01(\bR\x16displayBadgesOnProfile\x126\n" + + "\x16keepMutedChatsArchived\x18\n" + + " \x01(\bR\x16keepMutedChatsArchived\x126\n" + + "\x16hasSetMyStoriesPrivacy\x18\v \x01(\bR\x16hasSetMyStoriesPrivacy\x12:\n" + + "\x18hasViewedOnboardingStory\x18\f \x01(\bR\x18hasViewedOnboardingStory\x12(\n" + + "\x0fstoriesDisabled\x18\r \x01(\bR\x0fstoriesDisabled\x12?\n" + + "\x18storyViewReceiptsEnabled\x18\x0e \x01(\bH\x00R\x18storyViewReceiptsEnabled\x88\x01\x01\x12H\n" + + "\x1fhasSeenGroupStoryEducationSheet\x18\x0f \x01(\bR\x1fhasSeenGroupStoryEducationSheet\x12F\n" + + "\x1ehasCompletedUsernameOnboarding\x18\x10 \x01(\bR\x1ehasCompletedUsernameOnboarding\x12i\n" + + "\x16phoneNumberSharingMode\x18\x11 \x01(\x0e21.signal.backup.AccountData.PhoneNumberSharingModeR\x16phoneNumberSharingMode\x12D\n" + + "\x10defaultChatStyle\x18\x12 \x01(\v2\x18.signal.backup.ChatStyleR\x10defaultChatStyle\x12T\n" + + "\x10customChatColors\x18\x13 \x03(\v2(.signal.backup.ChatStyle.CustomChatColorR\x10customChatColorsB\x1b\n" + + "\x19_storyViewReceiptsEnabled\x1a\x86\x01\n" + + "\x0eSubscriberData\x12\"\n" + + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12\"\n" + + "\fcurrencyCode\x18\x02 \x01(\tR\fcurrencyCode\x12,\n" + + "\x11manuallyCancelled\x18\x03 \x01(\bR\x11manuallyCancelled\x1a\xac\x01\n" + + "\x11IAPSubscriberData\x12\"\n" + + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12&\n" + + "\rpurchaseToken\x18\x02 \x01(\tH\x00R\rpurchaseToken\x126\n" + + "\x15originalTransactionId\x18\x03 \x01(\x04H\x00R\x15originalTransactionIdB\x13\n" + + "\x11iapSubscriptionId\"@\n" + + "\x16PhoneNumberSharingMode\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\r\n" + + "\tEVERYBODY\x10\x01\x12\n" + + "\n" + + "\x06NOBODY\x10\x02B\v\n" + + "\t_usernameJ\x04\b\b\x10\t\"\x84\x03\n" + + "\tRecipient\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x122\n" + + "\acontact\x18\x02 \x01(\v2\x16.signal.backup.ContactH\x00R\acontact\x12,\n" + + "\x05group\x18\x03 \x01(\v2\x14.signal.backup.GroupH\x00R\x05group\x12Q\n" + + "\x10distributionList\x18\x04 \x01(\v2#.signal.backup.DistributionListItemH\x00R\x10distributionList\x12)\n" + + "\x04self\x18\x05 \x01(\v2\x13.signal.backup.SelfH\x00R\x04self\x12A\n" + + "\freleaseNotes\x18\x06 \x01(\v2\x1b.signal.backup.ReleaseNotesH\x00R\freleaseNotes\x125\n" + + "\bcallLink\x18\a \x01(\v2\x17.signal.backup.CallLinkH\x00R\bcallLinkB\r\n" + + "\vdestination\"\xcb\n" + + "\n" + + "\aContact\x12\x15\n" + + "\x03aci\x18\x01 \x01(\fH\x01R\x03aci\x88\x01\x01\x12\x15\n" + + "\x03pni\x18\x02 \x01(\fH\x02R\x03pni\x88\x01\x01\x12\x1f\n" + + "\busername\x18\x03 \x01(\tH\x03R\busername\x88\x01\x01\x12\x17\n" + + "\x04e164\x18\x04 \x01(\x04H\x04R\x04e164\x88\x01\x01\x12\x18\n" + + "\ablocked\x18\x05 \x01(\bR\ablocked\x12A\n" + + "\n" + + "visibility\x18\x06 \x01(\x0e2!.signal.backup.Contact.VisibilityR\n" + + "visibility\x12C\n" + + "\n" + + "registered\x18\a \x01(\v2!.signal.backup.Contact.RegisteredH\x00R\n" + + "registered\x12L\n" + + "\rnotRegistered\x18\b \x01(\v2$.signal.backup.Contact.NotRegisteredH\x00R\rnotRegistered\x12#\n" + + "\n" + + "profileKey\x18\t \x01(\fH\x05R\n" + + "profileKey\x88\x01\x01\x12&\n" + + "\x0eprofileSharing\x18\n" + + " \x01(\bR\x0eprofileSharing\x12/\n" + + "\x10profileGivenName\x18\v \x01(\tH\x06R\x10profileGivenName\x88\x01\x01\x121\n" + + "\x11profileFamilyName\x18\f \x01(\tH\aR\x11profileFamilyName\x88\x01\x01\x12\x1c\n" + + "\thideStory\x18\r \x01(\bR\thideStory\x12%\n" + + "\videntityKey\x18\x0e \x01(\fH\bR\videntityKey\x88\x01\x01\x12J\n" + + "\ridentityState\x18\x0f \x01(\x0e2$.signal.backup.Contact.IdentityStateR\ridentityState\x127\n" + + "\bnickname\x18\x10 \x01(\v2\x1b.signal.backup.Contact.NameR\bnickname\x12\x12\n" + + "\x04note\x18\x11 \x01(\tR\x04note\x12(\n" + + "\x0fsystemGivenName\x18\x12 \x01(\tR\x0fsystemGivenName\x12*\n" + + "\x10systemFamilyName\x18\x13 \x01(\tR\x10systemFamilyName\x12&\n" + + "\x0esystemNickname\x18\x14 \x01(\tR\x0esystemNickname\x12A\n" + + "\vavatarColor\x18\x15 \x01(\x0e2\x1a.signal.backup.AvatarColorH\tR\vavatarColor\x88\x01\x01\x1a\f\n" + + "\n" + + "Registered\x1aE\n" + + "\rNotRegistered\x124\n" + + "\x15unregisteredTimestamp\x18\x01 \x01(\x04R\x15unregisteredTimestamp\x1a4\n" + + "\x04Name\x12\x14\n" + + "\x05given\x18\x01 \x01(\tR\x05given\x12\x16\n" + + "\x06family\x18\x02 \x01(\tR\x06family\":\n" + + "\rIdentityState\x12\v\n" + + "\aDEFAULT\x10\x00\x12\f\n" + + "\bVERIFIED\x10\x01\x12\x0e\n" + + "\n" + + "UNVERIFIED\x10\x02\"A\n" + + "\n" + + "Visibility\x12\v\n" + + "\aVISIBLE\x10\x00\x12\n" + + "\n" + + "\x06HIDDEN\x10\x01\x12\x1a\n" + + "\x16HIDDEN_MESSAGE_REQUEST\x10\x02B\x0e\n" + + "\fregistrationB\x06\n" + + "\x04_aciB\x06\n" + + "\x04_pniB\v\n" + + "\t_usernameB\a\n" + + "\x05_e164B\r\n" + + "\v_profileKeyB\x13\n" + + "\x11_profileGivenNameB\x14\n" + + "\x12_profileFamilyNameB\x0e\n" + + "\f_identityKeyB\x0e\n" + + "\f_avatarColor\"\x8f\x12\n" + + "\x05Group\x12\x1c\n" + + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12 \n" + + "\vwhitelisted\x18\x02 \x01(\bR\vwhitelisted\x12\x1c\n" + + "\thideStory\x18\x03 \x01(\bR\thideStory\x12H\n" + + "\rstorySendMode\x18\x04 \x01(\x0e2\".signal.backup.Group.StorySendModeR\rstorySendMode\x12>\n" + + "\bsnapshot\x18\x05 \x01(\v2\".signal.backup.Group.GroupSnapshotR\bsnapshot\x12\x18\n" + + "\ablocked\x18\x06 \x01(\bR\ablocked\x12A\n" + + "\vavatarColor\x18\a \x01(\x0e2\x1a.signal.backup.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x1a\xc5\x06\n" + + "\rGroupSnapshot\x12=\n" + + "\x05title\x18\x02 \x01(\v2'.signal.backup.Group.GroupAttributeBlobR\x05title\x12I\n" + + "\vdescription\x18\v \x01(\v2'.signal.backup.Group.GroupAttributeBlobR\vdescription\x12\x1c\n" + + "\tavatarUrl\x18\x03 \x01(\tR\tavatarUrl\x12e\n" + + "\x19disappearingMessagesTimer\x18\x04 \x01(\v2'.signal.backup.Group.GroupAttributeBlobR\x19disappearingMessagesTimer\x12H\n" + + "\raccessControl\x18\x05 \x01(\v2\".signal.backup.Group.AccessControlR\raccessControl\x12\x18\n" + + "\aversion\x18\x06 \x01(\rR\aversion\x125\n" + + "\amembers\x18\a \x03(\v2\x1b.signal.backup.Group.MemberR\amembers\x12h\n" + + "\x18membersPendingProfileKey\x18\b \x03(\v2,.signal.backup.Group.MemberPendingProfileKeyR\x18membersPendingProfileKey\x12q\n" + + "\x1bmembersPendingAdminApproval\x18\t \x03(\v2/.signal.backup.Group.MemberPendingAdminApprovalR\x1bmembersPendingAdminApproval\x12.\n" + + "\x12inviteLinkPassword\x18\n" + + " \x01(\fR\x12inviteLinkPassword\x12-\n" + + "\x12announcements_only\x18\f \x01(\bR\x11announcementsOnly\x12H\n" + + "\x0emembers_banned\x18\r \x03(\v2!.signal.backup.Group.MemberBannedR\rmembersBannedJ\x04\b\x01\x10\x02\x1a\xc3\x01\n" + + "\x12GroupAttributeBlob\x12\x16\n" + + "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + + "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + + "\x1cdisappearingMessagesDuration\x18\x03 \x01(\rH\x00R\x1cdisappearingMessagesDuration\x12*\n" + + "\x0fdescriptionText\x18\x04 \x01(\tH\x00R\x0fdescriptionTextB\t\n" + + "\acontent\x1a\xc1\x01\n" + + "\x06Member\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x124\n" + + "\x04role\x18\x02 \x01(\x0e2 .signal.backup.Group.Member.RoleR\x04role\x12(\n" + + "\x0fjoinedAtVersion\x18\x05 \x01(\rR\x0fjoinedAtVersion\"3\n" + + "\x04Role\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\v\n" + + "\aDEFAULT\x10\x01\x12\x11\n" + + "\rADMINISTRATOR\x10\x02J\x04\b\x03\x10\x04J\x04\b\x04\x10\x05\x1a\x92\x01\n" + + "\x17MemberPendingProfileKey\x123\n" + + "\x06member\x18\x01 \x01(\v2\x1b.signal.backup.Group.MemberR\x06member\x12$\n" + + "\raddedByUserId\x18\x02 \x01(\fR\raddedByUserId\x12\x1c\n" + + "\ttimestamp\x18\x03 \x01(\x04R\ttimestamp\x1a^\n" + + "\x1aMemberPendingAdminApproval\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + + "\ttimestamp\x18\x04 \x01(\x04R\ttimestampJ\x04\b\x02\x10\x03J\x04\b\x03\x10\x04\x1aD\n" + + "\fMemberBanned\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x1a\xea\x02\n" + + "\rAccessControl\x12Q\n" + + "\n" + + "attributes\x18\x01 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\n" + + "attributes\x12K\n" + + "\amembers\x18\x02 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\amembers\x12_\n" + + "\x11addFromInviteLink\x18\x03 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + + "\x0eAccessRequired\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\a\n" + + "\x03ANY\x10\x01\x12\n" + + "\n" + + "\x06MEMBER\x10\x02\x12\x11\n" + + "\rADMINISTRATOR\x10\x03\x12\x11\n" + + "\rUNSATISFIABLE\x10\x04\"7\n" + + "\rStorySendMode\x12\v\n" + + "\aDEFAULT\x10\x00\x12\f\n" + + "\bDISABLED\x10\x01\x12\v\n" + + "\aENABLED\x10\x02B\x0e\n" + + "\f_avatarColor\"Y\n" + + "\x04Self\x12A\n" + + "\vavatarColor\x18\x01 \x01(\x0e2\x1a.signal.backup.AvatarColorH\x00R\vavatarColor\x88\x01\x01B\x0e\n" + + "\f_avatarColor\"\x0e\n" + + "\fReleaseNotes\"\xd3\x03\n" + + "\x04Chat\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12 \n" + + "\vrecipientId\x18\x02 \x01(\x04R\vrecipientId\x12\x1a\n" + + "\barchived\x18\x03 \x01(\bR\barchived\x12%\n" + + "\vpinnedOrder\x18\x04 \x01(\rH\x00R\vpinnedOrder\x88\x01\x01\x121\n" + + "\x11expirationTimerMs\x18\x05 \x01(\x04H\x01R\x11expirationTimerMs\x88\x01\x01\x12%\n" + + "\vmuteUntilMs\x18\x06 \x01(\x04H\x02R\vmuteUntilMs\x88\x01\x01\x12\"\n" + + "\fmarkedUnread\x18\a \x01(\bR\fmarkedUnread\x12B\n" + + "\x1cdontNotifyForMentionsIfMuted\x18\b \x01(\bR\x1cdontNotifyForMentionsIfMuted\x12.\n" + + "\x05style\x18\t \x01(\v2\x18.signal.backup.ChatStyleR\x05style\x12.\n" + + "\x12expireTimerVersion\x18\n" + + " \x01(\rR\x12expireTimerVersionB\x0e\n" + + "\f_pinnedOrderB\x14\n" + + "\x12_expirationTimerMsB\x0e\n" + + "\f_muteUntilMs\"\x8f\x02\n" + + "\bCallLink\x12\x18\n" + + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\x1f\n" + + "\badminKey\x18\x02 \x01(\fH\x00R\badminKey\x88\x01\x01\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12H\n" + + "\frestrictions\x18\x04 \x01(\x0e2$.signal.backup.CallLink.RestrictionsR\frestrictions\x12\"\n" + + "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\"9\n" + + "\fRestrictions\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\b\n" + + "\x04NONE\x10\x01\x12\x12\n" + + "\x0eADMIN_APPROVAL\x10\x02B\v\n" + + "\t_adminKey\"\xca\x01\n" + + "\tAdHocCall\x12\x16\n" + + "\x06callId\x18\x01 \x01(\x04R\x06callId\x12 \n" + + "\vrecipientId\x18\x02 \x01(\x04R\vrecipientId\x124\n" + + "\x05state\x18\x03 \x01(\x0e2\x1e.signal.backup.AdHocCall.StateR\x05state\x12$\n" + + "\rcallTimestamp\x18\x04 \x01(\x04R\rcallTimestamp\"'\n" + + "\x05State\x12\x11\n" + + "\rUNKNOWN_STATE\x10\x00\x12\v\n" + + "\aGENERIC\x10\x01\"\xc5\x01\n" + + "\x14DistributionListItem\x12&\n" + + "\x0edistributionId\x18\x01 \x01(\fR\x0edistributionId\x12.\n" + + "\x11deletionTimestamp\x18\x02 \x01(\x04H\x00R\x11deletionTimestamp\x12M\n" + + "\x10distributionList\x18\x03 \x01(\v2\x1f.signal.backup.DistributionListH\x00R\x10distributionListB\x06\n" + + "\x04item\"\x8d\x02\n" + + "\x10DistributionList\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\"\n" + + "\fallowReplies\x18\x02 \x01(\bR\fallowReplies\x12M\n" + + "\vprivacyMode\x18\x03 \x01(\x0e2+.signal.backup.DistributionList.PrivacyModeR\vprivacyMode\x12.\n" + + "\x12memberRecipientIds\x18\x04 \x03(\x04R\x12memberRecipientIds\"B\n" + + "\vPrivacyMode\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\r\n" + + "\tONLY_WITH\x10\x01\x12\x0e\n" + + "\n" + + "ALL_EXCEPT\x10\x02\x12\a\n" + + "\x03ALL\x10\x03\"\xa4\f\n" + + "\bChatItem\x12\x16\n" + + "\x06chatId\x18\x01 \x01(\x04R\x06chatId\x12\x1a\n" + + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12\x1a\n" + + "\bdateSent\x18\x03 \x01(\x04R\bdateSent\x12-\n" + + "\x0fexpireStartDate\x18\x04 \x01(\x04H\x02R\x0fexpireStartDate\x88\x01\x01\x12%\n" + + "\vexpiresInMs\x18\x05 \x01(\x04H\x03R\vexpiresInMs\x88\x01\x01\x125\n" + + "\trevisions\x18\x06 \x03(\v2\x17.signal.backup.ChatItemR\trevisions\x12\x10\n" + + "\x03sms\x18\a \x01(\bR\x03sms\x12L\n" + + "\bincoming\x18\b \x01(\v2..signal.backup.ChatItem.IncomingMessageDetailsH\x00R\bincoming\x12L\n" + + "\boutgoing\x18\t \x01(\v2..signal.backup.ChatItem.OutgoingMessageDetailsH\x00R\boutgoing\x12[\n" + + "\rdirectionless\x18\n" + + " \x01(\v23.signal.backup.ChatItem.DirectionlessMessageDetailsH\x00R\rdirectionless\x12J\n" + + "\x0fstandardMessage\x18\v \x01(\v2\x1e.signal.backup.StandardMessageH\x01R\x0fstandardMessage\x12G\n" + + "\x0econtactMessage\x18\f \x01(\v2\x1d.signal.backup.ContactMessageH\x01R\x0econtactMessage\x12G\n" + + "\x0estickerMessage\x18\r \x01(\v2\x1d.signal.backup.StickerMessageH\x01R\x0estickerMessage\x12Y\n" + + "\x14remoteDeletedMessage\x18\x0e \x01(\v2#.signal.backup.RemoteDeletedMessageH\x01R\x14remoteDeletedMessage\x12H\n" + + "\rupdateMessage\x18\x0f \x01(\v2 .signal.backup.ChatUpdateMessageH\x01R\rupdateMessage\x12V\n" + + "\x13paymentNotification\x18\x10 \x01(\v2\".signal.backup.PaymentNotificationH\x01R\x13paymentNotification\x128\n" + + "\tgiftBadge\x18\x11 \x01(\v2\x18.signal.backup.GiftBadgeH\x01R\tgiftBadge\x12J\n" + + "\x0fviewOnceMessage\x18\x12 \x01(\v2\x1e.signal.backup.ViewOnceMessageH\x01R\x0fviewOnceMessage\x12b\n" + + "\x17directStoryReplyMessage\x18\x13 \x01(\v2&.signal.backup.DirectStoryReplyMessageH\x01R\x17directStoryReplyMessage\x1a\xb4\x01\n" + + "\x16IncomingMessageDetails\x12\"\n" + + "\fdateReceived\x18\x01 \x01(\x04R\fdateReceived\x12+\n" + + "\x0edateServerSent\x18\x02 \x01(\x04H\x00R\x0edateServerSent\x88\x01\x01\x12\x12\n" + + "\x04read\x18\x03 \x01(\bR\x04read\x12\"\n" + + "\fsealedSender\x18\x04 \x01(\bR\fsealedSenderB\x11\n" + + "\x0f_dateServerSent\x1aS\n" + + "\x16OutgoingMessageDetails\x129\n" + + "\n" + + "sendStatus\x18\x01 \x03(\v2\x19.signal.backup.SendStatusR\n" + + "sendStatus\x1a\x1d\n" + + "\x1bDirectionlessMessageDetailsB\x14\n" + + "\x12directionalDetailsB\x06\n" + + "\x04itemB\x12\n" + + "\x10_expireStartDateB\x0e\n" + + "\f_expiresInMs\"\xeb\x06\n" + + "\n" + + "SendStatus\x12 \n" + + "\vrecipientId\x18\x01 \x01(\x04R\vrecipientId\x12\x1c\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12=\n" + + "\apending\x18\x03 \x01(\v2!.signal.backup.SendStatus.PendingH\x00R\apending\x124\n" + + "\x04sent\x18\x04 \x01(\v2\x1e.signal.backup.SendStatus.SentH\x00R\x04sent\x12C\n" + + "\tdelivered\x18\x05 \x01(\v2#.signal.backup.SendStatus.DeliveredH\x00R\tdelivered\x124\n" + + "\x04read\x18\x06 \x01(\v2\x1e.signal.backup.SendStatus.ReadH\x00R\x04read\x12:\n" + + "\x06viewed\x18\a \x01(\v2 .signal.backup.SendStatus.ViewedH\x00R\x06viewed\x12=\n" + + "\askipped\x18\b \x01(\v2!.signal.backup.SendStatus.SkippedH\x00R\askipped\x12:\n" + + "\x06failed\x18\t \x01(\v2 .signal.backup.SendStatus.FailedH\x00R\x06failed\x1a\t\n" + + "\aPending\x1a*\n" + + "\x04Sent\x12\"\n" + + "\fsealedSender\x18\x01 \x01(\bR\fsealedSender\x1a/\n" + + "\tDelivered\x12\"\n" + + "\fsealedSender\x18\x01 \x01(\bR\fsealedSender\x1a*\n" + + "\x04Read\x12\"\n" + + "\fsealedSender\x18\x01 \x01(\bR\fsealedSender\x1a,\n" + + "\x06Viewed\x12\"\n" + + "\fsealedSender\x18\x01 \x01(\bR\fsealedSender\x1a\t\n" + + "\aSkipped\x1a\x96\x01\n" + + "\x06Failed\x12F\n" + + "\x06reason\x18\x01 \x01(\x0e2..signal.backup.SendStatus.Failed.FailureReasonR\x06reason\"D\n" + + "\rFailureReason\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\v\n" + + "\aNETWORK\x10\x01\x12\x19\n" + + "\x15IDENTITY_KEY_MISMATCH\x10\x02B\x10\n" + + "\x0edeliveryStatus\"T\n" + + "\x04Text\x12\x12\n" + + "\x04body\x18\x01 \x01(\tR\x04body\x128\n" + + "\n" + + "bodyRanges\x18\x02 \x03(\v2\x18.signal.backup.BodyRangeR\n" + + "bodyRanges\"\x86\x03\n" + + "\x0fStandardMessage\x12/\n" + + "\x05quote\x18\x01 \x01(\v2\x14.signal.backup.QuoteH\x00R\x05quote\x88\x01\x01\x12,\n" + + "\x04text\x18\x02 \x01(\v2\x13.signal.backup.TextH\x01R\x04text\x88\x01\x01\x12B\n" + + "\vattachments\x18\x03 \x03(\v2 .signal.backup.MessageAttachmentR\vattachments\x12<\n" + + "\vlinkPreview\x18\x04 \x03(\v2\x1a.signal.backup.LinkPreviewR\vlinkPreview\x12;\n" + + "\blongText\x18\x05 \x01(\v2\x1a.signal.backup.FilePointerH\x02R\blongText\x88\x01\x01\x125\n" + + "\treactions\x18\x06 \x03(\v2\x17.signal.backup.ReactionR\treactionsB\b\n" + + "\x06_quoteB\a\n" + + "\x05_textB\v\n" + + "\t_longText\"\x83\x01\n" + + "\x0eContactMessage\x12:\n" + + "\acontact\x18\x01 \x01(\v2 .signal.backup.ContactAttachmentR\acontact\x125\n" + + "\treactions\x18\x02 \x03(\v2\x17.signal.backup.ReactionR\treactions\"\xb7\x02\n" + + "\x17DirectStoryReplyMessage\x12P\n" + + "\ttextReply\x18\x01 \x01(\v20.signal.backup.DirectStoryReplyMessage.TextReplyH\x00R\ttextReply\x12\x16\n" + + "\x05emoji\x18\x02 \x01(\tH\x00R\x05emoji\x125\n" + + "\treactions\x18\x03 \x03(\v2\x17.signal.backup.ReactionR\treactions\x1al\n" + + "\tTextReply\x12'\n" + + "\x04text\x18\x01 \x01(\v2\x13.signal.backup.TextR\x04text\x126\n" + + "\blongText\x18\x02 \x01(\v2\x1a.signal.backup.FilePointerR\blongTextB\a\n" + + "\x05replyJ\x04\b\x04\x10\x05\"\xdb\n" + + "\n" + + "\x13PaymentNotification\x12!\n" + + "\tamountMob\x18\x01 \x01(\tH\x00R\tamountMob\x88\x01\x01\x12\x1b\n" + + "\x06feeMob\x18\x02 \x01(\tH\x01R\x06feeMob\x88\x01\x01\x12\x17\n" + + "\x04note\x18\x03 \x01(\tH\x02R\x04note\x88\x01\x01\x12e\n" + + "\x12transactionDetails\x18\x04 \x01(\v25.signal.backup.PaymentNotification.TransactionDetailsR\x12transactionDetails\x1a\xe1\b\n" + + "\x12TransactionDetails\x12e\n" + + "\vtransaction\x18\x01 \x01(\v2A.signal.backup.PaymentNotification.TransactionDetails.TransactionH\x00R\vtransaction\x12w\n" + + "\x11failedTransaction\x18\x02 \x01(\v2G.signal.backup.PaymentNotification.TransactionDetails.FailedTransactionH\x00R\x11failedTransaction\x1aY\n" + + "\x1bMobileCoinTxoIdentification\x12\x1c\n" + + "\tpublicKey\x18\x01 \x03(\fR\tpublicKey\x12\x1c\n" + + "\tkeyImages\x18\x02 \x03(\fR\tkeyImages\x1a\xc5\x01\n" + + "\x11FailedTransaction\x12m\n" + + "\x06reason\x18\x01 \x01(\x0e2U.signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReasonR\x06reason\"A\n" + + "\rFailureReason\x12\v\n" + + "\aGENERIC\x10\x00\x12\v\n" + + "\aNETWORK\x10\x01\x12\x16\n" + + "\x12INSUFFICIENT_FUNDS\x10\x02\x1a\xbc\x04\n" + + "\vTransaction\x12`\n" + + "\x06status\x18\x01 \x01(\x0e2H.signal.backup.PaymentNotification.TransactionDetails.Transaction.StatusR\x06status\x12\x8d\x01\n" + + "\x18mobileCoinIdentification\x18\x02 \x01(\v2Q.signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentificationR\x18mobileCoinIdentification\x12!\n" + + "\ttimestamp\x18\x03 \x01(\x04H\x00R\ttimestamp\x88\x01\x01\x12#\n" + + "\n" + + "blockIndex\x18\x04 \x01(\x04H\x01R\n" + + "blockIndex\x88\x01\x01\x12+\n" + + "\x0eblockTimestamp\x18\x05 \x01(\x04H\x02R\x0eblockTimestamp\x88\x01\x01\x12%\n" + + "\vtransaction\x18\x06 \x01(\fH\x03R\vtransaction\x88\x01\x01\x12\x1d\n" + + "\areceipt\x18\a \x01(\fH\x04R\areceipt\x88\x01\x01\"4\n" + + "\x06Status\x12\v\n" + + "\aINITIAL\x10\x00\x12\r\n" + + "\tSUBMITTED\x10\x01\x12\x0e\n" + + "\n" + + "SUCCESSFUL\x10\x02B\f\n" + + "\n" + + "_timestampB\r\n" + + "\v_blockIndexB\x11\n" + + "\x0f_blockTimestampB\x0e\n" + + "\f_transactionB\n" + + "\n" + + "\b_receiptB\t\n" + + "\apaymentB\f\n" + + "\n" + + "_amountMobB\t\n" + + "\a_feeMobB\a\n" + + "\x05_note\"\xc4\x01\n" + + "\tGiftBadge\x12D\n" + + "\x1dreceiptCredentialPresentation\x18\x01 \x01(\fR\x1dreceiptCredentialPresentation\x124\n" + + "\x05state\x18\x02 \x01(\x0e2\x1e.signal.backup.GiftBadge.StateR\x05state\";\n" + + "\x05State\x12\f\n" + + "\bUNOPENED\x10\x00\x12\n" + + "\n" + + "\x06OPENED\x10\x01\x12\f\n" + + "\bREDEEMED\x10\x02\x12\n" + + "\n" + + "\x06FAILED\x10\x03\"\x8a\x01\n" + + "\x0fViewOnceMessage\x12@\n" + + "\n" + + "attachment\x18\x01 \x01(\v2 .signal.backup.MessageAttachmentR\n" + + "attachment\x125\n" + + "\treactions\x18\x02 \x03(\v2\x17.signal.backup.ReactionR\treactions\"\x89\n" + + "\n" + + "\x11ContactAttachment\x12>\n" + + "\x04name\x18\x01 \x01(\v2%.signal.backup.ContactAttachment.NameH\x00R\x04name\x88\x01\x01\x12>\n" + + "\x06number\x18\x03 \x03(\v2&.signal.backup.ContactAttachment.PhoneR\x06number\x12<\n" + + "\x05email\x18\x04 \x03(\v2&.signal.backup.ContactAttachment.EmailR\x05email\x12H\n" + + "\aaddress\x18\x05 \x03(\v2..signal.backup.ContactAttachment.PostalAddressR\aaddress\x127\n" + + "\x06avatar\x18\x06 \x01(\v2\x1a.signal.backup.FilePointerH\x01R\x06avatar\x88\x01\x01\x12\"\n" + + "\forganization\x18\a \x01(\tR\forganization\x1a\xb0\x01\n" + + "\x04Name\x12\x1c\n" + + "\tgivenName\x18\x01 \x01(\tR\tgivenName\x12\x1e\n" + + "\n" + + "familyName\x18\x02 \x01(\tR\n" + + "familyName\x12\x16\n" + + "\x06prefix\x18\x03 \x01(\tR\x06prefix\x12\x16\n" + + "\x06suffix\x18\x04 \x01(\tR\x06suffix\x12\x1e\n" + + "\n" + + "middleName\x18\x05 \x01(\tR\n" + + "middleName\x12\x1a\n" + + "\bnickname\x18\x06 \x01(\tR\bnickname\x1a\xb5\x01\n" + + "\x05Phone\x12\x14\n" + + "\x05value\x18\x01 \x01(\tR\x05value\x12?\n" + + "\x04type\x18\x02 \x01(\x0e2+.signal.backup.ContactAttachment.Phone.TypeR\x04type\x12\x14\n" + + "\x05label\x18\x03 \x01(\tR\x05label\"?\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\b\n" + + "\x04HOME\x10\x01\x12\n" + + "\n" + + "\x06MOBILE\x10\x02\x12\b\n" + + "\x04WORK\x10\x03\x12\n" + + "\n" + + "\x06CUSTOM\x10\x04\x1a\xb5\x01\n" + + "\x05Email\x12\x14\n" + + "\x05value\x18\x01 \x01(\tR\x05value\x12?\n" + + "\x04type\x18\x02 \x01(\x0e2+.signal.backup.ContactAttachment.Email.TypeR\x04type\x12\x14\n" + + "\x05label\x18\x03 \x01(\tR\x05label\"?\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\b\n" + + "\x04HOME\x10\x01\x12\n" + + "\n" + + "\x06MOBILE\x10\x02\x12\b\n" + + "\x04WORK\x10\x03\x12\n" + + "\n" + + "\x06CUSTOM\x10\x04\x1a\xd7\x02\n" + + "\rPostalAddress\x12G\n" + + "\x04type\x18\x01 \x01(\x0e23.signal.backup.ContactAttachment.PostalAddress.TypeR\x04type\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\x12\x16\n" + + "\x06street\x18\x03 \x01(\tR\x06street\x12\x14\n" + + "\x05pobox\x18\x04 \x01(\tR\x05pobox\x12\"\n" + + "\fneighborhood\x18\x05 \x01(\tR\fneighborhood\x12\x12\n" + + "\x04city\x18\x06 \x01(\tR\x04city\x12\x16\n" + + "\x06region\x18\a \x01(\tR\x06region\x12\x1a\n" + + "\bpostcode\x18\b \x01(\tR\bpostcode\x12\x18\n" + + "\acountry\x18\t \x01(\tR\acountry\"3\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\b\n" + + "\x04HOME\x10\x01\x12\b\n" + + "\x04WORK\x10\x02\x12\n" + + "\n" + + "\x06CUSTOM\x10\x03B\a\n" + + "\x05_nameB\t\n" + + "\a_avatar\"y\n" + + "\x0eStickerMessage\x120\n" + + "\asticker\x18\x01 \x01(\v2\x16.signal.backup.StickerR\asticker\x125\n" + + "\treactions\x18\x02 \x03(\v2\x17.signal.backup.ReactionR\treactions\"\x16\n" + + "\x14RemoteDeletedMessage\"\xae\x01\n" + + "\aSticker\x12\x16\n" + + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + + "\apackKey\x18\x02 \x01(\fR\apackKey\x12\x1c\n" + + "\tstickerId\x18\x03 \x01(\rR\tstickerId\x12\x19\n" + + "\x05emoji\x18\x04 \x01(\tH\x00R\x05emoji\x88\x01\x01\x12.\n" + + "\x04data\x18\x05 \x01(\v2\x1a.signal.backup.FilePointerR\x04dataB\b\n" + + "\x06_emoji\"\xde\x01\n" + + "\vLinkPreview\x12\x10\n" + + "\x03url\x18\x01 \x01(\tR\x03url\x12\x19\n" + + "\x05title\x18\x02 \x01(\tH\x00R\x05title\x88\x01\x01\x125\n" + + "\x05image\x18\x03 \x01(\v2\x1a.signal.backup.FilePointerH\x01R\x05image\x88\x01\x01\x12%\n" + + "\vdescription\x18\x04 \x01(\tH\x02R\vdescription\x88\x01\x01\x12\x17\n" + + "\x04date\x18\x05 \x01(\x04H\x03R\x04date\x88\x01\x01B\b\n" + + "\x06_titleB\b\n" + + "\x06_imageB\x0e\n" + + "\f_descriptionB\a\n" + + "\x05_date\"\x9c\x02\n" + + "\x11MessageAttachment\x124\n" + + "\apointer\x18\x01 \x01(\v2\x1a.signal.backup.FilePointerR\apointer\x129\n" + + "\x04flag\x18\x02 \x01(\x0e2%.signal.backup.MessageAttachment.FlagR\x04flag\x12$\n" + + "\rwasDownloaded\x18\x03 \x01(\bR\rwasDownloaded\x12#\n" + + "\n" + + "clientUuid\x18\x04 \x01(\fH\x00R\n" + + "clientUuid\x88\x01\x01\"<\n" + + "\x04Flag\x12\b\n" + + "\x04NONE\x10\x00\x12\x11\n" + + "\rVOICE_MESSAGE\x10\x01\x12\x0e\n" + + "\n" + + "BORDERLESS\x10\x02\x12\a\n" + + "\x03GIF\x10\x03B\r\n" + + "\v_clientUuid\"\xec\t\n" + + "\vFilePointer\x12P\n" + + "\rbackupLocator\x18\x01 \x01(\v2(.signal.backup.FilePointer.BackupLocatorH\x00R\rbackupLocator\x12\\\n" + + "\x11attachmentLocator\x18\x02 \x01(\v2,.signal.backup.FilePointer.AttachmentLocatorH\x00R\x11attachmentLocator\x12q\n" + + "\x18invalidAttachmentLocator\x18\x03 \x01(\v23.signal.backup.FilePointer.InvalidAttachmentLocatorH\x00R\x18invalidAttachmentLocator\x12%\n" + + "\vcontentType\x18\x04 \x01(\tH\x01R\vcontentType\x88\x01\x01\x12+\n" + + "\x0eincrementalMac\x18\x05 \x01(\fH\x02R\x0eincrementalMac\x88\x01\x01\x12=\n" + + "\x17incrementalMacChunkSize\x18\x06 \x01(\rH\x03R\x17incrementalMacChunkSize\x88\x01\x01\x12\x1f\n" + + "\bfileName\x18\a \x01(\tH\x04R\bfileName\x88\x01\x01\x12\x19\n" + + "\x05width\x18\b \x01(\rH\x05R\x05width\x88\x01\x01\x12\x1b\n" + + "\x06height\x18\t \x01(\rH\x06R\x06height\x88\x01\x01\x12\x1d\n" + + "\acaption\x18\n" + + " \x01(\tH\aR\acaption\x88\x01\x01\x12\x1f\n" + + "\bblurHash\x18\v \x01(\tH\bR\bblurHash\x88\x01\x01\x1a\x9f\x02\n" + + "\rBackupLocator\x12\x1c\n" + + "\tmediaName\x18\x01 \x01(\tR\tmediaName\x12!\n" + + "\tcdnNumber\x18\x02 \x01(\rH\x00R\tcdnNumber\x88\x01\x01\x12\x10\n" + + "\x03key\x18\x03 \x01(\fR\x03key\x12\x16\n" + + "\x06digest\x18\x04 \x01(\fR\x06digest\x12\x12\n" + + "\x04size\x18\x05 \x01(\rR\x04size\x12)\n" + + "\rtransitCdnKey\x18\x06 \x01(\tH\x01R\rtransitCdnKey\x88\x01\x01\x12/\n" + + "\x10transitCdnNumber\x18\a \x01(\rH\x02R\x10transitCdnNumber\x88\x01\x01B\f\n" + + "\n" + + "_cdnNumberB\x10\n" + + "\x0e_transitCdnKeyB\x13\n" + + "\x11_transitCdnNumber\x1a\xca\x01\n" + + "\x11AttachmentLocator\x12\x16\n" + + "\x06cdnKey\x18\x01 \x01(\tR\x06cdnKey\x12\x1c\n" + + "\tcdnNumber\x18\x02 \x01(\rR\tcdnNumber\x12-\n" + + "\x0fuploadTimestamp\x18\x03 \x01(\x04H\x00R\x0fuploadTimestamp\x88\x01\x01\x12\x10\n" + + "\x03key\x18\x04 \x01(\fR\x03key\x12\x16\n" + + "\x06digest\x18\x05 \x01(\fR\x06digest\x12\x12\n" + + "\x04size\x18\x06 \x01(\rR\x04sizeB\x12\n" + + "\x10_uploadTimestamp\x1a\x1a\n" + + "\x18InvalidAttachmentLocatorB\t\n" + + "\alocatorB\x0e\n" + + "\f_contentTypeB\x11\n" + + "\x0f_incrementalMacB\x1a\n" + + "\x18_incrementalMacChunkSizeB\v\n" + + "\t_fileNameB\b\n" + + "\x06_widthB\t\n" + + "\a_heightB\n" + + "\n" + + "\b_captionB\v\n" + + "\t_blurHash\"\xae\x04\n" + + "\x05Quote\x125\n" + + "\x13targetSentTimestamp\x18\x01 \x01(\x04H\x00R\x13targetSentTimestamp\x88\x01\x01\x12\x1a\n" + + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12,\n" + + "\x04text\x18\x03 \x01(\v2\x13.signal.backup.TextH\x01R\x04text\x88\x01\x01\x12G\n" + + "\vattachments\x18\x04 \x03(\v2%.signal.backup.Quote.QuotedAttachmentR\vattachments\x12-\n" + + "\x04type\x18\x05 \x01(\x0e2\x19.signal.backup.Quote.TypeR\x04type\x1a\xca\x01\n" + + "\x10QuotedAttachment\x12%\n" + + "\vcontentType\x18\x01 \x01(\tH\x00R\vcontentType\x88\x01\x01\x12\x1f\n" + + "\bfileName\x18\x02 \x01(\tH\x01R\bfileName\x88\x01\x01\x12C\n" + + "\tthumbnail\x18\x03 \x01(\v2 .signal.backup.MessageAttachmentH\x02R\tthumbnail\x88\x01\x01B\x0e\n" + + "\f_contentTypeB\v\n" + + "\t_fileNameB\f\n" + + "\n" + + "_thumbnail\">\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\n" + + "\n" + + "\x06NORMAL\x10\x01\x12\x0e\n" + + "\n" + + "GIFT_BADGE\x10\x02\x12\r\n" + + "\tVIEW_ONCE\x10\x03B\x16\n" + + "\x14_targetSentTimestampB\a\n" + + "\x05_text\"\xfe\x01\n" + + "\tBodyRange\x12\x14\n" + + "\x05start\x18\x01 \x01(\rR\x05start\x12\x16\n" + + "\x06length\x18\x02 \x01(\rR\x06length\x12 \n" + + "\n" + + "mentionAci\x18\x03 \x01(\fH\x00R\n" + + "mentionAci\x126\n" + + "\x05style\x18\x04 \x01(\x0e2\x1e.signal.backup.BodyRange.StyleH\x00R\x05style\"V\n" + + "\x05Style\x12\b\n" + + "\x04NONE\x10\x00\x12\b\n" + + "\x04BOLD\x10\x01\x12\n" + + "\n" + + "\x06ITALIC\x10\x02\x12\v\n" + + "\aSPOILER\x10\x03\x12\x11\n" + + "\rSTRIKETHROUGH\x10\x04\x12\r\n" + + "\tMONOSPACE\x10\x05B\x11\n" + + "\x0fassociatedValue\"\x80\x01\n" + + "\bReaction\x12\x14\n" + + "\x05emoji\x18\x01 \x01(\tR\x05emoji\x12\x1a\n" + + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12$\n" + + "\rsentTimestamp\x18\x03 \x01(\x04R\rsentTimestamp\x12\x1c\n" + + "\tsortOrder\x18\x04 \x01(\x04R\tsortOrder\"\xe8\x05\n" + + "\x11ChatUpdateMessage\x12E\n" + + "\fsimpleUpdate\x18\x01 \x01(\v2\x1f.signal.backup.SimpleChatUpdateH\x00R\fsimpleUpdate\x12H\n" + + "\vgroupChange\x18\x02 \x01(\v2$.signal.backup.GroupChangeChatUpdateH\x00R\vgroupChange\x12`\n" + + "\x15expirationTimerChange\x18\x03 \x01(\v2(.signal.backup.ExpirationTimerChatUpdateH\x00R\x15expirationTimerChange\x12N\n" + + "\rprofileChange\x18\x04 \x01(\v2&.signal.backup.ProfileChangeChatUpdateH\x00R\rprofileChange\x12H\n" + + "\vthreadMerge\x18\x05 \x01(\v2$.signal.backup.ThreadMergeChatUpdateH\x00R\vthreadMerge\x12Z\n" + + "\x11sessionSwitchover\x18\x06 \x01(\v2*.signal.backup.SessionSwitchoverChatUpdateH\x00R\x11sessionSwitchover\x12G\n" + + "\x0eindividualCall\x18\a \x01(\v2\x1d.signal.backup.IndividualCallH\x00R\x0eindividualCall\x128\n" + + "\tgroupCall\x18\b \x01(\v2\x18.signal.backup.GroupCallH\x00R\tgroupCall\x12]\n" + + "\x14learnedProfileChange\x18\t \x01(\v2'.signal.backup.LearnedProfileChatUpdateH\x00R\x14learnedProfileChangeB\b\n" + + "\x06update\"\x9d\x04\n" + + "\x0eIndividualCall\x12\x1b\n" + + "\x06callId\x18\x01 \x01(\x04H\x00R\x06callId\x88\x01\x01\x126\n" + + "\x04type\x18\x02 \x01(\x0e2\".signal.backup.IndividualCall.TypeR\x04type\x12E\n" + + "\tdirection\x18\x03 \x01(\x0e2'.signal.backup.IndividualCall.DirectionR\tdirection\x129\n" + + "\x05state\x18\x04 \x01(\x0e2#.signal.backup.IndividualCall.StateR\x05state\x122\n" + + "\x14startedCallTimestamp\x18\x05 \x01(\x04R\x14startedCallTimestamp\x12\x12\n" + + "\x04read\x18\x06 \x01(\bR\x04read\"8\n" + + "\x04Type\x12\x10\n" + + "\fUNKNOWN_TYPE\x10\x00\x12\x0e\n" + + "\n" + + "AUDIO_CALL\x10\x01\x12\x0e\n" + + "\n" + + "VIDEO_CALL\x10\x02\">\n" + + "\tDirection\x12\x15\n" + + "\x11UNKNOWN_DIRECTION\x10\x00\x12\f\n" + + "\bINCOMING\x10\x01\x12\f\n" + + "\bOUTGOING\x10\x02\"g\n" + + "\x05State\x12\x11\n" + + "\rUNKNOWN_STATE\x10\x00\x12\f\n" + + "\bACCEPTED\x10\x01\x12\x10\n" + + "\fNOT_ACCEPTED\x10\x02\x12\n" + + "\n" + + "\x06MISSED\x10\x03\x12\x1f\n" + + "\x1bMISSED_NOTIFICATION_PROFILE\x10\x04B\t\n" + + "\a_callId\"\xbd\x04\n" + + "\tGroupCall\x12\x1b\n" + + "\x06callId\x18\x01 \x01(\x04H\x00R\x06callId\x88\x01\x01\x124\n" + + "\x05state\x18\x02 \x01(\x0e2\x1e.signal.backup.GroupCall.StateR\x05state\x121\n" + + "\x11ringerRecipientId\x18\x03 \x01(\x04H\x01R\x11ringerRecipientId\x88\x01\x01\x12;\n" + + "\x16startedCallRecipientId\x18\x04 \x01(\x04H\x02R\x16startedCallRecipientId\x88\x01\x01\x122\n" + + "\x14startedCallTimestamp\x18\x05 \x01(\x04R\x14startedCallTimestamp\x123\n" + + "\x12endedCallTimestamp\x18\x06 \x01(\x04H\x03R\x12endedCallTimestamp\x88\x01\x01\x12\x12\n" + + "\x04read\x18\a \x01(\bR\x04read\"\x9c\x01\n" + + "\x05State\x12\x11\n" + + "\rUNKNOWN_STATE\x10\x00\x12\v\n" + + "\aGENERIC\x10\x01\x12\n" + + "\n" + + "\x06JOINED\x10\x02\x12\v\n" + + "\aRINGING\x10\x03\x12\f\n" + + "\bACCEPTED\x10\x04\x12\f\n" + + "\bDECLINED\x10\x05\x12\n" + + "\n" + + "\x06MISSED\x10\x06\x12\x1f\n" + + "\x1bMISSED_NOTIFICATION_PROFILE\x10\a\x12\x11\n" + + "\rOUTGOING_RING\x10\bB\t\n" + + "\a_callIdB\x14\n" + + "\x12_ringerRecipientIdB\x19\n" + + "\x17_startedCallRecipientIdB\x15\n" + + "\x13_endedCallTimestamp\"\xd3\x03\n" + + "\x10SimpleChatUpdate\x128\n" + + "\x04type\x18\x01 \x01(\x0e2$.signal.backup.SimpleChatUpdate.TypeR\x04type\"\x84\x03\n" + + "\x04Type\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\x11\n" + + "\rJOINED_SIGNAL\x10\x01\x12\x13\n" + + "\x0fIDENTITY_UPDATE\x10\x02\x12\x15\n" + + "\x11IDENTITY_VERIFIED\x10\x03\x12\x14\n" + + "\x10IDENTITY_DEFAULT\x10\x04\x12\x11\n" + + "\rCHANGE_NUMBER\x10\x05\x12$\n" + + " RELEASE_CHANNEL_DONATION_REQUEST\x10\x06\x12\x0f\n" + + "\vEND_SESSION\x10\a\x12\x18\n" + + "\x14CHAT_SESSION_REFRESH\x10\b\x12\x0f\n" + + "\vBAD_DECRYPT\x10\t\x12\x16\n" + + "\x12PAYMENTS_ACTIVATED\x10\n" + + "\x12\x1e\n" + + "\x1aPAYMENT_ACTIVATION_REQUEST\x10\v\x12 \n" + + "\x1cUNSUPPORTED_PROTOCOL_MESSAGE\x10\f\x12\x11\n" + + "\rREPORTED_SPAM\x10\r\x12\v\n" + + "\aBLOCKED\x10\x0e\x12\r\n" + + "\tUNBLOCKED\x10\x0f\x12\x1c\n" + + "\x18MESSAGE_REQUEST_ACCEPTED\x10\x10\"=\n" + + "\x19ExpirationTimerChatUpdate\x12 \n" + + "\vexpiresInMs\x18\x01 \x01(\x04R\vexpiresInMs\"W\n" + + "\x17ProfileChangeChatUpdate\x12\"\n" + + "\fpreviousName\x18\x01 \x01(\tR\fpreviousName\x12\x18\n" + + "\anewName\x18\x02 \x01(\tR\anewName\"^\n" + + "\x18LearnedProfileChatUpdate\x12\x14\n" + + "\x04e164\x18\x01 \x01(\x04H\x00R\x04e164\x12\x1c\n" + + "\busername\x18\x02 \x01(\tH\x00R\busernameB\x0e\n" + + "\fpreviousName\";\n" + + "\x15ThreadMergeChatUpdate\x12\"\n" + + "\fpreviousE164\x18\x01 \x01(\x04R\fpreviousE164\"1\n" + + "\x1bSessionSwitchoverChatUpdate\x12\x12\n" + + "\x04e164\x18\x01 \x01(\x04R\x04e164\"\x86\x1f\n" + + "\x15GroupChangeChatUpdate\x12E\n" + + "\aupdates\x18\x01 \x03(\v2+.signal.backup.GroupChangeChatUpdate.UpdateR\aupdates\x1a\xa5\x1e\n" + + "\x06Update\x12S\n" + + "\x12genericGroupUpdate\x18\x01 \x01(\v2!.signal.backup.GenericGroupUpdateH\x00R\x12genericGroupUpdate\x12V\n" + + "\x13groupCreationUpdate\x18\x02 \x01(\v2\".signal.backup.GroupCreationUpdateH\x00R\x13groupCreationUpdate\x12J\n" + + "\x0fgroupNameUpdate\x18\x03 \x01(\v2\x1e.signal.backup.GroupNameUpdateH\x00R\x0fgroupNameUpdate\x12P\n" + + "\x11groupAvatarUpdate\x18\x04 \x01(\v2 .signal.backup.GroupAvatarUpdateH\x00R\x11groupAvatarUpdate\x12_\n" + + "\x16groupDescriptionUpdate\x18\x05 \x01(\v2%.signal.backup.GroupDescriptionUpdateH\x00R\x16groupDescriptionUpdate\x12\x8f\x01\n" + + "&groupMembershipAccessLevelChangeUpdate\x18\x06 \x01(\v25.signal.backup.GroupMembershipAccessLevelChangeUpdateH\x00R&groupMembershipAccessLevelChangeUpdate\x12\x8f\x01\n" + + "&groupAttributesAccessLevelChangeUpdate\x18\a \x01(\v25.signal.backup.GroupAttributesAccessLevelChangeUpdateH\x00R&groupAttributesAccessLevelChangeUpdate\x12\x80\x01\n" + + "!groupAnnouncementOnlyChangeUpdate\x18\b \x01(\v20.signal.backup.GroupAnnouncementOnlyChangeUpdateH\x00R!groupAnnouncementOnlyChangeUpdate\x12_\n" + + "\x16groupAdminStatusUpdate\x18\t \x01(\v2%.signal.backup.GroupAdminStatusUpdateH\x00R\x16groupAdminStatusUpdate\x12\\\n" + + "\x15groupMemberLeftUpdate\x18\n" + + " \x01(\v2$.signal.backup.GroupMemberLeftUpdateH\x00R\x15groupMemberLeftUpdate\x12e\n" + + "\x18groupMemberRemovedUpdate\x18\v \x01(\v2'.signal.backup.GroupMemberRemovedUpdateH\x00R\x18groupMemberRemovedUpdate\x12e\n" + + "\x18selfInvitedToGroupUpdate\x18\f \x01(\v2'.signal.backup.SelfInvitedToGroupUpdateH\x00R\x18selfInvitedToGroupUpdate\x12\x80\x01\n" + + "!selfInvitedOtherUserToGroupUpdate\x18\r \x01(\v20.signal.backup.SelfInvitedOtherUserToGroupUpdateH\x00R!selfInvitedOtherUserToGroupUpdate\x12h\n" + + "\x19groupUnknownInviteeUpdate\x18\x0e \x01(\v2(.signal.backup.GroupUnknownInviteeUpdateH\x00R\x19groupUnknownInviteeUpdate\x12t\n" + + "\x1dgroupInvitationAcceptedUpdate\x18\x0f \x01(\v2,.signal.backup.GroupInvitationAcceptedUpdateH\x00R\x1dgroupInvitationAcceptedUpdate\x12t\n" + + "\x1dgroupInvitationDeclinedUpdate\x18\x10 \x01(\v2,.signal.backup.GroupInvitationDeclinedUpdateH\x00R\x1dgroupInvitationDeclinedUpdate\x12b\n" + + "\x17groupMemberJoinedUpdate\x18\x11 \x01(\v2&.signal.backup.GroupMemberJoinedUpdateH\x00R\x17groupMemberJoinedUpdate\x12_\n" + + "\x16groupMemberAddedUpdate\x18\x12 \x01(\v2%.signal.backup.GroupMemberAddedUpdateH\x00R\x16groupMemberAddedUpdate\x12}\n" + + " groupSelfInvitationRevokedUpdate\x18\x13 \x01(\v2/.signal.backup.GroupSelfInvitationRevokedUpdateH\x00R groupSelfInvitationRevokedUpdate\x12q\n" + + "\x1cgroupInvitationRevokedUpdate\x18\x14 \x01(\v2+.signal.backup.GroupInvitationRevokedUpdateH\x00R\x1cgroupInvitationRevokedUpdate\x12_\n" + + "\x16groupJoinRequestUpdate\x18\x15 \x01(\v2%.signal.backup.GroupJoinRequestUpdateH\x00R\x16groupJoinRequestUpdate\x12w\n" + + "\x1egroupJoinRequestApprovalUpdate\x18\x16 \x01(\v2-.signal.backup.GroupJoinRequestApprovalUpdateH\x00R\x1egroupJoinRequestApprovalUpdate\x12w\n" + + "\x1egroupJoinRequestCanceledUpdate\x18\x17 \x01(\v2-.signal.backup.GroupJoinRequestCanceledUpdateH\x00R\x1egroupJoinRequestCanceledUpdate\x12k\n" + + "\x1agroupInviteLinkResetUpdate\x18\x18 \x01(\v2).signal.backup.GroupInviteLinkResetUpdateH\x00R\x1agroupInviteLinkResetUpdate\x12q\n" + + "\x1cgroupInviteLinkEnabledUpdate\x18\x19 \x01(\v2+.signal.backup.GroupInviteLinkEnabledUpdateH\x00R\x1cgroupInviteLinkEnabledUpdate\x12\x83\x01\n" + + "\"groupInviteLinkAdminApprovalUpdate\x18\x1a \x01(\v21.signal.backup.GroupInviteLinkAdminApprovalUpdateH\x00R\"groupInviteLinkAdminApprovalUpdate\x12t\n" + + "\x1dgroupInviteLinkDisabledUpdate\x18\x1b \x01(\v2,.signal.backup.GroupInviteLinkDisabledUpdateH\x00R\x1dgroupInviteLinkDisabledUpdate\x12t\n" + + "\x1dgroupMemberJoinedByLinkUpdate\x18\x1c \x01(\v2,.signal.backup.GroupMemberJoinedByLinkUpdateH\x00R\x1dgroupMemberJoinedByLinkUpdate\x12_\n" + + "\x16groupV2MigrationUpdate\x18\x1d \x01(\v2%.signal.backup.GroupV2MigrationUpdateH\x00R\x16groupV2MigrationUpdate\x12\x80\x01\n" + + "!groupV2MigrationSelfInvitedUpdate\x18\x1e \x01(\v20.signal.backup.GroupV2MigrationSelfInvitedUpdateH\x00R!groupV2MigrationSelfInvitedUpdate\x12\x89\x01\n" + + "$groupV2MigrationInvitedMembersUpdate\x18\x1f \x01(\v23.signal.backup.GroupV2MigrationInvitedMembersUpdateH\x00R$groupV2MigrationInvitedMembersUpdate\x12\x89\x01\n" + + "$groupV2MigrationDroppedMembersUpdate\x18 \x01(\v23.signal.backup.GroupV2MigrationDroppedMembersUpdateH\x00R$groupV2MigrationDroppedMembersUpdate\x12\x92\x01\n" + + "'groupSequenceOfRequestsAndCancelsUpdate\x18! \x01(\v26.signal.backup.GroupSequenceOfRequestsAndCancelsUpdateH\x00R'groupSequenceOfRequestsAndCancelsUpdate\x12k\n" + + "\x1agroupExpirationTimerUpdate\x18\" \x01(\v2).signal.backup.GroupExpirationTimerUpdateH\x00R\x1agroupExpirationTimerUpdateB\b\n" + + "\x06update\"H\n" + + "\x12GenericGroupUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01B\r\n" + + "\v_updaterAci\"I\n" + + "\x13GroupCreationUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01B\r\n" + + "\v_updaterAci\"\x7f\n" + + "\x0fGroupNameUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12'\n" + + "\fnewGroupName\x18\x02 \x01(\tH\x01R\fnewGroupName\x88\x01\x01B\r\n" + + "\v_updaterAciB\x0f\n" + + "\r_newGroupName\"g\n" + + "\x11GroupAvatarUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12\x1e\n" + + "\n" + + "wasRemoved\x18\x02 \x01(\bR\n" + + "wasRemovedB\r\n" + + "\v_updaterAci\"\x8c\x01\n" + + "\x16GroupDescriptionUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12+\n" + + "\x0enewDescription\x18\x02 \x01(\tH\x01R\x0enewDescription\x88\x01\x01B\r\n" + + "\v_updaterAciB\x11\n" + + "\x0f_newDescription\"\xa1\x01\n" + + "&GroupMembershipAccessLevelChangeUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12C\n" + + "\vaccessLevel\x18\x02 \x01(\x0e2!.signal.backup.GroupV2AccessLevelR\vaccessLevelB\r\n" + + "\v_updaterAci\"\xa1\x01\n" + + "&GroupAttributesAccessLevelChangeUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12C\n" + + "\vaccessLevel\x18\x02 \x01(\x0e2!.signal.backup.GroupV2AccessLevelR\vaccessLevelB\r\n" + + "\v_updaterAci\"\x87\x01\n" + + "!GroupAnnouncementOnlyChangeUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12.\n" + + "\x12isAnnouncementOnly\x18\x02 \x01(\bR\x12isAnnouncementOnlyB\r\n" + + "\v_updaterAci\"\xa0\x01\n" + + "\x16GroupAdminStatusUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12\x1c\n" + + "\tmemberAci\x18\x02 \x01(\fR\tmemberAci\x124\n" + + "\x15wasAdminStatusGranted\x18\x03 \x01(\bR\x15wasAdminStatusGrantedB\r\n" + + "\v_updaterAci\")\n" + + "\x15GroupMemberLeftUpdate\x12\x10\n" + + "\x03aci\x18\x01 \x01(\fR\x03aci\"n\n" + + "\x18GroupMemberRemovedUpdate\x12#\n" + + "\n" + + "removerAci\x18\x01 \x01(\fH\x00R\n" + + "removerAci\x88\x01\x01\x12\x1e\n" + + "\n" + + "removedAci\x18\x02 \x01(\fR\n" + + "removedAciB\r\n" + + "\v_removerAci\"N\n" + + "\x18SelfInvitedToGroupUpdate\x12#\n" + + "\n" + + "inviterAci\x18\x01 \x01(\fH\x00R\n" + + "inviterAci\x88\x01\x01B\r\n" + + "\v_inviterAci\"O\n" + + "!SelfInvitedOtherUserToGroupUpdate\x12*\n" + + "\x10inviteeServiceId\x18\x01 \x01(\fR\x10inviteeServiceId\"s\n" + + "\x19GroupUnknownInviteeUpdate\x12#\n" + + "\n" + + "inviterAci\x18\x01 \x01(\fH\x00R\n" + + "inviterAci\x88\x01\x01\x12\"\n" + + "\finviteeCount\x18\x02 \x01(\rR\finviteeCountB\r\n" + + "\v_inviterAci\"w\n" + + "\x1dGroupInvitationAcceptedUpdate\x12#\n" + + "\n" + + "inviterAci\x18\x01 \x01(\fH\x00R\n" + + "inviterAci\x88\x01\x01\x12\"\n" + + "\fnewMemberAci\x18\x02 \x01(\fR\fnewMemberAciB\r\n" + + "\v_inviterAci\"\x87\x01\n" + + "\x1dGroupInvitationDeclinedUpdate\x12#\n" + + "\n" + + "inviterAci\x18\x01 \x01(\fH\x00R\n" + + "inviterAci\x88\x01\x01\x12#\n" + + "\n" + + "inviteeAci\x18\x02 \x01(\fH\x01R\n" + + "inviteeAci\x88\x01\x01B\r\n" + + "\v_inviterAciB\r\n" + + "\v_inviteeAci\"=\n" + + "\x17GroupMemberJoinedUpdate\x12\"\n" + + "\fnewMemberAci\x18\x01 \x01(\fR\fnewMemberAci\"\xd2\x01\n" + + "\x16GroupMemberAddedUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12\"\n" + + "\fnewMemberAci\x18\x02 \x01(\fR\fnewMemberAci\x12,\n" + + "\x11hadOpenInvitation\x18\x03 \x01(\bR\x11hadOpenInvitation\x12#\n" + + "\n" + + "inviterAci\x18\x04 \x01(\fH\x01R\n" + + "inviterAci\x88\x01\x01B\r\n" + + "\v_updaterAciB\r\n" + + "\v_inviterAci\"V\n" + + " GroupSelfInvitationRevokedUpdate\x12#\n" + + "\n" + + "revokerAci\x18\x01 \x01(\fH\x00R\n" + + "revokerAci\x88\x01\x01B\r\n" + + "\v_revokerAci\"\xcb\x02\n" + + "\x1cGroupInvitationRevokedUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12O\n" + + "\binvitees\x18\x02 \x03(\v23.signal.backup.GroupInvitationRevokedUpdate.InviteeR\binvitees\x1a\xa5\x01\n" + + "\aInvitee\x12#\n" + + "\n" + + "inviterAci\x18\x01 \x01(\fH\x00R\n" + + "inviterAci\x88\x01\x01\x12#\n" + + "\n" + + "inviteeAci\x18\x02 \x01(\fH\x01R\n" + + "inviteeAci\x88\x01\x01\x12#\n" + + "\n" + + "inviteePni\x18\x03 \x01(\fH\x02R\n" + + "inviteePni\x88\x01\x01B\r\n" + + "\v_inviterAciB\r\n" + + "\v_inviteeAciB\r\n" + + "\v_inviteePniB\r\n" + + "\v_updaterAci\"<\n" + + "\x16GroupJoinRequestUpdate\x12\"\n" + + "\frequestorAci\x18\x01 \x01(\fR\frequestorAci\"\x9a\x01\n" + + "\x1eGroupJoinRequestApprovalUpdate\x12\"\n" + + "\frequestorAci\x18\x01 \x01(\fR\frequestorAci\x12#\n" + + "\n" + + "updaterAci\x18\x02 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12 \n" + + "\vwasApproved\x18\x03 \x01(\bR\vwasApprovedB\r\n" + + "\v_updaterAci\"D\n" + + "\x1eGroupJoinRequestCanceledUpdate\x12\"\n" + + "\frequestorAci\x18\x01 \x01(\fR\frequestorAci\"c\n" + + "'GroupSequenceOfRequestsAndCancelsUpdate\x12\"\n" + + "\frequestorAci\x18\x01 \x01(\fR\frequestorAci\x12\x14\n" + + "\x05count\x18\x02 \x01(\rR\x05count\"P\n" + + "\x1aGroupInviteLinkResetUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01B\r\n" + + "\v_updaterAci\"\x90\x01\n" + + "\x1cGroupInviteLinkEnabledUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12<\n" + + "\x19linkRequiresAdminApproval\x18\x02 \x01(\bR\x19linkRequiresAdminApprovalB\r\n" + + "\v_updaterAci\"\x96\x01\n" + + "\"GroupInviteLinkAdminApprovalUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12<\n" + + "\x19linkRequiresAdminApproval\x18\x02 \x01(\bR\x19linkRequiresAdminApprovalB\r\n" + + "\v_updaterAci\"S\n" + + "\x1dGroupInviteLinkDisabledUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01B\r\n" + + "\v_updaterAci\"C\n" + + "\x1dGroupMemberJoinedByLinkUpdate\x12\"\n" + + "\fnewMemberAci\x18\x01 \x01(\fR\fnewMemberAci\"\x18\n" + + "\x16GroupV2MigrationUpdate\"#\n" + + "!GroupV2MigrationSelfInvitedUpdate\"X\n" + + "$GroupV2MigrationInvitedMembersUpdate\x120\n" + + "\x13invitedMembersCount\x18\x01 \x01(\rR\x13invitedMembersCount\"X\n" + + "$GroupV2MigrationDroppedMembersUpdate\x120\n" + + "\x13droppedMembersCount\x18\x01 \x01(\rR\x13droppedMembersCount\"r\n" + + "\x1aGroupExpirationTimerUpdate\x12 \n" + + "\vexpiresInMs\x18\x01 \x01(\x04R\vexpiresInMs\x12#\n" + + "\n" + + "updaterAci\x18\x02 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01B\r\n" + + "\v_updaterAci\"?\n" + + "\vStickerPack\x12\x16\n" + + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + + "\apackKey\x18\x02 \x01(\fR\apackKey\"\x80\r\n" + + "\tChatStyle\x12T\n" + + "\x0fwallpaperPreset\x18\x01 \x01(\x0e2(.signal.backup.ChatStyle.WallpaperPresetH\x00R\x0fwallpaperPreset\x12D\n" + + "\x0ewallpaperPhoto\x18\x02 \x01(\v2\x1a.signal.backup.FilePointerH\x00R\x0ewallpaperPhoto\x12Y\n" + + "\x0fautoBubbleColor\x18\x03 \x01(\v2-.signal.backup.ChatStyle.AutomaticBubbleColorH\x01R\x0fautoBubbleColor\x12Z\n" + + "\x11bubbleColorPreset\x18\x04 \x01(\x0e2*.signal.backup.ChatStyle.BubbleColorPresetH\x01R\x11bubbleColorPreset\x12&\n" + + "\rcustomColorId\x18\x05 \x01(\x04H\x01R\rcustomColorId\x126\n" + + "\x16dimWallpaperInDarkMode\x18\a \x01(\bR\x16dimWallpaperInDarkMode\x1aV\n" + + "\bGradient\x12\x14\n" + + "\x05angle\x18\x01 \x01(\rR\x05angle\x12\x16\n" + + "\x06colors\x18\x02 \x03(\aR\x06colors\x12\x1c\n" + + "\tpositions\x18\x03 \x03(\x02R\tpositions\x1a\x83\x01\n" + + "\x0fCustomChatColor\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x16\n" + + "\x05solid\x18\x02 \x01(\aH\x00R\x05solid\x12?\n" + + "\bgradient\x18\x03 \x01(\v2!.signal.backup.ChatStyle.GradientH\x00R\bgradientB\a\n" + + "\x05color\x1a\x16\n" + + "\x14AutomaticBubbleColor\"\xc1\x03\n" + + "\x0fWallpaperPreset\x12\x1c\n" + + "\x18UNKNOWN_WALLPAPER_PRESET\x10\x00\x12\x0f\n" + + "\vSOLID_BLUSH\x10\x01\x12\x10\n" + + "\fSOLID_COPPER\x10\x02\x12\x0e\n" + + "\n" + + "SOLID_DUST\x10\x03\x12\x11\n" + + "\rSOLID_CELADON\x10\x04\x12\x14\n" + + "\x10SOLID_RAINFOREST\x10\x05\x12\x11\n" + + "\rSOLID_PACIFIC\x10\x06\x12\x0f\n" + + "\vSOLID_FROST\x10\a\x12\x0e\n" + + "\n" + + "SOLID_NAVY\x10\b\x12\x0f\n" + + "\vSOLID_LILAC\x10\t\x12\x0e\n" + + "\n" + + "SOLID_PINK\x10\n" + + "\x12\x12\n" + + "\x0eSOLID_EGGPLANT\x10\v\x12\x10\n" + + "\fSOLID_SILVER\x10\f\x12\x13\n" + + "\x0fGRADIENT_SUNSET\x10\r\x12\x11\n" + + "\rGRADIENT_NOIR\x10\x0e\x12\x14\n" + + "\x10GRADIENT_HEATMAP\x10\x0f\x12\x11\n" + + "\rGRADIENT_AQUA\x10\x10\x12\x17\n" + + "\x13GRADIENT_IRIDESCENT\x10\x11\x12\x15\n" + + "\x11GRADIENT_MONSTERA\x10\x12\x12\x12\n" + + "\x0eGRADIENT_BLISS\x10\x13\x12\x10\n" + + "\fGRADIENT_SKY\x10\x14\x12\x12\n" + + "\x0eGRADIENT_PEACH\x10\x15\"\xe9\x03\n" + + "\x11BubbleColorPreset\x12\x1f\n" + + "\x1bUNKNOWN_BUBBLE_COLOR_PRESET\x10\x00\x12\x15\n" + + "\x11SOLID_ULTRAMARINE\x10\x01\x12\x11\n" + + "\rSOLID_CRIMSON\x10\x02\x12\x13\n" + + "\x0fSOLID_VERMILION\x10\x03\x12\x10\n" + + "\fSOLID_BURLAP\x10\x04\x12\x10\n" + + "\fSOLID_FOREST\x10\x05\x12\x15\n" + + "\x11SOLID_WINTERGREEN\x10\x06\x12\x0e\n" + + "\n" + + "SOLID_TEAL\x10\a\x12\x0e\n" + + "\n" + + "SOLID_BLUE\x10\b\x12\x10\n" + + "\fSOLID_INDIGO\x10\t\x12\x10\n" + + "\fSOLID_VIOLET\x10\n" + + "\x12\x0e\n" + + "\n" + + "SOLID_PLUM\x10\v\x12\x0f\n" + + "\vSOLID_TAUPE\x10\f\x12\x0f\n" + + "\vSOLID_STEEL\x10\r\x12\x12\n" + + "\x0eGRADIENT_EMBER\x10\x0e\x12\x15\n" + + "\x11GRADIENT_MIDNIGHT\x10\x0f\x12\x15\n" + + "\x11GRADIENT_INFRARED\x10\x10\x12\x13\n" + + "\x0fGRADIENT_LAGOON\x10\x11\x12\x18\n" + + "\x14GRADIENT_FLUORESCENT\x10\x12\x12\x12\n" + + "\x0eGRADIENT_BASIL\x10\x13\x12\x14\n" + + "\x10GRADIENT_SUBLIME\x10\x14\x12\x10\n" + + "\fGRADIENT_SEA\x10\x15\x12\x16\n" + + "\x12GRADIENT_TANGERINE\x10\x16B\v\n" + + "\twallpaperB\r\n" + + "\vbubbleColor\"\xd8\x04\n" + + "\x13NotificationProfile\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + + "\x05emoji\x18\x02 \x01(\tH\x00R\x05emoji\x88\x01\x01\x12\x14\n" + + "\x05color\x18\x03 \x01(\aR\x05color\x12 \n" + + "\vcreatedAtMs\x18\x04 \x01(\x04R\vcreatedAtMs\x12$\n" + + "\rallowAllCalls\x18\x05 \x01(\bR\rallowAllCalls\x12*\n" + + "\x10allowAllMentions\x18\x06 \x01(\bR\x10allowAllMentions\x12&\n" + + "\x0eallowedMembers\x18\a \x03(\x04R\x0eallowedMembers\x12(\n" + + "\x0fscheduleEnabled\x18\b \x01(\bR\x0fscheduleEnabled\x12,\n" + + "\x11scheduleStartTime\x18\t \x01(\rR\x11scheduleStartTime\x12(\n" + + "\x0fscheduleEndTime\x18\n" + + " \x01(\rR\x0fscheduleEndTime\x12^\n" + + "\x13scheduleDaysEnabled\x18\v \x03(\x0e2,.signal.backup.NotificationProfile.DayOfWeekR\x13scheduleDaysEnabled\"t\n" + + "\tDayOfWeek\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\n" + + "\n" + + "\x06MONDAY\x10\x01\x12\v\n" + + "\aTUESDAY\x10\x02\x12\r\n" + + "\tWEDNESDAY\x10\x03\x12\f\n" + + "\bTHURSDAY\x10\x04\x12\n" + + "\n" + + "\x06FRIDAY\x10\x05\x12\f\n" + + "\bSATURDAY\x10\x06\x12\n" + + "\n" + + "\x06SUNDAY\x10\aB\b\n" + + "\x06_emoji\"\xd0\x03\n" + + "\n" + + "ChatFolder\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12&\n" + + "\x0eshowOnlyUnread\x18\x02 \x01(\bR\x0eshowOnlyUnread\x12&\n" + + "\x0eshowMutedChats\x18\x03 \x01(\bR\x0eshowMutedChats\x12<\n" + + "\x19includeAllIndividualChats\x18\x04 \x01(\bR\x19includeAllIndividualChats\x122\n" + + "\x14includeAllGroupChats\x18\x05 \x01(\bR\x14includeAllGroupChats\x12D\n" + + "\n" + + "folderType\x18\x06 \x01(\x0e2$.signal.backup.ChatFolder.FolderTypeR\n" + + "folderType\x122\n" + + "\x14includedRecipientIds\x18\a \x03(\x04R\x14includedRecipientIds\x122\n" + + "\x14excludedRecipientIds\x18\b \x03(\x04R\x14excludedRecipientIds\x12\x0e\n" + + "\x02id\x18\t \x01(\fR\x02id\".\n" + + "\n" + + "FolderType\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\a\n" + + "\x03ALL\x10\x01\x12\n" + + "\n" + + "\x06CUSTOM\x10\x02*\x85\x01\n" + + "\vAvatarColor\x12\b\n" + + "\x04A100\x10\x00\x12\b\n" + + "\x04A110\x10\x01\x12\b\n" + + "\x04A120\x10\x02\x12\b\n" + + "\x04A130\x10\x03\x12\b\n" + + "\x04A140\x10\x04\x12\b\n" + + "\x04A150\x10\x05\x12\b\n" + + "\x04A160\x10\x06\x12\b\n" + + "\x04A170\x10\a\x12\b\n" + + "\x04A180\x10\b\x12\b\n" + + "\x04A190\x10\t\x12\b\n" + + "\x04A200\x10\n" + + "\x12\b\n" + + "\x04A210\x10\v*\\\n" + + "\x12GroupV2AccessLevel\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\a\n" + + "\x03ANY\x10\x01\x12\n" + + "\n" + + "\x06MEMBER\x10\x02\x12\x11\n" + + "\rADMINISTRATOR\x10\x03\x12\x11\n" + + "\rUNSATISFIABLE\x10\x04B;\n" + + "*org.thoughtcrime.securesms.backup.v2.proto\xba\x02\fBackupProto_b\x06proto3" var ( file_backuppb_Backup_proto_rawDescOnce sync.Once - file_backuppb_Backup_proto_rawDescData = file_backuppb_Backup_proto_rawDesc + file_backuppb_Backup_proto_rawDescData []byte ) func file_backuppb_Backup_proto_rawDescGZIP() []byte { file_backuppb_Backup_proto_rawDescOnce.Do(func() { - file_backuppb_Backup_proto_rawDescData = protoimpl.X.CompressGZIP(file_backuppb_Backup_proto_rawDescData) + file_backuppb_Backup_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc))) }) return file_backuppb_Backup_proto_rawDescData } @@ -11725,7 +12791,7 @@ func file_backuppb_Backup_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_backuppb_Backup_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), NumEnums: 31, NumMessages: 122, NumExtensions: 0, @@ -11737,7 +12803,6 @@ func file_backuppb_Backup_proto_init() { MessageInfos: file_backuppb_Backup_proto_msgTypes, }.Build() File_backuppb_Backup_proto = out.File - file_backuppb_Backup_proto_rawDesc = nil file_backuppb_Backup_proto_goTypes = nil file_backuppb_Backup_proto_depIdxs = nil } diff --git a/pkg/signalmeow/protobuf/build-protos.sh b/pkg/signalmeow/protobuf/build-protos.sh index 86cc261..54116ec 100755 --- a/pkg/signalmeow/protobuf/build-protos.sh +++ b/pkg/signalmeow/protobuf/build-protos.sh @@ -6,12 +6,10 @@ do protoc --go_out=. \ --go_opt=M${file}=$PKG_IMPORT_PATH \ --go_opt=paths=source_relative \ - --go_opt=embed_raw=true \ $file done protoc --go_out=. \ --go_opt=Mbackuppb/Backup.proto=$PKG_IMPORT_PATH/backuppb \ --go_opt=paths=source_relative \ - --go_opt=embed_raw=true \ backuppb/Backup.proto pre-commit run -a From 408cfbd9b5c6519540140f16c4dc1eb9be7af081 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 24 Apr 2025 19:18:01 +0300 Subject: [PATCH 458/718] signalmeow/store: fix reading last message ID --- pkg/signalmeow/store/backup_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/store/backup_store.go b/pkg/signalmeow/store/backup_store.go index 823fe54..edcb658 100644 --- a/pkg/signalmeow/store/backup_store.go +++ b/pkg/signalmeow/store/backup_store.go @@ -271,7 +271,7 @@ func scanChat(row dbutil.Scannable) (*BackupChat, error) { return &BackupChat{ Chat: &chat, TotalMessages: int(totalMessageCount.Int64), - LatestMessageID: uint64(totalMessageCount.Int64), + LatestMessageID: uint64(latestMessageID.Int64), }, nil } From 5e72e4daddf617a586dcd5dcdf9da21728b6ed63 Mon Sep 17 00:00:00 2001 From: Toni Spets Date: Tue, 29 Apr 2025 14:12:08 +0300 Subject: [PATCH 459/718] signalwebsocket: Close and wait for main loop when socket is closed (#597) --- pkg/signalmeow/web/signalwebsocket.go | 34 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 47cc2e3..f856ec9 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -50,6 +50,8 @@ type SignalWebsocket struct { statusChannel chan SignalWebsocketConnectionStatus closeLock sync.RWMutex closeEvt *exsync.Event + closeCalled bool + cancel context.CancelFunc } func NewSignalWebsocket(basicAuth *url.Userinfo) *SignalWebsocket { @@ -96,16 +98,22 @@ func (s *SignalWebsocket) IsConnected() bool { return s.ws != nil } -func (s *SignalWebsocket) Close() error { - defer func() { - if s != nil { - s.ws = nil - } - }() - if s != nil && s.ws != nil { - return s.ws.Close(websocket.StatusNormalClosure, "") +func (s *SignalWebsocket) Close() (err error) { + if s == nil { + return nil } - return nil + + s.closeCalled = true + if s.ws != nil { + err = s.ws.Close(websocket.StatusNormalClosure, "") + s.ws = nil + } + if s.cancel != nil { + s.cancel() + s.cancel = nil + } + <-s.closeEvt.GetChan() + return err } func (s *SignalWebsocket) Connect(ctx context.Context, requestHandler RequestHandlerFunc) chan SignalWebsocketConnectionStatus { @@ -149,12 +157,12 @@ func (s *SignalWebsocket) connectLoop( log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_connect_loop"). Logger() - ctx, cancel := context.WithCancel(ctx) + ctx, s.cancel = context.WithCancel(ctx) incomingRequestChan := make(chan *signalpb.WebSocketRequestMessage, 256) defer func() { s.closeEvt.Set() - cancel() + s.cancel() s.closeLock.Lock() defer s.closeLock.Unlock() @@ -298,6 +306,10 @@ func (s *SignalWebsocket) connectLoop( if err != nil { err = fmt.Errorf("error in readLoop: %w", err) } + if s.closeCalled { + // Exit during Close() so cancel the reconnect loop as well + s.cancel() + } loopCancel(err) log.Info().Msg("readLoop exited") }() From 760ae1ed0935b892d7dc137e82bed74ff842d169 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 29 Apr 2025 23:41:49 +0300 Subject: [PATCH 460/718] signalmeow/web: fix panic caused by race on close --- pkg/signalmeow/web/signalwebsocket.go | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index f856ec9..089a601 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -25,6 +25,7 @@ import ( "net/url" "strings" "sync" + "sync/atomic" "time" "github.com/coder/websocket" @@ -44,14 +45,14 @@ type SimpleResponse struct { type RequestHandlerFunc func(context.Context, *signalpb.WebSocketRequestMessage) (*SimpleResponse, error) type SignalWebsocket struct { - ws *websocket.Conn + ws atomic.Pointer[websocket.Conn] basicAuth *url.Userinfo sendChannel chan SignalWebsocketSendMessage statusChannel chan SignalWebsocketConnectionStatus closeLock sync.RWMutex closeEvt *exsync.Event - closeCalled bool - cancel context.CancelFunc + closeCalled atomic.Bool + cancel atomic.Pointer[context.CancelFunc] } func NewSignalWebsocket(basicAuth *url.Userinfo) *SignalWebsocket { @@ -95,7 +96,7 @@ type SignalWebsocketConnectionStatus struct { } func (s *SignalWebsocket) IsConnected() bool { - return s.ws != nil + return s.ws.Load() != nil } func (s *SignalWebsocket) Close() (err error) { @@ -103,14 +104,12 @@ func (s *SignalWebsocket) Close() (err error) { return nil } - s.closeCalled = true - if s.ws != nil { - err = s.ws.Close(websocket.StatusNormalClosure, "") - s.ws = nil + s.closeCalled.Store(true) + if ws := s.ws.Swap(nil); ws != nil { + err = ws.Close(websocket.StatusNormalClosure, "") } - if s.cancel != nil { - s.cancel() - s.cancel = nil + if cancelLoop := s.cancel.Swap(nil); cancelLoop != nil { + (*cancelLoop)() } <-s.closeEvt.GetChan() return err @@ -157,12 +156,13 @@ func (s *SignalWebsocket) connectLoop( log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_connect_loop"). Logger() - ctx, s.cancel = context.WithCancel(ctx) + ctx, cancel := context.WithCancel(ctx) + s.cancel.Store(&cancel) incomingRequestChan := make(chan *signalpb.WebSocketRequestMessage, 256) defer func() { s.closeEvt.Set() - s.cancel() + cancel() s.closeLock.Lock() defer s.closeLock.Unlock() @@ -178,7 +178,7 @@ func (s *SignalWebsocket) connectLoop( const backoffIncrement = 5 * time.Second const maxBackoff = 60 * time.Second - if s.ws != nil { + if s.ws.Load() != nil { panic("Already connected") } @@ -289,7 +289,7 @@ func (s *SignalWebsocket) connectLoop( // Succssfully connected s.pushStatus(ctx, SignalWebsocketConnectionEventConnected, nil) - s.ws = ws + s.ws.Store(ws) retrying = false backoff = initialBackoff @@ -306,9 +306,9 @@ func (s *SignalWebsocket) connectLoop( if err != nil { err = fmt.Errorf("error in readLoop: %w", err) } - if s.closeCalled { + if s.closeCalled.Load() { // Exit during Close() so cancel the reconnect loop as well - s.cancel() + cancel() } loopCancel(err) log.Info().Msg("readLoop exited") From cfa7f3c496783a9990d35ede7fb43870f399a13d Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Wed, 7 May 2025 15:01:13 +0100 Subject: [PATCH 461/718] signalmeow: increase initial backoff to 10s --- pkg/signalmeow/web/signalwebsocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 089a601..3ea0b0a 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -174,7 +174,7 @@ func (s *SignalWebsocket) connectLoop( s.sendChannel = nil }() - const initialBackoff = 2 * time.Second + const initialBackoff = 10 * time.Second const backoffIncrement = 5 * time.Second const maxBackoff = 60 * time.Second From d3b05748cb1012a3da27f8b19282c7d5e7388f7a Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Wed, 7 May 2025 15:01:34 +0100 Subject: [PATCH 462/718] signalmeow: immediately react to context cancellations in the websocket loop --- pkg/signalmeow/web/signalwebsocket.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 3ea0b0a..f4cf4aa 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -241,10 +241,16 @@ func (s *SignalWebsocket) connectLoop( backoff = maxBackoff } log.Warn().Dur("backoff", backoff).Msg("Failed to connect, waiting to retry...") - time.Sleep(backoff) + select { + case <-time.After(backoff): + case <-ctx.Done(): + } backoff += backoffIncrement - } else if !isFirstConnect && s.basicAuth != nil && ctx.Err() == nil { - time.Sleep(initialBackoff) + } else if !isFirstConnect && s.basicAuth != nil { + select { + case <-time.After(initialBackoff): + case <-ctx.Done(): + } } if ctx.Err() != nil { log.Info().Msg("ctx done, stopping connection loop") From f6c5e01165d2a023553218b01996beb9517aa650 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 8 May 2025 15:09:39 +0300 Subject: [PATCH 463/718] handlematrix: use client-generated transaction IDs --- go.mod | 6 +++--- go.sum | 8 ++++---- pkg/connector/connector.go | 10 +++++++++ pkg/connector/handlematrix.go | 38 +++++++++++++++++++++++++++-------- pkg/msgconv/from-matrix.go | 10 ++------- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 28e17e8..4322e00 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.23.0 -toolchain go1.24.2 +toolchain go1.24.3 require ( github.com/coder/websocket v1.8.13 @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.6 + go.mau.fi/util v0.8.7-0.20250504163337-fc01e957f535 golang.org/x/crypto v0.37.0 golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 golang.org/x/net v0.39.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.23.3 + maunium.net/go/mautrix v0.23.4-0.20250508122520-376fa1f36898 ) require ( diff --git a/go.sum b/go.sum index fc57e3c..e45bd46 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI= github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.8.6 h1:AEK13rfgtiZJL2YsNK+W4ihhYCuukcRom8WPP/w/L54= -go.mau.fi/util v0.8.6/go.mod h1:uNB3UTXFbkpp7xL1M/WvQks90B/L4gvbLpbS0603KOE= +go.mau.fi/util v0.8.7-0.20250504163337-fc01e957f535 h1:ESKcyK5hWCzx8dzfSGKEuhuRD3Dg3eCtxOjxmjpnO5s= +go.mau.fi/util v0.8.7-0.20250504163337-fc01e957f535/go.mod h1:uNB3UTXFbkpp7xL1M/WvQks90B/L4gvbLpbS0603KOE= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= @@ -99,5 +99,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.23.3 h1:U+fzdcLhFKLUm5gf2+Q0hEUqWkwDMRfvE+paUH9ogSk= -maunium.net/go/mautrix v0.23.3/go.mod h1:LX+3evXVKSvh/b43BVC3rkvN2qV7b0bkIV4fY7Snn/4= +maunium.net/go/mautrix v0.23.4-0.20250508122520-376fa1f36898 h1:ZS1FV3+vmGquh//RGBRk3TzdoqCPOwEr40cA7k9e/jA= +maunium.net/go/mautrix v0.23.4-0.20250508122520-376fa1f36898/go.mod h1:pT4G5RZQ+nLfKzsmeDa4NhHghOVTrasLLwY9tZ2mO08= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 229d4ea..00032b8 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -19,12 +19,17 @@ package connector import ( "context" "fmt" + "strconv" "text/template" + "time" "github.com/google/uuid" "go.mau.fi/util/dbutil" "go.mau.fi/util/exsync" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/pkg/msgconv" "go.mau.fi/mautrix-signal/pkg/signalmeow" @@ -40,6 +45,7 @@ type SignalConnector struct { var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) +var _ bridgev2.TransactionIDGeneratingNetwork = (*SignalConnector)(nil) func (s *SignalConnector) GetName() bridgev2.BridgeName { return bridgev2.BridgeName{ @@ -105,3 +111,7 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use login.Client = sc return nil } + +func (s *SignalConnector) GenerateTransactionID(userID id.UserID, roomID id.RoomID, eventType event.Type) networkid.RawTransactionID { + return networkid.RawTransactionID(strconv.FormatInt(time.Now().UnixMilli(), 10)) +} diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index a329c0c..8137c84 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -21,6 +21,7 @@ import ( "crypto/sha256" "errors" "fmt" + "strconv" "time" "github.com/google/uuid" @@ -78,12 +79,29 @@ func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.Porta } } +func getTimestampForEvent(txnID networkid.RawTransactionID, evt *event.Event, origSender *bridgev2.OrigSender) uint64 { + if origSender != nil { + // Relaybot messages are never allowed to set the timestamp + return uint64(time.Now().UnixMilli()) + } + if len(txnID) > 0 { + parsed, err := strconv.ParseUint(string(txnID), 10, 64) + if err == nil { + return parsed + } + } + return uint64(evt.Timestamp) +} + func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) { - converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, msg.OrigSender != nil, msg.ReplyTo) + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) + converted, err := s.Main.MsgConv.ToSignal( + ctx, s.Client, msg.Portal, msg.Event, msg.Content, ts, msg.OrigSender != nil, msg.ReplyTo, + ) if err != nil { return nil, err } - msgID := signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) + msgID := signalid.MakeMessageID(s.Client.Store.ACI, ts) msg.AddPendingToIgnore(networkid.TransactionID(msgID)) err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) if err != nil { @@ -92,7 +110,7 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma dbMsg := &database.Message{ ID: msgID, SenderID: signalid.MakeUserID(s.Client.Store.ACI), - Timestamp: time.UnixMilli(int64(converted.GetTimestamp())), + Timestamp: time.UnixMilli(int64(ts)), Metadata: &signalid.MessageMetadata{ ContainsAttachments: len(converted.Attachments) > 0, }, @@ -117,7 +135,8 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri return fmt.Errorf("failed to get message reply target: %w", err) } } - converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, msg.OrigSender != nil, replyTo) + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) + converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, ts, msg.OrigSender != nil, replyTo) if err != nil { return err } @@ -128,7 +147,7 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri if err != nil { return bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } - msg.EditTarget.ID = signalid.MakeMessageID(s.Client.Store.ACI, converted.GetTimestamp()) + msg.EditTarget.ID = signalid.MakeMessageID(s.Client.Store.ACI, ts) msg.EditTarget.Metadata = &signalid.MessageMetadata{ContainsAttachments: len(converted.Attachments) > 0} msg.EditTarget.EditCount++ return nil @@ -147,9 +166,10 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M if err != nil { return nil, fmt.Errorf("failed to parse target message ID: %w", err) } + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) wrappedContent := &signalpb.Content{ DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + Timestamp: proto.Uint64(ts), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ Emoji: proto.String(msg.PreHandleResp.Emoji), @@ -171,9 +191,10 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid if err != nil { return fmt.Errorf("failed to parse target message ID: %w", err) } + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) wrappedContent := &signalpb.Content{ DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + Timestamp: proto.Uint64(ts), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ Emoji: proto.String(msg.TargetReaction.Emoji), @@ -197,9 +218,10 @@ func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridg } else if msg.TargetMessage.SenderID != signalid.MakeUserID(s.Client.Store.ACI) { return fmt.Errorf("cannot delete other people's messages") } + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) wrappedContent := &signalpb.Content{ DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(uint64(msg.Event.Timestamp)), + Timestamp: proto.Uint64(ts), Delete: &signalpb.DataMessage_Delete{ TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 8edf40f..367bb1f 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "strings" - "time" "github.com/rs/zerolog" "go.mau.fi/util/exmime" @@ -44,6 +43,7 @@ func (mc *MessageConverter) ToSignal( portal *bridgev2.Portal, evt *event.Event, content *event.MessageEventContent, + timestamp uint64, relaybotFormatted bool, replyTo *database.Message, ) (*signalpb.DataMessage, error) { @@ -53,14 +53,8 @@ func (mc *MessageConverter) ToSignal( content.MsgType = event.MessageType(event.EventSticker.Type) } - // Matrix timestamps can be faked, but if the user is using their own Signal account, faking timestamps is their problem. - ts := uint64(evt.Timestamp) - // However, when relaying, timestamps shouldn't be trusted because anyone can send a message with any timestamp. - if relaybotFormatted { - ts = uint64(time.Now().UnixMilli()) - } dm := &signalpb.DataMessage{ - Timestamp: &ts, + Timestamp: ×tamp, Preview: mc.convertURLPreviewToSignal(ctx, content), } if replyTo != nil { From 9944eb3507c8916d8180878c1d4a937220e03891 Mon Sep 17 00:00:00 2001 From: Toni Spets Date: Fri, 9 May 2025 13:57:28 +0300 Subject: [PATCH 464/718] Initial direct media support Everything still happens in-memory but any file can be downloaded using direct media URIs. --- pkg/connector/chatinfo.go | 48 +++++-- pkg/connector/directmedia.go | 122 ++++++++++++++++ pkg/connector/groupinfo.go | 65 +++++++-- pkg/connector/handlesignal.go | 11 +- pkg/msgconv/from-signal.go | 59 +++++--- pkg/msgconv/msgconv.go | 1 + pkg/signalid/media.go | 230 ++++++++++++++++++++++++++++++ pkg/signalmeow/attachments.go | 12 +- pkg/signalmeow/groups.go | 45 ++---- pkg/signalmeow/receiving.go | 2 +- pkg/signalmeow/types/identifer.go | 2 +- 11 files changed, 509 insertions(+), 88 deletions(-) create mode 100644 pkg/connector/directmedia.go create mode 100644 pkg/signalid/media.go diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 5b142cf..6fff853 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -58,13 +58,13 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( if !s.Main.Config.UseOutdatedProfiles && meta.ProfileFetchedAt.After(contact.Profile.FetchedAt) { return nil, nil } - return s.contactToUserInfo(contact), nil + return s.contactToUserInfo(ctx, contact) } func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { userID, groupID, err := signalid.ParsePortalID(portal.ID) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse portal id: %w", err) } if groupID != "" { return s.getGroupInfo(ctx, groupID, 0, nil) @@ -78,7 +78,7 @@ func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) } } -func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.UserInfo { +func (s *SignalClient) contactToUserInfo(ctx context.Context, contact *types.Recipient) (*bridgev2.UserInfo, error) { isBot := false ui := &bridgev2.UserInfo{ IsBot: &isBot, @@ -115,12 +115,33 @@ func (s *SignalClient) contactToUserInfo(contact *types.Recipient) *bridgev2.Use } else if contact.Profile.AvatarPath != "" { ui.Avatar = &bridgev2.Avatar{ ID: makeAvatarPathID(contact.Profile.AvatarPath), - Get: func(ctx context.Context) ([]byte, error) { + } + + if s.Main.MsgConv.DirectMedia { + userID, err := signalid.ParseUserLoginID(s.UserLogin.ID) + if err != nil { + return nil, fmt.Errorf("failed to parse user login ID: %w", err) + } + mediaID, err := signalid.DirectMediaProfileAvatar{ + UserID: userID, + ContactID: contact.ACI, + ProfileAvatarPath: contact.Profile.AvatarPath, + }.AsMediaID() + if err != nil { + return nil, err + } + ui.Avatar.MXC, err = s.Main.Bridge.Matrix.GenerateContentURI(ctx, mediaID) + if err != nil { + return nil, err + } + ui.Avatar.Hash = signalid.HashMediaID(mediaID) + } else { + ui.Avatar.Get = func(ctx context.Context) ([]byte, error) { return s.Client.DownloadUserAvatar(ctx, contact.Profile.AvatarPath, contact.Profile.Key) - }, + } } } - return ui + return ui, nil } var _ bridgev2.IdentifierValidatingNetwork = (*SignalConnector)(nil) @@ -177,6 +198,11 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre Stringer("pni", pni). Msg("Found resolve identifier target user") + userInfo, err := s.contactToUserInfo(ctx, recipient) + if err != nil { + return nil, fmt.Errorf("failed to convert contact: %w", err) + } + // createChat is a no-op: chats don't need to be created, and we always return chat info if aci != uuid.Nil { ghost, err := s.Main.Bridge.GetGhostByID(ctx, signalid.MakeUserID(aci)) @@ -185,14 +211,14 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre } return &bridgev2.ResolveIdentifierResponse{ UserID: signalid.MakeUserID(aci), - UserInfo: s.contactToUserInfo(recipient), + UserInfo: userInfo, Ghost: ghost, Chat: s.makeCreateDMResponse(ctx, recipient, nil), }, nil } else { return &bridgev2.ResolveIdentifierResponse{ UserID: signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), - UserInfo: s.contactToUserInfo(recipient), + UserInfo: userInfo, Chat: s.makeCreateDMResponse(ctx, recipient, nil), }, nil } @@ -210,8 +236,12 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI } resp := make([]*bridgev2.ResolveIdentifierResponse, len(recipients)) for i, recipient := range recipients { + userInfo, err := s.contactToUserInfo(ctx, recipient) + if err != nil { + return nil, fmt.Errorf("failed to convert contact: %w", err) + } recipientResp := &bridgev2.ResolveIdentifierResponse{ - UserInfo: s.contactToUserInfo(recipient), + UserInfo: userInfo, Chat: s.makeCreateDMResponse(ctx, recipient, nil), } if recipient.ACI != uuid.Nil { diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go new file mode 100644 index 0000000..b24c033 --- /dev/null +++ b/pkg/connector/directmedia.go @@ -0,0 +1,122 @@ +package connector + +import ( + "context" + "encoding/base64" + "fmt" + "io" + + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/mediaproxy" + + "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +var _ bridgev2.DirectMediableNetwork = (*SignalConnector)(nil) + +func (s *SignalConnector) SetUseDirectMedia() { + s.MsgConv.DirectMedia = true +} + +func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaID, params map[string]string) (mediaproxy.GetMediaResponse, error) { + log := s.Bridge.Log.With().Str("component", "direct download").Logger() + + info, err := signalid.ParseDirectMediaInfo(mediaID) + if err != nil { + return nil, fmt.Errorf("failed to parse direct media id: %w", err) + } + + switch info := info.(type) { + case *signalid.DirectMediaAttachment: + log.Info(). + Uint64("cdn_id", info.CDNID). + Str("cdn_key", info.CDNKey). + Uint32("cdn_number", info.CDNNumber). + Int("key_len", len(info.Key)). + Int("digest_len", len(info.Digest)). + Uint32("size", info.Size). + Msg("Direct downloading attachment") + + return &mediaproxy.GetMediaResponseCallback{ + Callback: func(w io.Writer) (int64, error) { + data, err := signalmeow.DownloadAttachment(ctx, info.CDNID, info.CDNKey, info.CDNNumber, info.Key, info.Digest, info.Size) + if err != nil { + log.Err(err).Msg("Direct download failed") + return 0, err + } + + _, err = w.Write(data) + return int64(info.Size), err + }, + }, nil + case *signalid.DirectMediaGroupAvatar: + log.Info(). + Stringer("user_id", info.UserID). + Hex("group_id", info.GroupID[:]). + Str("group_avatar_path", info.GroupAvatarPath). + Msg("Direct downloading group avatar") + + groupID := types.GroupIdentifier(base64.StdEncoding.EncodeToString(info.GroupID[:])) + + userLogin, err := s.Bridge.GetExistingUserLoginByID(ctx, signalid.MakeUserLoginID(info.UserID)) + if err != nil { + return nil, fmt.Errorf("failed to get user login: %w", err) + } + + client := userLogin.Client.(*SignalClient) + + groupMasterKey, err := client.Client.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, groupID) + if err != nil { + return nil, fmt.Errorf("failed to to get group master key: %w", err) + } + + return &mediaproxy.GetMediaResponseCallback{ + Callback: func(w io.Writer) (int64, error) { + data, err := client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) + if err != nil { + log.Err(err).Msg("Direct download failed") + return 0, err + } + + _, err = w.Write(data) + return int64(len(data)), err + }, + }, nil + case *signalid.DirectMediaProfileAvatar: + log.Info(). + Stringer("user_id", info.UserID). + Stringer("contact_id", info.ContactID). + Str("profile_avatar_path", info.ProfileAvatarPath). + Msg("Direct downloading profile avatar") + + userLogin, err := s.Bridge.GetExistingUserLoginByID(ctx, signalid.MakeUserLoginID(info.UserID)) + if err != nil { + return nil, fmt.Errorf("failed to get user login: %w", err) + } + + client := userLogin.Client.(*SignalClient) + + profileKey, err := client.Client.Store.RecipientStore.LoadProfileKey(ctx, info.ContactID) + if err != nil { + return nil, fmt.Errorf("failed to get contact: %w", err) + } + + return &mediaproxy.GetMediaResponseCallback{ + Callback: func(w io.Writer) (int64, error) { + data, err := client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) + if err != nil { + log.Err(err).Msg("Direct download failed") + return 0, err + } + + _, err = w.Write(data) + return int64(len(data)), err + }, + }, nil + default: + return nil, fmt.Errorf("no downloader for direct media type: %T", info) + } +} diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 0cb3ce5..0527ecf 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -18,6 +18,7 @@ package connector import ( "context" + "fmt" "time" "github.com/google/uuid" @@ -97,7 +98,7 @@ func inviteLinkToJoinRule(inviteLinkAccess signalmeow.AccessControl) event.JoinR func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32, backupChat *store.BackupChat) (*bridgev2.ChatInfo, error) { groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, minRevision) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to retrieve group by id: %w", err) } members := &bridgev2.ChatMemberList{ IsFull: true, @@ -160,10 +161,14 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get backup chat for group") } } + avatar, err := s.makeGroupAvatar(ctx, groupID, &groupInfo.AvatarPath, groupInfo.GroupMasterKey) + if err != nil { + return nil, fmt.Errorf("failed to make group avatar: %w", err) + } return &bridgev2.ChatInfo{ Name: &groupInfo.Title, Topic: &groupInfo.Description, - Avatar: s.makeGroupAvatar(groupInfo), + Avatar: avatar, Disappear: &database.DisappearingSetting{ Type: database.DisappearingTypeAfterRead, Timer: time.Duration(groupInfo.DisappearingMessagesDuration) * time.Second, @@ -176,18 +181,42 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden }, nil } -func (s *SignalClient) makeGroupAvatar(meta signalmeow.GroupAvatarMeta) *bridgev2.Avatar { - path := meta.GetAvatarPath() +func (s *SignalClient) makeGroupAvatar(ctx context.Context, groupID types.GroupIdentifier, path *string, groupMasterKey types.SerializedGroupMasterKey) (*bridgev2.Avatar, error) { if path == nil { - return nil + return nil, nil } - return &bridgev2.Avatar{ - ID: makeAvatarPathID(*path), - Get: func(ctx context.Context) ([]byte, error) { - return s.Client.DownloadGroupAvatar(ctx, meta) - }, + avatar := &bridgev2.Avatar{ + ID: makeAvatarPathID(*path), Remove: *path == "", } + if s.Main.MsgConv.DirectMedia { + userID, err := signalid.ParseUserLoginID(s.UserLogin.ID) + if err != nil { + return nil, fmt.Errorf("failed to parse user login ID: %w", err) + } + groupIDBytes, err := groupID.Bytes() + if err != nil { + return nil, fmt.Errorf("failed to get group id bytes: %w", err) + } + mediaID, err := signalid.DirectMediaGroupAvatar{ + UserID: userID, + GroupID: groupIDBytes, + GroupAvatarPath: *path, + }.AsMediaID() + if err != nil { + return nil, err + } + avatar.MXC, err = s.Main.Bridge.Matrix.GenerateContentURI(ctx, mediaID) + if err != nil { + return nil, err + } + avatar.Hash = signalid.HashMediaID(mediaID) + } else { + avatar.Get = func(ctx context.Context) ([]byte, error) { + return s.Client.DownloadGroupAvatar(ctx, *path, groupMasterKey) + } + } + return avatar, nil } func makeRevisionUpdater(rev uint32) func(ctx context.Context, portal *bridgev2.Portal) bool { @@ -201,13 +230,17 @@ func makeRevisionUpdater(rev uint32) func(ctx context.Context, portal *bridgev2. } } -func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint32, groupChange *signalmeow.GroupChange) *bridgev2.ChatInfoChange { +func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, groupID types.GroupIdentifier, rev uint32, groupChange *signalmeow.GroupChange) (*bridgev2.ChatInfoChange, error) { + avatar, err := s.makeGroupAvatar(ctx, groupID, groupChange.ModifyAvatar, groupChange.GroupMasterKey) + if err != nil { + return nil, err + } ic := &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ ExtraUpdates: makeRevisionUpdater(rev), Name: groupChange.ModifyTitle, Topic: groupChange.ModifyDescription, - Avatar: s.makeGroupAvatar(groupChange), + Avatar: avatar, }, } if groupChange.ModifyDisappearingMessagesDuration != nil { @@ -350,7 +383,7 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, rev uint if len(mc) > 0 || pls != nil { ic.MemberChanges = &bridgev2.ChatMemberList{Members: mc, PowerLevels: pls} } - return ic + return ic, nil } func (s *SignalClient) maybeResolvePNItoACI(ctx context.Context, serviceID *libsignalgo.ServiceID) *uuid.UUID { @@ -390,8 +423,10 @@ func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal } for _, gc := range groupChanges { log.Debug().Uint32("current_rev", gc.GroupChange.Revision).Msg("Processing group change") - chatInfoChange := s.groupChangeToChatInfoChange(ctx, gc.GroupChange.Revision, gc.GroupChange) - if gc.GroupChange.SourceServiceID.Type == libsignalgo.ServiceIDTypeACI { + chatInfoChange, err := s.groupChangeToChatInfoChange(ctx, types.GroupIdentifier(portal.ID), gc.GroupChange.Revision, gc.GroupChange) + if err != nil { + log.Err(err).Msg("Failed to convert group info") + } else if gc.GroupChange.SourceServiceID.Type == libsignalgo.ServiceIDTypeACI { portal.ProcessChatInfoChange(ctx, s.makeEventSender(gc.GroupChange.SourceServiceID.UUID), s.UserLogin, chatInfoChange, time.UnixMilli(int64(ts))) } if gc.GroupChange.Revision == toRevision { diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 16cfb50..8a94016 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -34,6 +34,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { @@ -188,7 +189,8 @@ func (evt *Bv2ChatEvent) GetChatInfoChange(ctx context.Context) (*bridgev2.ChatI if err != nil { return nil, fmt.Errorf("failed to decrypt group change: %w", err) } - return evt.s.groupChangeToChatInfoChange(ctx, gv2.GetRevision(), groupChange), nil + // XXX: is this ID compatible with types.GroupIdentifier? + return evt.s.groupChangeToChatInfoChange(ctx, types.GroupIdentifier(evt.Info.ChatID), gv2.GetRevision(), groupChange) } func (evt *Bv2ChatEvent) PreHandle(ctx context.Context, portal *bridgev2.Portal) { @@ -503,7 +505,12 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { log.Err(err).Msg("Failed to get ghost to update contact info") continue } - ghost.UpdateInfo(ctx, s.contactToUserInfo(contact)) + userInfo, err := s.contactToUserInfo(ctx, contact) + if err != nil { + log.Err(err).Msg("Failed to convert contact info") + continue + } + ghost.UpdateInfo(ctx, userInfo) if contact.ACI == s.Client.Store.ACI { s.updateRemoteProfile(ctx, true) } diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index fb80394..da5becb 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -478,40 +478,55 @@ func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalp return nil, ErrBackupNotSupported } } - return signalmeow.DownloadAttachment(ctx, att) + return signalmeow.DownloadAttachmentWithPointer(ctx, att) } func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*bridgev2.ConvertedMessagePart, error) { - data, err := mc.downloadAttachment(ctx, att, attMap) - if err != nil { - return nil, err - } - mimeType := att.GetContentType() - if mimeType == "" { - mimeType = http.DetectContentType(data) - } fileName := att.GetFileName() content := &event.MessageEventContent{ Info: &event.FileInfo{ Width: int(att.GetWidth()), Height: int(att.GetHeight()), - Size: len(data), + Size: int(att.GetSize()), }, } - if att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 && ffmpeg.Supported() { - data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mimeType) + mimeType := att.GetContentType() + if mc.DirectMedia { + mediaID, err := signalid.DirectMediaAttachment{ + CDNID: att.GetCdnId(), + CDNKey: att.GetCdnKey(), + CDNNumber: att.GetCdnNumber(), + Key: att.Key, + Digest: att.Digest, + Size: att.GetSize(), + }.AsMediaID() if err != nil { - return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err) + return nil, err + } + content.URL, err = mc.Bridge.Matrix.GenerateContentURI(ctx, mediaID) + } else { + data, err := mc.downloadAttachment(ctx, att, attMap) + if err != nil { + return nil, err + } + if mimeType == "" { + mimeType = http.DetectContentType(data) + } + if att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 && ffmpeg.Supported() { + data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mimeType) + if err != nil { + return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err) + } + fileName += ".ogg" + mimeType = "audio/ogg" + content.MSC3245Voice = &event.MSC3245Voice{} + // TODO include duration here (and in info) if there's some easy way to extract it with ffmpeg + //content.MSC1767Audio = &event.MSC1767Audio{} + } + content.URL, content.File, err = getIntent(ctx).UploadMedia(ctx, getPortal(ctx).MXID, data, fileName, mimeType) + if err != nil { + return nil, err } - fileName += ".ogg" - mimeType = "audio/ogg" - content.MSC3245Voice = &event.MSC3245Voice{} - // TODO include duration here (and in info) if there's some easy way to extract it with ffmpeg - //content.MSC1767Audio = &event.MSC1767Audio{} - } - content.URL, content.File, err = getIntent(ctx).UploadMedia(ctx, getPortal(ctx).MXID, data, fileName, mimeType) - if err != nil { - return nil, err } if att.GetBlurHash() != "" { content.Info.Blurhash = att.GetBlurHash() diff --git a/pkg/msgconv/msgconv.go b/pkg/msgconv/msgconv.go index 80717fc..01d46a6 100644 --- a/pkg/msgconv/msgconv.go +++ b/pkg/msgconv/msgconv.go @@ -47,6 +47,7 @@ type MessageConverter struct { MaxFileSize int64 LocationFormat string DisappearViewOnce bool + DirectMedia bool } func NewMessageConverter(br *bridgev2.Bridge) *MessageConverter { diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go new file mode 100644 index 0000000..defd4e5 --- /dev/null +++ b/pkg/signalid/media.go @@ -0,0 +1,230 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalid + +import ( + "bufio" + "bytes" + "crypto/sha256" + "encoding/binary" + "fmt" + "io" + + "github.com/google/uuid" + "maunium.net/go/mautrix/bridgev2/networkid" +) + +type directMediaType byte + +const ( + directMediaTypeAttachment directMediaType = iota + directMediaTypeGroupAvatar + directMediaTypeProfileAvatar +) + +type DirectMediaInfo interface { + AsMediaID() (networkid.MediaID, error) +} + +var ( + _ DirectMediaInfo = (*DirectMediaAttachment)(nil) + _ DirectMediaInfo = (*DirectMediaGroupAvatar)(nil) + _ DirectMediaInfo = (*DirectMediaProfileAvatar)(nil) +) + +type DirectMediaAttachment struct { + CDNID uint64 + CDNKey string + CDNNumber uint32 + Key []byte + Digest []byte + Size uint32 +} + +func (m DirectMediaAttachment) AsMediaID() (mediaID networkid.MediaID, err error) { + buf := &bytes.Buffer{} + + if err = binary.Write(buf, binary.BigEndian, directMediaTypeAttachment); err != nil { + return + } else if err = writeUvarint(buf, m.CDNID); err != nil { + return + } else if err = writeByteSlice(buf, []byte(m.CDNKey)); err != nil { + return + } else if err = writeUvarint(buf, uint64(m.CDNNumber)); err != nil { + return + } else if err = writeByteSlice(buf, m.Key); err != nil { + return + } else if err = writeByteSlice(buf, m.Digest); err != nil { + return + } else if err = writeUvarint(buf, uint64(m.Size)); err != nil { + return + } + + return networkid.MediaID(buf.Bytes()), nil +} + +type DirectMediaGroupAvatar struct { + UserID uuid.UUID + GroupID [32]byte + GroupAvatarPath string +} + +func (m DirectMediaGroupAvatar) AsMediaID() (mediaID networkid.MediaID, err error) { + buf := &bytes.Buffer{} + + if err = binary.Write(buf, binary.BigEndian, directMediaTypeGroupAvatar); err != nil { + return + } else if err = binary.Write(buf, binary.BigEndian, m.UserID); err != nil { + return + } else if err = binary.Write(buf, binary.BigEndian, m.GroupID); err != nil { + return + } else if err = writeByteSlice(buf, []byte(m.GroupAvatarPath)); err != nil { + return + } + + return networkid.MediaID(buf.Bytes()), nil +} + +type DirectMediaProfileAvatar struct { + UserID uuid.UUID + ContactID uuid.UUID + ProfileAvatarPath string +} + +func (m DirectMediaProfileAvatar) AsMediaID() (mediaID networkid.MediaID, err error) { + buf := &bytes.Buffer{} + + if err = binary.Write(buf, binary.BigEndian, directMediaTypeProfileAvatar); err != nil { + return + } else if err = binary.Write(buf, binary.BigEndian, m.UserID); err != nil { + return + } else if err = binary.Write(buf, binary.BigEndian, m.ContactID); err != nil { + return + } else if err = writeByteSlice(buf, []byte(m.ProfileAvatarPath)); err != nil { + return + } + + return networkid.MediaID(buf.Bytes()), nil +} + +func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err error) { + mediaIDLen := len(mediaID) + if mediaIDLen == 0 { + return nil, fmt.Errorf("empty media ID") + } + + buf := bufio.NewReader(bytes.NewBuffer(mediaID)) + + // type byte + var mediaType directMediaType + if err := binary.Read(buf, binary.BigEndian, &mediaType); err != nil { + return nil, fmt.Errorf("failed to read media type: %w", err) + } + + switch mediaType { + case directMediaTypeAttachment: + var info DirectMediaAttachment + + if info.CDNID, err = binary.ReadUvarint(buf); err != nil { + return info, fmt.Errorf("failed to read cdn id: %w", err) + } + if cdnKey, err := readByteSlice(buf, mediaIDLen); err != nil { + return info, fmt.Errorf("failed to read cdn key: %w", err) + } else { + info.CDNKey = string(cdnKey) + } + if cdnNumber, err := binary.ReadUvarint(buf); err != nil { + return info, fmt.Errorf("failed to read cdn number: %w", err) + } else { + info.CDNNumber = uint32(cdnNumber) + } + if info.Key, err = readByteSlice(buf, mediaIDLen); err != nil { + return info, fmt.Errorf("failed to read key: %w", err) + } else if info.Digest, err = readByteSlice(buf, mediaIDLen); err != nil { + return info, fmt.Errorf("failed to read digest: %w", err) + } + if size, err := binary.ReadUvarint(buf); err != nil { + return info, fmt.Errorf("failed to read cdn id: %w", err) + } else { + info.Size = uint32(size) + } + + return &info, nil + case directMediaTypeGroupAvatar: + var info DirectMediaGroupAvatar + + if err = binary.Read(buf, binary.BigEndian, &info.UserID); err != nil { + return info, fmt.Errorf("failed to read user id: %w", err) + } else if binary.Read(buf, binary.BigEndian, &info.GroupID); err != nil { + return info, fmt.Errorf("failed to read group id: %w", err) + } + if groupAvatarPath, err := readByteSlice(buf, mediaIDLen); err != nil { + return info, fmt.Errorf("failed to read group avatar path: %w", err) + } else { + info.GroupAvatarPath = string(groupAvatarPath) + } + + return &info, nil + case directMediaTypeProfileAvatar: + var info DirectMediaProfileAvatar + + if err = binary.Read(buf, binary.BigEndian, &info.UserID); err != nil { + return info, fmt.Errorf("failed to read user id: %w", err) + } else if err = binary.Read(buf, binary.BigEndian, &info.ContactID); err != nil { + return info, fmt.Errorf("failed to read contact id: %w", err) + } + if profileAvatarPath, err := readByteSlice(buf, mediaIDLen); err != nil { + return info, fmt.Errorf("failed to read profile avatar path: %w", err) + } else { + info.ProfileAvatarPath = string(profileAvatarPath) + } + } + + return nil, fmt.Errorf("invalid direct media type %d", mediaType) +} + +func HashMediaID(mediaID networkid.MediaID) [32]byte { + return sha256.Sum256(mediaID) +} + +func writeUvarint(w io.Writer, i uint64) error { + _, err := w.Write(binary.AppendUvarint(nil, i)) + return err +} + +func writeByteSlice(w io.Writer, b []byte) error { + if err := writeUvarint(w, uint64(len(b))); err != nil { + return err + } + _, err := w.Write(b) + return err +} + +func readByteSlice(r *bufio.Reader, maxLength int) ([]byte, error) { + length, err := binary.ReadUvarint(r) + if err != nil { + return nil, fmt.Errorf("reading uvarint failed: %w", err) + } else if int(length) > maxLength { + return nil, fmt.Errorf("byte slice size larger than expected: %d > %d", length, maxLength) + } else if length == 0 { + return nil, nil + } + + buf := make([]byte, length) + _, err = io.ReadFull(r, buf) + return buf, err +} diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index d733b40..386d9cc 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -59,9 +59,13 @@ var ErrInvalidMACForAttachment = errors.New("invalid MAC for attachment") var ErrInvalidDigestForAttachment = errors.New("invalid digest for attachment") var ErrAttachmentNotFound = errors.New("attachment not found on server") -func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]byte, error) { - path := getAttachmentPath(a.GetCdnId(), a.GetCdnKey()) - resp, err := web.GetAttachment(ctx, path, a.GetCdnNumber(), nil) +func DownloadAttachmentWithPointer(ctx context.Context, a *signalpb.AttachmentPointer) ([]byte, error) { + return DownloadAttachment(ctx, a.GetCdnId(), a.GetCdnKey(), a.GetCdnNumber(), a.Key, a.Digest, a.GetSize()) +} + +func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNumber uint32, key, digest []byte, size uint32) ([]byte, error) { + path := getAttachmentPath(cdnID, cdnKey) + resp, err := web.GetAttachment(ctx, path, cdnNumber, nil) if err != nil { return nil, err } @@ -84,7 +88,7 @@ func DownloadAttachment(ctx context.Context, a *signalpb.AttachmentPointer) ([]b return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } - return decryptAttachment(body, a.Key, a.Digest, *a.Size) + return decryptAttachment(body, key, digest, size) } const MACLength = 32 diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index ae44e12..f0b0815 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -42,11 +42,6 @@ import ( type GroupMemberRole int32 -type GroupAvatarMeta interface { - getGroupMasterKey() types.SerializedGroupMasterKey - GetAvatarPath() *string -} - const ( // Note: right now we assume these match the equivalent values in the protobuf (signalpb.Member_Role) GroupMember_UNKNOWN GroupMemberRole = 0 @@ -76,7 +71,7 @@ func (gm *GroupMember) UserServiceID() libsignalgo.ServiceID { } type Group struct { - groupMasterKey types.SerializedGroupMasterKey // We should keep this relatively private + GroupMasterKey types.SerializedGroupMasterKey // We should keep this relatively private GroupIdentifier types.GroupIdentifier // This is what we should use to identify a group outside this file Title string @@ -98,7 +93,7 @@ func (group *Group) GetInviteLink() (string, error) { if group.InviteLinkPassword == nil { return "", fmt.Errorf("no invite link password set") } - masterKeyBytes := masterKeyToBytes(group.groupMasterKey) + masterKeyBytes := masterKeyToBytes(group.GroupMasterKey) inviteLinkPasswordBytes, err := inviteLinkPasswordToBytes(*group.InviteLinkPassword) if err != nil { return "", fmt.Errorf("couldn't decode invite link password") @@ -124,13 +119,6 @@ type GroupAccessControl struct { Attributes AccessControl } -func (group *Group) getGroupMasterKey() types.SerializedGroupMasterKey { - return group.groupMasterKey -} -func (group *Group) GetAvatarPath() *string { - return &group.AvatarPath -} - type AddMember struct { GroupMember JoinFromInviteLink bool @@ -176,8 +164,7 @@ type BannedMember struct { } type GroupChange struct { - groupMasterKey types.SerializedGroupMasterKey - + GroupMasterKey types.SerializedGroupMasterKey SourceServiceID libsignalgo.ServiceID Revision uint32 AddMembers []*AddMember @@ -310,14 +297,6 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } } -func (groupChange *GroupChange) getGroupMasterKey() types.SerializedGroupMasterKey { - return groupChange.groupMasterKey -} - -func (groupChange *GroupChange) GetAvatarPath() *string { - return groupChange.ModifyAvatar -} - type GroupChangeState struct { GroupState *Group GroupChange *GroupChange @@ -481,7 +460,7 @@ func groupIdentifierFromMasterKey(masterKey types.SerializedGroupMasterKey) (typ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { log := zerolog.Ctx(ctx).With().Str("action", "decrypt group").Logger() decryptedGroup := &Group{ - groupMasterKey: groupMasterKey, + GroupMasterKey: groupMasterKey, } groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) @@ -642,7 +621,7 @@ func decryptGroupAvatar(encryptedAvatar []byte, groupMasterKey types.SerializedG } func groupMetadataForDataMessage(group Group) *signalpb.GroupContextV2 { - masterKey := masterKeyToBytes(group.groupMasterKey) + masterKey := masterKeyToBytes(group.GroupMasterKey) masterKeyBytes := masterKey[:] return &signalpb.GroupContextV2{ MasterKey: masterKeyBytes, @@ -710,16 +689,14 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t return group, nil } -func (cli *Client) DownloadGroupAvatar(ctx context.Context, group GroupAvatarMeta) ([]byte, error) { - groupMasterKey := group.getGroupMasterKey() - avatarPath := group.GetAvatarPath() +func (cli *Client) DownloadGroupAvatar(ctx context.Context, avatarPath string, groupMasterKey types.SerializedGroupMasterKey) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ Host: web.CDN1Hostname, Username: &username, Password: &password, } - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, *avatarPath, opts) + resp, err := web.SendHTTPRequest(ctx, http.MethodGet, avatarPath, opts) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } @@ -853,7 +830,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return nil, fmt.Errorf("wrong serviceid kind: expected aci, got pni") } decryptedGroupChange := &GroupChange{ - groupMasterKey: groupMasterKey, + GroupMasterKey: groupMasterKey, Revision: encryptedActions.Revision, SourceServiceID: sourceServiceID, } @@ -1221,7 +1198,7 @@ func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.Req func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroupChange *GroupChange, gid types.GroupIdentifier) (*signalpb.GroupChange, error) { log := zerolog.Ctx(ctx).With().Str("action", "EncryptGroupChange").Logger() - groupMasterKey := decryptedGroupChange.groupMasterKey + groupMasterKey := decryptedGroupChange.GroupMasterKey masterKeyBytes := masterKeyToBytes(groupMasterKey) groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyBytes) if err != nil { @@ -1573,7 +1550,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi log.Err(err).Msg("Could not get master key from group id") return 0, err } - groupChange.groupMasterKey = groupMasterKey + groupChange.GroupMasterKey = groupMasterKey masterKeyBytes := masterKeyToBytes(groupMasterKey) var refetchedAddMemberCredentials bool var signedGroupChange *signalpb.GroupChange @@ -1789,7 +1766,7 @@ func (cli *Client) CreateGroup(ctx context.Context, decryptedGroup *Group, avata log.Err(err).Msg("Error creating group on server") return nil, err } - masterKeyBytes := masterKeyToBytes(group.groupMasterKey) + masterKeyBytes := masterKeyToBytes(group.GroupMasterKey) groupContext := &signalpb.GroupContextV2{Revision: &group.Revision, MasterKey: masterKeyBytes[:]} _, err = cli.SendGroupUpdate(ctx, group, groupContext, nil) if err != nil { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 6ea9885..f9324f7 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -812,7 +812,7 @@ func (cli *Client) handleDecryptedResult( log.Debug().Msg("Recieved sync message contacts") blob := content.SyncMessage.Contacts.Blob if blob != nil { - contactsBytes, err := DownloadAttachment(ctx, blob) + contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob) if err != nil { log.Err(err).Msg("Contacts Sync DownloadAttachment error") } diff --git a/pkg/signalmeow/types/identifer.go b/pkg/signalmeow/types/identifer.go index c11238c..87ed647 100644 --- a/pkg/signalmeow/types/identifer.go +++ b/pkg/signalmeow/types/identifer.go @@ -31,7 +31,7 @@ func (gid GroupIdentifier) String() string { func (gid GroupIdentifier) Bytes() (raw libsignalgo.GroupIdentifier, err error) { var decoded []byte - decoded, err = base64.RawStdEncoding.DecodeString(string(gid)) + decoded, err = base64.StdEncoding.DecodeString(string(gid)) if err == nil { if len(decoded) != 32 { err = fmt.Errorf("invalid group identifier length") From 03af354d09444151bdece99545fb6f2e554c353d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 14:20:49 +0300 Subject: [PATCH 465/718] signalmeow/receiving: refactor decryption code --- pkg/signalmeow/receiving.go | 408 +++++++++++++----------------------- 1 file changed, 144 insertions(+), 264 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index f9324f7..27394b2 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -345,12 +345,11 @@ func (cli *Client) decryptEnvelope( case signalpb.Envelope_UNIDENTIFIED_SENDER: result, err := cli.decryptUnidentifiedSenderEnvelope(ctx, destinationServiceID, envelope) if err != nil { - log.Err(err).Msg("Failed to decrypt sealed sender message") result.Err = fmt.Errorf("failed to decrypt unidentified sender envelope: %w", err) } return result - case signalpb.Envelope_PREKEY_BUNDLE: + case signalpb.Envelope_PREKEY_BUNDLE, signalpb.Envelope_CIPHERTEXT: sender, err := libsignalgo.NewUUIDAddressFromString( *envelope.SourceServiceId, uint(*envelope.SourceDevice), @@ -358,79 +357,23 @@ func (cli *Client) decryptEnvelope( if err != nil { return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} } - result, err := cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) - if err != nil { - log.Err(err).Msg("Failed to decrypt prekey bundle message") - return DecryptionResult{Err: fmt.Errorf("failed to decrypt prekey bundle envelope: %w", err), SenderAddress: sender} + var result *DecryptionResult + var bundleType string + if *envelope.Type == signalpb.Envelope_PREKEY_BUNDLE { + result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) + bundleType = "prekey bundle" + } else { + result, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, sender, envelope.Content) + bundleType = "ciphertext" + } + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to decrypt %s envelope: %w", bundleType, err), SenderAddress: sender} } - log.Trace(). - Any("sender_address", result.SenderAddress). - Any("content", result.Content). - Msg("Prekey bundle decryption result") return *result case signalpb.Envelope_PLAINTEXT_CONTENT: return DecryptionResult{Err: fmt.Errorf("plaintext messages are not supported")} - case signalpb.Envelope_CIPHERTEXT: - senderAddress, err := libsignalgo.NewUUIDAddressFromString( - *envelope.SourceServiceId, - uint(*envelope.SourceDevice), - ) - if err != nil { - return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %w", err)} - } - message, err := libsignalgo.DeserializeMessage(envelope.Content) - if err != nil { - log.Err(err).Msg("Failed to deserialize ciphertext message") - return DecryptionResult{ - Err: fmt.Errorf("failed to deserialize message: %w", err), - SenderAddress: senderAddress, - } - } - sessionStore := cli.Store.SessionStore(destinationServiceID) - if sessionStore == nil { - return DecryptionResult{ - Err: fmt.Errorf("no session store for destination service ID %s", destinationServiceID), - SenderAddress: senderAddress, - } - } - identityStore := cli.Store.IdentityStore(destinationServiceID) - if identityStore == nil { - return DecryptionResult{ - Err: fmt.Errorf("no identity store for destination service ID %s", destinationServiceID), - SenderAddress: senderAddress, - } - } - decryptedText, err := libsignalgo.Decrypt( - ctx, - message, - senderAddress, - sessionStore, - identityStore, - ) - if err != nil { - if strings.Contains(err.Error(), "message with old counter") { - log.Warn().Err(err).Msg("Duplicate message error while decrypting whisper ciphertext") - } else { - log.Err(err).Msg("Failed to decrypt whisper ciphertext message") - } - return DecryptionResult{Err: fmt.Errorf("failed to decrypt ciphertext message: %w", err), SenderAddress: senderAddress} - } - err = stripPadding(&decryptedText) - if err != nil { - return DecryptionResult{Err: fmt.Errorf("failed to strip padding: %w", err), SenderAddress: senderAddress} - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - return DecryptionResult{Err: fmt.Errorf("failed to unmarshal decrypted message: %w", err), SenderAddress: senderAddress} - } - return DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - } - case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} @@ -441,10 +384,133 @@ func (cli *Client) decryptEnvelope( return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} default: - return DecryptionResult{Err: fmt.Errorf("unrecognized envelope type")} + return DecryptionResult{Err: fmt.Errorf("unrecognized envelope type %d", envelope.GetType())} } } +func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.ServiceID, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { + preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) + if err != nil { + return nil, fmt.Errorf("failed to deserialize prekey message: %w", err) + } else if preKeyMessage == nil { + return nil, fmt.Errorf("deserializing prekey message returned nil") + } + pks := cli.Store.PreKeyStore(destination) + if pks == nil { + return nil, fmt.Errorf("no prekey store found for %s", destination) + } + ss := cli.Store.SessionStore(destination) + if ss == nil { + return nil, fmt.Errorf("no session store found for %s", destination) + } + is := cli.Store.IdentityStore(destination) + if is == nil { + return nil, fmt.Errorf("no identity store found for %s", destination) + } + + data, err := libsignalgo.DecryptPreKey( + ctx, + preKeyMessage, + sender, + ss, + is, + pks, + pks, + pks, + ) + if err != nil { + return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) + } + err = stripPadding(&data) + if err != nil { + return nil, fmt.Errorf("failed to strip padding: %w", err) + } + content := &signalpb.Content{} + err = proto.Unmarshal(data, content) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted prekey message: %w", err) + } + return &DecryptionResult{ + SenderAddress: sender, + Content: content, + }, nil +} + +func (cli *Client) decryptCiphertextEnvelope( + ctx context.Context, + destinationServiceID libsignalgo.ServiceID, + senderAddress *libsignalgo.Address, + ciphertext []byte, +) (*DecryptionResult, error) { + log := zerolog.Ctx(ctx) + message, err := libsignalgo.DeserializeMessage(ciphertext) + if err != nil { + log.Err(err).Msg("Failed to deserialize ciphertext message") + return nil, fmt.Errorf("failed to deserialize message: %w", err) + } + sessionStore := cli.Store.SessionStore(destinationServiceID) + if sessionStore == nil { + return nil, fmt.Errorf("no session store for destination service ID %s", destinationServiceID) + } + identityStore := cli.Store.IdentityStore(destinationServiceID) + if identityStore == nil { + return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) + } + decryptedText, err := libsignalgo.Decrypt( + ctx, + message, + senderAddress, + sessionStore, + identityStore, + ) + if err != nil { + if strings.Contains(err.Error(), "message with old counter") { + log.Warn().Err(err).Msg("Duplicate message error while decrypting whisper ciphertext") + } else { + log.Err(err).Msg("Failed to decrypt whisper ciphertext message") + } + return nil, fmt.Errorf("failed to decrypt ciphertext message: %w", err) + } + err = stripPadding(&decryptedText) + if err != nil { + return nil, fmt.Errorf("failed to strip padding: %w", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted message: %w", err) + } + return &DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, + }, nil +} + +func (cli *Client) decryptSenderKeyMessage(ctx context.Context, senderAddress *libsignalgo.Address, ciphertext []byte) (*DecryptionResult, error) { + decryptedText, err := libsignalgo.GroupDecrypt( + ctx, + ciphertext, + senderAddress, + cli.Store.SenderKeyStore, + ) + if err != nil { + return nil, fmt.Errorf("failed to decrypt sender key message: %w", err) + } + err = stripPadding(&decryptedText) + if err != nil { + return nil, fmt.Errorf("failed to strip padding: %w", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted sender key message: %w", err) + } + return &DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, + }, nil +} + func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destinationServiceID libsignalgo.ServiceID, envelope *signalpb.Envelope) (result DecryptionResult, err error) { log := zerolog.Ctx(ctx) @@ -515,121 +581,25 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin } } + var resultPtr *DecryptionResult switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: - decryptedText, err := libsignalgo.GroupDecrypt( - ctx, - usmcContents, - senderAddress, - cli.Store.SenderKeyStore, - ) - if err != nil { - if strings.Contains(err.Error(), "message with old counter") { - log.Warn().Err(err).Msg("Duplicate message error while decrypting sealed sender sender key") - return result, err - } - log.Err(err).Msg("Failed to decrypt sealed sender sender key message, trying generic function") - return cli.fallbackDecryptSealedSender(ctx, result, envelope) - } - err = stripPadding(&decryptedText) - if err != nil { - return result, fmt.Errorf("failed to strip padding: %w", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - return result, fmt.Errorf("failed to unmarshal decrypted sender key message: %w", err) - } - result.Content = &content - return result, nil - + resultPtr, err = cli.decryptSenderKeyMessage(ctx, senderAddress, usmcContents) case libsignalgo.CiphertextMessageTypePreKey: - var resultPtr *DecryptionResult resultPtr, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) - if err != nil { - log.Err(err).Msg("Failed to decrypt sealed sender prekey message, trying generic function") - return cli.fallbackDecryptSealedSender(ctx, result, envelope) - } - return *resultPtr, nil - case libsignalgo.CiphertextMessageTypeWhisper: - message, err := libsignalgo.DeserializeMessage(usmcContents) - if err != nil { - return result, fmt.Errorf("failed to deserialize whisper message: %w", err) - } - decryptedText, err := libsignalgo.Decrypt( - ctx, - message, - senderAddress, - cli.Store.ACISessionStore, - cli.Store.ACIIdentityStore, - ) - if err != nil { - log.Err(err).Msg("Failed to decrypt whisper message, trying generic function") - return cli.fallbackDecryptSealedSender(ctx, result, envelope) - } - err = stripPadding(&decryptedText) - if err != nil { - return result, fmt.Errorf("failed to strip padding: %w", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - return result, fmt.Errorf("failed to unmarshal decrypted whisper message: %w", err) - } - result.Content = &content - return result, nil - + resultPtr, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, senderAddress, usmcContents) case libsignalgo.CiphertextMessageTypePlaintext: - log.Warn().Msg("Unsupported plaintext sealed sender message") // TODO: handle plaintext (usually DecryptionErrorMessage) and retries - // when implementing SenderKey groups - - //plaintextContent, err := libsignalgo.DeserializePlaintextContent(usmcContents) - //if err != nil { - // log.Err(err).Msg("DeserializePlaintextContent error") - //} - //body, err := plaintextContent.GetBody() - //if err != nil { - // log.Err(err).Msg("PlaintextContent GetBody error") - //} - //content := signalpb.Content{} - //err = proto.Unmarshal(body, &content) - //if err != nil { - // log.Err(err).Msg("PlaintextContent Unmarshal error") - //} - //result = &DecryptionResult{ - // SenderAddress: *senderAddress, - // Content: &content, - // SealedSender: true, - //} - - return result, fmt.Errorf("plaintext sealed sender messages are not supported") - + // when implementing SenderKey groups + return result, fmt.Errorf("unsupported plaintext sealed sender message") default: - log.Warn().Msg("Unrecognized sealed sender message type") - return cli.fallbackDecryptSealedSender(ctx, result, envelope) + return result, fmt.Errorf("unsupported sealed sender message type %d", messageType) } -} - -func (cli *Client) fallbackDecryptSealedSender(ctx context.Context, fallbackResult DecryptionResult, envelope *signalpb.Envelope) (DecryptionResult, error) { - log := zerolog.Ctx(ctx) - result, err := cli.sealedSenderDecrypt(ctx, envelope) if err != nil { - if strings.Contains(err.Error(), "self send of a sealed sender message") { - log.Debug().Msg("Message sent by us, ignoring") - } else if strings.Contains(err.Error(), "message with old counter") { - log.Info().Msg("Duplicate message, ignoring (sealedSenderDecrypt)") - } else { - log.Err(err).Msg("Failed to decrypt sealed sender message with fallback method") - } - return fallbackResult, fmt.Errorf("failed to decrypt unrecognized sealed sender message: %w", err) + return result, err } - log.Trace(). - Any("sender_address", result.SenderAddress). - Any("content", result.Content). - Msg("SealedSender decrypt result") - return *result, nil + return *resultPtr, nil } // TODO: we should split this up into multiple functions @@ -1118,7 +1088,6 @@ type DecryptionResult struct { SenderAddress *libsignalgo.Address Content *signalpb.Content ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint - SealedSender bool Err error } @@ -1132,95 +1101,6 @@ func init() { prodServerTrustRootKey.CancelFinalizer() } -func (cli *Client) sealedSenderDecrypt(ctx context.Context, envelope *signalpb.Envelope) (*DecryptionResult, error) { - localAddress := libsignalgo.NewSealedSenderAddress( - cli.Store.Number, - cli.Store.ACI, - uint32(cli.Store.DeviceID), - ) - result, err := libsignalgo.SealedSenderDecrypt( - ctx, - envelope.Content, - localAddress, - prodServerTrustRootKey, - envelope.GetTimestamp(), - cli.Store.ACISessionStore, - cli.Store.ACIIdentityStore, - cli.Store.ACIPreKeyStore, - cli.Store.ACIPreKeyStore, - ) - if err != nil { - return nil, err - } - - msg := result.Message - err = stripPadding(&msg) - if err != nil { - return nil, fmt.Errorf("failed to strip padding: %w", err) - } - address, err := libsignalgo.NewACIServiceID(result.Sender.UUID).Address(uint(result.Sender.DeviceID)) - if err != nil { - return nil, fmt.Errorf("failed to wrap sender address: %w", err) - } - content := &signalpb.Content{} - err = proto.Unmarshal(msg, content) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal decrypted content: %w", err) - } - return &DecryptionResult{ - SenderAddress: address, - Content: content, - }, nil -} - -func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.ServiceID, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { - preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) - if err != nil { - return nil, fmt.Errorf("failed to deserialize prekey message: %w", err) - } else if preKeyMessage == nil { - return nil, fmt.Errorf("deserializing prekey message returned nil") - } - pks := cli.Store.PreKeyStore(destination) - if pks == nil { - return nil, fmt.Errorf("no prekey store found for %s", destination) - } - ss := cli.Store.SessionStore(destination) - if ss == nil { - return nil, fmt.Errorf("no session store found for %s", destination) - } - is := cli.Store.IdentityStore(destination) - if is == nil { - return nil, fmt.Errorf("no identity store found for %s", destination) - } - - data, err := libsignalgo.DecryptPreKey( - ctx, - preKeyMessage, - sender, - ss, - is, - pks, - pks, - pks, - ) - if err != nil { - return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) - } - err = stripPadding(&data) - if err != nil { - return nil, fmt.Errorf("failed to strip padding: %w", err) - } - content := &signalpb.Content{} - err = proto.Unmarshal(data, content) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal decrypted prekey message: %w", err) - } - return &DecryptionResult{ - SenderAddress: sender, - Content: content, - }, nil -} - func stripPadding(contents *[]byte) error { for i := len(*contents) - 1; i >= 0; i-- { if (*contents)[i] == 0x80 { From 25497d1601a6ab2ff88ebc1f43880d6b8c1e6bba Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 14:27:16 +0300 Subject: [PATCH 466/718] signalmeow/receiving: split decrypting code to separate file --- pkg/signalmeow/receiving.go | 293 +------------------------ pkg/signalmeow/receiving_decrypt.go | 327 ++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+), 292 deletions(-) create mode 100644 pkg/signalmeow/receiving_decrypt.go diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 27394b2..18c2240 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -1,5 +1,6 @@ // mautrix-signal - A Matrix-signal puppeting bridge. // Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 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 @@ -329,279 +330,6 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. }, nil } -func (cli *Client) decryptEnvelope( - ctx context.Context, - envelope *signalpb.Envelope, -) DecryptionResult { - log := zerolog.Ctx(ctx) - - destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) - if err != nil { - log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") - return DecryptionResult{Err: fmt.Errorf("failed to parse destination service ID: %w", err)} - } - - switch *envelope.Type { - case signalpb.Envelope_UNIDENTIFIED_SENDER: - result, err := cli.decryptUnidentifiedSenderEnvelope(ctx, destinationServiceID, envelope) - if err != nil { - result.Err = fmt.Errorf("failed to decrypt unidentified sender envelope: %w", err) - } - return result - - case signalpb.Envelope_PREKEY_BUNDLE, signalpb.Envelope_CIPHERTEXT: - sender, err := libsignalgo.NewUUIDAddressFromString( - *envelope.SourceServiceId, - uint(*envelope.SourceDevice), - ) - if err != nil { - return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} - } - var result *DecryptionResult - var bundleType string - if *envelope.Type == signalpb.Envelope_PREKEY_BUNDLE { - result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) - bundleType = "prekey bundle" - } else { - result, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, sender, envelope.Content) - bundleType = "ciphertext" - } - if err != nil { - return DecryptionResult{Err: fmt.Errorf("failed to decrypt %s envelope: %w", bundleType, err), SenderAddress: sender} - } - return *result - - case signalpb.Envelope_PLAINTEXT_CONTENT: - return DecryptionResult{Err: fmt.Errorf("plaintext messages are not supported")} - - case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: - return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} - - case signalpb.Envelope_SENDERKEY_MESSAGE: - return DecryptionResult{Err: fmt.Errorf("senderkey message envelopes are not yet supported")} - - case signalpb.Envelope_UNKNOWN: - return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} - - default: - return DecryptionResult{Err: fmt.Errorf("unrecognized envelope type %d", envelope.GetType())} - } -} - -func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.ServiceID, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { - preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) - if err != nil { - return nil, fmt.Errorf("failed to deserialize prekey message: %w", err) - } else if preKeyMessage == nil { - return nil, fmt.Errorf("deserializing prekey message returned nil") - } - pks := cli.Store.PreKeyStore(destination) - if pks == nil { - return nil, fmt.Errorf("no prekey store found for %s", destination) - } - ss := cli.Store.SessionStore(destination) - if ss == nil { - return nil, fmt.Errorf("no session store found for %s", destination) - } - is := cli.Store.IdentityStore(destination) - if is == nil { - return nil, fmt.Errorf("no identity store found for %s", destination) - } - - data, err := libsignalgo.DecryptPreKey( - ctx, - preKeyMessage, - sender, - ss, - is, - pks, - pks, - pks, - ) - if err != nil { - return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) - } - err = stripPadding(&data) - if err != nil { - return nil, fmt.Errorf("failed to strip padding: %w", err) - } - content := &signalpb.Content{} - err = proto.Unmarshal(data, content) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal decrypted prekey message: %w", err) - } - return &DecryptionResult{ - SenderAddress: sender, - Content: content, - }, nil -} - -func (cli *Client) decryptCiphertextEnvelope( - ctx context.Context, - destinationServiceID libsignalgo.ServiceID, - senderAddress *libsignalgo.Address, - ciphertext []byte, -) (*DecryptionResult, error) { - log := zerolog.Ctx(ctx) - message, err := libsignalgo.DeserializeMessage(ciphertext) - if err != nil { - log.Err(err).Msg("Failed to deserialize ciphertext message") - return nil, fmt.Errorf("failed to deserialize message: %w", err) - } - sessionStore := cli.Store.SessionStore(destinationServiceID) - if sessionStore == nil { - return nil, fmt.Errorf("no session store for destination service ID %s", destinationServiceID) - } - identityStore := cli.Store.IdentityStore(destinationServiceID) - if identityStore == nil { - return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) - } - decryptedText, err := libsignalgo.Decrypt( - ctx, - message, - senderAddress, - sessionStore, - identityStore, - ) - if err != nil { - if strings.Contains(err.Error(), "message with old counter") { - log.Warn().Err(err).Msg("Duplicate message error while decrypting whisper ciphertext") - } else { - log.Err(err).Msg("Failed to decrypt whisper ciphertext message") - } - return nil, fmt.Errorf("failed to decrypt ciphertext message: %w", err) - } - err = stripPadding(&decryptedText) - if err != nil { - return nil, fmt.Errorf("failed to strip padding: %w", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal decrypted message: %w", err) - } - return &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - }, nil -} - -func (cli *Client) decryptSenderKeyMessage(ctx context.Context, senderAddress *libsignalgo.Address, ciphertext []byte) (*DecryptionResult, error) { - decryptedText, err := libsignalgo.GroupDecrypt( - ctx, - ciphertext, - senderAddress, - cli.Store.SenderKeyStore, - ) - if err != nil { - return nil, fmt.Errorf("failed to decrypt sender key message: %w", err) - } - err = stripPadding(&decryptedText) - if err != nil { - return nil, fmt.Errorf("failed to strip padding: %w", err) - } - content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal decrypted sender key message: %w", err) - } - return &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, - }, nil -} - -func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destinationServiceID libsignalgo.ServiceID, envelope *signalpb.Envelope) (result DecryptionResult, err error) { - log := zerolog.Ctx(ctx) - - if destinationServiceID != cli.Store.ACIServiceID() { - log.Warn().Stringer("destination_service_id", destinationServiceID). - Msg("Received UNIDENTIFIED_SENDER envelope for non-ACI destination") - return result, fmt.Errorf("received unidentified sender envelope for non-ACI destination") - } - usmc, err := libsignalgo.SealedSenderDecryptToUSMC( - ctx, - envelope.GetContent(), - cli.Store.ACIIdentityStore, - ) - if err != nil { - return result, fmt.Errorf("failed to decrypt to USMC: %w", err) - } else if usmc == nil { - return result, fmt.Errorf("decrypting to USMC returned nil") - } - - messageType, err := usmc.GetMessageType() - if err != nil { - return result, fmt.Errorf("failed to get message type: %w", err) - } - senderCertificate, err := usmc.GetSenderCertificate() - if err != nil { - return result, fmt.Errorf("failed to get sender certificate: %w", err) - } - contentHint, err := usmc.GetContentHint() - if err != nil { - return result, fmt.Errorf("failed to get content hint: %w", err) - } - result.ContentHint = signalpb.UnidentifiedSenderMessage_Message_ContentHint(contentHint) - senderUUID, err := senderCertificate.GetSenderUUID() - if err != nil { - return result, fmt.Errorf("failed to get sender UUID: %w", err) - } - senderDeviceID, err := senderCertificate.GetDeviceID() - if err != nil { - return result, fmt.Errorf("failed to get sender device ID: %w", err) - } - senderAddress, err := libsignalgo.NewACIServiceID(senderUUID).Address(uint(senderDeviceID)) - if err != nil { - return result, fmt.Errorf("failed to create sender address: %w", err) - } - result.SenderAddress = senderAddress - senderE164, err := senderCertificate.GetSenderE164() - if err != nil { - return result, fmt.Errorf("failed to get sender E164: %w", err) - } - usmcContents, err := usmc.GetContents() - if err != nil { - return result, fmt.Errorf("failed to get USMC contents: %w", err) - } - newLog := log.With(). - Stringer("sender_uuid", senderUUID). - Uint32("sender_device_id", senderDeviceID). - Str("sender_e164", senderE164). - Uint8("sealed_sender_type", uint8(messageType)). - Logger() - log = &newLog - ctx = log.WithContext(ctx) - log.Trace().Msg("Received SealedSender message") - - if senderE164 != "" { - _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) - if err != nil { - log.Warn().Err(err).Msg("Failed to update sender E164 in recipient store") - } - } - - var resultPtr *DecryptionResult - switch messageType { - case libsignalgo.CiphertextMessageTypeSenderKey: - resultPtr, err = cli.decryptSenderKeyMessage(ctx, senderAddress, usmcContents) - case libsignalgo.CiphertextMessageTypePreKey: - resultPtr, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) - case libsignalgo.CiphertextMessageTypeWhisper: - resultPtr, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, senderAddress, usmcContents) - case libsignalgo.CiphertextMessageTypePlaintext: - // TODO: handle plaintext (usually DecryptionErrorMessage) and retries - // when implementing SenderKey groups - return result, fmt.Errorf("unsupported plaintext sealed sender message") - default: - return result, fmt.Errorf("unsupported sealed sender message type %d", messageType) - } - if err != nil { - return result, err - } - return *resultPtr, nil -} - // TODO: we should split this up into multiple functions func (cli *Client) handleDecryptedResult( ctx context.Context, @@ -1084,13 +812,6 @@ func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps return nil } -type DecryptionResult struct { - SenderAddress *libsignalgo.Address - Content *signalpb.Content - ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint - Err error -} - const prodServerTrustRootStr = "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" var prodServerTrustRootBytes = exerrors.Must(base64.StdEncoding.DecodeString(prodServerTrustRootStr)) @@ -1100,15 +821,3 @@ func init() { // It's never going to be freed anyway prodServerTrustRootKey.CancelFinalizer() } - -func stripPadding(contents *[]byte) error { - for i := len(*contents) - 1; i >= 0; i-- { - if (*contents)[i] == 0x80 { - *contents = (*contents)[:i] - return nil - } else if (*contents)[i] != 0x00 { - return fmt.Errorf("Invalid ISO7816 padding") - } - } - return fmt.Errorf("Invalid ISO7816 padding, len(contents): %v", len(*contents)) -} diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go new file mode 100644 index 0000000..1c9c408 --- /dev/null +++ b/pkg/signalmeow/receiving_decrypt.go @@ -0,0 +1,327 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2023 Scott Weber +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "google.golang.org/protobuf/proto" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" +) + +type DecryptionResult struct { + SenderAddress *libsignalgo.Address + Content *signalpb.Content + ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint + Err error +} + +func (cli *Client) decryptEnvelope( + ctx context.Context, + envelope *signalpb.Envelope, +) DecryptionResult { + log := zerolog.Ctx(ctx) + + destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) + if err != nil { + log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") + return DecryptionResult{Err: fmt.Errorf("failed to parse destination service ID: %w", err)} + } + + switch *envelope.Type { + case signalpb.Envelope_UNIDENTIFIED_SENDER: + result, err := cli.decryptUnidentifiedSenderEnvelope(ctx, destinationServiceID, envelope) + if err != nil { + result.Err = fmt.Errorf("failed to decrypt unidentified sender envelope: %w", err) + } + return result + + case signalpb.Envelope_PREKEY_BUNDLE, signalpb.Envelope_CIPHERTEXT: + sender, err := libsignalgo.NewUUIDAddressFromString( + *envelope.SourceServiceId, + uint(*envelope.SourceDevice), + ) + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} + } + var result *DecryptionResult + var bundleType string + if *envelope.Type == signalpb.Envelope_PREKEY_BUNDLE { + result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) + bundleType = "prekey bundle" + } else { + result, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, sender, envelope.Content) + bundleType = "ciphertext" + } + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to decrypt %s envelope: %w", bundleType, err), SenderAddress: sender} + } + return *result + + case signalpb.Envelope_PLAINTEXT_CONTENT: + return DecryptionResult{Err: fmt.Errorf("plaintext messages are not supported")} + + case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: + return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} + + case signalpb.Envelope_SENDERKEY_MESSAGE: + return DecryptionResult{Err: fmt.Errorf("senderkey message envelopes are not yet supported")} + + case signalpb.Envelope_UNKNOWN: + return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} + + default: + return DecryptionResult{Err: fmt.Errorf("unrecognized envelope type %d", envelope.GetType())} + } +} + +func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.ServiceID, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { + preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) + if err != nil { + return nil, fmt.Errorf("failed to deserialize prekey message: %w", err) + } else if preKeyMessage == nil { + return nil, fmt.Errorf("deserializing prekey message returned nil") + } + pks := cli.Store.PreKeyStore(destination) + if pks == nil { + return nil, fmt.Errorf("no prekey store found for %s", destination) + } + ss := cli.Store.SessionStore(destination) + if ss == nil { + return nil, fmt.Errorf("no session store found for %s", destination) + } + is := cli.Store.IdentityStore(destination) + if is == nil { + return nil, fmt.Errorf("no identity store found for %s", destination) + } + + data, err := libsignalgo.DecryptPreKey( + ctx, + preKeyMessage, + sender, + ss, + is, + pks, + pks, + pks, + ) + if err != nil { + return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) + } + err = stripPadding(&data) + if err != nil { + return nil, fmt.Errorf("failed to strip padding: %w", err) + } + content := &signalpb.Content{} + err = proto.Unmarshal(data, content) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted prekey message: %w", err) + } + return &DecryptionResult{ + SenderAddress: sender, + Content: content, + }, nil +} + +func (cli *Client) decryptCiphertextEnvelope( + ctx context.Context, + destinationServiceID libsignalgo.ServiceID, + senderAddress *libsignalgo.Address, + ciphertext []byte, +) (*DecryptionResult, error) { + log := zerolog.Ctx(ctx) + message, err := libsignalgo.DeserializeMessage(ciphertext) + if err != nil { + log.Err(err).Msg("Failed to deserialize ciphertext message") + return nil, fmt.Errorf("failed to deserialize message: %w", err) + } + sessionStore := cli.Store.SessionStore(destinationServiceID) + if sessionStore == nil { + return nil, fmt.Errorf("no session store for destination service ID %s", destinationServiceID) + } + identityStore := cli.Store.IdentityStore(destinationServiceID) + if identityStore == nil { + return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) + } + decryptedText, err := libsignalgo.Decrypt( + ctx, + message, + senderAddress, + sessionStore, + identityStore, + ) + if err != nil { + if strings.Contains(err.Error(), "message with old counter") { + log.Warn().Err(err).Msg("Duplicate message error while decrypting whisper ciphertext") + } else { + log.Err(err).Msg("Failed to decrypt whisper ciphertext message") + } + return nil, fmt.Errorf("failed to decrypt ciphertext message: %w", err) + } + err = stripPadding(&decryptedText) + if err != nil { + return nil, fmt.Errorf("failed to strip padding: %w", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted message: %w", err) + } + return &DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, + }, nil +} + +func (cli *Client) decryptSenderKeyMessage( + ctx context.Context, + senderAddress *libsignalgo.Address, + ciphertext []byte, +) (*DecryptionResult, error) { + decryptedText, err := libsignalgo.GroupDecrypt( + ctx, + ciphertext, + senderAddress, + cli.Store.SenderKeyStore, + ) + if err != nil { + return nil, fmt.Errorf("failed to decrypt sender key message: %w", err) + } + err = stripPadding(&decryptedText) + if err != nil { + return nil, fmt.Errorf("failed to strip padding: %w", err) + } + content := signalpb.Content{} + err = proto.Unmarshal(decryptedText, &content) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted sender key message: %w", err) + } + return &DecryptionResult{ + SenderAddress: senderAddress, + Content: &content, + }, nil +} + +func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destinationServiceID libsignalgo.ServiceID, envelope *signalpb.Envelope) (result DecryptionResult, err error) { + log := zerolog.Ctx(ctx) + + if destinationServiceID != cli.Store.ACIServiceID() { + log.Warn().Stringer("destination_service_id", destinationServiceID). + Msg("Received UNIDENTIFIED_SENDER envelope for non-ACI destination") + return result, fmt.Errorf("received unidentified sender envelope for non-ACI destination") + } + usmc, err := libsignalgo.SealedSenderDecryptToUSMC( + ctx, + envelope.GetContent(), + cli.Store.ACIIdentityStore, + ) + if err != nil { + return result, fmt.Errorf("failed to decrypt to USMC: %w", err) + } else if usmc == nil { + return result, fmt.Errorf("decrypting to USMC returned nil") + } + + messageType, err := usmc.GetMessageType() + if err != nil { + return result, fmt.Errorf("failed to get message type: %w", err) + } + senderCertificate, err := usmc.GetSenderCertificate() + if err != nil { + return result, fmt.Errorf("failed to get sender certificate: %w", err) + } + contentHint, err := usmc.GetContentHint() + if err != nil { + return result, fmt.Errorf("failed to get content hint: %w", err) + } + result.ContentHint = signalpb.UnidentifiedSenderMessage_Message_ContentHint(contentHint) + senderUUID, err := senderCertificate.GetSenderUUID() + if err != nil { + return result, fmt.Errorf("failed to get sender UUID: %w", err) + } + senderDeviceID, err := senderCertificate.GetDeviceID() + if err != nil { + return result, fmt.Errorf("failed to get sender device ID: %w", err) + } + senderAddress, err := libsignalgo.NewACIServiceID(senderUUID).Address(uint(senderDeviceID)) + if err != nil { + return result, fmt.Errorf("failed to create sender address: %w", err) + } + result.SenderAddress = senderAddress + senderE164, err := senderCertificate.GetSenderE164() + if err != nil { + return result, fmt.Errorf("failed to get sender E164: %w", err) + } + usmcContents, err := usmc.GetContents() + if err != nil { + return result, fmt.Errorf("failed to get USMC contents: %w", err) + } + newLog := log.With(). + Stringer("sender_uuid", senderUUID). + Uint32("sender_device_id", senderDeviceID). + Str("sender_e164", senderE164). + Uint8("sealed_sender_type", uint8(messageType)). + Logger() + log = &newLog + ctx = log.WithContext(ctx) + log.Trace().Msg("Received SealedSender message") + + if senderE164 != "" { + _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, senderUUID, uuid.Nil, senderE164) + if err != nil { + log.Warn().Err(err).Msg("Failed to update sender E164 in recipient store") + } + } + + var resultPtr *DecryptionResult + switch messageType { + case libsignalgo.CiphertextMessageTypeSenderKey: + resultPtr, err = cli.decryptSenderKeyMessage(ctx, senderAddress, usmcContents) + case libsignalgo.CiphertextMessageTypePreKey: + resultPtr, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) + case libsignalgo.CiphertextMessageTypeWhisper: + resultPtr, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, senderAddress, usmcContents) + case libsignalgo.CiphertextMessageTypePlaintext: + // TODO: handle plaintext (usually DecryptionErrorMessage) and retries + // when implementing SenderKey groups + return result, fmt.Errorf("unsupported plaintext sealed sender message") + default: + return result, fmt.Errorf("unsupported sealed sender message type %d", messageType) + } + if err != nil { + return result, err + } + return *resultPtr, nil +} + +func stripPadding(contents *[]byte) error { + for i := len(*contents) - 1; i >= 0; i-- { + if (*contents)[i] == 0x80 { + *contents = (*contents)[:i] + return nil + } else if (*contents)[i] != 0x00 { + return fmt.Errorf("Invalid ISO7816 padding") + } + } + return fmt.Errorf("Invalid ISO7816 padding, len(contents): %v", len(*contents)) +} From 90c621853534f1828583c0cbd7c461fa7c7cf9ef Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 14:28:58 +0300 Subject: [PATCH 467/718] signalmeow/receiving: remove unused server trust root --- pkg/signalmeow/receiving.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 18c2240..8720195 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -27,7 +27,6 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" - "go.mau.fi/util/exerrors" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -811,13 +810,3 @@ func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps } return nil } - -const prodServerTrustRootStr = "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF" - -var prodServerTrustRootBytes = exerrors.Must(base64.StdEncoding.DecodeString(prodServerTrustRootStr)) -var prodServerTrustRootKey = exerrors.Must(libsignalgo.DeserializePublicKey(prodServerTrustRootBytes)) - -func init() { - // It's never going to be freed anyway - prodServerTrustRootKey.CancelFinalizer() -} From 3fb64cbc3338305b7a98831ad8e9f949ac2e4aa2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 14:31:31 +0300 Subject: [PATCH 468/718] signalmeow/receiving: don't use pointers for stripping padding --- pkg/signalmeow/receiving_decrypt.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 1c9c408..9d12ff6 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -129,7 +129,7 @@ func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.Se if err != nil { return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) } - err = stripPadding(&data) + data, err = stripPadding(data) if err != nil { return nil, fmt.Errorf("failed to strip padding: %w", err) } @@ -179,7 +179,7 @@ func (cli *Client) decryptCiphertextEnvelope( } return nil, fmt.Errorf("failed to decrypt ciphertext message: %w", err) } - err = stripPadding(&decryptedText) + decryptedText, err = stripPadding(decryptedText) if err != nil { return nil, fmt.Errorf("failed to strip padding: %w", err) } @@ -208,7 +208,7 @@ func (cli *Client) decryptSenderKeyMessage( if err != nil { return nil, fmt.Errorf("failed to decrypt sender key message: %w", err) } - err = stripPadding(&decryptedText) + decryptedText, err = stripPadding(decryptedText) if err != nil { return nil, fmt.Errorf("failed to strip padding: %w", err) } @@ -314,14 +314,14 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin return *resultPtr, nil } -func stripPadding(contents *[]byte) error { - for i := len(*contents) - 1; i >= 0; i-- { - if (*contents)[i] == 0x80 { - *contents = (*contents)[:i] - return nil - } else if (*contents)[i] != 0x00 { - return fmt.Errorf("Invalid ISO7816 padding") +func stripPadding(contents []byte) ([]byte, error) { + for i := len(contents) - 1; i >= 0; i-- { + if contents[i] == 0x80 { + contents = contents[:i] + return contents, nil + } else if contents[i] != 0x00 { + return nil, fmt.Errorf("invalid ISO7816 padding") } } - return fmt.Errorf("Invalid ISO7816 padding, len(contents): %v", len(*contents)) + return nil, fmt.Errorf("invalid ISO7816 padding (length %d)", len(contents)) } From da84e97ceab6ae189aed71bd67825a28321d40e9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 16:39:54 +0300 Subject: [PATCH 469/718] signalmeow/receiving: add persistent buffer for decryption to prevent double processing --- pkg/signalmeow/receiving.go | 12 +- pkg/signalmeow/receiving_decrypt.go | 150 ++++++++++++------ pkg/signalmeow/store/container.go | 1 + pkg/signalmeow/store/device.go | 6 + pkg/signalmeow/store/event_buffer.go | 79 +++++++++ pkg/signalmeow/store/upgrades/00-latest.sql | 21 ++- .../store/upgrades/21-event-buffer.sql | 11 ++ 7 files changed, 223 insertions(+), 57 deletions(-) create mode 100644 pkg/signalmeow/store/event_buffer.go create mode 100644 pkg/signalmeow/store/upgrades/21-event-buffer.sql diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 8720195..35d1d3a 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -21,6 +21,7 @@ import ( "bytes" "context" "encoding/base64" + "errors" "fmt" "net/http" "strings" @@ -337,6 +338,14 @@ func (cli *Client) handleDecryptedResult( destinationServiceID libsignalgo.ServiceID, ) error { log := zerolog.Ctx(ctx) + if result.CiphertextHash != nil { + defer func() { + err := cli.Store.EventBuffer.ClearBufferedEventPlaintext(ctx, *result.CiphertextHash) + if err != nil { + log.Err(err).Msg("Failed to clear buffered event plaintext") + } + }() + } // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted @@ -361,7 +370,8 @@ func (cli *Client) handleDecryptedResult( // to prevent spamming errors for typing notifications and whatnot if envelope.GetUrgent() && result.ContentHint != signalpb.UnidentifiedSenderMessage_Message_IMPLICIT && - !strings.Contains(result.Err.Error(), "message with old counter") { + !strings.Contains(result.Err.Error(), "message with old counter") && + !errors.Is(err, EventAlreadyProcessed) { cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 9d12ff6..e8d30b0 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -19,8 +19,10 @@ package signalmeow import ( "context" + "crypto/sha256" + "errors" "fmt" - "strings" + "time" "github.com/google/uuid" "github.com/rs/zerolog" @@ -28,13 +30,15 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/store" ) type DecryptionResult struct { - SenderAddress *libsignalgo.Address - Content *signalpb.Content - ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint - Err error + SenderAddress *libsignalgo.Address + CiphertextHash *[32]byte + Content *signalpb.Content + ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint + Err error } func (cli *Client) decryptEnvelope( @@ -68,10 +72,10 @@ func (cli *Client) decryptEnvelope( var result *DecryptionResult var bundleType string if *envelope.Type == signalpb.Envelope_PREKEY_BUNDLE { - result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content) + result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content, envelope.GetServerTimestamp()) bundleType = "prekey bundle" } else { - result, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, sender, envelope.Content) + result, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, sender, envelope.Content, envelope.GetServerTimestamp()) bundleType = "ciphertext" } if err != nil { @@ -96,7 +100,45 @@ func (cli *Client) decryptEnvelope( } } -func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.ServiceID, sender *libsignalgo.Address, encryptedContent []byte) (*DecryptionResult, error) { +var EventAlreadyProcessed = errors.New("event was already processed") + +func (cli *Client) bufferedDecryptTxn(ctx context.Context, ciphertext []byte, serverTimestamp uint64, decrypt func(context.Context) ([]byte, error)) (plaintext []byte, ciphertextHash [32]byte, err error) { + ciphertextHash = sha256.Sum256(ciphertext) + + var buf *store.BufferedEvent + buf, err = cli.Store.EventBuffer.GetBufferedEvent(ctx, ciphertextHash) + if err != nil { + err = fmt.Errorf("failed to get buffered event: %w", err) + return + } else if buf != nil { + plaintext = buf.Plaintext + if plaintext == nil { + err = fmt.Errorf("%w at %s", EventAlreadyProcessed, time.UnixMilli(buf.InsertTimestamp).String()) + } + return + } + + err = cli.Store.DoDecryptionTxn(ctx, func(ctx context.Context) (innerErr error) { + plaintext, innerErr = decrypt(ctx) + if innerErr != nil { + return + } + innerErr = cli.Store.EventBuffer.PutBufferedEvent(ctx, ciphertextHash, plaintext, serverTimestamp) + if innerErr != nil { + innerErr = fmt.Errorf("failed to save decrypted event to buffer: %w", innerErr) + } + return + }) + return +} + +func (cli *Client) prekeyDecrypt( + ctx context.Context, + destination libsignalgo.ServiceID, + sender *libsignalgo.Address, + encryptedContent []byte, + serverTimestamp uint64, +) (*DecryptionResult, error) { preKeyMessage, err := libsignalgo.DeserializePreKeyMessage(encryptedContent) if err != nil { return nil, fmt.Errorf("failed to deserialize prekey message: %w", err) @@ -116,31 +158,34 @@ func (cli *Client) prekeyDecrypt(ctx context.Context, destination libsignalgo.Se return nil, fmt.Errorf("no identity store found for %s", destination) } - data, err := libsignalgo.DecryptPreKey( - ctx, - preKeyMessage, - sender, - ss, - is, - pks, - pks, - pks, - ) + plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, encryptedContent, serverTimestamp, func(ctx context.Context) ([]byte, error) { + return libsignalgo.DecryptPreKey( + ctx, + preKeyMessage, + sender, + ss, + is, + pks, + pks, + pks, + ) + }) if err != nil { return nil, fmt.Errorf("failed to decrypt prekey message: %w", err) } - data, err = stripPadding(data) + plaintext, err = stripPadding(plaintext) if err != nil { return nil, fmt.Errorf("failed to strip padding: %w", err) } content := &signalpb.Content{} - err = proto.Unmarshal(data, content) + err = proto.Unmarshal(plaintext, content) if err != nil { return nil, fmt.Errorf("failed to unmarshal decrypted prekey message: %w", err) } return &DecryptionResult{ - SenderAddress: sender, - Content: content, + SenderAddress: sender, + Content: content, + CiphertextHash: &ciphertextHash, }, nil } @@ -149,6 +194,7 @@ func (cli *Client) decryptCiphertextEnvelope( destinationServiceID libsignalgo.ServiceID, senderAddress *libsignalgo.Address, ciphertext []byte, + serverTimestamp uint64, ) (*DecryptionResult, error) { log := zerolog.Ctx(ctx) message, err := libsignalgo.DeserializeMessage(ciphertext) @@ -164,33 +210,31 @@ func (cli *Client) decryptCiphertextEnvelope( if identityStore == nil { return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) } - decryptedText, err := libsignalgo.Decrypt( - ctx, - message, - senderAddress, - sessionStore, - identityStore, - ) + plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, ciphertext, serverTimestamp, func(ctx context.Context) ([]byte, error) { + return libsignalgo.Decrypt( + ctx, + message, + senderAddress, + sessionStore, + identityStore, + ) + }) if err != nil { - if strings.Contains(err.Error(), "message with old counter") { - log.Warn().Err(err).Msg("Duplicate message error while decrypting whisper ciphertext") - } else { - log.Err(err).Msg("Failed to decrypt whisper ciphertext message") - } return nil, fmt.Errorf("failed to decrypt ciphertext message: %w", err) } - decryptedText, err = stripPadding(decryptedText) + plaintext, err = stripPadding(plaintext) if err != nil { return nil, fmt.Errorf("failed to strip padding: %w", err) } content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) + err = proto.Unmarshal(plaintext, &content) if err != nil { return nil, fmt.Errorf("failed to unmarshal decrypted message: %w", err) } return &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, + SenderAddress: senderAddress, + Content: &content, + CiphertextHash: &ciphertextHash, }, nil } @@ -198,28 +242,32 @@ func (cli *Client) decryptSenderKeyMessage( ctx context.Context, senderAddress *libsignalgo.Address, ciphertext []byte, + serverTimestamp uint64, ) (*DecryptionResult, error) { - decryptedText, err := libsignalgo.GroupDecrypt( - ctx, - ciphertext, - senderAddress, - cli.Store.SenderKeyStore, - ) + plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, ciphertext, serverTimestamp, func(ctx context.Context) ([]byte, error) { + return libsignalgo.GroupDecrypt( + ctx, + ciphertext, + senderAddress, + cli.Store.SenderKeyStore, + ) + }) if err != nil { return nil, fmt.Errorf("failed to decrypt sender key message: %w", err) } - decryptedText, err = stripPadding(decryptedText) + plaintext, err = stripPadding(plaintext) if err != nil { return nil, fmt.Errorf("failed to strip padding: %w", err) } content := signalpb.Content{} - err = proto.Unmarshal(decryptedText, &content) + err = proto.Unmarshal(plaintext, &content) if err != nil { return nil, fmt.Errorf("failed to unmarshal decrypted sender key message: %w", err) } return &DecryptionResult{ - SenderAddress: senderAddress, - Content: &content, + SenderAddress: senderAddress, + Content: &content, + CiphertextHash: &ciphertextHash, }, nil } @@ -296,11 +344,11 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin var resultPtr *DecryptionResult switch messageType { case libsignalgo.CiphertextMessageTypeSenderKey: - resultPtr, err = cli.decryptSenderKeyMessage(ctx, senderAddress, usmcContents) + resultPtr, err = cli.decryptSenderKeyMessage(ctx, senderAddress, usmcContents, envelope.GetServerTimestamp()) case libsignalgo.CiphertextMessageTypePreKey: - resultPtr, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents) + resultPtr, err = cli.prekeyDecrypt(ctx, destinationServiceID, senderAddress, usmcContents, envelope.GetServerTimestamp()) case libsignalgo.CiphertextMessageTypeWhisper: - resultPtr, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, senderAddress, usmcContents) + resultPtr, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, senderAddress, usmcContents, envelope.GetServerTimestamp()) case libsignalgo.CiphertextMessageTypePlaintext: // TODO: handle plaintext (usually DecryptionErrorMessage) and retries // when implementing SenderKey groups diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index 18f9b99..f6842ac 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -108,6 +108,7 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.RecipientStore = baseStore device.DeviceStore = baseStore device.BackupStore = baseStore + device.EventBuffer = baseStore device.sqlStore = baseStore device.db = c.db return &device, nil diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index fc7fac6..aabee03 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -79,6 +79,7 @@ type Device struct { RecipientStore RecipientStore DeviceStore DeviceStore BackupStore BackupStore + EventBuffer EventBuffer sqlStore *sqlStore db *dbutil.Database @@ -98,6 +99,11 @@ func (d *Device) DoContactTxn(ctx context.Context, fn func(context.Context) erro return d.db.DoTxn(ctx, nil, fn) } +func (d *Device) DoDecryptionTxn(ctx context.Context, fn func(context.Context) error) error { + ctx = context.WithValue(ctx, dbutil.ContextKeyDoTxnCallerSkip, 2) + return d.db.DoTxn(ctx, nil, fn) +} + func (d *Device) ClearDeviceKeys(ctx context.Context) error { // We need to clear out keys associated with the Signal device that no longer has valid credentials if d == nil { diff --git a/pkg/signalmeow/store/event_buffer.go b/pkg/signalmeow/store/event_buffer.go new file mode 100644 index 0000000..f5aa314 --- /dev/null +++ b/pkg/signalmeow/store/event_buffer.go @@ -0,0 +1,79 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package store + +import ( + "context" + "database/sql" + "errors" + "time" +) + +type BufferedEvent struct { + Plaintext []byte + ServerTimestamp uint64 + InsertTimestamp int64 +} + +type EventBuffer interface { + GetBufferedEvent(ctx context.Context, ciphertextHash [32]byte) (*BufferedEvent, error) + PutBufferedEvent(ctx context.Context, ciphertextHash [32]byte, plaintext []byte, serverTimestamp uint64) error + ClearBufferedEventPlaintext(ctx context.Context, ciphertextHash [32]byte) error + DeleteBufferedEvent(ctx context.Context, ciphertextHash [32]byte) error +} + +var _ EventBuffer = (*sqlStore)(nil) + +const ( + getBufferedEventQuery = ` + SELECT plaintext, server_timestamp, insert_timestamp + FROM signalmeow_event_buffer + WHERE account_id=$1 AND ciphertext_hash=$2 + ` + putBufferedEventQuery = ` + INSERT INTO signalmeow_event_buffer (account_id, ciphertext_hash, plaintext, server_timestamp, insert_timestamp) + VALUES ($1, $2, $3, $4, $5) + ` + clearBufferedEventPlaintextQuery = `UPDATE signalmeow_event_buffer SET plaintext=NULL WHERE account_id=$1 AND ciphertext_hash=$2` + deleteBufferedEventQuery = `DELETE FROM signalmeow_event_buffer WHERE account_id=$1 AND ciphertext_hash=$2` +) + +func (s *sqlStore) GetBufferedEvent(ctx context.Context, ciphertextHash [32]byte) (*BufferedEvent, error) { + var evt BufferedEvent + err := s.db.QueryRow(ctx, getBufferedEventQuery, s.AccountID, ciphertextHash[:]).Scan(&evt.Plaintext, &evt.ServerTimestamp, &evt.InsertTimestamp) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } else if err != nil { + return nil, err + } + return &evt, nil +} + +func (s *sqlStore) PutBufferedEvent(ctx context.Context, ciphertextHash [32]byte, plaintext []byte, serverTimestamp uint64) error { + _, err := s.db.Exec(ctx, putBufferedEventQuery, s.AccountID, ciphertextHash[:], plaintext, serverTimestamp, time.Now().UnixMilli()) + return err +} + +func (s *sqlStore) ClearBufferedEventPlaintext(ctx context.Context, ciphertextHash [32]byte) error { + _, err := s.db.Exec(ctx, clearBufferedEventPlaintextQuery, s.AccountID, ciphertextHash[:]) + return err +} + +func (s *sqlStore) DeleteBufferedEvent(ctx context.Context, ciphertextHash [32]byte) error { + _, err := s.db.Exec(ctx, deleteBufferedEventQuery, s.AccountID, ciphertextHash[:]) + return err +} diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 670f0e0..cb7e693 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v20 (compatible with v13+): Latest revision +-- v0 -> v21 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -63,6 +63,17 @@ CREATE TABLE signalmeow_sessions ( FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); +CREATE TABLE signalmeow_event_buffer ( + account_id TEXT NOT NULL, + ciphertext_hash bytea NOT NULL, + plaintext bytea, + server_timestamp BIGINT NOT NULL, + insert_timestamp BIGINT NOT NULL, + + PRIMARY KEY (account_id, ciphertext_hash), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); + CREATE TABLE signalmeow_profile_keys ( account_id TEXT NOT NULL, their_aci_uuid TEXT NOT NULL, @@ -131,10 +142,10 @@ CREATE INDEX signalmeow_backup_recipient_group_idx ON signalmeow_backup_recipien CREATE INDEX signalmeow_backup_recipient_aci_idx ON signalmeow_backup_recipient (account_id, aci_uuid); CREATE TABLE signalmeow_backup_chat ( - account_id TEXT NOT NULL, - chat_id BIGINT NOT NULL, - recipient_id BIGINT NOT NULL, - data bytea NOT NULL, + account_id TEXT NOT NULL, + chat_id BIGINT NOT NULL, + recipient_id BIGINT NOT NULL, + data bytea NOT NULL, latest_message_id BIGINT, total_message_count INTEGER, diff --git a/pkg/signalmeow/store/upgrades/21-event-buffer.sql b/pkg/signalmeow/store/upgrades/21-event-buffer.sql new file mode 100644 index 0000000..bfc289a --- /dev/null +++ b/pkg/signalmeow/store/upgrades/21-event-buffer.sql @@ -0,0 +1,11 @@ +-- v21 (compatible with v13+): Add event buffer +CREATE TABLE signalmeow_event_buffer ( + account_id TEXT NOT NULL, + ciphertext_hash bytea NOT NULL, + plaintext bytea, + server_timestamp BIGINT NOT NULL, + insert_timestamp BIGINT NOT NULL, + + PRIMARY KEY (account_id, ciphertext_hash), + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); From 901b812bb8efd1739548f7442e573970609a902f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 18:37:19 +0300 Subject: [PATCH 470/718] signalmeow/receiving: delete old incoming ciphertext hashes --- pkg/signalmeow/client.go | 2 ++ pkg/signalmeow/receiving.go | 39 +++++++++++++++++++++++++-- pkg/signalmeow/store/event_buffer.go | 8 +++--- pkg/signalmeow/web/signalwebsocket.go | 7 ++++- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 0f03354..d3ba6b6 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -60,6 +60,8 @@ type Client struct { cdAuthLock sync.Mutex cdAuth *basicExpiringCredentials cdToken []byte + + writeCallbackCounter chan time.Time } func (cli *Client) handleEvent(evt events.SignalEvent) { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 35d1d3a..cd071c6 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -25,6 +25,7 @@ import ( "fmt" "net/http" "strings" + "time" "github.com/google/uuid" "github.com/rs/zerolog" @@ -100,6 +101,8 @@ func (cli *Client) startWebsocketsInternal( func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnectionStatus, error) { log := zerolog.Ctx(ctx).With().Str("action", "start receive loops").Logger() + cbc := make(chan time.Time, 1) + cli.writeCallbackCounter = cbc authChan, unauthChan, loopCtx, loopCancel, err := cli.startWebsocketsInternal(log.WithContext(ctx)) if err != nil { @@ -110,7 +113,28 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection initialConnectChan := make(chan struct{}) // Combine both websocket status channels into a single, more generic "Signal" connection status channel - cli.loopWg.Add(1) + cli.loopWg.Add(2) + go func() { + defer cli.loopWg.Done() + writeCallbackTimer := time.Now() + callbackCount := 0 + for { + select { + case <-loopCtx.Done(): + return + case nextTS := <-cbc: + if callbackCount >= 4 && time.Since(writeCallbackTimer) > 1*time.Minute { + err := cli.Store.EventBuffer.DeleteBufferedEventsOlderThan(ctx, writeCallbackTimer) + if err != nil { + log.Err(err).Msg("Failed to delete old buffered event hashes") + } + writeCallbackTimer = nextTS + } else { + callbackCount++ + } + } + } + }() go func() { defer cli.loopWg.Done() defer close(statusChan) @@ -326,10 +350,21 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. } return &web.SimpleResponse{ - Status: 200, + Status: 200, + WriteCallback: cli.writeCallback, }, nil } +func (cli *Client) writeCallback(preWriteTime time.Time) { + ch := cli.writeCallbackCounter + if ch != nil { + select { + case ch <- preWriteTime: + default: + } + } +} + // TODO: we should split this up into multiple functions func (cli *Client) handleDecryptedResult( ctx context.Context, diff --git a/pkg/signalmeow/store/event_buffer.go b/pkg/signalmeow/store/event_buffer.go index f5aa314..6b8d6cf 100644 --- a/pkg/signalmeow/store/event_buffer.go +++ b/pkg/signalmeow/store/event_buffer.go @@ -33,7 +33,7 @@ type EventBuffer interface { GetBufferedEvent(ctx context.Context, ciphertextHash [32]byte) (*BufferedEvent, error) PutBufferedEvent(ctx context.Context, ciphertextHash [32]byte, plaintext []byte, serverTimestamp uint64) error ClearBufferedEventPlaintext(ctx context.Context, ciphertextHash [32]byte) error - DeleteBufferedEvent(ctx context.Context, ciphertextHash [32]byte) error + DeleteBufferedEventsOlderThan(ctx context.Context, maxTS time.Time) error } var _ EventBuffer = (*sqlStore)(nil) @@ -49,7 +49,7 @@ const ( VALUES ($1, $2, $3, $4, $5) ` clearBufferedEventPlaintextQuery = `UPDATE signalmeow_event_buffer SET plaintext=NULL WHERE account_id=$1 AND ciphertext_hash=$2` - deleteBufferedEventQuery = `DELETE FROM signalmeow_event_buffer WHERE account_id=$1 AND ciphertext_hash=$2` + deleteOldBufferedEventsQuery = `DELETE FROM signalmeow_event_buffer WHERE account_id=$1 AND insert_timestamp<$2 AND plaintext IS NULL` ) func (s *sqlStore) GetBufferedEvent(ctx context.Context, ciphertextHash [32]byte) (*BufferedEvent, error) { @@ -73,7 +73,7 @@ func (s *sqlStore) ClearBufferedEventPlaintext(ctx context.Context, ciphertextHa return err } -func (s *sqlStore) DeleteBufferedEvent(ctx context.Context, ciphertextHash [32]byte) error { - _, err := s.db.Exec(ctx, deleteBufferedEventQuery, s.AccountID, ciphertextHash[:]) +func (s *sqlStore) DeleteBufferedEventsOlderThan(ctx context.Context, maxTS time.Time) error { + _, err := s.db.Exec(ctx, deleteOldBufferedEventsQuery, s.AccountID, maxTS.UnixMilli()) return err } diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index f4cf4aa..16a7463 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -40,7 +40,8 @@ const WebsocketProvisioningPath = "/v1/websocket/provisioning/" const WebsocketPath = "/v1/websocket/" type SimpleResponse struct { - Status int + Status int + WriteCallback func(time.Time) } type RequestHandlerFunc func(context.Context, *signalpb.WebSocketRequestMessage) (*SimpleResponse, error) @@ -541,10 +542,14 @@ func writeLoop( Uint64("request_id", *request.RequestMessage.Id). Int("response_status", request.ResponseMessage.Status). Msg("Sending WS response") + writeStartTime := time.Now() err := wspb.Write(ctx, ws, message) if err != nil { return fmt.Errorf("error writing response message: %w", err) } + if request.ResponseMessage.WriteCallback != nil { + request.ResponseMessage.WriteCallback(writeStartTime) + } } else { return fmt.Errorf("invalid request: %+v", request) } From f26198cce3678cc0b59545a8f9f110b1fcc24707 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 18:55:32 +0300 Subject: [PATCH 471/718] signalmeow/receiving: reset write counter on disconnect --- pkg/signalmeow/receiving.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index cd071c6..dd3589b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -111,6 +111,7 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection statusChan := make(chan SignalConnectionStatus, 128) initialConnectChan := make(chan struct{}) + resetWriteCount := make(chan struct{}, 1) // Combine both websocket status channels into a single, more generic "Signal" connection status channel cli.loopWg.Add(2) @@ -122,6 +123,8 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection select { case <-loopCtx.Done(): return + case <-resetWriteCount: + callbackCount = 0 case nextTS := <-cbc: if callbackCount >= 4 && time.Since(writeCallbackTimer) > 1*time.Minute { err := cli.Store.EventBuffer.DeleteBufferedEventsOlderThan(ctx, writeCallbackTimer) @@ -165,6 +168,12 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection case web.SignalWebsocketConnectionEventCleanShutdown: log.Info().Msg("Authed websocket clean shutdown") } + if status.Event != web.SignalWebsocketConnectionEventConnected { + select { + case resetWriteCount <- struct{}{}: + default: + } + } case status := <-unauthChan: lastUnauthStatus = status currentStatus = status From 00af0d3cc677673a780c4aa7a3b0e949d12ef7c3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 19:10:19 +0300 Subject: [PATCH 472/718] signalmeow/receiving: log ciphertext hashes --- pkg/signalmeow/receiving.go | 8 +++++++- pkg/signalmeow/receiving_decrypt.go | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index dd3589b..7f2f21d 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -386,7 +386,13 @@ func (cli *Client) handleDecryptedResult( defer func() { err := cli.Store.EventBuffer.ClearBufferedEventPlaintext(ctx, *result.CiphertextHash) if err != nil { - log.Err(err).Msg("Failed to clear buffered event plaintext") + log.Err(err). + Hex("ciphertext_hash", result.CiphertextHash[:]). + Msg("Failed to clear buffered event plaintext") + } else { + log.Debug(). + Hex("ciphertext_hash", result.CiphertextHash[:]). + Msg("Deleted event plaintext from buffer") } }() } diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index e8d30b0..7d85c43 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -112,8 +112,18 @@ func (cli *Client) bufferedDecryptTxn(ctx context.Context, ciphertext []byte, se return } else if buf != nil { plaintext = buf.Plaintext + insertTime := time.UnixMilli(buf.InsertTimestamp) if plaintext == nil { - err = fmt.Errorf("%w at %s", EventAlreadyProcessed, time.UnixMilli(buf.InsertTimestamp).String()) + zerolog.Ctx(ctx).Debug(). + Hex("ciphertext_hash", ciphertextHash[:]). + Time("insertion_time", insertTime). + Msg("Returning event already processed error") + err = fmt.Errorf("%w at %s", EventAlreadyProcessed, insertTime.String()) + } else { + zerolog.Ctx(ctx).Debug(). + Hex("ciphertext_hash", ciphertextHash[:]). + Time("insertion_time", insertTime). + Msg("Returning previously decrypted plaintext") } return } @@ -127,6 +137,9 @@ func (cli *Client) bufferedDecryptTxn(ctx context.Context, ciphertext []byte, se if innerErr != nil { innerErr = fmt.Errorf("failed to save decrypted event to buffer: %w", innerErr) } + zerolog.Ctx(ctx).Debug(). + Hex("ciphertext_hash", ciphertextHash[:]). + Msg("Successfully decrypted and saved event") return }) return From c3bc814a9eb4ac4d83f5a63009027debf79261e5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 19:12:05 +0300 Subject: [PATCH 473/718] signalmeow/receiving: remove content fields log --- pkg/signalmeow/receiving.go | 53 ------------------------------------- pkg/signalmeow/sending.go | 1 - 2 files changed, 54 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 7f2f21d..4e46a66 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -30,7 +30,6 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" @@ -451,7 +450,6 @@ func (cli *Client) handleDecryptedResult( Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("client_ts", envelope.GetTimestamp()). Msg("Decrypted message") - printContentFieldString(ctx, content, "Decrypted content fields") // If there's a sender key distribution message, process it if content.GetSenderKeyDistributionMessage() != nil { @@ -672,57 +670,6 @@ func (cli *Client) handleDecryptedResult( return nil } -func printStructFields(message protoreflect.Message, parent string, builder *strings.Builder) { - message.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - fieldName := string(fd.Name()) - currentField := parent + fieldName - fmt.Fprintf(builder, "%s (%s), ", currentField, fd.Kind().String()) - //builder.WriteString(fmt.Sprintf("%s (%s): %s, ", currentField, fd.Kind().String(), v.String())) // DEBUG: printing value, don't commit - if fd.Kind() == protoreflect.MessageKind && !fd.IsList() && v.Message().IsValid() { - builder.WriteString("{ ") - printStructFields(v.Message(), "", builder) - builder.WriteString("} ") - } else if fd.Kind() == protoreflect.MessageKind && fd.IsList() { - builder.WriteString("[ ") - for i := 0; i < v.List().Len(); i++ { - v := v.List().Get(i) - builder.WriteString("{ ") - printStructFields(v.Message(), "", builder) - builder.WriteString("} ") - } - builder.WriteString("] ") - } else if fd.IsList() { - builder.WriteString("[ ") - for i := 0; i < v.List().Len(); i++ { - //v := v.List().Get(i) - //builder.WriteString(fmt.Sprintf("%s, ", v.String())) // DEBUG: printing value, don't commit - builder.WriteString("<>, ") - } - builder.WriteString("] ") - } - return true - }) -} - -func printContentFieldString(ctx context.Context, c *signalpb.Content, message string) { - log := zerolog.Ctx(ctx) - go func() { - // catch panic - defer func() { - if r := recover(); r != nil { - log.Warn().Any("recover", r).Msg("Panic in contentFieldsString") - } - }() - log.Debug().Str("content_fields", contentFieldsString(c)).Msg(message) - }() -} - -func contentFieldsString(c *signalpb.Content) string { - var builder strings.Builder - printStructFields(c.ProtoReflect(), "", &builder) - return builder.String() -} - func groupOrUserID(groupID types.GroupIdentifier, userID libsignalgo.ServiceID) string { if groupID == "" { return userID.String() diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 7687da8..69545d9 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -849,7 +849,6 @@ func (cli *Client) sendContent( Uint64("timestamp", messageTimestamp). Logger() ctx = log.WithContext(ctx) - printContentFieldString(ctx, content, "Outgoing message") log.Trace().Any("raw_content", content).Stringer("recipient", recipient).Msg("Raw data of outgoing message") // If it's a data message, add our profile key From 708ef26c923c4a05fa45d4bb2979f8577c0923b1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 12 May 2025 20:04:14 +0300 Subject: [PATCH 474/718] libsignal: update to v0.71.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 14 ++++++++++++++ pkg/libsignalgo/version.go | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index efe13e9..eac4cf5 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit efe13e9b363d2c115dba61b76e5e53bbfc2874bc +Subproject commit eac4cf58ed9b102778b477a9657d4a348cf28f9c diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 82f1f7f..20bd8e1 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -143,6 +143,20 @@ typedef enum { SignalDirectionReceiving = 1, } SignalDirection; +/** + * The result of saving a new identity key for a protocol address. + */ +typedef enum { + /** + * The protocol address didn't have an identity key or had the same key. + */ + SignalIdentityChangeNewOrUnchanged, + /** + * The new identity key replaced a different key for the protocol address. + */ + SignalIdentityChangeReplacedExisting, +} SignalIdentityChange; + typedef enum { SignalLogLevelError = 1, SignalLogLevelWarn, diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 631a0a2..bce148c 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.70.0" +const Version = "v0.71.0" From 5eec76697dc705d212ba4707577e3fc0fa829308 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 May 2025 16:00:53 +0300 Subject: [PATCH 475/718] libsignal: update to v0.72.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 294 +++++++++++++++++++++++++++++++- pkg/libsignalgo/sealedsender.go | 55 ------ pkg/libsignalgo/session_test.go | 90 ---------- pkg/libsignalgo/version.go | 2 +- 5 files changed, 294 insertions(+), 149 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index eac4cf5..7d1cacb 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit eac4cf58ed9b102778b477a9657d4a348cf28f9c +Subproject commit 7d1cacbaa8a885932b8838dfc3cddbf631dbddae diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 20bd8e1..c2c0068 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -143,6 +143,12 @@ typedef enum { SignalDirectionReceiving = 1, } SignalDirection; +enum SignalFfiPublicKeyType { + SignalFfiPublicKeyTypeECC, + SignalFfiPublicKeyTypeKyber, +}; +typedef uint8_t SignalFfiPublicKeyType; + /** * The result of saving a new identity key for a protocol address. */ @@ -165,6 +171,12 @@ typedef enum { SignalLogLevelTrace, } SignalLogLevel; +enum SignalRequestedInformation { + SignalRequestedInformationPushChallenge, + SignalRequestedInformationCaptcha, +}; +typedef uint8_t SignalRequestedInformation; + typedef enum { SignalErrorCodeUnknownError = 1, SignalErrorCodeInvalidState = 2, @@ -227,8 +239,29 @@ typedef enum { SignalErrorCodeConnectionInvalidated = 172, SignalErrorCodeConnectedElsewhere = 173, SignalErrorCodeBackupValidation = 180, + SignalErrorCodeRegistrationInvalidSessionId = 190, + SignalErrorCodeRegistrationRequestNotValid, + SignalErrorCodeRegistrationUnknown, + SignalErrorCodeRegistrationSessionNotFound, + SignalErrorCodeRegistrationNotReadyForVerification, + SignalErrorCodeRegistrationSendVerificationCodeFailed, + SignalErrorCodeRegistrationCodeNotDeliverable, + SignalErrorCodeRegistrationSessionUpdateRejected, + SignalErrorCodeRegistrationCredentialsCouldNotBeParsed, + SignalErrorCodeRegistrationDeviceTransferPossible, + SignalErrorCodeRegistrationRecoveryVerificationFailed, + SignalErrorCodeRegistrationLock, } SignalErrorCode; +enum SignalSvr2CredentialsResult { + SignalSvr2CredentialsResultMatch, + SignalSvr2CredentialsResultNoMatch, + SignalSvr2CredentialsResultInvalid, +}; +typedef uint8_t SignalSvr2CredentialsResult; + +typedef struct SignalAccountAttributes SignalAccountAttributes; + /** * A wrapper around [`ctr::Ctr32BE`] that uses a smaller nonce and supports an initial counter. */ @@ -300,6 +333,14 @@ typedef struct SignalProtocolAddress SignalProtocolAddress; typedef struct SignalPublicKey SignalPublicKey; +typedef struct SignalRegisterAccountRequest SignalRegisterAccountRequest; + +typedef struct SignalRegisterAccountResponse SignalRegisterAccountResponse; + +typedef struct SignalRegistrationService SignalRegistrationService; + +typedef struct SignalRegistrationSession SignalRegistrationSession; + typedef struct SignalSanitizedMetadata SignalSanitizedMetadata; typedef struct SignalSenderCertificate SignalSenderCertificate; @@ -820,6 +861,32 @@ typedef struct { const SignalFingerprint *raw; } SignalConstPointerFingerprint; +typedef struct { + /** + * The badge ID. + */ + const char *id; + /** + * Whether the badge is currently configured to be visible. + */ + bool visible; + /** + * When the badge expires. + */ + double expiration_secs; +} SignalFfiRegisterResponseBadge; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalFfiRegisterResponseBadge *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfFfiRegisterResponseBadge; + typedef struct { SignalSenderKeyRecord *raw; } SignalMutPointerSenderKeyRecord; @@ -994,6 +1061,145 @@ typedef struct { const SignalSenderKeyDistributionMessage *raw; } SignalConstPointerSenderKeyDistributionMessage; +typedef struct { + SignalRegisterAccountRequest *raw; +} SignalMutPointerRegisterAccountRequest; + +typedef struct { + const SignalRegisterAccountRequest *raw; +} SignalConstPointerRegisterAccountRequest; + +typedef struct { + uint32_t key_id; + SignalFfiPublicKeyType public_key_type; + const void *public_key; + SignalBorrowedBuffer signature; +} SignalFfiSignedPublicPreKey; + +typedef struct { + SignalRegisterAccountResponse *raw; +} SignalMutPointerRegisterAccountResponse; + +typedef struct { + const SignalRegisterAccountResponse *raw; +} SignalConstPointerRegisterAccountResponse; + +typedef uint8_t SignalOptionalUuid[17]; + +typedef SignalAccountAttributes SignalRegistrationAccountAttributes; + +typedef struct { + SignalRegistrationAccountAttributes *raw; +} SignalMutPointerRegistrationAccountAttributes; + +typedef struct { + const size_t *base; + size_t length; +} SignalBorrowedSliceOfusize; + +typedef struct { + SignalBorrowedBuffer bytes; + SignalBorrowedSliceOfusize lengths; +} SignalBorrowedBytestringArray; + +typedef struct { + /** + * Bridged as a string of bytes, but each entry is a UTF-8 `String` key + * concatenated with a byte for the value. + */ + SignalBytestringArray entries; +} SignalFfiCheckSvr2CredentialsResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiCheckSvr2CredentialsResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiCheckSvr2CredentialsResponse; + +typedef struct { + const SignalRegistrationService *raw; +} SignalConstPointerRegistrationService; + +typedef struct { + SignalRegistrationService *raw; +} SignalMutPointerRegistrationService; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerRegistrationService *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerRegistrationService; + +typedef struct { + const char *number; + const char *push_token; + const char *mcc; + const char *mnc; +} SignalFfiRegistrationCreateSessionRequest; + +typedef const SignalConnectionManager *(*SignalGetConnectChatConnectionManager)(void *ctx); + +typedef void (*SignalDestroyConnectChatBridge)(void *ctx); + +/** + * A ref-counting pointer to a [`ConnectionManager`] and a callback to + * decrement the count. + */ +typedef struct { + void *ctx; + SignalGetConnectChatConnectionManager get_connection_manager; + SignalDestroyConnectChatBridge destroy; +} SignalFfiConnectChatBridgeStruct; + +typedef struct { + const SignalFfiConnectChatBridgeStruct *raw; +} SignalConstPointerFfiConnectChatBridgeStruct; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerRegisterAccountResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerRegisterAccountResponse; + +typedef struct { + const SignalRegistrationAccountAttributes *raw; +} SignalConstPointerRegistrationAccountAttributes; + +typedef struct { + SignalRegistrationSession *raw; +} SignalMutPointerRegistrationSession; + +typedef struct { + const SignalRegistrationSession *raw; +} SignalConstPointerRegistrationSession; + typedef struct { const SignalSanitizedMetadata *raw; } SignalConstPointerSanitizedMetadata; @@ -1103,6 +1309,8 @@ typedef struct { typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN]; +typedef uint8_t SignalUnidentifiedAccessKey[SignalACCESS_KEY_LEN]; + SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy); SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy); @@ -1363,6 +1571,10 @@ SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalMutPoi SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); +SignalFfiError *signal_error_get_registration_error_not_deliverable(const SignalFfiError *err, const char **out_reason, bool *out_permanent); + +SignalFfiError *signal_error_get_registration_lock(const SignalFfiError *err, uint64_t *out_time_remaining_seconds, const char **out_svr2_username, const char **out_svr2_password); + SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); @@ -1395,6 +1607,8 @@ void signal_free_buffer(const unsigned char *buf, size_t buf_len); void signal_free_bytestring_array(SignalBytestringArray array); +void signal_free_list_of_register_response_badges(SignalOwnedBufferOfFfiRegisterResponseBadge buffer); + void signal_free_list_of_strings(SignalOwnedBufferOfCStringPtr buffer); void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); @@ -1811,6 +2025,84 @@ SignalFfiError *signal_receipt_credential_request_context_get_request(unsigned c SignalFfiError *signal_receipt_credential_response_check_valid_contents(SignalBorrowedBuffer buffer); +SignalFfiError *signal_register_account_request_create(SignalMutPointerRegisterAccountRequest *out); + +SignalFfiError *signal_register_account_request_destroy(SignalMutPointerRegisterAccountRequest p); + +SignalFfiError *signal_register_account_request_set_account_password(SignalConstPointerRegisterAccountRequest register_account, const char *account_password); + +SignalFfiError *signal_register_account_request_set_apn_push_token(SignalConstPointerRegisterAccountRequest register_account, const char *apn_push_token); + +SignalFfiError *signal_register_account_request_set_identity_pq_last_resort_pre_key(SignalConstPointerRegisterAccountRequest register_account, uint8_t identity_type, SignalFfiSignedPublicPreKey pq_last_resort_pre_key); + +SignalFfiError *signal_register_account_request_set_identity_public_key(SignalConstPointerRegisterAccountRequest register_account, uint8_t identity_type, SignalConstPointerPublicKey identity_key); + +SignalFfiError *signal_register_account_request_set_identity_signed_pre_key(SignalConstPointerRegisterAccountRequest register_account, uint8_t identity_type, SignalFfiSignedPublicPreKey signed_pre_key); + +SignalFfiError *signal_register_account_request_set_skip_device_transfer(SignalConstPointerRegisterAccountRequest register_account); + +SignalFfiError *signal_register_account_response_destroy(SignalMutPointerRegisterAccountResponse p); + +SignalFfiError *signal_register_account_response_get_entitlement_backup_expiration_seconds(uint64_t *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_entitlement_backup_level(uint64_t *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_entitlement_badges(SignalOwnedBufferOfFfiRegisterResponseBadge *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_identity(SignalServiceIdFixedWidthBinaryBytes *out, SignalConstPointerRegisterAccountResponse response, uint8_t identity_type); + +SignalFfiError *signal_register_account_response_get_number(const char **out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_reregistration(bool *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_storage_capable(bool *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_username_hash(SignalOwnedBuffer *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_register_account_response_get_username_link_handle(SignalOptionalUuid *out, SignalConstPointerRegisterAccountResponse response); + +SignalFfiError *signal_registration_account_attributes_create(SignalMutPointerRegistrationAccountAttributes *out, SignalBorrowedBuffer recovery_password, uint16_t aci_registration_id, uint16_t pni_registration_id, const char *registration_lock, const uint8_t (*unidentified_access_key)[16], bool unrestricted_unidentified_access, SignalBorrowedBytestringArray capabilities, bool discoverable_by_phone_number); + +SignalFfiError *signal_registration_account_attributes_destroy(SignalMutPointerRegistrationAccountAttributes p); + +SignalFfiError *signal_registration_service_check_svr2_credentials(SignalCPromiseFfiCheckSvr2CredentialsResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, SignalBorrowedBytestringArray svr_tokens); + +SignalFfiError *signal_registration_service_create_session(SignalCPromiseMutPointerRegistrationService *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalFfiRegistrationCreateSessionRequest create_session, SignalConstPointerFfiConnectChatBridgeStruct connect_chat); + +SignalFfiError *signal_registration_service_destroy(SignalMutPointerRegistrationService p); + +SignalFfiError *signal_registration_service_register_account(SignalCPromiseMutPointerRegisterAccountResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, SignalConstPointerRegisterAccountRequest register_account, SignalConstPointerRegistrationAccountAttributes account_attributes); + +SignalFfiError *signal_registration_service_registration_session(SignalMutPointerRegistrationSession *out, SignalConstPointerRegistrationService service); + +SignalFfiError *signal_registration_service_request_push_challenge(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *push_token, const void *push_token_type); + +SignalFfiError *signal_registration_service_request_verification_code(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *transport, const char *client, SignalBorrowedBytestringArray languages); + +SignalFfiError *signal_registration_service_resume_session(SignalCPromiseMutPointerRegistrationService *promise, SignalConstPointerTokioAsyncContext async_runtime, const char *session_id, const char *number, SignalConstPointerFfiConnectChatBridgeStruct connect_chat); + +SignalFfiError *signal_registration_service_session_id(const char **out, SignalConstPointerRegistrationService service); + +SignalFfiError *signal_registration_service_submit_captcha(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *captcha_value); + +SignalFfiError *signal_registration_service_submit_push_challenge(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *push_challenge); + +SignalFfiError *signal_registration_service_submit_verification_code(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *code); + +SignalFfiError *signal_registration_session_destroy(SignalMutPointerRegistrationSession p); + +SignalFfiError *signal_registration_session_get_allowed_to_request_code(bool *out, SignalConstPointerRegistrationSession session); + +SignalFfiError *signal_registration_session_get_next_call_seconds(uint32_t *out, SignalConstPointerRegistrationSession session); + +SignalFfiError *signal_registration_session_get_next_sms_seconds(uint32_t *out, SignalConstPointerRegistrationSession session); + +SignalFfiError *signal_registration_session_get_next_verification_attempt_seconds(uint32_t *out, SignalConstPointerRegistrationSession session); + +SignalFfiError *signal_registration_session_get_requested_information(SignalOwnedBuffer *out, SignalConstPointerRegistrationSession session); + +SignalFfiError *signal_registration_session_get_verified(bool *out, SignalConstPointerRegistrationSession session); + #if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_clone(SignalMutPointerSanitizedMetadata *new_obj, SignalConstPointerSanitizedMetadata obj); #endif @@ -1835,8 +2127,6 @@ SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer * SignalFfiError *signal_sealed_sender_multi_recipient_message_for_single_recipient(SignalOwnedBuffer *out, SignalBorrowedBuffer encoded_multi_recipient_message); -SignalFfiError *signal_sealed_session_cipher_decrypt(SignalOwnedBuffer *out, const char **sender_e164, const char **sender_uuid, uint32_t *sender_device_id, SignalBorrowedBuffer ctext, SignalConstPointerPublicKey trust_root, uint64_t timestamp, const char *local_e164, const char *local_uuid, unsigned int local_device_id, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store); - SignalFfiError *signal_sealed_session_cipher_decrypt_to_usmc(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer ctext, SignalConstPointerFfiIdentityKeyStoreStruct identity_store); SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress destination, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 1e93410..1530183 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -107,61 +107,6 @@ func SealedSenderDecryptToUSMC( return wrapUnidentifiedSenderMessageContent(usmc.raw), nil } -func SealedSenderDecrypt( - ctx context.Context, - ciphertext []byte, - localAddress *SealedSenderAddress, - trustRoot *PublicKey, - timestamp uint64, - sessionStore SessionStore, - identityStore IdentityKeyStore, - preKeyStore PreKeyStore, - signedPreKeyStore SignedPreKeyStore, -) (result SealedSenderResult, err error) { - callbackCtx := NewCallbackContext(ctx) - defer callbackCtx.Unref() - - var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} - var senderE164 *C.char - var senderUUID *C.char - var senderDeviceID C.uint32_t - - signalFfiError := C.signal_sealed_session_cipher_decrypt( - &decrypted, - &senderE164, - &senderUUID, - &senderDeviceID, - BytesToBuffer(ciphertext), - trustRoot.constPtr(), - C.uint64_t(timestamp), - C.CString(localAddress.E164), - C.CString(localAddress.UUID.String()), - C.uint32_t(localAddress.DeviceID), - callbackCtx.wrapSessionStore(sessionStore), - callbackCtx.wrapIdentityKeyStore(identityStore), - callbackCtx.wrapPreKeyStore(preKeyStore), - callbackCtx.wrapSignedPreKeyStore(signedPreKeyStore), - ) - runtime.KeepAlive(localAddress) - runtime.KeepAlive(trustRoot) - if signalFfiError != nil { - err = callbackCtx.wrapError(signalFfiError) - return - } - - defer C.signal_free_string(senderE164) - defer C.signal_free_string(senderUUID) - - return SealedSenderResult{ - Message: CopySignalOwnedBufferToBytes(decrypted), - Sender: SealedSenderAddress{ - E164: C.GoString(senderE164), - UUID: uuid.MustParse(C.GoString(senderUUID)), - DeviceID: uint32(senderDeviceID), - }, - }, nil -} - type UnidentifiedSenderMessageContentHint uint32 const ( diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index 1840fc3..30af762 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -247,96 +247,6 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) { } } -// From SessionTests.swift:testSealedSenderSession -func TestSealedSenderSession(t *testing.T) { - ctx := context.TODO() - - setupLogging() - - aliceAddress, err := libsignalgo.NewUUIDAddressFromString("9d0652a3-dcc3-4d11-975f-74d61598733f", 1) - assert.NoError(t, err) - bobAddress, err := libsignalgo.NewUUIDAddressFromString("6838237D-02F6-4098-B110-698253D15961", 1) - assert.NoError(t, err) - - aliceStore := NewInMemorySignalProtocolStore() - bobStore := NewInMemorySignalProtocolStore() - - initializeSessions(t, aliceStore, bobStore, bobAddress) - - trustRoot, err := libsignalgo.GenerateIdentityKeyPair() - assert.NoError(t, err) - serverKeys, err := libsignalgo.GenerateIdentityKeyPair() - assert.NoError(t, err) - serverCert, err := libsignalgo.NewServerCertificate(1, serverKeys.GetPublicKey(), trustRoot.GetPrivateKey()) - assert.NoError(t, err) - aliceName, err := aliceAddress.Name() - assert.NoError(t, err) - senderAddress := libsignalgo.NewSealedSenderAddress("+14151111111", uuid.MustParse(aliceName), 1) - - aliceIdentityKeyPair, err := aliceStore.GetIdentityKeyPair(ctx) - require.NoError(t, err) - senderCert, err := libsignalgo.NewSenderCertificate(senderAddress, aliceIdentityKeyPair.GetPublicKey(), time.UnixMilli(31337), serverCert, serverKeys.GetPrivateKey()) - assert.NoError(t, err) - - message := []byte("2020 vision") - ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore) - require.NoError(t, err) - assert.NotNil(t, ciphertext) - - bobName, err := bobAddress.Name() - require.NoError(t, err) - recipientAddress := libsignalgo.NewSealedSenderAddress("", uuid.MustParse(bobName), 1) - - t.Skip("This test is broken") // TODO fix - - plaintext, err := libsignalgo.SealedSenderDecrypt( - ctx, - ciphertext, - recipientAddress, - trustRoot.GetPublicKey(), - 31335, - bobStore, - bobStore, - bobStore, - bobStore, - ) - require.NoError(t, err) - assert.Equal(t, message, plaintext.Message) - assert.Equal(t, senderAddress.DeviceID, plaintext.Sender.DeviceID) - assert.Equal(t, senderAddress.E164, plaintext.Sender.E164) - assert.Equal(t, senderAddress.UUID, plaintext.Sender.UUID) - - innerMessage, err := libsignalgo.Encrypt(ctx, []byte{}, bobAddress, aliceStore, aliceStore) - require.NoError(t, err) - - hints := []libsignalgo.UnidentifiedSenderMessageContentHint{ - 200, - libsignalgo.UnidentifiedSenderMessageContentHintDefault, - libsignalgo.UnidentifiedSenderMessageContentHintResendable, - libsignalgo.UnidentifiedSenderMessageContentHintImplicit, - } - - for _, hint := range hints { - content, err := libsignalgo.NewUnidentifiedSenderMessageContent( - innerMessage, - senderCert, - hint, - []byte{}, - ) - require.NoError(t, err) - - _, err = libsignalgo.SealedSenderEncrypt(ctx, content, bobAddress, aliceStore) - require.NoError(t, err) - - // decryptedContent, err := libsignalgo.NewUnidentifiedSenderMessageContent(ciphertext) - - // let decryptedContent = try UnidentifiedSenderMessageContent(message: ciphertext, - // identityStore: bob_store, - // context: NullContext()) - // XCTAssertEqual(decryptedContent.contentHint, hint) - } -} - // From SessionTests.swift:testArchiveSession func TestArchiveSession(t *testing.T) { ctx := context.TODO() diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index bce148c..5a7e360 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.71.0" +const Version = "v0.72.1" From 79701f572a6ccfd5dbdc7c71a31f51e8adaf43bb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 May 2025 16:01:09 +0300 Subject: [PATCH 476/718] dependencies: update --- go.mod | 22 +++++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 4322e00..5c63d64 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.7-0.20250504163337-fc01e957f535 - golang.org/x/crypto v0.37.0 - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 - golang.org/x/net v0.39.0 + go.mau.fi/util v0.8.7-0.20250515110144-747f5904911e + golang.org/x/crypto v0.38.0 + golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 + golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.23.4-0.20250508122520-376fa1f36898 + maunium.net/go/mautrix v0.23.4-0.20250515111534-978e0983eadf ) require ( @@ -30,8 +30,8 @@ require ( github.com/lib/pq v1.10.9 // 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.27 // indirect - github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a // indirect + github.com/mattn/go-sqlite3 v1.14.28 // indirect + github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -39,11 +39,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.10 // indirect + github.com/yuin/goldmark v1.7.11 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.24.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index e45bd46..47ed096 100644 --- a/go.sum +++ b/go.sum @@ -38,10 +38,10 @@ 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.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= -github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a h1:S+AGcmAESQ0pXCUNnRH7V+bOUIgkSX5qVt2cNKCrm0Q= -github.com/petermattis/goid v0.0.0-20250319124200-ccd6737f222a/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb h1:3PrKuO92dUTMrQ9dx0YNejC6U/Si6jqKmyQ9vWjwqR4= +github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -67,27 +67,27 @@ 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.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI= -github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.8.7-0.20250504163337-fc01e957f535 h1:ESKcyK5hWCzx8dzfSGKEuhuRD3Dg3eCtxOjxmjpnO5s= -go.mau.fi/util v0.8.7-0.20250504163337-fc01e957f535/go.mod h1:uNB3UTXFbkpp7xL1M/WvQks90B/L4gvbLpbS0603KOE= +github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo= +github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +go.mau.fi/util v0.8.7-0.20250515110144-747f5904911e h1:8kfjOQ+L38Zq2HbhMFVhbkTdwiGbAmgTriioRnRB+LQ= +go.mau.fi/util v0.8.7-0.20250515110144-747f5904911e/go.mod h1:j6R3cENakc1f8HpQeFl0N15UiSTcNmIfDBNJUbL71RY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -99,5 +99,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.23.4-0.20250508122520-376fa1f36898 h1:ZS1FV3+vmGquh//RGBRk3TzdoqCPOwEr40cA7k9e/jA= -maunium.net/go/mautrix v0.23.4-0.20250508122520-376fa1f36898/go.mod h1:pT4G5RZQ+nLfKzsmeDa4NhHghOVTrasLLwY9tZ2mO08= +maunium.net/go/mautrix v0.23.4-0.20250515111534-978e0983eadf h1:kCBKSVfLrKtaSD4XBp/cj+dkqNWesMdyu5KODrMtVYc= +maunium.net/go/mautrix v0.23.4-0.20250515111534-978e0983eadf/go.mod h1:A9WfZ8F6jxM7F8eKaVZ4TAC7dWoqHBShMA8baCvtpZU= From 99d026d51009f4de7a4a8a53d083afc0024ae955 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 May 2025 08:16:28 +0300 Subject: [PATCH 477/718] Bump version to v0.8.3 --- CHANGELOG.md | 12 +++++++++++- cmd/mautrix-signal/main.go | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 722ed55..e9da97b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ +# v0.8.3 (2025-05-16) + +* Updated libsignal to v0.72.1. +* Added initial support for direct media access. + * Note that media is only kept on the Signal servers for 45 days, after which + any direct media links will permanently stop working. +* Added buffer for decrypted events to prevent losing messages if the bridge is + stopped in the middle of event handling. +* Fixed backfilling messages in existing portals after relogining. + # v0.8.2 (2025-04-16) -* Updated libsignal to v0.70.0 +* Updated libsignal to v0.70.0. * Fixed panics in some cases when the bridge was under heavy load. # v0.8.1 (2025-03-16) diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index c1689d6..b2eccfb 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.2", + Version: "0.8.3", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 5c63d64..ac1eb60 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.7-0.20250515110144-747f5904911e + go.mau.fi/util v0.8.7 golang.org/x/crypto v0.38.0 golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.23.4-0.20250515111534-978e0983eadf + maunium.net/go/mautrix v0.24.0 ) require ( diff --git a/go.sum b/go.sum index 47ed096..7e503f1 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo= github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.8.7-0.20250515110144-747f5904911e h1:8kfjOQ+L38Zq2HbhMFVhbkTdwiGbAmgTriioRnRB+LQ= -go.mau.fi/util v0.8.7-0.20250515110144-747f5904911e/go.mod h1:j6R3cENakc1f8HpQeFl0N15UiSTcNmIfDBNJUbL71RY= +go.mau.fi/util v0.8.7 h1:ywKarPxouJQEEijTs4mPlxC7F4AWEKokEpWc+2TYy6c= +go.mau.fi/util v0.8.7/go.mod h1:j6R3cENakc1f8HpQeFl0N15UiSTcNmIfDBNJUbL71RY= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= @@ -99,5 +99,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.23.4-0.20250515111534-978e0983eadf h1:kCBKSVfLrKtaSD4XBp/cj+dkqNWesMdyu5KODrMtVYc= -maunium.net/go/mautrix v0.23.4-0.20250515111534-978e0983eadf/go.mod h1:A9WfZ8F6jxM7F8eKaVZ4TAC7dWoqHBShMA8baCvtpZU= +maunium.net/go/mautrix v0.24.0 h1:kBeyWhgL1W8/d8BEFlBSlgIpItPgP1l37hzF8cN3R70= +maunium.net/go/mautrix v0.24.0/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= From 1b1136537d3125d8ede55ce490dcfc6bd27a3f34 Mon Sep 17 00:00:00 2001 From: Adam Van Ymeren Date: Mon, 19 May 2025 08:00:11 -0700 Subject: [PATCH 478/718] directmedia: actually return properly decoded profile avatar info (#600) --- pkg/signalid/media.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go index defd4e5..533463c 100644 --- a/pkg/signalid/media.go +++ b/pkg/signalid/media.go @@ -192,6 +192,7 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err } else { info.ProfileAvatarPath = string(profileAvatarPath) } + return &info, nil } return nil, fmt.Errorf("invalid direct media type %d", mediaType) From 6b06430c028aada0c518800e88517a6360a5c1da Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 26 May 2025 15:33:49 +0300 Subject: [PATCH 479/718] signalmeow/receiving: change log level for already processed events --- pkg/signalmeow/receiving.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 4e46a66..b24d167 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -414,13 +414,23 @@ func (cli *Client) handleDecryptedResult( } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") } + if errors.Is(result.Err, EventAlreadyProcessed) { + logEvt.Discard().Msg("") + log.Debug().Err(result.Err). + Bool("urgent", envelope.GetUrgent()). + Stringer("content_hint", result.ContentHint). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Stringer("sender", theirServiceID). + Msg("Ignoring already processed event") + return nil + } logEvt.Stringer("sender", theirServiceID).Msg("Decryption error with known sender") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot if envelope.GetUrgent() && result.ContentHint != signalpb.UnidentifiedSenderMessage_Message_IMPLICIT && - !strings.Contains(result.Err.Error(), "message with old counter") && - !errors.Is(err, EventAlreadyProcessed) { + !strings.Contains(result.Err.Error(), "message with old counter") { cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, From 7eb997b46067bacec0cff9ce870adee481194dd2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 26 May 2025 15:37:05 +0300 Subject: [PATCH 480/718] handlesignal: add missing details to decryption error event --- pkg/connector/handlesignal.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 8a94016..183cfa4 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -107,12 +107,14 @@ func (s *SignalClient) wrapDecryptionError(evt *events.DecryptionError) bridgev2 Type: bridgev2.RemoteEventMessage, LogContext: func(c zerolog.Context) zerolog.Context { c = c.Stringer("sender_id", evt.Sender) + c = c.Uint64("message_ts", evt.Timestamp) return c }, PortalKey: s.makePortalKey(evt.Sender.String()), CreatePortal: true, Sender: s.makeEventSender(evt.Sender), Timestamp: time.UnixMilli(int64(evt.Timestamp)), + StreamOrder: int64(evt.Timestamp), }, Data: evt, // TODO use main message id and edit it if it later becomes decryptable? From 55321a53e63022f027678159b33e93792b67f9ce Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 27 May 2025 11:44:34 +0300 Subject: [PATCH 481/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- pkg/msgconv/urlpreview.go | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index ac1eb60..c1184f2 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.0 + maunium.net/go/mautrix v0.24.1-0.20250527083757-8a745c0d03ec ) require ( diff --git a/go.sum b/go.sum index 7e503f1..138e781 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.24.0 h1:kBeyWhgL1W8/d8BEFlBSlgIpItPgP1l37hzF8cN3R70= -maunium.net/go/mautrix v0.24.0/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= +maunium.net/go/mautrix v0.24.1-0.20250527083757-8a745c0d03ec h1:kn/SHMTE4FiafMFS9WKXzHQc/Z9yN09Aa7TiFOgYfSY= +maunium.net/go/mautrix v0.24.1-0.20250527083757-8a745c0d03ec/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= diff --git a/pkg/msgconv/urlpreview.go b/pkg/msgconv/urlpreview.go index fcb32fb..66b186a 100644 --- a/pkg/msgconv/urlpreview.go +++ b/pkg/msgconv/urlpreview.go @@ -52,9 +52,9 @@ func (mc *MessageConverter) convertURLPreviewToBeeper(ctx context.Context, previ output.ImageURL = msg.Content.URL output.ImageEncryption = msg.Content.File output.ImageType = msg.Content.Info.MimeType - output.ImageSize = msg.Content.Info.Size - output.ImageHeight = msg.Content.Info.Height - output.ImageWidth = msg.Content.Info.Width + output.ImageSize = event.IntOrString(msg.Content.Info.Size) + output.ImageHeight = event.IntOrString(msg.Content.Info.Height) + output.ImageWidth = event.IntOrString(msg.Content.Info.Width) } } return output From 58f62f72b7f8de5726a9fc1091add05451866a95 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 27 May 2025 14:42:51 +0300 Subject: [PATCH 482/718] signalmeow/contactdiscovery: update enclave id --- pkg/signalmeow/contactdiscovery.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index 33b0ad3..2360457 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -40,7 +40,7 @@ import ( ) const ProdContactDiscoveryServer = "cdsi.signal.org" -const ProdContactDiscoveryMrenclave = "0f6fd79cdfdaa5b2e6337f534d3baf999318b0c462a7ac1f41297a3e4b424a57" +const ProdContactDiscoveryMrenclave = "c6ff0682219217f7045624be472a077c0d4b06193fe71632eb0adb50051d5da1" const ContactDiscoveryAuthTTL = 23 * time.Hour const rateLimitCloseCode = websocket.StatusCode(4008) From 3c960fe56288700af98b16cda18c76febb4ddb64 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 31 May 2025 18:07:07 +0300 Subject: [PATCH 483/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c1184f2..abd27a4 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.1-0.20250527083757-8a745c0d03ec + maunium.net/go/mautrix v0.24.1-0.20250531150347-788621f7e035 ) require ( diff --git a/go.sum b/go.sum index 138e781..6257f3b 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.24.1-0.20250527083757-8a745c0d03ec h1:kn/SHMTE4FiafMFS9WKXzHQc/Z9yN09Aa7TiFOgYfSY= -maunium.net/go/mautrix v0.24.1-0.20250527083757-8a745c0d03ec/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= +maunium.net/go/mautrix v0.24.1-0.20250531150347-788621f7e035 h1:jGg4WFHZhtnr7Lo6Y0RVPaxmHiPNLHhfcf8lrCz+pXY= +maunium.net/go/mautrix v0.24.1-0.20250531150347-788621f7e035/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= From c33b32631e0fafec77a6660d9301bf1b561df88e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 31 May 2025 18:47:45 +0300 Subject: [PATCH 484/718] handlesignal: don't panic in getters --- pkg/connector/handlesignal.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 183cfa4..c2b0139 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -252,7 +252,7 @@ func (evt *Bv2ChatEvent) GetSender() bridgev2.EventSender { func (evt *Bv2ChatEvent) GetID() networkid.MessageID { ts := evt.getDataMsgTimestamp() if ts == 0 { - panic(fmt.Errorf("GetID() called for non-DataMessage event")) + return "" } return signalid.MakeMessageID(evt.Info.Sender, ts) } @@ -288,12 +288,12 @@ func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { case innerEvt.Delete != nil: targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() default: - panic(fmt.Errorf("GetTargetMessage() called for message type without target")) + return "" } case *signalpb.EditMessage: targetSentTS = innerEvt.GetTargetSentTimestamp() default: - panic(fmt.Errorf("GetTargetMessage() called for message type without target")) + return "" } targetAuthorUUID := evt.Info.Sender if targetAuthorACI != "" { From 286197927ca0dc9769a576327b868dfc9af96635 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Jun 2025 18:11:30 +0300 Subject: [PATCH 485/718] directmedia: add nil checks for direct media --- pkg/connector/directmedia.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go index b24c033..8507626 100644 --- a/pkg/connector/directmedia.go +++ b/pkg/connector/directmedia.go @@ -64,6 +64,8 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI userLogin, err := s.Bridge.GetExistingUserLoginByID(ctx, signalid.MakeUserLoginID(info.UserID)) if err != nil { return nil, fmt.Errorf("failed to get user login: %w", err) + } else if userLogin == nil { + return nil, bridgev2.ErrNotLoggedIn } client := userLogin.Client.(*SignalClient) @@ -95,6 +97,8 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI userLogin, err := s.Bridge.GetExistingUserLoginByID(ctx, signalid.MakeUserLoginID(info.UserID)) if err != nil { return nil, fmt.Errorf("failed to get user login: %w", err) + } else if userLogin == nil { + return nil, bridgev2.ErrNotLoggedIn } client := userLogin.Client.(*SignalClient) @@ -102,6 +106,8 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI profileKey, err := client.Client.Store.RecipientStore.LoadProfileKey(ctx, info.ContactID) if err != nil { return nil, fmt.Errorf("failed to get contact: %w", err) + } else if profileKey == nil { + return nil, fmt.Errorf("profile key not found") } return &mediaproxy.GetMediaResponseCallback{ From 18ecb3fff9ab76d4c17e58a2e8e85553779d54a4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Jun 2025 19:33:43 +0300 Subject: [PATCH 486/718] msgconv/from-matrix: guess mime type if not specified --- pkg/msgconv/from-matrix.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 367bb1f..36391f3 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -19,6 +19,7 @@ package msgconv import ( "context" "fmt" + "net/http" "strings" "github.com/rs/zerolog" @@ -154,6 +155,9 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. fileName = content.FileName } mime := content.GetInfo().MimeType + if mime == "" { + mime = http.DetectContentType(data) + } if content.MSC3245Voice != nil && mime != "audio/aac" && ffmpeg.Supported() { data, err = ffmpeg.ConvertBytes(ctx, data, ".aac", []string{}, []string{"-c:a", "aac"}, mime) if err != nil { From f378624e8703c91750605df1887084170d93ecc9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Jun 2025 16:54:03 +0300 Subject: [PATCH 487/718] legacymigrate: drop invalid disappearing message rows --- cmd/mautrix-signal/legacymigrate.sql | 3 ++- cmd/mautrix-signal/main.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/mautrix-signal/legacymigrate.sql b/cmd/mautrix-signal/legacymigrate.sql index 1895bfd..cbf06e3 100644 --- a/cmd/mautrix-signal/legacymigrate.sql +++ b/cmd/mautrix-signal/legacymigrate.sql @@ -129,7 +129,8 @@ SELECT expiration_seconds * 1000000000, -- timer CASE WHEN expiration_ts IS NOT NULL THEN expiration_ts * 1000000000 END -- disappear_at FROM disappearing_message_old -WHERE expiration_ts < 9000000000; +WHERE expiration_ts < 9000000000 + AND room_id IN (SELECT mxid FROM portal WHERE mxid IS NOT NULL); INSERT INTO reaction ( bridge_id, message_id, message_part_id, sender_id, emoji_id, emoji, diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index b2eccfb..72b91c8 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -51,7 +51,7 @@ func main() { 20, "v0.5.1", "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 18), + m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 21), true, ) } From 6bba293cd45cf0c8ec52e5ef0a9a8d15d44fad45 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Jun 2025 20:25:55 +0300 Subject: [PATCH 488/718] libsignal: update to v0.73.2 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 68 +++++++++++++++++++++++++-------- pkg/libsignalgo/version.go | 2 +- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 7d1cacb..f8bcdb0 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 7d1cacbaa8a885932b8838dfc3cddbf631dbddae +Subproject commit f8bcdb016abb9edb3b8d92851636208f3aa4c238 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index c2c0068..6c17995 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -240,17 +240,19 @@ typedef enum { SignalErrorCodeConnectedElsewhere = 173, SignalErrorCodeBackupValidation = 180, SignalErrorCodeRegistrationInvalidSessionId = 190, - SignalErrorCodeRegistrationRequestNotValid, - SignalErrorCodeRegistrationUnknown, - SignalErrorCodeRegistrationSessionNotFound, - SignalErrorCodeRegistrationNotReadyForVerification, - SignalErrorCodeRegistrationSendVerificationCodeFailed, - SignalErrorCodeRegistrationCodeNotDeliverable, - SignalErrorCodeRegistrationSessionUpdateRejected, - SignalErrorCodeRegistrationCredentialsCouldNotBeParsed, - SignalErrorCodeRegistrationDeviceTransferPossible, - SignalErrorCodeRegistrationRecoveryVerificationFailed, - SignalErrorCodeRegistrationLock, + SignalErrorCodeRegistrationRequestNotValid = 191, + SignalErrorCodeRegistrationUnknown = 192, + SignalErrorCodeRegistrationSessionNotFound = 193, + SignalErrorCodeRegistrationNotReadyForVerification = 194, + SignalErrorCodeRegistrationSendVerificationCodeFailed = 195, + SignalErrorCodeRegistrationCodeNotDeliverable = 196, + SignalErrorCodeRegistrationSessionUpdateRejected = 197, + SignalErrorCodeRegistrationCredentialsCouldNotBeParsed = 198, + SignalErrorCodeRegistrationDeviceTransferPossible = 199, + SignalErrorCodeRegistrationRecoveryVerificationFailed = 200, + SignalErrorCodeRegistrationLock = 201, + SignalErrorCodeKeyTransparencyError = 210, + SignalErrorCodeKeyTransparencyVerificationFailed = 211, } SignalErrorCode; enum SignalSvr2CredentialsResult { @@ -952,6 +954,30 @@ typedef struct { SignalLogFlushCallback flush; } SignalFfiLogger; +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseOwnedBufferOfc_uchar; + +typedef struct { + const SignalUnauthenticatedChatConnection *raw; +} SignalConstPointerUnauthenticatedChatConnection; + +typedef struct { + bool present; + SignalBorrowedBuffer value; +} SignalOptionalBorrowedSliceOfc_uchar; + typedef SignalKeyPair SignalKyberKeyPair; typedef struct { @@ -1293,10 +1319,6 @@ typedef struct { SignalCancellationId cancellation_id; } SignalCPromiseMutPointerUnauthenticatedChatConnection; -typedef struct { - const SignalUnauthenticatedChatConnection *raw; -} SignalConstPointerUnauthenticatedChatConnection; - typedef struct { SignalValidatingMac *raw; } SignalMutPointerValidatingMac; @@ -1733,6 +1755,18 @@ SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutP bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); +SignalFfiError *signal_key_transparency_aci_search_key(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *aci); + +SignalFfiError *signal_key_transparency_distinguished(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head); + +SignalFfiError *signal_key_transparency_e164_search_key(SignalOwnedBuffer *out, const char *e164); + +SignalFfiError *signal_key_transparency_monitor(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head); + +SignalFfiError *signal_key_transparency_search(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head); + +SignalFfiError *signal_key_transparency_username_hash_search_key(SignalOwnedBuffer *out, SignalBorrowedBuffer hash); + SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj); SignalFfiError *signal_kyber_key_pair_destroy(SignalMutPointerKyberKeyPair p); @@ -1881,7 +1915,7 @@ SignalFfiError *signal_pre_key_bundle_get_device_id(uint32_t *out, SignalConstPo SignalFfiError *signal_pre_key_bundle_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle p); -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle bundle); SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalMutPointerKyberPublicKey *out, SignalConstPointerPreKeyBundle bundle); @@ -2079,6 +2113,8 @@ SignalFfiError *signal_registration_service_request_push_challenge(SignalCPromis SignalFfiError *signal_registration_service_request_verification_code(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *transport, const char *client, SignalBorrowedBytestringArray languages); +SignalFfiError *signal_registration_service_reregister_account(SignalCPromiseMutPointerRegisterAccountResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerFfiConnectChatBridgeStruct connect_chat, const char *number, SignalConstPointerRegisterAccountRequest register_account, SignalConstPointerRegistrationAccountAttributes account_attributes); + SignalFfiError *signal_registration_service_resume_session(SignalCPromiseMutPointerRegistrationService *promise, SignalConstPointerTokioAsyncContext async_runtime, const char *session_id, const char *number, SignalConstPointerFfiConnectChatBridgeStruct connect_chat); SignalFfiError *signal_registration_service_session_id(const char **out, SignalConstPointerRegistrationService service); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 5a7e360..0ea03a5 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.72.1" +const Version = "v0.73.2" From 086e97edac46d78b73428728815f56c1c7c98440 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 3 Jun 2025 20:26:10 +0300 Subject: [PATCH 489/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 402 ++++++++++++------ pkg/signalmeow/protobuf/backuppb/Backup.proto | 20 + pkg/signalmeow/protobuf/update-protos.sh | 4 +- 3 files changed, 298 insertions(+), 128 deletions(-) diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index cce9b50..dc65ac7 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -4595,6 +4595,7 @@ type FilePointer struct { // *FilePointer_BackupLocator_ // *FilePointer_AttachmentLocator_ // *FilePointer_InvalidAttachmentLocator_ + // *FilePointer_LocalLocator_ Locator isFilePointer_Locator `protobuf_oneof:"locator"` ContentType *string `protobuf:"bytes,4,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` IncrementalMac []byte `protobuf:"bytes,5,opt,name=incrementalMac,proto3,oneof" json:"incrementalMac,omitempty"` @@ -4672,6 +4673,15 @@ func (x *FilePointer) GetInvalidAttachmentLocator() *FilePointer_InvalidAttachme return nil } +func (x *FilePointer) GetLocalLocator() *FilePointer_LocalLocator { + if x != nil { + if x, ok := x.Locator.(*FilePointer_LocalLocator_); ok { + return x.LocalLocator + } + } + return nil +} + func (x *FilePointer) GetContentType() string { if x != nil && x.ContentType != nil { return *x.ContentType @@ -4744,12 +4754,18 @@ type FilePointer_InvalidAttachmentLocator_ struct { InvalidAttachmentLocator *FilePointer_InvalidAttachmentLocator `protobuf:"bytes,3,opt,name=invalidAttachmentLocator,proto3,oneof"` } +type FilePointer_LocalLocator_ struct { + LocalLocator *FilePointer_LocalLocator `protobuf:"bytes,12,opt,name=localLocator,proto3,oneof"` +} + func (*FilePointer_BackupLocator_) isFilePointer_Locator() {} func (*FilePointer_AttachmentLocator_) isFilePointer_Locator() {} func (*FilePointer_InvalidAttachmentLocator_) isFilePointer_Locator() {} +func (*FilePointer_LocalLocator_) isFilePointer_Locator() {} + type Quote struct { state protoimpl.MessageState `protogen:"open.v1"` TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp,proto3,oneof" json:"targetSentTimestamp,omitempty"` // null if the target message could not be found at time of quote insert @@ -7643,6 +7659,7 @@ type NotificationProfile struct { ScheduleStartTime uint32 `protobuf:"varint,9,opt,name=scheduleStartTime,proto3" json:"scheduleStartTime,omitempty"` // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) ScheduleEndTime uint32 `protobuf:"varint,10,opt,name=scheduleEndTime,proto3" json:"scheduleEndTime,omitempty"` // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) ScheduleDaysEnabled []NotificationProfile_DayOfWeek `protobuf:"varint,11,rep,packed,name=scheduleDaysEnabled,proto3,enum=signal.backup.NotificationProfile_DayOfWeek" json:"scheduleDaysEnabled,omitempty"` + Id []byte `protobuf:"bytes,12,opt,name=id,proto3" json:"id,omitempty"` // should be 16 bytes unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -7754,6 +7771,13 @@ func (x *NotificationProfile) GetScheduleDaysEnabled() []NotificationProfile_Day return nil } +func (x *NotificationProfile) GetId() []byte { + if x != nil { + return x.Id + } + return nil +} + type ChatFolder struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -10245,6 +10269,113 @@ func (*FilePointer_InvalidAttachmentLocator) Descriptor() ([]byte, []int) { return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 2} } +// References attachments in a local encrypted backup. +// Importers should first attempt to read the file from the local backup, +// and on failure fallback to backup and transit cdn if possible. +type FilePointer_LocalLocator struct { + state protoimpl.MessageState `protogen:"open.v1"` + MediaName string `protobuf:"bytes,1,opt,name=mediaName,proto3" json:"mediaName,omitempty"` + // Separate key used to encrypt this file for the local backup. + // Generally required. Missing field indicates attachment was not + // available locally when the backup was generated, but remote + // backup or transit info was available. + LocalKey []byte `protobuf:"bytes,2,opt,name=localKey,proto3,oneof" json:"localKey,omitempty"` + RemoteKey []byte `protobuf:"bytes,3,opt,name=remoteKey,proto3" json:"remoteKey,omitempty"` + RemoteDigest []byte `protobuf:"bytes,4,opt,name=remoteDigest,proto3" json:"remoteDigest,omitempty"` + Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` + BackupCdnNumber *uint32 `protobuf:"varint,6,opt,name=backupCdnNumber,proto3,oneof" json:"backupCdnNumber,omitempty"` + TransitCdnKey *string `protobuf:"bytes,7,opt,name=transitCdnKey,proto3,oneof" json:"transitCdnKey,omitempty"` + TransitCdnNumber *uint32 `protobuf:"varint,8,opt,name=transitCdnNumber,proto3,oneof" json:"transitCdnNumber,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilePointer_LocalLocator) Reset() { + *x = FilePointer_LocalLocator{} + mi := &file_backuppb_Backup_proto_msgTypes[116] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilePointer_LocalLocator) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilePointer_LocalLocator) ProtoMessage() {} + +func (x *FilePointer_LocalLocator) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[116] + 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 FilePointer_LocalLocator.ProtoReflect.Descriptor instead. +func (*FilePointer_LocalLocator) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 3} +} + +func (x *FilePointer_LocalLocator) GetMediaName() string { + if x != nil { + return x.MediaName + } + return "" +} + +func (x *FilePointer_LocalLocator) GetLocalKey() []byte { + if x != nil { + return x.LocalKey + } + return nil +} + +func (x *FilePointer_LocalLocator) GetRemoteKey() []byte { + if x != nil { + return x.RemoteKey + } + return nil +} + +func (x *FilePointer_LocalLocator) GetRemoteDigest() []byte { + if x != nil { + return x.RemoteDigest + } + return nil +} + +func (x *FilePointer_LocalLocator) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *FilePointer_LocalLocator) GetBackupCdnNumber() uint32 { + if x != nil && x.BackupCdnNumber != nil { + return *x.BackupCdnNumber + } + return 0 +} + +func (x *FilePointer_LocalLocator) GetTransitCdnKey() string { + if x != nil && x.TransitCdnKey != nil { + return *x.TransitCdnKey + } + return "" +} + +func (x *FilePointer_LocalLocator) GetTransitCdnNumber() uint32 { + if x != nil && x.TransitCdnNumber != nil { + return *x.TransitCdnNumber + } + return 0 +} + type Quote_QuotedAttachment struct { state protoimpl.MessageState `protogen:"open.v1"` ContentType *string `protobuf:"bytes,1,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` @@ -10256,7 +10387,7 @@ type Quote_QuotedAttachment struct { func (x *Quote_QuotedAttachment) Reset() { *x = Quote_QuotedAttachment{} - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10268,7 +10399,7 @@ func (x *Quote_QuotedAttachment) String() string { func (*Quote_QuotedAttachment) ProtoMessage() {} func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10352,7 +10483,7 @@ type GroupChangeChatUpdate_Update struct { func (x *GroupChangeChatUpdate_Update) Reset() { *x = GroupChangeChatUpdate_Update{} - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10364,7 +10495,7 @@ func (x *GroupChangeChatUpdate_Update) String() string { func (*GroupChangeChatUpdate_Update) ProtoMessage() {} func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10938,7 +11069,7 @@ type GroupInvitationRevokedUpdate_Invitee struct { func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { *x = GroupInvitationRevokedUpdate_Invitee{} - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10950,7 +11081,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) String() string { func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10998,7 +11129,7 @@ type ChatStyle_Gradient struct { func (x *ChatStyle_Gradient) Reset() { *x = ChatStyle_Gradient{} - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11010,7 +11141,7 @@ func (x *ChatStyle_Gradient) String() string { func (*ChatStyle_Gradient) ProtoMessage() {} func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11063,7 +11194,7 @@ type ChatStyle_CustomChatColor struct { func (x *ChatStyle_CustomChatColor) Reset() { *x = ChatStyle_CustomChatColor{} - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11075,7 +11206,7 @@ func (x *ChatStyle_CustomChatColor) String() string { func (*ChatStyle_CustomChatColor) ProtoMessage() {} func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11147,7 +11278,7 @@ type ChatStyle_AutomaticBubbleColor struct { func (x *ChatStyle_AutomaticBubbleColor) Reset() { *x = ChatStyle_AutomaticBubbleColor{} - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11159,7 +11290,7 @@ func (x *ChatStyle_AutomaticBubbleColor) String() string { func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11698,11 +11829,12 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "BORDERLESS\x10\x02\x12\a\n" + "\x03GIF\x10\x03B\r\n" + - "\v_clientUuid\"\xec\t\n" + + "\v_clientUuid\"\xb4\r\n" + "\vFilePointer\x12P\n" + "\rbackupLocator\x18\x01 \x01(\v2(.signal.backup.FilePointer.BackupLocatorH\x00R\rbackupLocator\x12\\\n" + "\x11attachmentLocator\x18\x02 \x01(\v2,.signal.backup.FilePointer.AttachmentLocatorH\x00R\x11attachmentLocator\x12q\n" + - "\x18invalidAttachmentLocator\x18\x03 \x01(\v23.signal.backup.FilePointer.InvalidAttachmentLocatorH\x00R\x18invalidAttachmentLocator\x12%\n" + + "\x18invalidAttachmentLocator\x18\x03 \x01(\v23.signal.backup.FilePointer.InvalidAttachmentLocatorH\x00R\x18invalidAttachmentLocator\x12M\n" + + "\flocalLocator\x18\f \x01(\v2'.signal.backup.FilePointer.LocalLocatorH\x00R\flocalLocator\x12%\n" + "\vcontentType\x18\x04 \x01(\tH\x01R\vcontentType\x88\x01\x01\x12+\n" + "\x0eincrementalMac\x18\x05 \x01(\fH\x02R\x0eincrementalMac\x88\x01\x01\x12=\n" + "\x17incrementalMacChunkSize\x18\x06 \x01(\rH\x03R\x17incrementalMacChunkSize\x88\x01\x01\x12\x1f\n" + @@ -11732,7 +11864,20 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x06digest\x18\x05 \x01(\fR\x06digest\x12\x12\n" + "\x04size\x18\x06 \x01(\rR\x04sizeB\x12\n" + "\x10_uploadTimestamp\x1a\x1a\n" + - "\x18InvalidAttachmentLocatorB\t\n" + + "\x18InvalidAttachmentLocator\x1a\xf6\x02\n" + + "\fLocalLocator\x12\x1c\n" + + "\tmediaName\x18\x01 \x01(\tR\tmediaName\x12\x1f\n" + + "\blocalKey\x18\x02 \x01(\fH\x00R\blocalKey\x88\x01\x01\x12\x1c\n" + + "\tremoteKey\x18\x03 \x01(\fR\tremoteKey\x12\"\n" + + "\fremoteDigest\x18\x04 \x01(\fR\fremoteDigest\x12\x12\n" + + "\x04size\x18\x05 \x01(\rR\x04size\x12-\n" + + "\x0fbackupCdnNumber\x18\x06 \x01(\rH\x01R\x0fbackupCdnNumber\x88\x01\x01\x12)\n" + + "\rtransitCdnKey\x18\a \x01(\tH\x02R\rtransitCdnKey\x88\x01\x01\x12/\n" + + "\x10transitCdnNumber\x18\b \x01(\rH\x03R\x10transitCdnNumber\x88\x01\x01B\v\n" + + "\t_localKeyB\x12\n" + + "\x10_backupCdnNumberB\x10\n" + + "\x0e_transitCdnKeyB\x13\n" + + "\x11_transitCdnNumberB\t\n" + "\alocatorB\x0e\n" + "\f_contentTypeB\x11\n" + "\x0f_incrementalMacB\x1a\n" + @@ -12178,7 +12323,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\fGRADIENT_SEA\x10\x15\x12\x16\n" + "\x12GRADIENT_TANGERINE\x10\x16B\v\n" + "\twallpaperB\r\n" + - "\vbubbleColor\"\xd8\x04\n" + + "\vbubbleColor\"\xe8\x04\n" + "\x13NotificationProfile\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x19\n" + "\x05emoji\x18\x02 \x01(\tH\x00R\x05emoji\x88\x01\x01\x12\x14\n" + @@ -12191,7 +12336,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x11scheduleStartTime\x18\t \x01(\rR\x11scheduleStartTime\x12(\n" + "\x0fscheduleEndTime\x18\n" + " \x01(\rR\x0fscheduleEndTime\x12^\n" + - "\x13scheduleDaysEnabled\x18\v \x03(\x0e2,.signal.backup.NotificationProfile.DayOfWeekR\x13scheduleDaysEnabled\"t\n" + + "\x13scheduleDaysEnabled\x18\v \x03(\x0e2,.signal.backup.NotificationProfile.DayOfWeekR\x13scheduleDaysEnabled\x12\x0e\n" + + "\x02id\x18\f \x01(\fR\x02id\"t\n" + "\tDayOfWeek\x12\v\n" + "\aUNKNOWN\x10\x00\x12\n" + "\n" + @@ -12260,7 +12406,7 @@ func file_backuppb_Backup_proto_rawDescGZIP() []byte { } var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 31) -var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 122) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 123) var file_backuppb_Backup_proto_goTypes = []any{ (AvatarColor)(0), // 0: signal.backup.AvatarColor (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel @@ -12409,12 +12555,13 @@ var file_backuppb_Backup_proto_goTypes = []any{ (*FilePointer_BackupLocator)(nil), // 144: signal.backup.FilePointer.BackupLocator (*FilePointer_AttachmentLocator)(nil), // 145: signal.backup.FilePointer.AttachmentLocator (*FilePointer_InvalidAttachmentLocator)(nil), // 146: signal.backup.FilePointer.InvalidAttachmentLocator - (*Quote_QuotedAttachment)(nil), // 147: signal.backup.Quote.QuotedAttachment - (*GroupChangeChatUpdate_Update)(nil), // 148: signal.backup.GroupChangeChatUpdate.Update - (*GroupInvitationRevokedUpdate_Invitee)(nil), // 149: signal.backup.GroupInvitationRevokedUpdate.Invitee - (*ChatStyle_Gradient)(nil), // 150: signal.backup.ChatStyle.Gradient - (*ChatStyle_CustomChatColor)(nil), // 151: signal.backup.ChatStyle.CustomChatColor - (*ChatStyle_AutomaticBubbleColor)(nil), // 152: signal.backup.ChatStyle.AutomaticBubbleColor + (*FilePointer_LocalLocator)(nil), // 147: signal.backup.FilePointer.LocalLocator + (*Quote_QuotedAttachment)(nil), // 148: signal.backup.Quote.QuotedAttachment + (*GroupChangeChatUpdate_Update)(nil), // 149: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 150: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 151: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 152: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 153: signal.backup.ChatStyle.AutomaticBubbleColor } var file_backuppb_Backup_proto_depIdxs = []int32{ 33, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData @@ -12499,104 +12646,105 @@ var file_backuppb_Backup_proto_depIdxs = []int32{ 144, // 79: signal.backup.FilePointer.backupLocator:type_name -> signal.backup.FilePointer.BackupLocator 145, // 80: signal.backup.FilePointer.attachmentLocator:type_name -> signal.backup.FilePointer.AttachmentLocator 146, // 81: signal.backup.FilePointer.invalidAttachmentLocator:type_name -> signal.backup.FilePointer.InvalidAttachmentLocator - 46, // 82: signal.backup.Quote.text:type_name -> signal.backup.Text - 147, // 83: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 20, // 84: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 21, // 85: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 66, // 86: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 72, // 87: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 67, // 88: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 68, // 89: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 70, // 90: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 71, // 91: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 64, // 92: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 65, // 93: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 69, // 94: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 22, // 95: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 23, // 96: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 24, // 97: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 25, // 98: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 26, // 99: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 148, // 100: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 1, // 101: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 1, // 102: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 149, // 103: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 27, // 104: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 59, // 105: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 152, // 106: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 28, // 107: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 29, // 108: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 30, // 109: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 3, // 110: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 2, // 111: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 108, // 112: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 151, // 113: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 119, // 114: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 115: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 116: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 124, // 117: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 120, // 118: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 121, // 119: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 122, // 120: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 123, // 121: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 7, // 122: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 120, // 123: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 8, // 124: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 125: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 126: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 45, // 127: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 12, // 128: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 46, // 129: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 59, // 130: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 139, // 131: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 138, // 132: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 13, // 133: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 14, // 134: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 137, // 135: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 16, // 136: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 17, // 137: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 18, // 138: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 58, // 139: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 73, // 140: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 74, // 141: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 75, // 142: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 76, // 143: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 77, // 144: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 78, // 145: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 79, // 146: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 80, // 147: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 81, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 82, // 149: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 83, // 150: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 84, // 151: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 85, // 152: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 86, // 153: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 87, // 154: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 88, // 155: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 89, // 156: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 90, // 157: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 91, // 158: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 92, // 159: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 93, // 160: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 94, // 161: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 95, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 97, // 163: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 98, // 164: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 99, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 100, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 101, // 167: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 102, // 168: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 103, // 169: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 104, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 105, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 96, // 172: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 106, // 173: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 150, // 174: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 175, // [175:175] is the sub-list for method output_type - 175, // [175:175] is the sub-list for method input_type - 175, // [175:175] is the sub-list for extension type_name - 175, // [175:175] is the sub-list for extension extendee - 0, // [0:175] is the sub-list for field type_name + 147, // 82: signal.backup.FilePointer.localLocator:type_name -> signal.backup.FilePointer.LocalLocator + 46, // 83: signal.backup.Quote.text:type_name -> signal.backup.Text + 148, // 84: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 20, // 85: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 21, // 86: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 66, // 87: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 72, // 88: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 67, // 89: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 68, // 90: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 70, // 91: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 71, // 92: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 64, // 93: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 65, // 94: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 69, // 95: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 22, // 96: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 23, // 97: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 24, // 98: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 25, // 99: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 26, // 100: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 149, // 101: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 102: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 103: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 150, // 104: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 27, // 105: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 59, // 106: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 153, // 107: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 28, // 108: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 29, // 109: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 30, // 110: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 3, // 111: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 2, // 112: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 108, // 113: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 152, // 114: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 119, // 115: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 116: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 117: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 124, // 118: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 120, // 119: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 121, // 120: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 122, // 121: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 123, // 122: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 7, // 123: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 120, // 124: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 8, // 125: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 126: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 127: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 45, // 128: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 12, // 129: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 46, // 130: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 59, // 131: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 139, // 132: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 138, // 133: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 13, // 134: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 14, // 135: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 137, // 136: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 16, // 137: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 17, // 138: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 18, // 139: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 58, // 140: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 73, // 141: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 74, // 142: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 75, // 143: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 76, // 144: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 77, // 145: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 78, // 146: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 79, // 147: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 80, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 81, // 149: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 82, // 150: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 83, // 151: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 84, // 152: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 85, // 153: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 86, // 154: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 87, // 155: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 88, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 89, // 157: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 90, // 158: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 91, // 159: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 92, // 160: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 93, // 161: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 94, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 95, // 163: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 97, // 164: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 98, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 99, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 100, // 167: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 101, // 168: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 102, // 169: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 103, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 104, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 105, // 172: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 96, // 173: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 106, // 174: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 151, // 175: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 176, // [176:176] is the sub-list for method output_type + 176, // [176:176] is the sub-list for method input_type + 176, // [176:176] is the sub-list for extension type_name + 176, // [176:176] is the sub-list for extension extendee + 0, // [0:176] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -12672,6 +12820,7 @@ func file_backuppb_Backup_proto_init() { (*FilePointer_BackupLocator_)(nil), (*FilePointer_AttachmentLocator_)(nil), (*FilePointer_InvalidAttachmentLocator_)(nil), + (*FilePointer_LocalLocator_)(nil), } file_backuppb_Backup_proto_msgTypes[29].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[30].OneofWrappers = []any{ @@ -12746,7 +12895,8 @@ func file_backuppb_Backup_proto_init() { file_backuppb_Backup_proto_msgTypes[113].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{ (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), @@ -12782,8 +12932,8 @@ func file_backuppb_Backup_proto_init() { (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), } - file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[121].OneofWrappers = []any{ (*ChatStyle_CustomChatColor_Solid)(nil), (*ChatStyle_CustomChatColor_Gradient)(nil), } @@ -12793,7 +12943,7 @@ func file_backuppb_Backup_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), NumEnums: 31, - NumMessages: 122, + NumMessages: 123, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 9fe2079..3840f93 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -724,11 +724,30 @@ message FilePointer { message InvalidAttachmentLocator { } + // References attachments in a local encrypted backup. + // Importers should first attempt to read the file from the local backup, + // and on failure fallback to backup and transit cdn if possible. + message LocalLocator { + string mediaName = 1; + // Separate key used to encrypt this file for the local backup. + // Generally required. Missing field indicates attachment was not + // available locally when the backup was generated, but remote + // backup or transit info was available. + optional bytes localKey = 2; + bytes remoteKey = 3; + bytes remoteDigest = 4; + uint32 size = 5; + optional uint32 backupCdnNumber = 6; + optional string transitCdnKey = 7; + optional uint32 transitCdnNumber = 8; + } + // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. oneof locator { BackupLocator backupLocator = 1; AttachmentLocator attachmentLocator = 2; InvalidAttachmentLocator invalidAttachmentLocator = 3; + LocalLocator localLocator = 12; } optional string contentType = 4; @@ -1291,6 +1310,7 @@ message NotificationProfile { uint32 scheduleStartTime = 9; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) uint32 scheduleEndTime = 10; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) repeated DayOfWeek scheduleDaysEnabled = 11; + bytes id = 12; // should be 16 bytes } message ChatFolder { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 1dd2e40..c95420d 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-68058264729cb237bd8523df404d9455cb3f622f} -DESKTOP_GIT_REVISION=${1:-c861161f22e553ecb81982bc2c7b7d495ee42fcc} +ANDROID_GIT_REVISION=${1:-23669c3c372284d42db486a218d9f29bef247abf} +DESKTOP_GIT_REVISION=${1:-010c38ae9bce84c676a9c464a04f7c26e7a2c9e0} update_proto() { case "$1" in From f029bbbef03333bf6a96ada1afe00c7c80186ef0 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Tue, 3 Jun 2025 15:23:44 +0100 Subject: [PATCH 490/718] signalmeow: expose way to fetch profile with custom refresh interval --- pkg/connector/chatinfo.go | 10 ++++++++-- pkg/signalmeow/contact.go | 13 +++++++++---- pkg/signalmeow/profile.go | 10 ++++++---- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 6fff853..1937318 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -22,6 +22,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/google/uuid" "github.com/rs/zerolog" @@ -34,6 +35,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) @@ -41,7 +43,7 @@ import ( const PrivateChatTopic = "Signal private chat" const NoteToSelfName = "Signal Note to Self" -func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { +func (s *SignalClient) GetUserInfoWithRefreshAfter(ctx context.Context, ghost *bridgev2.Ghost, refreshAfter time.Duration) (*bridgev2.UserInfo, error) { userID, err := signalid.ParseUserID(ghost.ID) if err != nil { return nil, err @@ -50,7 +52,7 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( // Don't do unnecessary fetches in background mode return nil, nil } - contact, err := s.Client.ContactByACI(ctx, userID) + contact, err := s.Client.ContactByACIWithRefreshAfter(ctx, userID, refreshAfter) if err != nil { return nil, err } @@ -61,6 +63,10 @@ func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) ( return s.contactToUserInfo(ctx, contact) } +func (s *SignalClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { + return s.GetUserInfoWithRefreshAfter(ctx, ghost, signalmeow.DefaultProfileRefreshAfter) +} + func (s *SignalClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { userID, groupID, err := signalid.ParsePortalID(portal.ID) if err != nil { diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index 9e7eec2..8407b74 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -25,6 +25,7 @@ import ( "fmt" "net/http" "strings" + "time" "github.com/google/uuid" "github.com/rs/zerolog" @@ -71,14 +72,14 @@ func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDeta }) } -func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, aci uuid.UUID) (*types.Recipient, error) { +func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, aci uuid.UUID, refreshAfter time.Duration) (*types.Recipient, error) { log := zerolog.Ctx(ctx).With(). Str("action", "fetch contact then try and update with profile"). Stringer("profile_aci", aci). Logger() ctx = log.WithContext(ctx) - profile, err := cli.RetrieveProfileByID(ctx, aci) + profile, err := cli.RetrieveProfileByID(ctx, aci, refreshAfter) if err != nil { log.Debug().Err(err).Msg("Failed to fetch profile") // Continue to return contact without profile @@ -96,7 +97,11 @@ func (cli *Client) fetchContactThenTryAndUpdateWithProfile(ctx context.Context, } func (cli *Client) ContactByACI(ctx context.Context, aci uuid.UUID) (*types.Recipient, error) { - return cli.fetchContactThenTryAndUpdateWithProfile(ctx, aci) + return cli.fetchContactThenTryAndUpdateWithProfile(ctx, aci, DefaultProfileRefreshAfter) +} + +func (cli *Client) ContactByACIWithRefreshAfter(ctx context.Context, aci uuid.UUID, refreshAfter time.Duration) (*types.Recipient, error) { + return cli.fetchContactThenTryAndUpdateWithProfile(ctx, aci, refreshAfter) } func (cli *Client) ContactByE164(ctx context.Context, e164 string) (*types.Recipient, error) { @@ -109,7 +114,7 @@ func (cli *Client) ContactByE164(ctx context.Context, e164 string) (*types.Recip return nil, nil } if contact.ACI != uuid.Nil { - contact, err = cli.fetchContactThenTryAndUpdateWithProfile(ctx, contact.ACI) + contact, err = cli.fetchContactThenTryAndUpdateWithProfile(ctx, contact.ACI, DefaultProfileRefreshAfter) } return contact, err } diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index bbd31f3..3aa88ff 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -41,6 +41,8 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) +const DefaultProfileRefreshAfter = 1 * time.Hour + type Capabilities struct { SenderKey bool `json:"senderKey"` AnnouncementGroup bool `json:"announcementGroup"` @@ -114,11 +116,11 @@ func (cli *Client) ProfileKeyForSignalID(ctx context.Context, signalACI uuid.UUI var errProfileKeyNotFound = errors.New("profile key not found") -func (cli *Client) getCachedProfileByID(signalID uuid.UUID) (*types.Profile, error) { +func (cli *Client) getCachedProfileByID(signalID uuid.UUID, refreshAfter time.Duration) (*types.Profile, error) { cli.ProfileCache.lock.RLock() defer cli.ProfileCache.lock.RUnlock() lastFetched, ok := cli.ProfileCache.lastFetched[signalID.String()] - if ok && time.Since(lastFetched) < 1*time.Hour { + if ok && time.Since(lastFetched) < refreshAfter { profile, ok := cli.ProfileCache.profiles[signalID.String()] if ok { return profile, nil @@ -131,7 +133,7 @@ func (cli *Client) getCachedProfileByID(signalID uuid.UUID) (*types.Profile, err return nil, nil } -func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) (*types.Profile, error) { +func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID, refreshAfter time.Duration) (*types.Profile, error) { if cli.ProfileCache == nil { cli.ProfileCache = &ProfileCache{ profiles: make(map[string]*types.Profile), @@ -142,7 +144,7 @@ func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID) // Check if we have a cached profile that is less than an hour old // or if we have a cached error that is less than an hour old - profile, err := cli.getCachedProfileByID(signalID) + profile, err := cli.getCachedProfileByID(signalID, refreshAfter) if err != nil || profile != nil { return profile, err } From cca55180cf4bed1ce9819bb137e1a5d8aa79bbe5 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Tue, 3 Jun 2025 15:23:52 +0100 Subject: [PATCH 491/718] client: immediately sync DM ghosts when viewed --- pkg/connector/client.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 7a4d003..5a0b740 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -56,6 +56,7 @@ var ( _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) ) var pushCfg = &bridgev2.PushConfig{ @@ -338,3 +339,36 @@ func (s *SignalClient) IsLoggedIn() bool { } return s.Client.IsLoggedIn() } + +func (s *SignalClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { + if msg.Portal == nil || msg.Portal.OtherUserID == "" { + // Group chat changes are sent by Signal so no need to fetch them on view + return nil + } + + // Sync other user ghost info in DM rooms + ghost, err := s.Main.Bridge.GetExistingGhostByID(ctx, msg.Portal.OtherUserID) + if err != nil { + return fmt.Errorf("failed to get ghost for sync: %w", err) + } else if ghost == nil { + zerolog.Ctx(ctx).Warn(). + Str("other_user_id", string(msg.Portal.OtherUserID)). + Msg("No ghost found for other user in portal") + return nil + } + + meta := ghost.Metadata.(*signalid.GhostMetadata) + if meta.ProfileFetchedAt.Time.Add(5 * time.Minute).After(time.Now()) { + // Limit profile fetches to max one per 5 minutes + return nil + } + + // Reset, but don't save, portal last sync time for immediate sync now + meta.ProfileFetchedAt.Time = time.Time{} + info, err := s.GetUserInfoWithRefreshAfter(ctx, ghost, 5*time.Minute) + if err != nil { + return fmt.Errorf("failed to get user info: %w", err) + } + ghost.UpdateInfo(ctx, info) + return nil +} From 23ae2e2f7b7e1b1a7893ba7d02ead014a138ae8a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 6 Jun 2025 14:08:48 +0300 Subject: [PATCH 492/718] login: fix invalid return in Start if provision state is error --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/login.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index abd27a4..54ce972 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.1-0.20250531150347-788621f7e035 + maunium.net/go/mautrix v0.24.1-0.20250606110819-d296f7b6604b ) require ( diff --git a/go.sum b/go.sum index 6257f3b..5f5fe5f 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.24.1-0.20250531150347-788621f7e035 h1:jGg4WFHZhtnr7Lo6Y0RVPaxmHiPNLHhfcf8lrCz+pXY= -maunium.net/go/mautrix v0.24.1-0.20250531150347-788621f7e035/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= +maunium.net/go/mautrix v0.24.1-0.20250606110819-d296f7b6604b h1:coJOie9e6rdLBP8Ky9PjauvARytLvbue2pvdzEJssPM= +maunium.net/go/mautrix v0.24.1-0.20250606110819-d296f7b6604b/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 15a48c3..1805be8 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -86,7 +86,7 @@ func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { var resp signalmeow.ProvisioningResponse select { case resp = <-qr.ProvChan: - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + if resp.Err != nil { return nil, resp.Err } else if resp.State != signalmeow.StateProvisioningURLReceived { return nil, fmt.Errorf("unexpected state %v", resp.State) From b8d7cd4f494642b607224763efcb923045f7ac4f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Jun 2025 21:13:54 +0300 Subject: [PATCH 493/718] signalmeow/receiving: adjust decryption logs --- pkg/signalmeow/receiving.go | 20 ++++++++++++-------- pkg/signalmeow/receiving_decrypt.go | 2 +- pkg/signalmeow/web/signalwebsocket.go | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index b24d167..aea9b08 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -330,17 +330,20 @@ func (cli *Client) incomingRequestHandler(ctx context.Context, req *signalpb.Web } func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.WebSocketRequestMessage) (*web.SimpleResponse, error) { - log := zerolog.Ctx(ctx) + log := *zerolog.Ctx(ctx) envelope := &signalpb.Envelope{} err := proto.Unmarshal(req.Body, envelope) if err != nil { log.Err(err).Msg("Unmarshal error") return nil, err } - destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) - log.Trace(). - Uint64("timestamp", envelope.GetTimestamp()). + log = log.With(). + Uint64("envelope_timestamp", envelope.GetTimestamp()). Uint64("server_timestamp", envelope.GetServerTimestamp()). + Logger() + ctx = log.WithContext(ctx) + destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) + log.Debug(). Str("destination_service_id", envelope.GetDestinationServiceId()). Str("source_service_id", envelope.GetSourceServiceId()). Uint32("source_device_id", envelope.GetSourceDevice()). @@ -456,10 +459,11 @@ func (cli *Client) handleDecryptedResult( Logger() log = &newLog ctx = log.WithContext(ctx) - log.Debug(). - Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). - Msg("Decrypted message") + logEvt := log.Debug() + if result.CiphertextHash != nil { + logEvt = logEvt.Hex("ciphertext_hash", result.CiphertextHash[:]) + } + logEvt.Msg("Decrypted message") // If there's a sender key distribution message, process it if content.GetSenderKeyDistributionMessage() != nil { diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 7d85c43..1ffceb0 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -137,7 +137,7 @@ func (cli *Client) bufferedDecryptTxn(ctx context.Context, ciphertext []byte, se if innerErr != nil { innerErr = fmt.Errorf("failed to save decrypted event to buffer: %w", innerErr) } - zerolog.Ctx(ctx).Debug(). + zerolog.Ctx(ctx).Trace(). Hex("ciphertext_hash", ciphertextHash[:]). Msg("Successfully decrypted and saved event") return diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 16a7463..c4030d6 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -429,7 +429,7 @@ func readLoop( if msg.Request == nil { return errors.New("received request message with no request") } - log.Debug(). + log.Trace(). Uint64("request_id", *msg.Request.Id). Str("request_verb", *msg.Request.Verb). Str("request_path", *msg.Request.Path). From b39a9c4fd207a248a8ca508bd0ebd0d79c7151fa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 11 Jun 2025 15:34:59 +0300 Subject: [PATCH 494/718] login: fix more invalid returns --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/login.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 54ce972..69eaa73 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.1-0.20250606110819-d296f7b6604b + maunium.net/go/mautrix v0.24.1-0.20250611123434-15d0b63eb6ab ) require ( diff --git a/go.sum b/go.sum index 5f5fe5f..cec7d6d 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.24.1-0.20250606110819-d296f7b6604b h1:coJOie9e6rdLBP8Ky9PjauvARytLvbue2pvdzEJssPM= -maunium.net/go/mautrix v0.24.1-0.20250606110819-d296f7b6604b/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= +maunium.net/go/mautrix v0.24.1-0.20250611123434-15d0b63eb6ab h1:2oysPkLLkQkLhtH29C+hOXFxRU486dLQCmngTFw7oAA= +maunium.net/go/mautrix v0.24.1-0.20250611123434-15d0b63eb6ab/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 1805be8..12d548d 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -122,7 +122,7 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { select { case resp := <-qr.ProvChan: - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + if resp.Err != nil { qr.cancelChan() return nil, resp.Err } else if resp.State != signalmeow.StateProvisioningDataReceived { @@ -164,7 +164,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err select { case resp := <-qr.ProvChan: - if resp.Err != nil || resp.State == signalmeow.StateProvisioningError { + if resp.Err != nil { return nil, resp.Err } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { return nil, fmt.Errorf("unexpected state %v", resp.State) From 483bc4b8f2c08f9387f8900ed3ba798bde7dd95d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 11 Jun 2025 16:33:33 +0300 Subject: [PATCH 495/718] libsignal: update to v0.74.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 12 ++++++------ pkg/libsignalgo/prekey.go | 1 + pkg/libsignalgo/prekeybundle.go | 1 + pkg/libsignalgo/version.go | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index f8bcdb0..fd34ab3 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit f8bcdb016abb9edb3b8d92851636208f3aa4c238 +Subproject commit fd34ab35ce21d1133ff254a44a7060a3ef72cf1b diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 6c17995..1967ddd 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -25,8 +25,6 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalMEDIA_ENCRYPTION_KEY_LEN (32 + 32) -#define SignalBackupKey_MASTER_KEY_LEN SignalSVR_KEY_LEN - #define SignalBackupId_LEN 16 #define SignalNUM_AUTH_CRED_ATTRIBUTES 3 @@ -1559,7 +1557,7 @@ SignalFfiError *signal_create_otp_from_base64(const char **out, const char *user SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); -SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); +SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store, bool use_pq_ratchet); SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); @@ -1859,11 +1857,13 @@ SignalFfiError *signal_message_get_counter(uint32_t *out, SignalConstPointerSign SignalFfiError *signal_message_get_message_version(uint32_t *out, SignalConstPointerSignalMessage obj); +SignalFfiError *signal_message_get_pq_ratchet(SignalOwnedBuffer *out, SignalConstPointerSignalMessage msg); + SignalFfiError *signal_message_get_sender_ratchet_key(SignalMutPointerPublicKey *out, SignalConstPointerSignalMessage m); SignalFfiError *signal_message_get_serialized(SignalOwnedBuffer *out, SignalConstPointerSignalMessage obj); -SignalFfiError *signal_message_new(SignalMutPointerSignalMessage *out, uint8_t message_version, SignalBorrowedBuffer mac_key, SignalConstPointerPublicKey sender_ratchet_key, uint32_t counter, uint32_t previous_counter, SignalBorrowedBuffer ciphertext, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key); +SignalFfiError *signal_message_new(SignalMutPointerSignalMessage *out, uint8_t message_version, SignalBorrowedBuffer mac_key, SignalConstPointerPublicKey sender_ratchet_key, uint32_t counter, uint32_t previous_counter, SignalBorrowedBuffer ciphertext, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key, SignalBorrowedBuffer pq_ratchet); SignalFfiError *signal_message_verify_mac(bool *out, SignalConstPointerSignalMessage msg, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key, SignalBorrowedBuffer mac_key); @@ -1993,7 +1993,7 @@ SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstP SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); -SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); +SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now, bool use_pq_ratchet); SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); @@ -2447,4 +2447,4 @@ SignalFfiError *signal_validating_mac_update(int32_t *out, SignalMutPointerValid SignalFfiError *signal_webp_sanitizer_sanitize(SignalConstPointerFfiSyncInputStreamStruct input); #endif -#endif /* SIGNAL_FFI_H_ */ +#endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/prekey.go b/pkg/libsignalgo/prekey.go index 4d01f89..7713c76 100644 --- a/pkg/libsignalgo/prekey.go +++ b/pkg/libsignalgo/prekey.go @@ -39,6 +39,7 @@ func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddres callbackCtx.wrapPreKeyStore(preKeyStore), callbackCtx.wrapSignedPreKeyStore(signedPreKeyStore), callbackCtx.wrapKyberPreKeyStore(kyberPreKeyStore), + false, // no pq ratchets yet ) runtime.KeepAlive(preKeyMessage) runtime.KeepAlive(fromAddress) diff --git a/pkg/libsignalgo/prekeybundle.go b/pkg/libsignalgo/prekeybundle.go index 4cd5547..7d8536e 100644 --- a/pkg/libsignalgo/prekeybundle.go +++ b/pkg/libsignalgo/prekeybundle.go @@ -37,6 +37,7 @@ func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress * callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), now, + false, // no pq ratchets yet ) runtime.KeepAlive(bundle) runtime.KeepAlive(forAddress) diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 0ea03a5..d7458b0 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.73.2" +const Version = "v0.74.1" From 17b67552dc3cc091ed18d81e4bd8ea3b918c70e5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 11 Jun 2025 16:36:25 +0300 Subject: [PATCH 496/718] docker: update to Alpine 3.22 --- Dockerfile | 4 ++-- Dockerfile.ci | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index a022666..9c5e495 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ ARG DBG=0 RUN ./build-rust.sh # -- Build mautrix-signal (with Go) -- -FROM golang:1-alpine3.21 AS go-builder +FROM golang:1-alpine3.22 AS go-builder RUN apk add --no-cache git ca-certificates build-base olm-dev WORKDIR /build @@ -39,7 +39,7 @@ EOF RUN ./build-go.sh # -- Run mautrix-signal -- -FROM alpine:3.21 +FROM alpine:3.22 ENV UID=1337 \ GID=1337 diff --git a/Dockerfile.ci b/Dockerfile.ci index 556dfc1..dc554ab 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,4 +1,4 @@ -FROM alpine:3.21 +FROM alpine:3.22 ENV UID=1337 \ GID=1337 From 46e2158a6a46c65d413a5ff6b814a890d369ef38 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Jun 2025 16:06:37 +0300 Subject: [PATCH 497/718] groupinfo: fall back to resyncing group if catchup fails --- pkg/connector/groupinfo.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 0527ecf..dfd4faf 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -419,6 +419,7 @@ func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal groupChanges, err := s.Client.GetGroupHistoryPage(ctx, types.GroupIdentifier(portal.ID), fromRevision, false) if err != nil { log.Err(err).Msg("Failed to get group history page") + s.catchUpGroup(ctx, portal, 0, toRevision, ts) return } for _, gc := range groupChanges { From fa57784c65239e5c2a9a10d953e4bbe85448f5cc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Jun 2025 17:56:17 +0300 Subject: [PATCH 498/718] dependencies: update --- go.mod | 18 +++++++++--------- go.sum | 32 ++++++++++++++++---------------- pkg/signalmeow/groups.go | 1 + 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 69eaa73..5e58f75 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.23.0 -toolchain go1.24.3 +toolchain go1.24.4 require ( github.com/coder/websocket v1.8.13 @@ -13,12 +13,12 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.7 - golang.org/x/crypto v0.38.0 - golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 - golang.org/x/net v0.40.0 + go.mau.fi/util v0.8.8 + golang.org/x/crypto v0.39.0 + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 + golang.org/x/net v0.41.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.1-0.20250611123434-15d0b63eb6ab + maunium.net/go/mautrix v0.24.1 ) require ( @@ -39,11 +39,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.11 // indirect + github.com/yuin/goldmark v1.7.12 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.14.0 // indirect + golang.org/x/sync v0.15.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect + golang.org/x/text v0.26.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index cec7d6d..a23b95e 100644 --- a/go.sum +++ b/go.sum @@ -67,27 +67,27 @@ 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.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo= -github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.8.7 h1:ywKarPxouJQEEijTs4mPlxC7F4AWEKokEpWc+2TYy6c= -go.mau.fi/util v0.8.7/go.mod h1:j6R3cENakc1f8HpQeFl0N15UiSTcNmIfDBNJUbL71RY= +github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= +github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +go.mau.fi/util v0.8.8 h1:OnuEEc/sIJFhnq4kFggiImUpcmnmL/xpvQMRu5Fiy5c= +go.mau.fi/util v0.8.8/go.mod h1:Y/kS3loxTEhy8Vill513EtPXr+CRDdae+Xj2BXXMy/c= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -99,5 +99,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.24.1-0.20250611123434-15d0b63eb6ab h1:2oysPkLLkQkLhtH29C+hOXFxRU486dLQCmngTFw7oAA= -maunium.net/go/mautrix v0.24.1-0.20250611123434-15d0b63eb6ab/go.mod h1:HqA1HUutQYJkrYRPkK64itARDz79PCec1oWVEB72HVQ= +maunium.net/go/mautrix v0.24.1 h1:09/xi4qTeA03g1n/DPmmqAlT8Cx4QrgwiPlmLVzA9AU= +maunium.net/go/mautrix v0.24.1/go.mod h1:Xy6o+pXmbqmgWsUWh15EQ1eozjC+k/VT/7kloByv9PI= diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index f0b0815..35544f7 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -795,6 +795,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp } return cli.decryptGroupChange(ctx, encryptedGroupChange, groupMasterKey, true) } + func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange *signalpb.GroupChange, groupMasterKey types.SerializedGroupMasterKey, verifySignature bool) (*GroupChange, error) { log := zerolog.Ctx(ctx).With().Str("action", "decrypt group change").Logger() serverSignature := encryptedGroupChange.ServerSignature From b690026f42e788615cac3749b3c5fdd233cc7c92 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Jun 2025 18:06:43 +0300 Subject: [PATCH 499/718] Bump version to v0.8.4 --- CHANGELOG.md | 8 ++++++++ cmd/mautrix-signal/main.go | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9da97b..f314ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# v0.8.4 (2025-06-16) + +* Updated libsignal to v0.74.1. +* Updated Docker image to Alpine 3.22. +* Fixed avatars when using direct media. +* Fixed starting chats with non-contact users. +* Fixed Matrix media being rejected if the mime type isn't specified. + # v0.8.3 (2025-05-16) * Updated libsignal to v0.72.1. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 72b91c8..565e9bf 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.3", + Version: "0.8.4", Connector: &connector.SignalConnector{}, } From bb09c6fa0e434f4acdf58d955833f2f2eb321407 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 17 Jun 2025 22:24:34 +0530 Subject: [PATCH 500/718] handlesignal: plumb event handling result to signalmeow (#603) --- go.mod | 2 +- go.sum | 4 +-- pkg/connector/handlesignal.go | 28 ++++++++++++--------- pkg/signalmeow/client.go | 8 +++--- pkg/signalmeow/receiving.go | 46 ++++++++++++++++++++--------------- 5 files changed, 49 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 5e58f75..54e1fd9 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 golang.org/x/net v0.41.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.1 + maunium.net/go/mautrix v0.24.2-0.20250617163829-26da46dbbf6e ) require ( diff --git a/go.sum b/go.sum index a23b95e..b0dbd1c 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.24.1 h1:09/xi4qTeA03g1n/DPmmqAlT8Cx4QrgwiPlmLVzA9AU= -maunium.net/go/mautrix v0.24.1/go.mod h1:Xy6o+pXmbqmgWsUWh15EQ1eozjC+k/VT/7kloByv9PI= +maunium.net/go/mautrix v0.24.2-0.20250617163829-26da46dbbf6e h1:Y8kbRpPcKMZn2gIjUFd15xzMB5GJ2bS6ZcOfvlx4KnE= +maunium.net/go/mautrix v0.24.2-0.20250617163829-26da46dbbf6e/go.mod h1:Xy6o+pXmbqmgWsUWh15EQ1eozjC+k/VT/7kloByv9PI= diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index c2b0139..634c5ca 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -37,18 +37,18 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { +func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) bool { switch evt := rawEvt.(type) { case *events.ChatEvent: - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) + return s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}).Success case *events.DecryptionError: - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapDecryptionError(evt)) + return s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapDecryptionError(evt)).Success case *events.Receipt: - s.handleSignalReceipt(evt) + return s.handleSignalReceipt(evt) case *events.ReadSelf: - s.handleSignalReadSelf(evt) + return s.handleSignalReadSelf(evt) case *events.Call: - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapCallEvent(evt)) + return s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapCallEvent(evt)).Success case *events.ContactList: s.handleSignalContactList(evt) case *events.ACIFound: @@ -58,6 +58,7 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { default: s.UserLogin.Log.Warn().Type("event_type", evt).Msg("Unrecognized signalmeow event type") } + return true } func (s *SignalClient) wrapCallEvent(evt *events.Call) bridgev2.RemoteMessage { @@ -427,17 +428,20 @@ func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func( return receipts } -func (s *SignalClient) dispatchReceipts(sender uuid.UUID, receiptType signalpb.ReceiptMessage_Type, receipts map[networkid.PortalKey]*Bv2Receipt) { +func (s *SignalClient) dispatchReceipts(sender uuid.UUID, receiptType signalpb.ReceiptMessage_Type, receipts map[networkid.PortalKey]*Bv2Receipt) bool { evtSender := s.makeEventSender(sender) for chat, receiptEvt := range receipts { receiptEvt.Chat = chat receiptEvt.Sender = evtSender receiptEvt.Type = receiptType - s.Main.Bridge.QueueRemoteEvent(s.UserLogin, receiptEvt) + if !s.Main.Bridge.QueueRemoteEvent(s.UserLogin, receiptEvt).Success { + return false + } } + return true } -func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { +func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) bool { log := s.UserLogin.Log.With(). Str("action", "handle signal receipt"). Stringer("sender_id", evt.Sender). @@ -447,10 +451,10 @@ func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) { receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, signalid.MakeMessageID(s.Client.Store.ACI, msgTS)) }) - s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) + return s.dispatchReceipts(evt.Sender, evt.Content.GetType(), receipts) } -func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { +func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) bool { log := s.UserLogin.Log.With(). Str("action", "handle signal read self"). Logger() @@ -462,7 +466,7 @@ func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) { } return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, signalid.MakeMessageID(aciUUID, msgInfo.GetTimestamp())) }) - s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) + return s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) } func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index d3ba6b6..42979c1 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -53,7 +53,7 @@ type Client struct { loopCancel context.CancelFunc loopWg sync.WaitGroup - EventHandler func(events.SignalEvent) + EventHandler func(events.SignalEvent) bool storageAuthLock sync.Mutex storageAuth *basicExpiringCredentials @@ -64,10 +64,8 @@ type Client struct { writeCallbackCounter chan time.Time } -func (cli *Client) handleEvent(evt events.SignalEvent) { - if cli.EventHandler != nil { - cli.EventHandler(evt) - } +func (cli *Client) handleEvent(evt events.SignalEvent) bool { + return cli.EventHandler(evt) } func (cli *Client) IsConnected() bool { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index aea9b08..5b9f212 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -376,6 +376,8 @@ func (cli *Client) writeCallback(preWriteTime time.Time) { } } +var ErrHandlerFailed = errors.New("event handler returned non-success status") + // TODO: we should split this up into multiple functions func (cli *Client) handleDecryptedResult( ctx context.Context, @@ -399,6 +401,7 @@ func (cli *Client) handleDecryptedResult( }() } + handlerSuccess := true // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted if result.Err != nil { @@ -434,13 +437,16 @@ func (cli *Client) handleDecryptedResult( if envelope.GetUrgent() && result.ContentHint != signalpb.UnidentifiedSenderMessage_Message_IMPLICIT && !strings.Contains(result.Err.Error(), "message with old counter") { - cli.handleEvent(&events.DecryptionError{ + handlerSuccess = cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, Timestamp: envelope.GetTimestamp(), }) } - // TODO there are probably no cases with both content and an error + if !handlerSuccess { + return ErrHandlerFailed + } + return nil } content := result.Content @@ -612,28 +618,29 @@ func (cli *Client) handleDecryptedResult( if err != nil { log.Err(err).Msg("Error storing contacts") } else { - cli.handleEvent(&events.ContactList{ + handlerSuccess = cli.handleEvent(&events.ContactList{ Contacts: convertedContacts, }) } } } if content.SyncMessage.Read != nil { - cli.handleEvent(&events.ReadSelf{ + handlerSuccess = cli.handleEvent(&events.ReadSelf{ Messages: content.SyncMessage.GetRead(), }) } } - var sendDeliveryReceipt bool + sendDeliveryReceipt := true if content.DataMessage != nil { - sendDeliveryReceipt = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) + handlerSuccess = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) } else if content.EditMessage != nil { - sendDeliveryReceipt = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) + handlerSuccess = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) + } else { + sendDeliveryReceipt = false } - if sendDeliveryReceipt { - // TODO send delivery receipts after actually bridging instead of here + if sendDeliveryReceipt && handlerSuccess { err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) if err != nil { log.Err(err).Msg("sendDeliveryReceipts error") @@ -646,6 +653,7 @@ func (cli *Client) handleDecryptedResult( gidBytes := content.TypingMessage.GetGroupId() groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) } + // No handler success check here, nobody cares if typing notifications are dropped cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ Sender: theirServiceID.UUID, @@ -658,7 +666,7 @@ func (cli *Client) handleDecryptedResult( // DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { - cli.handleEvent(&events.Call{ + handlerSuccess = cli.handleEvent(&events.Call{ Info: events.MessageInfo{ Sender: theirServiceID.UUID, ChatID: theirServiceID.String(), @@ -667,7 +675,7 @@ func (cli *Client) handleDecryptedResult( // CallMessage doesn't have its own timestamp, use one from the envelope Timestamp: envelope.GetTimestamp(), IsRinging: content.CallMessage.Offer != nil, - }) + }) && handlerSuccess } // Read and delivery receipts @@ -676,10 +684,13 @@ func (cli *Client) handleDecryptedResult( // Ignore delivery receipts from other own devices return nil } - cli.handleEvent(&events.Receipt{ + handlerSuccess = cli.handleEvent(&events.Receipt{ Sender: theirServiceID.UUID, Content: content.ReceiptMessage, - }) + }) && handlerSuccess + } + if !handlerSuccess { + return ErrHandlerFailed } return nil } @@ -757,7 +768,7 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp } groupRevision = editMessage.GetDataMessage().GetGroupV2().GetRevision() } - cli.handleEvent(&events.ChatEvent{ + return cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ Sender: messageSenderACI, ChatID: groupOrUserID(groupID, chatRecipient), @@ -766,7 +777,6 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp }, Event: editMessage, }) - return true } func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID, serverTimestamp uint64) bool { @@ -805,19 +815,17 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp // Hacky special case for group calls to cache the state if dataMessage.GroupCallUpdate != nil { isRinging := cli.UpdateActiveCalls(groupID, dataMessage.GroupCallUpdate.GetEraId()) - cli.handleEvent(&events.Call{ + return cli.handleEvent(&events.Call{ Info: evtInfo, Timestamp: dataMessage.GetTimestamp(), IsRinging: isRinging, }) } else { - cli.handleEvent(&events.ChatEvent{ + return cli.handleEvent(&events.ChatEvent{ Info: evtInfo, Event: dataMessage, }) } - - return true } func (cli *Client) sendDeliveryReceipts(ctx context.Context, deliveredTimestamps []uint64, senderUUID uuid.UUID) error { From 97287928b8d71d82f4397bcf8746d84a472d8a54 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 30 Jun 2025 13:18:41 +0300 Subject: [PATCH 501/718] libsignal: update to v0.76.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 51 +++++++++++++++++++-------------- pkg/libsignalgo/version.go | 2 +- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index fd34ab3..6dc0f85 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit fd34ab35ce21d1133ff254a44a7060a3ef72cf1b +Subproject commit 6dc0f85b07d890fd02e727a0f8484a1f3f864f7e diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 1967ddd..0288e34 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -123,6 +123,12 @@ SPDX-License-Identifier: AGPL-3.0-only */ #define SignalFourCC_ENCODED_LEN 4 +enum SignalChallengeOption { + SignalChallengeOptionPushChallenge, + SignalChallengeOptionCaptcha, +}; +typedef uint8_t SignalChallengeOption; + typedef enum { SignalCiphertextMessageTypeWhisper = 2, SignalCiphertextMessageTypePreKey = 3, @@ -169,12 +175,6 @@ typedef enum { SignalLogLevelTrace, } SignalLogLevel; -enum SignalRequestedInformation { - SignalRequestedInformationPushChallenge, - SignalRequestedInformationCaptcha, -}; -typedef uint8_t SignalRequestedInformation; - typedef enum { SignalErrorCodeUnknownError = 1, SignalErrorCodeInvalidState = 2, @@ -201,6 +201,7 @@ typedef enum { SignalErrorCodeInvalidRegistrationId = 81, SignalErrorCodeInvalidSession = 82, SignalErrorCodeInvalidSenderKeySession = 83, + SignalErrorCodeInvalidProtocolAddress = 84, SignalErrorCodeDuplicatedMessage = 90, SignalErrorCodeCallbackError = 100, SignalErrorCodeVerificationFailure = 110, @@ -229,6 +230,7 @@ typedef enum { SignalErrorCodeConnectionFailed = 148, SignalErrorCodeChatServiceInactive = 149, SignalErrorCodeRequestTimedOut = 150, + SignalErrorCodeRateLimitChallenge = 151, SignalErrorCodeSvrDataMissing = 160, SignalErrorCodeSvrRestoreFailed = 161, SignalErrorCodeSvrRotationMachineTooManySteps = 162, @@ -238,7 +240,6 @@ typedef enum { SignalErrorCodeConnectedElsewhere = 173, SignalErrorCodeBackupValidation = 180, SignalErrorCodeRegistrationInvalidSessionId = 190, - SignalErrorCodeRegistrationRequestNotValid = 191, SignalErrorCodeRegistrationUnknown = 192, SignalErrorCodeRegistrationSessionNotFound = 193, SignalErrorCodeRegistrationNotReadyForVerification = 194, @@ -466,6 +467,16 @@ typedef struct { const SignalConnectionManager *raw; } SignalConstPointerConnectionManager; +typedef struct { + const size_t *base; + size_t length; +} SignalBorrowedSliceOfusize; + +typedef struct { + SignalBorrowedBuffer bytes; + SignalBorrowedSliceOfusize lengths; +} SignalBorrowedBytestringArray; + /** * A C callback used to report the results of Rust futures. * @@ -1116,16 +1127,6 @@ typedef struct { SignalRegistrationAccountAttributes *raw; } SignalMutPointerRegistrationAccountAttributes; -typedef struct { - const size_t *base; - size_t length; -} SignalBorrowedSliceOfusize; - -typedef struct { - SignalBorrowedBuffer bytes; - SignalBorrowedSliceOfusize lengths; -} SignalBorrowedBytestringArray; - typedef struct { /** * Bridged as a string of bytes, but each entry is a UTF-8 `String` key @@ -1391,7 +1392,7 @@ SignalFfiError *signal_auth_credential_with_pni_check_valid_contents(SignalBorro SignalFfiError *signal_auth_credential_with_pni_response_check_valid_contents(SignalBorrowedBuffer bytes); -SignalFfiError *signal_authenticated_chat_connection_connect(SignalCPromiseMutPointerAuthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories); +SignalFfiError *signal_authenticated_chat_connection_connect(SignalCPromiseMutPointerAuthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password, bool receive_stories, SignalBorrowedBytestringArray languages); SignalFfiError *signal_authenticated_chat_connection_destroy(SignalMutPointerAuthenticatedChatConnection p); @@ -1589,14 +1590,22 @@ void signal_error_free(SignalFfiError *err); SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalMutPointerProtocolAddress *out); +SignalFfiError *signal_error_get_invalid_protocol_address(const SignalFfiError *err, const char **name_out, uint32_t *device_id_out); + SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); +SignalFfiError *signal_error_get_our_fingerprint_version(const SignalFfiError *err, uint32_t *out); + +SignalFfiError *signal_error_get_rate_limit_challenge(const SignalFfiError *err, const char **out_token, SignalOwnedBuffer *out_options); + SignalFfiError *signal_error_get_registration_error_not_deliverable(const SignalFfiError *err, const char **out_reason, bool *out_permanent); SignalFfiError *signal_error_get_registration_lock(const SignalFfiError *err, uint64_t *out_time_remaining_seconds, const char **out_svr2_username, const char **out_svr2_password); SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_their_fingerprint_version(const SignalFfiError *err, uint32_t *out); + SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); uint32_t signal_error_get_type(const SignalFfiError *err); @@ -1915,11 +1924,11 @@ SignalFfiError *signal_pre_key_bundle_get_device_id(uint32_t *out, SignalConstPo SignalFfiError *signal_pre_key_bundle_get_identity_key(SignalMutPointerPublicKey *out, SignalConstPointerPreKeyBundle p); -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle bundle); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_public(SignalMutPointerKyberPublicKey *out, SignalConstPointerPreKeyBundle bundle); -SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle bundle); +SignalFfiError *signal_pre_key_bundle_get_kyber_pre_key_signature(SignalOwnedBuffer *out, SignalConstPointerPreKeyBundle obj); SignalFfiError *signal_pre_key_bundle_get_pre_key_id(uint32_t *out, SignalConstPointerPreKeyBundle obj); @@ -2387,7 +2396,7 @@ SignalFfiError *signal_tokio_async_context_destroy(SignalMutPointerTokioAsyncCon SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext *out); -SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); +SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, SignalBorrowedBytestringArray languages); SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index d7458b0..e9ce0db 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.74.1" +const Version = "v0.76.1" From 3b2548d70c896b6241b1dc05f53b65e07ac0d385 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 30 Jun 2025 13:22:34 +0300 Subject: [PATCH 502/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/StorageService.pb.go | 999 +++++++++++++----- pkg/signalmeow/protobuf/StorageService.proto | 159 ++- .../protobuf/UnidentifiedDelivery.pb.go | 18 +- .../protobuf/UnidentifiedDelivery.proto | 5 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 521 ++++++--- pkg/signalmeow/protobuf/backuppb/Backup.proto | 59 ++ pkg/signalmeow/protobuf/update-protos.sh | 4 +- 7 files changed, 1302 insertions(+), 463 deletions(-) diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 3826c83..c6ce93e 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -171,6 +171,7 @@ const ( ManifestRecord_Identifier_STORY_DISTRIBUTION_LIST ManifestRecord_Identifier_Type = 5 ManifestRecord_Identifier_CALL_LINK ManifestRecord_Identifier_Type = 7 ManifestRecord_Identifier_CHAT_FOLDER ManifestRecord_Identifier_Type = 8 + ManifestRecord_Identifier_NOTIFICATION_PROFILE ManifestRecord_Identifier_Type = 9 ) // Enum value maps for ManifestRecord_Identifier_Type. @@ -184,6 +185,7 @@ var ( 5: "STORY_DISTRIBUTION_LIST", 7: "CALL_LINK", 8: "CHAT_FOLDER", + 9: "NOTIFICATION_PROFILE", } ManifestRecord_Identifier_Type_value = map[string]int32{ "UNKNOWN": 0, @@ -194,6 +196,7 @@ var ( "STORY_DISTRIBUTION_LIST": 5, "CALL_LINK": 7, "CHAT_FOLDER": 8, + "NOTIFICATION_PROFILE": 9, } ) @@ -485,7 +488,71 @@ func (x ChatFolderRecord_FolderType) Number() protoreflect.EnumNumber { // Deprecated: Use ChatFolderRecord_FolderType.Descriptor instead. func (ChatFolderRecord_FolderType) EnumDescriptor() ([]byte, []int) { - return file_StorageService_proto_rawDescGZIP(), []int{14, 0} + return file_StorageService_proto_rawDescGZIP(), []int{15, 0} +} + +type NotificationProfile_DayOfWeek int32 + +const ( + NotificationProfile_UNKNOWN NotificationProfile_DayOfWeek = 0 // Interpret as "Monday" + NotificationProfile_MONDAY NotificationProfile_DayOfWeek = 1 + NotificationProfile_TUESDAY NotificationProfile_DayOfWeek = 2 + NotificationProfile_WEDNESDAY NotificationProfile_DayOfWeek = 3 + NotificationProfile_THURSDAY NotificationProfile_DayOfWeek = 4 + NotificationProfile_FRIDAY NotificationProfile_DayOfWeek = 5 + NotificationProfile_SATURDAY NotificationProfile_DayOfWeek = 6 + NotificationProfile_SUNDAY NotificationProfile_DayOfWeek = 7 +) + +// Enum value maps for NotificationProfile_DayOfWeek. +var ( + NotificationProfile_DayOfWeek_name = map[int32]string{ + 0: "UNKNOWN", + 1: "MONDAY", + 2: "TUESDAY", + 3: "WEDNESDAY", + 4: "THURSDAY", + 5: "FRIDAY", + 6: "SATURDAY", + 7: "SUNDAY", + } + NotificationProfile_DayOfWeek_value = map[string]int32{ + "UNKNOWN": 0, + "MONDAY": 1, + "TUESDAY": 2, + "WEDNESDAY": 3, + "THURSDAY": 4, + "FRIDAY": 5, + "SATURDAY": 6, + "SUNDAY": 7, + } +) + +func (x NotificationProfile_DayOfWeek) Enum() *NotificationProfile_DayOfWeek { + p := new(NotificationProfile_DayOfWeek) + *p = x + return p +} + +func (x NotificationProfile_DayOfWeek) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (NotificationProfile_DayOfWeek) Descriptor() protoreflect.EnumDescriptor { + return file_StorageService_proto_enumTypes[8].Descriptor() +} + +func (NotificationProfile_DayOfWeek) Type() protoreflect.EnumType { + return &file_StorageService_proto_enumTypes[8] +} + +func (x NotificationProfile_DayOfWeek) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use NotificationProfile_DayOfWeek.Descriptor instead. +func (NotificationProfile_DayOfWeek) EnumDescriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{16, 0} } type StorageManifest struct { @@ -827,6 +894,7 @@ type StorageRecord struct { // *StorageRecord_StoryDistributionList // *StorageRecord_CallLink // *StorageRecord_ChatFolder + // *StorageRecord_NotificationProfile Record isStorageRecord_Record `protobuf_oneof:"record"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -932,6 +1000,15 @@ func (x *StorageRecord) GetChatFolder() *ChatFolderRecord { return nil } +func (x *StorageRecord) GetNotificationProfile() *NotificationProfile { + if x != nil { + if x, ok := x.Record.(*StorageRecord_NotificationProfile); ok { + return x.NotificationProfile + } + } + return nil +} + type isStorageRecord_Record interface { isStorageRecord_Record() } @@ -964,6 +1041,10 @@ type StorageRecord_ChatFolder struct { ChatFolder *ChatFolderRecord `protobuf:"bytes,8,opt,name=chatFolder,proto3,oneof"` } +type StorageRecord_NotificationProfile struct { + NotificationProfile *NotificationProfile `protobuf:"bytes,9,opt,name=notificationProfile,proto3,oneof"` +} + func (*StorageRecord_Contact) isStorageRecord_Record() {} func (*StorageRecord_GroupV1) isStorageRecord_Record() {} @@ -978,6 +1059,8 @@ func (*StorageRecord_CallLink) isStorageRecord_Record() {} func (*StorageRecord_ChatFolder) isStorageRecord_Record() {} +func (*StorageRecord_NotificationProfile) isStorageRecord_Record() {} + type ContactRecord struct { state protoimpl.MessageState `protogen:"open.v1"` Aci string `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` @@ -1459,45 +1542,46 @@ func (x *Payments) GetEntropy() []byte { } type AccountRecord struct { - state protoimpl.MessageState `protogen:"open.v1"` - ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` - GivenName string `protobuf:"bytes,2,opt,name=givenName,proto3" json:"givenName,omitempty"` - FamilyName string `protobuf:"bytes,3,opt,name=familyName,proto3" json:"familyName,omitempty"` - AvatarUrlPath string `protobuf:"bytes,4,opt,name=avatarUrlPath,proto3" json:"avatarUrlPath,omitempty"` - NoteToSelfArchived bool `protobuf:"varint,5,opt,name=noteToSelfArchived,proto3" json:"noteToSelfArchived,omitempty"` - ReadReceipts bool `protobuf:"varint,6,opt,name=readReceipts,proto3" json:"readReceipts,omitempty"` - SealedSenderIndicators bool `protobuf:"varint,7,opt,name=sealedSenderIndicators,proto3" json:"sealedSenderIndicators,omitempty"` - TypingIndicators bool `protobuf:"varint,8,opt,name=typingIndicators,proto3" json:"typingIndicators,omitempty"` - NoteToSelfMarkedUnread bool `protobuf:"varint,10,opt,name=noteToSelfMarkedUnread,proto3" json:"noteToSelfMarkedUnread,omitempty"` - LinkPreviews bool `protobuf:"varint,11,opt,name=linkPreviews,proto3" json:"linkPreviews,omitempty"` - PhoneNumberSharingMode AccountRecord_PhoneNumberSharingMode `protobuf:"varint,12,opt,name=phoneNumberSharingMode,proto3,enum=signalservice.AccountRecord_PhoneNumberSharingMode" json:"phoneNumberSharingMode,omitempty"` - UnlistedPhoneNumber bool `protobuf:"varint,13,opt,name=unlistedPhoneNumber,proto3" json:"unlistedPhoneNumber,omitempty"` - PinnedConversations []*AccountRecord_PinnedConversation `protobuf:"bytes,14,rep,name=pinnedConversations,proto3" json:"pinnedConversations,omitempty"` - PreferContactAvatars bool `protobuf:"varint,15,opt,name=preferContactAvatars,proto3" json:"preferContactAvatars,omitempty"` - Payments *Payments `protobuf:"bytes,16,opt,name=payments,proto3" json:"payments,omitempty"` - UniversalExpireTimer uint32 `protobuf:"varint,17,opt,name=universalExpireTimer,proto3" json:"universalExpireTimer,omitempty"` - PrimarySendsSms bool `protobuf:"varint,18,opt,name=primarySendsSms,proto3" json:"primarySendsSms,omitempty"` - E164 string `protobuf:"bytes,19,opt,name=e164,proto3" json:"e164,omitempty"` - PreferredReactionEmoji []string `protobuf:"bytes,20,rep,name=preferredReactionEmoji,proto3" json:"preferredReactionEmoji,omitempty"` - SubscriberId []byte `protobuf:"bytes,21,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` - SubscriberCurrencyCode string `protobuf:"bytes,22,opt,name=subscriberCurrencyCode,proto3" json:"subscriberCurrencyCode,omitempty"` - DisplayBadgesOnProfile bool `protobuf:"varint,23,opt,name=displayBadgesOnProfile,proto3" json:"displayBadgesOnProfile,omitempty"` - SubscriptionManuallyCancelled bool `protobuf:"varint,24,opt,name=subscriptionManuallyCancelled,proto3" json:"subscriptionManuallyCancelled,omitempty"` - KeepMutedChatsArchived bool `protobuf:"varint,25,opt,name=keepMutedChatsArchived,proto3" json:"keepMutedChatsArchived,omitempty"` - HasSetMyStoriesPrivacy bool `protobuf:"varint,26,opt,name=hasSetMyStoriesPrivacy,proto3" json:"hasSetMyStoriesPrivacy,omitempty"` - HasViewedOnboardingStory bool `protobuf:"varint,27,opt,name=hasViewedOnboardingStory,proto3" json:"hasViewedOnboardingStory,omitempty"` - StoriesDisabled bool `protobuf:"varint,29,opt,name=storiesDisabled,proto3" json:"storiesDisabled,omitempty"` - StoryViewReceiptsEnabled OptionalBool `protobuf:"varint,30,opt,name=storyViewReceiptsEnabled,proto3,enum=signalservice.OptionalBool" json:"storyViewReceiptsEnabled,omitempty"` - HasSeenGroupStoryEducationSheet bool `protobuf:"varint,32,opt,name=hasSeenGroupStoryEducationSheet,proto3" json:"hasSeenGroupStoryEducationSheet,omitempty"` - Username string `protobuf:"bytes,33,opt,name=username,proto3" json:"username,omitempty"` - HasCompletedUsernameOnboarding bool `protobuf:"varint,34,opt,name=hasCompletedUsernameOnboarding,proto3" json:"hasCompletedUsernameOnboarding,omitempty"` - UsernameLink *AccountRecord_UsernameLink `protobuf:"bytes,35,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` - HasBackup *bool `protobuf:"varint,39,opt,name=hasBackup,proto3,oneof" json:"hasBackup,omitempty"` // Set to true after backups are enabled and one is uploaded. - BackupTier *uint64 `protobuf:"varint,40,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` // See zkgroup for integer particular values - BackupSubscriberData *AccountRecord_IAPSubscriberData `protobuf:"bytes,41,opt,name=backupSubscriberData,proto3" json:"backupSubscriberData,omitempty"` - AvatarColor *AvatarColor `protobuf:"varint,42,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + GivenName string `protobuf:"bytes,2,opt,name=givenName,proto3" json:"givenName,omitempty"` + FamilyName string `protobuf:"bytes,3,opt,name=familyName,proto3" json:"familyName,omitempty"` + AvatarUrlPath string `protobuf:"bytes,4,opt,name=avatarUrlPath,proto3" json:"avatarUrlPath,omitempty"` + NoteToSelfArchived bool `protobuf:"varint,5,opt,name=noteToSelfArchived,proto3" json:"noteToSelfArchived,omitempty"` + ReadReceipts bool `protobuf:"varint,6,opt,name=readReceipts,proto3" json:"readReceipts,omitempty"` + SealedSenderIndicators bool `protobuf:"varint,7,opt,name=sealedSenderIndicators,proto3" json:"sealedSenderIndicators,omitempty"` + TypingIndicators bool `protobuf:"varint,8,opt,name=typingIndicators,proto3" json:"typingIndicators,omitempty"` + NoteToSelfMarkedUnread bool `protobuf:"varint,10,opt,name=noteToSelfMarkedUnread,proto3" json:"noteToSelfMarkedUnread,omitempty"` + LinkPreviews bool `protobuf:"varint,11,opt,name=linkPreviews,proto3" json:"linkPreviews,omitempty"` + PhoneNumberSharingMode AccountRecord_PhoneNumberSharingMode `protobuf:"varint,12,opt,name=phoneNumberSharingMode,proto3,enum=signalservice.AccountRecord_PhoneNumberSharingMode" json:"phoneNumberSharingMode,omitempty"` + UnlistedPhoneNumber bool `protobuf:"varint,13,opt,name=unlistedPhoneNumber,proto3" json:"unlistedPhoneNumber,omitempty"` + PinnedConversations []*AccountRecord_PinnedConversation `protobuf:"bytes,14,rep,name=pinnedConversations,proto3" json:"pinnedConversations,omitempty"` + PreferContactAvatars bool `protobuf:"varint,15,opt,name=preferContactAvatars,proto3" json:"preferContactAvatars,omitempty"` + Payments *Payments `protobuf:"bytes,16,opt,name=payments,proto3" json:"payments,omitempty"` + UniversalExpireTimer uint32 `protobuf:"varint,17,opt,name=universalExpireTimer,proto3" json:"universalExpireTimer,omitempty"` + PrimarySendsSms bool `protobuf:"varint,18,opt,name=primarySendsSms,proto3" json:"primarySendsSms,omitempty"` + PreferredReactionEmoji []string `protobuf:"bytes,20,rep,name=preferredReactionEmoji,proto3" json:"preferredReactionEmoji,omitempty"` + SubscriberId []byte `protobuf:"bytes,21,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` + SubscriberCurrencyCode string `protobuf:"bytes,22,opt,name=subscriberCurrencyCode,proto3" json:"subscriberCurrencyCode,omitempty"` + DisplayBadgesOnProfile bool `protobuf:"varint,23,opt,name=displayBadgesOnProfile,proto3" json:"displayBadgesOnProfile,omitempty"` + SubscriptionManuallyCancelled bool `protobuf:"varint,24,opt,name=subscriptionManuallyCancelled,proto3" json:"subscriptionManuallyCancelled,omitempty"` + KeepMutedChatsArchived bool `protobuf:"varint,25,opt,name=keepMutedChatsArchived,proto3" json:"keepMutedChatsArchived,omitempty"` + HasSetMyStoriesPrivacy bool `protobuf:"varint,26,opt,name=hasSetMyStoriesPrivacy,proto3" json:"hasSetMyStoriesPrivacy,omitempty"` + HasViewedOnboardingStory bool `protobuf:"varint,27,opt,name=hasViewedOnboardingStory,proto3" json:"hasViewedOnboardingStory,omitempty"` + StoriesDisabled bool `protobuf:"varint,29,opt,name=storiesDisabled,proto3" json:"storiesDisabled,omitempty"` + StoryViewReceiptsEnabled OptionalBool `protobuf:"varint,30,opt,name=storyViewReceiptsEnabled,proto3,enum=signalservice.OptionalBool" json:"storyViewReceiptsEnabled,omitempty"` + HasSeenGroupStoryEducationSheet bool `protobuf:"varint,32,opt,name=hasSeenGroupStoryEducationSheet,proto3" json:"hasSeenGroupStoryEducationSheet,omitempty"` + Username string `protobuf:"bytes,33,opt,name=username,proto3" json:"username,omitempty"` + HasCompletedUsernameOnboarding bool `protobuf:"varint,34,opt,name=hasCompletedUsernameOnboarding,proto3" json:"hasCompletedUsernameOnboarding,omitempty"` + UsernameLink *AccountRecord_UsernameLink `protobuf:"bytes,35,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` + HasBackup *bool `protobuf:"varint,39,opt,name=hasBackup,proto3,oneof" json:"hasBackup,omitempty"` // Set to true after backups are enabled and one is uploaded. + BackupTier *uint64 `protobuf:"varint,40,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` // See zkgroup for integer particular values. Unset if backups are not enabled. + BackupSubscriberData *AccountRecord_IAPSubscriberData `protobuf:"bytes,41,opt,name=backupSubscriberData,proto3" json:"backupSubscriberData,omitempty"` + AvatarColor *AvatarColor `protobuf:"varint,42,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` + BackupTierHistory *AccountRecord_BackupTierHistory `protobuf:"bytes,43,opt,name=backupTierHistory,proto3" json:"backupTierHistory,omitempty"` + NotificationProfileManualOverride *AccountRecord_NotificationProfileManualOverride `protobuf:"bytes,44,opt,name=notificationProfileManualOverride,proto3" json:"notificationProfileManualOverride,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountRecord) Reset() { @@ -1649,13 +1733,6 @@ func (x *AccountRecord) GetPrimarySendsSms() bool { return false } -func (x *AccountRecord) GetE164() string { - if x != nil { - return x.E164 - } - return "" -} - func (x *AccountRecord) GetPreferredReactionEmoji() []string { if x != nil { return x.PreferredReactionEmoji @@ -1782,6 +1859,20 @@ func (x *AccountRecord) GetAvatarColor() AvatarColor { return AvatarColor_A100 } +func (x *AccountRecord) GetBackupTierHistory() *AccountRecord_BackupTierHistory { + if x != nil { + return x.BackupTierHistory + } + return nil +} + +func (x *AccountRecord) GetNotificationProfileManualOverride() *AccountRecord_NotificationProfileManualOverride { + if x != nil { + return x.NotificationProfileManualOverride + } + return nil +} + type StoryDistributionListRecord struct { state protoimpl.MessageState `protogen:"open.v1"` Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` @@ -1926,26 +2017,124 @@ func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 { return 0 } +type Recipient struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Identifier: + // + // *Recipient_Contact_ + // *Recipient_LegacyGroupId + // *Recipient_GroupMasterKey + Identifier isRecipient_Identifier `protobuf_oneof:"identifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Recipient) Reset() { + *x = Recipient{} + mi := &file_StorageService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Recipient) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Recipient) ProtoMessage() {} + +func (x *Recipient) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[14] + 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 Recipient.ProtoReflect.Descriptor instead. +func (*Recipient) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{14} +} + +func (x *Recipient) GetIdentifier() isRecipient_Identifier { + if x != nil { + return x.Identifier + } + return nil +} + +func (x *Recipient) GetContact() *Recipient_Contact { + if x != nil { + if x, ok := x.Identifier.(*Recipient_Contact_); ok { + return x.Contact + } + } + return nil +} + +func (x *Recipient) GetLegacyGroupId() []byte { + if x != nil { + if x, ok := x.Identifier.(*Recipient_LegacyGroupId); ok { + return x.LegacyGroupId + } + } + return nil +} + +func (x *Recipient) GetGroupMasterKey() []byte { + if x != nil { + if x, ok := x.Identifier.(*Recipient_GroupMasterKey); ok { + return x.GroupMasterKey + } + } + return nil +} + +type isRecipient_Identifier interface { + isRecipient_Identifier() +} + +type Recipient_Contact_ struct { + Contact *Recipient_Contact `protobuf:"bytes,1,opt,name=contact,proto3,oneof"` +} + +type Recipient_LegacyGroupId struct { + LegacyGroupId []byte `protobuf:"bytes,2,opt,name=legacyGroupId,proto3,oneof"` +} + +type Recipient_GroupMasterKey struct { + GroupMasterKey []byte `protobuf:"bytes,3,opt,name=groupMasterKey,proto3,oneof"` +} + +func (*Recipient_Contact_) isRecipient_Identifier() {} + +func (*Recipient_LegacyGroupId) isRecipient_Identifier() {} + +func (*Recipient_GroupMasterKey) isRecipient_Identifier() {} + type ChatFolderRecord struct { - state protoimpl.MessageState `protogen:"open.v1"` - Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Position uint32 `protobuf:"varint,3,opt,name=position,proto3" json:"position,omitempty"` - ShowOnlyUnread bool `protobuf:"varint,4,opt,name=showOnlyUnread,proto3" json:"showOnlyUnread,omitempty"` - ShowMutedChats bool `protobuf:"varint,5,opt,name=showMutedChats,proto3" json:"showMutedChats,omitempty"` - IncludeAllIndividualChats bool `protobuf:"varint,6,opt,name=includeAllIndividualChats,proto3" json:"includeAllIndividualChats,omitempty"` // Folder includes all 1:1 chats, unless excluded - IncludeAllGroupChats bool `protobuf:"varint,7,opt,name=includeAllGroupChats,proto3" json:"includeAllGroupChats,omitempty"` // Folder includes all group chats, unless excluded - FolderType ChatFolderRecord_FolderType `protobuf:"varint,8,opt,name=folderType,proto3,enum=signalservice.ChatFolderRecord_FolderType" json:"folderType,omitempty"` - IncludedRecipients []*ChatFolderRecord_Recipient `protobuf:"bytes,9,rep,name=includedRecipients,proto3" json:"includedRecipients,omitempty"` - ExcludedRecipients []*ChatFolderRecord_Recipient `protobuf:"bytes,10,rep,name=excludedRecipients,proto3" json:"excludedRecipients,omitempty"` - DeletedAtTimestampMs uint64 `protobuf:"varint,11,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` // When non-zero, `position` should be set to -1 and includedRecipients should be empty + state protoimpl.MessageState `protogen:"open.v1"` + Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Position uint32 `protobuf:"varint,3,opt,name=position,proto3" json:"position,omitempty"` + ShowOnlyUnread bool `protobuf:"varint,4,opt,name=showOnlyUnread,proto3" json:"showOnlyUnread,omitempty"` + ShowMutedChats bool `protobuf:"varint,5,opt,name=showMutedChats,proto3" json:"showMutedChats,omitempty"` + IncludeAllIndividualChats bool `protobuf:"varint,6,opt,name=includeAllIndividualChats,proto3" json:"includeAllIndividualChats,omitempty"` // Folder includes all 1:1 chats, unless excluded + IncludeAllGroupChats bool `protobuf:"varint,7,opt,name=includeAllGroupChats,proto3" json:"includeAllGroupChats,omitempty"` // Folder includes all group chats, unless excluded + FolderType ChatFolderRecord_FolderType `protobuf:"varint,8,opt,name=folderType,proto3,enum=signalservice.ChatFolderRecord_FolderType" json:"folderType,omitempty"` + IncludedRecipients []*Recipient `protobuf:"bytes,9,rep,name=includedRecipients,proto3" json:"includedRecipients,omitempty"` + ExcludedRecipients []*Recipient `protobuf:"bytes,10,rep,name=excludedRecipients,proto3" json:"excludedRecipients,omitempty"` + DeletedAtTimestampMs uint64 `protobuf:"varint,11,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` // When non-zero, `position` should be set to -1 and includedRecipients should be empty unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *ChatFolderRecord) Reset() { *x = ChatFolderRecord{} - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1957,7 +2146,7 @@ func (x *ChatFolderRecord) String() string { func (*ChatFolderRecord) ProtoMessage() {} func (x *ChatFolderRecord) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[14] + mi := &file_StorageService_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1970,7 +2159,7 @@ func (x *ChatFolderRecord) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatFolderRecord.ProtoReflect.Descriptor instead. func (*ChatFolderRecord) Descriptor() ([]byte, []int) { - return file_StorageService_proto_rawDescGZIP(), []int{14} + return file_StorageService_proto_rawDescGZIP(), []int{15} } func (x *ChatFolderRecord) GetIdentifier() []byte { @@ -2029,14 +2218,14 @@ func (x *ChatFolderRecord) GetFolderType() ChatFolderRecord_FolderType { return ChatFolderRecord_UNKNOWN } -func (x *ChatFolderRecord) GetIncludedRecipients() []*ChatFolderRecord_Recipient { +func (x *ChatFolderRecord) GetIncludedRecipients() []*Recipient { if x != nil { return x.IncludedRecipients } return nil } -func (x *ChatFolderRecord) GetExcludedRecipients() []*ChatFolderRecord_Recipient { +func (x *ChatFolderRecord) GetExcludedRecipients() []*Recipient { if x != nil { return x.ExcludedRecipients } @@ -2050,6 +2239,146 @@ func (x *ChatFolderRecord) GetDeletedAtTimestampMs() uint64 { return 0 } +type NotificationProfile struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Emoji *string `protobuf:"bytes,3,opt,name=emoji,proto3,oneof" json:"emoji,omitempty"` + Color uint32 `protobuf:"fixed32,4,opt,name=color,proto3" json:"color,omitempty"` // 0xAARRGGBB + CreatedAtMs uint64 `protobuf:"varint,5,opt,name=createdAtMs,proto3" json:"createdAtMs,omitempty"` + AllowAllCalls bool `protobuf:"varint,6,opt,name=allowAllCalls,proto3" json:"allowAllCalls,omitempty"` + AllowAllMentions bool `protobuf:"varint,7,opt,name=allowAllMentions,proto3" json:"allowAllMentions,omitempty"` + AllowedMembers []*Recipient `protobuf:"bytes,8,rep,name=allowedMembers,proto3" json:"allowedMembers,omitempty"` + ScheduleEnabled bool `protobuf:"varint,9,opt,name=scheduleEnabled,proto3" json:"scheduleEnabled,omitempty"` + ScheduleStartTime uint32 `protobuf:"varint,10,opt,name=scheduleStartTime,proto3" json:"scheduleStartTime,omitempty"` // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + ScheduleEndTime uint32 `protobuf:"varint,11,opt,name=scheduleEndTime,proto3" json:"scheduleEndTime,omitempty"` // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + ScheduleDaysEnabled []NotificationProfile_DayOfWeek `protobuf:"varint,12,rep,packed,name=scheduleDaysEnabled,proto3,enum=signalservice.NotificationProfile_DayOfWeek" json:"scheduleDaysEnabled,omitempty"` + DeletedAtTimestampMs uint64 `protobuf:"varint,13,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NotificationProfile) Reset() { + *x = NotificationProfile{} + mi := &file_StorageService_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NotificationProfile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotificationProfile) ProtoMessage() {} + +func (x *NotificationProfile) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[16] + 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 NotificationProfile.ProtoReflect.Descriptor instead. +func (*NotificationProfile) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{16} +} + +func (x *NotificationProfile) GetId() []byte { + if x != nil { + return x.Id + } + return nil +} + +func (x *NotificationProfile) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NotificationProfile) GetEmoji() string { + if x != nil && x.Emoji != nil { + return *x.Emoji + } + return "" +} + +func (x *NotificationProfile) GetColor() uint32 { + if x != nil { + return x.Color + } + return 0 +} + +func (x *NotificationProfile) GetCreatedAtMs() uint64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *NotificationProfile) GetAllowAllCalls() bool { + if x != nil { + return x.AllowAllCalls + } + return false +} + +func (x *NotificationProfile) GetAllowAllMentions() bool { + if x != nil { + return x.AllowAllMentions + } + return false +} + +func (x *NotificationProfile) GetAllowedMembers() []*Recipient { + if x != nil { + return x.AllowedMembers + } + return nil +} + +func (x *NotificationProfile) GetScheduleEnabled() bool { + if x != nil { + return x.ScheduleEnabled + } + return false +} + +func (x *NotificationProfile) GetScheduleStartTime() uint32 { + if x != nil { + return x.ScheduleStartTime + } + return 0 +} + +func (x *NotificationProfile) GetScheduleEndTime() uint32 { + if x != nil { + return x.ScheduleEndTime + } + return 0 +} + +func (x *NotificationProfile) GetScheduleDaysEnabled() []NotificationProfile_DayOfWeek { + if x != nil { + return x.ScheduleDaysEnabled + } + return nil +} + +func (x *NotificationProfile) GetDeletedAtTimestampMs() uint64 { + if x != nil { + return x.DeletedAtTimestampMs + } + return 0 +} + type ManifestRecord_Identifier struct { state protoimpl.MessageState `protogen:"open.v1"` Raw []byte `protobuf:"bytes,1,opt,name=raw,proto3" json:"raw,omitempty"` @@ -2060,7 +2389,7 @@ type ManifestRecord_Identifier struct { func (x *ManifestRecord_Identifier) Reset() { *x = ManifestRecord_Identifier{} - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2072,7 +2401,7 @@ func (x *ManifestRecord_Identifier) String() string { func (*ManifestRecord_Identifier) ProtoMessage() {} func (x *ManifestRecord_Identifier) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[15] + mi := &file_StorageService_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2112,7 +2441,7 @@ type ContactRecord_Name struct { func (x *ContactRecord_Name) Reset() { *x = ContactRecord_Name{} - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2124,7 +2453,7 @@ func (x *ContactRecord_Name) String() string { func (*ContactRecord_Name) ProtoMessage() {} func (x *ContactRecord_Name) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[16] + mi := &file_StorageService_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2168,7 +2497,7 @@ type AccountRecord_PinnedConversation struct { func (x *AccountRecord_PinnedConversation) Reset() { *x = AccountRecord_PinnedConversation{} - mi := &file_StorageService_proto_msgTypes[17] + mi := &file_StorageService_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2180,7 +2509,7 @@ func (x *AccountRecord_PinnedConversation) String() string { func (*AccountRecord_PinnedConversation) ProtoMessage() {} func (x *AccountRecord_PinnedConversation) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[17] + mi := &file_StorageService_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2265,7 +2594,7 @@ type AccountRecord_UsernameLink struct { func (x *AccountRecord_UsernameLink) Reset() { *x = AccountRecord_UsernameLink{} - mi := &file_StorageService_proto_msgTypes[18] + mi := &file_StorageService_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2277,7 +2606,7 @@ func (x *AccountRecord_UsernameLink) String() string { func (*AccountRecord_UsernameLink) ProtoMessage() {} func (x *AccountRecord_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[18] + mi := &file_StorageService_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2328,7 +2657,7 @@ type AccountRecord_IAPSubscriberData struct { func (x *AccountRecord_IAPSubscriberData) Reset() { *x = AccountRecord_IAPSubscriberData{} - mi := &file_StorageService_proto_msgTypes[19] + mi := &file_StorageService_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2340,7 +2669,7 @@ func (x *AccountRecord_IAPSubscriberData) String() string { func (*AccountRecord_IAPSubscriberData) ProtoMessage() {} func (x *AccountRecord_IAPSubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[19] + mi := &file_StorageService_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2408,6 +2737,143 @@ func (*AccountRecord_IAPSubscriberData_PurchaseToken) isAccountRecord_IAPSubscri func (*AccountRecord_IAPSubscriberData_OriginalTransactionId) isAccountRecord_IAPSubscriberData_IapSubscriptionId() { } +type AccountRecord_BackupTierHistory struct { + state protoimpl.MessageState `protogen:"open.v1"` + // See zkgroup for integer particular values. Unset if backups are not enabled. + BackupTier *uint64 `protobuf:"varint,1,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` + EndedAtTimestamp *uint64 `protobuf:"varint,2,opt,name=endedAtTimestamp,proto3,oneof" json:"endedAtTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountRecord_BackupTierHistory) Reset() { + *x = AccountRecord_BackupTierHistory{} + mi := &file_StorageService_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountRecord_BackupTierHistory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord_BackupTierHistory) ProtoMessage() {} + +func (x *AccountRecord_BackupTierHistory) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[22] + 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 AccountRecord_BackupTierHistory.ProtoReflect.Descriptor instead. +func (*AccountRecord_BackupTierHistory) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 3} +} + +func (x *AccountRecord_BackupTierHistory) GetBackupTier() uint64 { + if x != nil && x.BackupTier != nil { + return *x.BackupTier + } + return 0 +} + +func (x *AccountRecord_BackupTierHistory) GetEndedAtTimestamp() uint64 { + if x != nil && x.EndedAtTimestamp != nil { + return *x.EndedAtTimestamp + } + return 0 +} + +type AccountRecord_NotificationProfileManualOverride struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Override: + // + // *AccountRecord_NotificationProfileManualOverride_DisabledAtTimestampMs + // *AccountRecord_NotificationProfileManualOverride_Enabled + Override isAccountRecord_NotificationProfileManualOverride_Override `protobuf_oneof:"override"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountRecord_NotificationProfileManualOverride) Reset() { + *x = AccountRecord_NotificationProfileManualOverride{} + mi := &file_StorageService_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountRecord_NotificationProfileManualOverride) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountRecord_NotificationProfileManualOverride) ProtoMessage() {} + +func (x *AccountRecord_NotificationProfileManualOverride) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[23] + 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 AccountRecord_NotificationProfileManualOverride.ProtoReflect.Descriptor instead. +func (*AccountRecord_NotificationProfileManualOverride) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 4} +} + +func (x *AccountRecord_NotificationProfileManualOverride) GetOverride() isAccountRecord_NotificationProfileManualOverride_Override { + if x != nil { + return x.Override + } + return nil +} + +func (x *AccountRecord_NotificationProfileManualOverride) GetDisabledAtTimestampMs() uint64 { + if x != nil { + if x, ok := x.Override.(*AccountRecord_NotificationProfileManualOverride_DisabledAtTimestampMs); ok { + return x.DisabledAtTimestampMs + } + } + return 0 +} + +func (x *AccountRecord_NotificationProfileManualOverride) GetEnabled() *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled { + if x != nil { + if x, ok := x.Override.(*AccountRecord_NotificationProfileManualOverride_Enabled); ok { + return x.Enabled + } + } + return nil +} + +type isAccountRecord_NotificationProfileManualOverride_Override interface { + isAccountRecord_NotificationProfileManualOverride_Override() +} + +type AccountRecord_NotificationProfileManualOverride_DisabledAtTimestampMs struct { + DisabledAtTimestampMs uint64 `protobuf:"varint,1,opt,name=disabledAtTimestampMs,proto3,oneof"` +} + +type AccountRecord_NotificationProfileManualOverride_Enabled struct { + Enabled *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled `protobuf:"bytes,2,opt,name=enabled,proto3,oneof"` +} + +func (*AccountRecord_NotificationProfileManualOverride_DisabledAtTimestampMs) isAccountRecord_NotificationProfileManualOverride_Override() { +} + +func (*AccountRecord_NotificationProfileManualOverride_Enabled) isAccountRecord_NotificationProfileManualOverride_Override() { +} + type AccountRecord_PinnedConversation_Contact struct { state protoimpl.MessageState `protogen:"open.v1"` ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` @@ -2418,7 +2884,7 @@ type AccountRecord_PinnedConversation_Contact struct { func (x *AccountRecord_PinnedConversation_Contact) Reset() { *x = AccountRecord_PinnedConversation_Contact{} - mi := &file_StorageService_proto_msgTypes[20] + mi := &file_StorageService_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2430,7 +2896,7 @@ func (x *AccountRecord_PinnedConversation_Contact) String() string { func (*AccountRecord_PinnedConversation_Contact) ProtoMessage() {} func (x *AccountRecord_PinnedConversation_Contact) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[20] + mi := &file_StorageService_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2460,33 +2926,30 @@ func (x *AccountRecord_PinnedConversation_Contact) GetE164() string { return "" } -type ChatFolderRecord_Recipient struct { +type AccountRecord_NotificationProfileManualOverride_ManuallyEnabled struct { state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Identifier: - // - // *ChatFolderRecord_Recipient_Contact_ - // *ChatFolderRecord_Recipient_LegacyGroupId - // *ChatFolderRecord_Recipient_GroupMasterKey - Identifier isChatFolderRecord_Recipient_Identifier `protobuf_oneof:"identifier"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // This will be unset if no timespan was chosen in the UI. + EndAtTimestampMs uint64 `protobuf:"varint,3,opt,name=endAtTimestampMs,proto3" json:"endAtTimestampMs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *ChatFolderRecord_Recipient) Reset() { - *x = ChatFolderRecord_Recipient{} - mi := &file_StorageService_proto_msgTypes[21] +func (x *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) Reset() { + *x = AccountRecord_NotificationProfileManualOverride_ManuallyEnabled{} + mi := &file_StorageService_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ChatFolderRecord_Recipient) String() string { +func (x *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ChatFolderRecord_Recipient) ProtoMessage() {} +func (*AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) ProtoMessage() {} -func (x *ChatFolderRecord_Recipient) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[21] +func (x *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2497,68 +2960,26 @@ func (x *ChatFolderRecord_Recipient) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ChatFolderRecord_Recipient.ProtoReflect.Descriptor instead. -func (*ChatFolderRecord_Recipient) Descriptor() ([]byte, []int) { - return file_StorageService_proto_rawDescGZIP(), []int{14, 0} +// Deprecated: Use AccountRecord_NotificationProfileManualOverride_ManuallyEnabled.ProtoReflect.Descriptor instead. +func (*AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{11, 4, 0} } -func (x *ChatFolderRecord_Recipient) GetIdentifier() isChatFolderRecord_Recipient_Identifier { +func (x *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) GetId() []byte { if x != nil { - return x.Identifier + return x.Id } return nil } -func (x *ChatFolderRecord_Recipient) GetContact() *ChatFolderRecord_Recipient_Contact { +func (x *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) GetEndAtTimestampMs() uint64 { if x != nil { - if x, ok := x.Identifier.(*ChatFolderRecord_Recipient_Contact_); ok { - return x.Contact - } + return x.EndAtTimestampMs } - return nil + return 0 } -func (x *ChatFolderRecord_Recipient) GetLegacyGroupId() []byte { - if x != nil { - if x, ok := x.Identifier.(*ChatFolderRecord_Recipient_LegacyGroupId); ok { - return x.LegacyGroupId - } - } - return nil -} - -func (x *ChatFolderRecord_Recipient) GetGroupMasterKey() []byte { - if x != nil { - if x, ok := x.Identifier.(*ChatFolderRecord_Recipient_GroupMasterKey); ok { - return x.GroupMasterKey - } - } - return nil -} - -type isChatFolderRecord_Recipient_Identifier interface { - isChatFolderRecord_Recipient_Identifier() -} - -type ChatFolderRecord_Recipient_Contact_ struct { - Contact *ChatFolderRecord_Recipient_Contact `protobuf:"bytes,1,opt,name=contact,proto3,oneof"` -} - -type ChatFolderRecord_Recipient_LegacyGroupId struct { - LegacyGroupId []byte `protobuf:"bytes,2,opt,name=legacyGroupId,proto3,oneof"` -} - -type ChatFolderRecord_Recipient_GroupMasterKey struct { - GroupMasterKey []byte `protobuf:"bytes,3,opt,name=groupMasterKey,proto3,oneof"` -} - -func (*ChatFolderRecord_Recipient_Contact_) isChatFolderRecord_Recipient_Identifier() {} - -func (*ChatFolderRecord_Recipient_LegacyGroupId) isChatFolderRecord_Recipient_Identifier() {} - -func (*ChatFolderRecord_Recipient_GroupMasterKey) isChatFolderRecord_Recipient_Identifier() {} - -type ChatFolderRecord_Recipient_Contact struct { +type Recipient_Contact struct { state protoimpl.MessageState `protogen:"open.v1"` ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` @@ -2566,21 +2987,21 @@ type ChatFolderRecord_Recipient_Contact struct { sizeCache protoimpl.SizeCache } -func (x *ChatFolderRecord_Recipient_Contact) Reset() { - *x = ChatFolderRecord_Recipient_Contact{} - mi := &file_StorageService_proto_msgTypes[22] +func (x *Recipient_Contact) Reset() { + *x = Recipient_Contact{} + mi := &file_StorageService_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ChatFolderRecord_Recipient_Contact) String() string { +func (x *Recipient_Contact) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ChatFolderRecord_Recipient_Contact) ProtoMessage() {} +func (*Recipient_Contact) ProtoMessage() {} -func (x *ChatFolderRecord_Recipient_Contact) ProtoReflect() protoreflect.Message { - mi := &file_StorageService_proto_msgTypes[22] +func (x *Recipient_Contact) ProtoReflect() protoreflect.Message { + mi := &file_StorageService_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2591,19 +3012,19 @@ func (x *ChatFolderRecord_Recipient_Contact) ProtoReflect() protoreflect.Message return mi.MessageOf(x) } -// Deprecated: Use ChatFolderRecord_Recipient_Contact.ProtoReflect.Descriptor instead. -func (*ChatFolderRecord_Recipient_Contact) Descriptor() ([]byte, []int) { - return file_StorageService_proto_rawDescGZIP(), []int{14, 0, 0} +// Deprecated: Use Recipient_Contact.ProtoReflect.Descriptor instead. +func (*Recipient_Contact) Descriptor() ([]byte, []int) { + return file_StorageService_proto_rawDescGZIP(), []int{14, 0} } -func (x *ChatFolderRecord_Recipient_Contact) GetServiceId() string { +func (x *Recipient_Contact) GetServiceId() string { if x != nil { return x.ServiceId } return "" } -func (x *ChatFolderRecord_Recipient_Contact) GetE164() string { +func (x *Recipient_Contact) GetE164() string { if x != nil { return x.E164 } @@ -2631,16 +3052,16 @@ const file_StorageService_proto_rawDesc = "" + "insertItem\x18\x02 \x03(\v2\x1a.signalservice.StorageItemR\n" + "insertItem\x12\x1c\n" + "\tdeleteKey\x18\x03 \x03(\fR\tdeleteKey\x12\x1a\n" + - "\bclearAll\x18\x04 \x01(\bR\bclearAll\"\xa3\x03\n" + + "\bclearAll\x18\x04 \x01(\bR\bclearAll\"\xbd\x03\n" + "\x0eManifestRecord\x12\x18\n" + "\aversion\x18\x01 \x01(\x04R\aversion\x12\"\n" + "\fsourceDevice\x18\x03 \x01(\rR\fsourceDevice\x12J\n" + "\videntifiers\x18\x02 \x03(\v2(.signalservice.ManifestRecord.IdentifierR\videntifiers\x12\x1c\n" + - "\trecordIkm\x18\x04 \x01(\fR\trecordIkm\x1a\xe8\x01\n" + + "\trecordIkm\x18\x04 \x01(\fR\trecordIkm\x1a\x82\x02\n" + "\n" + "Identifier\x12\x10\n" + "\x03raw\x18\x01 \x01(\fR\x03raw\x12A\n" + - "\x04type\x18\x02 \x01(\x0e2-.signalservice.ManifestRecord.Identifier.TypeR\x04type\"\x84\x01\n" + + "\x04type\x18\x02 \x01(\x0e2-.signalservice.ManifestRecord.Identifier.TypeR\x04type\"\x9e\x01\n" + "\x04Type\x12\v\n" + "\aUNKNOWN\x10\x00\x12\v\n" + "\aCONTACT\x10\x01\x12\v\n" + @@ -2649,7 +3070,8 @@ const file_StorageService_proto_rawDesc = "" + "\aACCOUNT\x10\x04\x12\x1b\n" + "\x17STORY_DISTRIBUTION_LIST\x10\x05\x12\r\n" + "\tCALL_LINK\x10\a\x12\x0f\n" + - "\vCHAT_FOLDER\x10\b\"\xe5\x03\n" + + "\vCHAT_FOLDER\x10\b\x12\x18\n" + + "\x14NOTIFICATION_PROFILE\x10\t\"\xbd\x04\n" + "\rStorageRecord\x128\n" + "\acontact\x18\x01 \x01(\v2\x1c.signalservice.ContactRecordH\x00R\acontact\x128\n" + "\agroupV1\x18\x02 \x01(\v2\x1c.signalservice.GroupV1RecordH\x00R\agroupV1\x128\n" + @@ -2659,7 +3081,8 @@ const file_StorageService_proto_rawDesc = "" + "\bcallLink\x18\a \x01(\v2\x1d.signalservice.CallLinkRecordH\x00R\bcallLink\x12A\n" + "\n" + "chatFolder\x18\b \x01(\v2\x1f.signalservice.ChatFolderRecordH\x00R\n" + - "chatFolderB\b\n" + + "chatFolder\x12V\n" + + "\x13notificationProfile\x18\t \x01(\v2\".signalservice.NotificationProfileH\x00R\x13notificationProfileB\b\n" + "\x06record\"\x9d\b\n" + "\rContactRecord\x12\x10\n" + "\x03aci\x18\x01 \x01(\tR\x03aci\x12\x12\n" + @@ -2727,7 +3150,7 @@ const file_StorageService_proto_rawDesc = "" + "\">\n" + "\bPayments\x12\x18\n" + "\aenabled\x18\x01 \x01(\bR\aenabled\x12\x18\n" + - "\aentropy\x18\x02 \x01(\fR\aentropy\"\xf7\x15\n" + + "\aentropy\x18\x02 \x01(\fR\aentropy\"\x8b\x1b\n" + "\rAccountRecord\x12\x1e\n" + "\n" + "profileKey\x18\x01 \x01(\fR\n" + @@ -2750,8 +3173,7 @@ const file_StorageService_proto_rawDesc = "" + "\x14preferContactAvatars\x18\x0f \x01(\bR\x14preferContactAvatars\x123\n" + "\bpayments\x18\x10 \x01(\v2\x17.signalservice.PaymentsR\bpayments\x122\n" + "\x14universalExpireTimer\x18\x11 \x01(\rR\x14universalExpireTimer\x12(\n" + - "\x0fprimarySendsSms\x18\x12 \x01(\bR\x0fprimarySendsSms\x12\x12\n" + - "\x04e164\x18\x13 \x01(\tR\x04e164\x126\n" + + "\x0fprimarySendsSms\x18\x12 \x01(\bR\x0fprimarySendsSms\x126\n" + "\x16preferredReactionEmoji\x18\x14 \x03(\tR\x16preferredReactionEmoji\x12\"\n" + "\fsubscriberId\x18\x15 \x01(\fR\fsubscriberId\x126\n" + "\x16subscriberCurrencyCode\x18\x16 \x01(\tR\x16subscriberCurrencyCode\x126\n" + @@ -2771,7 +3193,9 @@ const file_StorageService_proto_rawDesc = "" + "backupTier\x18( \x01(\x04H\x01R\n" + "backupTier\x88\x01\x01\x12b\n" + "\x14backupSubscriberData\x18) \x01(\v2..signalservice.AccountRecord.IAPSubscriberDataR\x14backupSubscriberData\x12A\n" + - "\vavatarColor\x18* \x01(\x0e2\x1a.signalservice.AvatarColorH\x02R\vavatarColor\x88\x01\x01\x1a\x86\x02\n" + + "\vavatarColor\x18* \x01(\x0e2\x1a.signalservice.AvatarColorH\x02R\vavatarColor\x88\x01\x01\x12\\\n" + + "\x11backupTierHistory\x18+ \x01(\v2..signalservice.AccountRecord.BackupTierHistoryR\x11backupTierHistory\x12\x8c\x01\n" + + "!notificationProfileManualOverride\x18, \x01(\v2>.signalservice.AccountRecord.NotificationProfileManualOverrideR!notificationProfileManualOverride\x1a\x86\x02\n" + "\x12PinnedConversation\x12S\n" + "\acontact\x18\x01 \x01(\v27.signalservice.AccountRecord.PinnedConversation.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x03 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + @@ -2801,7 +3225,22 @@ const file_StorageService_proto_rawDesc = "" + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12&\n" + "\rpurchaseToken\x18\x02 \x01(\tH\x00R\rpurchaseToken\x126\n" + "\x15originalTransactionId\x18\x03 \x01(\x04H\x00R\x15originalTransactionIdB\x13\n" + - "\x11iapSubscriptionId\"@\n" + + "\x11iapSubscriptionId\x1a\x8d\x01\n" + + "\x11BackupTierHistory\x12#\n" + + "\n" + + "backupTier\x18\x01 \x01(\x04H\x00R\n" + + "backupTier\x88\x01\x01\x12/\n" + + "\x10endedAtTimestamp\x18\x02 \x01(\x04H\x01R\x10endedAtTimestamp\x88\x01\x01B\r\n" + + "\v_backupTierB\x13\n" + + "\x11_endedAtTimestamp\x1a\xa2\x02\n" + + "!NotificationProfileManualOverride\x126\n" + + "\x15disabledAtTimestampMs\x18\x01 \x01(\x04H\x00R\x15disabledAtTimestampMs\x12j\n" + + "\aenabled\x18\x02 \x01(\v2N.signalservice.AccountRecord.NotificationProfileManualOverride.ManuallyEnabledH\x00R\aenabled\x1aM\n" + + "\x0fManuallyEnabled\x12\x0e\n" + + "\x02id\x18\x01 \x01(\fR\x02id\x12*\n" + + "\x10endAtTimestampMs\x18\x03 \x01(\x04R\x10endAtTimestampMsB\n" + + "\n" + + "\boverride\"@\n" + "\x16PhoneNumberSharingMode\x12\v\n" + "\aUNKNOWN\x10\x00\x12\r\n" + "\tEVERYBODY\x10\x01\x12\n" + @@ -2811,7 +3250,7 @@ const file_StorageService_proto_rawDesc = "" + "_hasBackupB\r\n" + "\v_backupTierB\x0e\n" + "\f_avatarColorJ\x04\b\t\x10\n" + - "J\x04\b\x1c\x10\x1dJ\x04\b\x1f\x10 J\x04\b$\x10%J\x04\b%\x10&J\x04\b&\x10'\"\xfb\x01\n" + + "J\x04\b\x13\x10\x14J\x04\b\x1c\x10\x1dJ\x04\b\x1f\x10 J\x04\b$\x10%J\x04\b%\x10&J\x04\b&\x10'\"\xfb\x01\n" + "\x1bStoryDistributionListRecord\x12\x1e\n" + "\n" + "identifier\x18\x01 \x01(\fR\n" + @@ -2824,7 +3263,16 @@ const file_StorageService_proto_rawDesc = "" + "\x0eCallLinkRecord\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + - "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\"\x84\a\n" + + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\"\xe6\x01\n" + + "\tRecipient\x12<\n" + + "\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" + + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + + "\x0egroupMasterKey\x18\x03 \x01(\fH\x00R\x0egroupMasterKey\x1a;\n" + + "\aContact\x12\x1c\n" + + "\tserviceId\x18\x01 \x01(\tR\tserviceId\x12\x12\n" + + "\x04e164\x18\x02 \x01(\tR\x04e164B\f\n" + + "\n" + + "identifier\"\xe8\x04\n" + "\x10ChatFolderRecord\x12\x1e\n" + "\n" + "identifier\x18\x01 \x01(\fR\n" + @@ -2837,26 +3285,45 @@ const file_StorageService_proto_rawDesc = "" + "\x14includeAllGroupChats\x18\a \x01(\bR\x14includeAllGroupChats\x12J\n" + "\n" + "folderType\x18\b \x01(\x0e2*.signalservice.ChatFolderRecord.FolderTypeR\n" + - "folderType\x12Y\n" + - "\x12includedRecipients\x18\t \x03(\v2).signalservice.ChatFolderRecord.RecipientR\x12includedRecipients\x12Y\n" + + "folderType\x12H\n" + + "\x12includedRecipients\x18\t \x03(\v2\x18.signalservice.RecipientR\x12includedRecipients\x12H\n" + "\x12excludedRecipients\x18\n" + - " \x03(\v2).signalservice.ChatFolderRecord.RecipientR\x12excludedRecipients\x122\n" + - "\x14deletedAtTimestampMs\x18\v \x01(\x04R\x14deletedAtTimestampMs\x1a\xf7\x01\n" + - "\tRecipient\x12M\n" + - "\acontact\x18\x01 \x01(\v21.signalservice.ChatFolderRecord.Recipient.ContactH\x00R\acontact\x12&\n" + - "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + - "\x0egroupMasterKey\x18\x03 \x01(\fH\x00R\x0egroupMasterKey\x1a;\n" + - "\aContact\x12\x1c\n" + - "\tserviceId\x18\x01 \x01(\tR\tserviceId\x12\x12\n" + - "\x04e164\x18\x02 \x01(\tR\x04e164B\f\n" + - "\n" + - "identifier\".\n" + + " \x03(\v2\x18.signalservice.RecipientR\x12excludedRecipients\x122\n" + + "\x14deletedAtTimestampMs\x18\v \x01(\x04R\x14deletedAtTimestampMs\".\n" + "\n" + "FolderType\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ALL\x10\x01\x12\n" + "\n" + - "\x06CUSTOM\x10\x02*4\n" + + "\x06CUSTOM\x10\x02\"\xb6\x05\n" + + "\x13NotificationProfile\x12\x0e\n" + + "\x02id\x18\x01 \x01(\fR\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x19\n" + + "\x05emoji\x18\x03 \x01(\tH\x00R\x05emoji\x88\x01\x01\x12\x14\n" + + "\x05color\x18\x04 \x01(\aR\x05color\x12 \n" + + "\vcreatedAtMs\x18\x05 \x01(\x04R\vcreatedAtMs\x12$\n" + + "\rallowAllCalls\x18\x06 \x01(\bR\rallowAllCalls\x12*\n" + + "\x10allowAllMentions\x18\a \x01(\bR\x10allowAllMentions\x12@\n" + + "\x0eallowedMembers\x18\b \x03(\v2\x18.signalservice.RecipientR\x0eallowedMembers\x12(\n" + + "\x0fscheduleEnabled\x18\t \x01(\bR\x0fscheduleEnabled\x12,\n" + + "\x11scheduleStartTime\x18\n" + + " \x01(\rR\x11scheduleStartTime\x12(\n" + + "\x0fscheduleEndTime\x18\v \x01(\rR\x0fscheduleEndTime\x12^\n" + + "\x13scheduleDaysEnabled\x18\f \x03(\x0e2,.signalservice.NotificationProfile.DayOfWeekR\x13scheduleDaysEnabled\x122\n" + + "\x14deletedAtTimestampMs\x18\r \x01(\x04R\x14deletedAtTimestampMs\"t\n" + + "\tDayOfWeek\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\n" + + "\n" + + "\x06MONDAY\x10\x01\x12\v\n" + + "\aTUESDAY\x10\x02\x12\r\n" + + "\tWEDNESDAY\x10\x03\x12\f\n" + + "\bTHURSDAY\x10\x04\x12\n" + + "\n" + + "\x06FRIDAY\x10\x05\x12\f\n" + + "\bSATURDAY\x10\x06\x12\n" + + "\n" + + "\x06SUNDAY\x10\aB\b\n" + + "\x06_emoji*4\n" + "\fOptionalBool\x12\t\n" + "\x05UNSET\x10\x00\x12\v\n" + "\aENABLED\x10\x01\x12\f\n" + @@ -2889,77 +3356,88 @@ func file_StorageService_proto_rawDescGZIP() []byte { return file_StorageService_proto_rawDescData } -var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_StorageService_proto_enumTypes = make([]protoimpl.EnumInfo, 9) +var file_StorageService_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_StorageService_proto_goTypes = []any{ - (OptionalBool)(0), // 0: signalservice.OptionalBool - (AvatarColor)(0), // 1: signalservice.AvatarColor - (ManifestRecord_Identifier_Type)(0), // 2: signalservice.ManifestRecord.Identifier.Type - (ContactRecord_IdentityState)(0), // 3: signalservice.ContactRecord.IdentityState - (GroupV2Record_StorySendMode)(0), // 4: signalservice.GroupV2Record.StorySendMode - (AccountRecord_PhoneNumberSharingMode)(0), // 5: signalservice.AccountRecord.PhoneNumberSharingMode - (AccountRecord_UsernameLink_Color)(0), // 6: signalservice.AccountRecord.UsernameLink.Color - (ChatFolderRecord_FolderType)(0), // 7: signalservice.ChatFolderRecord.FolderType - (*StorageManifest)(nil), // 8: signalservice.StorageManifest - (*StorageItem)(nil), // 9: signalservice.StorageItem - (*StorageItems)(nil), // 10: signalservice.StorageItems - (*ReadOperation)(nil), // 11: signalservice.ReadOperation - (*WriteOperation)(nil), // 12: signalservice.WriteOperation - (*ManifestRecord)(nil), // 13: signalservice.ManifestRecord - (*StorageRecord)(nil), // 14: signalservice.StorageRecord - (*ContactRecord)(nil), // 15: signalservice.ContactRecord - (*GroupV1Record)(nil), // 16: signalservice.GroupV1Record - (*GroupV2Record)(nil), // 17: signalservice.GroupV2Record - (*Payments)(nil), // 18: signalservice.Payments - (*AccountRecord)(nil), // 19: signalservice.AccountRecord - (*StoryDistributionListRecord)(nil), // 20: signalservice.StoryDistributionListRecord - (*CallLinkRecord)(nil), // 21: signalservice.CallLinkRecord - (*ChatFolderRecord)(nil), // 22: signalservice.ChatFolderRecord - (*ManifestRecord_Identifier)(nil), // 23: signalservice.ManifestRecord.Identifier - (*ContactRecord_Name)(nil), // 24: signalservice.ContactRecord.Name - (*AccountRecord_PinnedConversation)(nil), // 25: signalservice.AccountRecord.PinnedConversation - (*AccountRecord_UsernameLink)(nil), // 26: signalservice.AccountRecord.UsernameLink - (*AccountRecord_IAPSubscriberData)(nil), // 27: signalservice.AccountRecord.IAPSubscriberData - (*AccountRecord_PinnedConversation_Contact)(nil), // 28: signalservice.AccountRecord.PinnedConversation.Contact - (*ChatFolderRecord_Recipient)(nil), // 29: signalservice.ChatFolderRecord.Recipient - (*ChatFolderRecord_Recipient_Contact)(nil), // 30: signalservice.ChatFolderRecord.Recipient.Contact + (OptionalBool)(0), // 0: signalservice.OptionalBool + (AvatarColor)(0), // 1: signalservice.AvatarColor + (ManifestRecord_Identifier_Type)(0), // 2: signalservice.ManifestRecord.Identifier.Type + (ContactRecord_IdentityState)(0), // 3: signalservice.ContactRecord.IdentityState + (GroupV2Record_StorySendMode)(0), // 4: signalservice.GroupV2Record.StorySendMode + (AccountRecord_PhoneNumberSharingMode)(0), // 5: signalservice.AccountRecord.PhoneNumberSharingMode + (AccountRecord_UsernameLink_Color)(0), // 6: signalservice.AccountRecord.UsernameLink.Color + (ChatFolderRecord_FolderType)(0), // 7: signalservice.ChatFolderRecord.FolderType + (NotificationProfile_DayOfWeek)(0), // 8: signalservice.NotificationProfile.DayOfWeek + (*StorageManifest)(nil), // 9: signalservice.StorageManifest + (*StorageItem)(nil), // 10: signalservice.StorageItem + (*StorageItems)(nil), // 11: signalservice.StorageItems + (*ReadOperation)(nil), // 12: signalservice.ReadOperation + (*WriteOperation)(nil), // 13: signalservice.WriteOperation + (*ManifestRecord)(nil), // 14: signalservice.ManifestRecord + (*StorageRecord)(nil), // 15: signalservice.StorageRecord + (*ContactRecord)(nil), // 16: signalservice.ContactRecord + (*GroupV1Record)(nil), // 17: signalservice.GroupV1Record + (*GroupV2Record)(nil), // 18: signalservice.GroupV2Record + (*Payments)(nil), // 19: signalservice.Payments + (*AccountRecord)(nil), // 20: signalservice.AccountRecord + (*StoryDistributionListRecord)(nil), // 21: signalservice.StoryDistributionListRecord + (*CallLinkRecord)(nil), // 22: signalservice.CallLinkRecord + (*Recipient)(nil), // 23: signalservice.Recipient + (*ChatFolderRecord)(nil), // 24: signalservice.ChatFolderRecord + (*NotificationProfile)(nil), // 25: signalservice.NotificationProfile + (*ManifestRecord_Identifier)(nil), // 26: signalservice.ManifestRecord.Identifier + (*ContactRecord_Name)(nil), // 27: signalservice.ContactRecord.Name + (*AccountRecord_PinnedConversation)(nil), // 28: signalservice.AccountRecord.PinnedConversation + (*AccountRecord_UsernameLink)(nil), // 29: signalservice.AccountRecord.UsernameLink + (*AccountRecord_IAPSubscriberData)(nil), // 30: signalservice.AccountRecord.IAPSubscriberData + (*AccountRecord_BackupTierHistory)(nil), // 31: signalservice.AccountRecord.BackupTierHistory + (*AccountRecord_NotificationProfileManualOverride)(nil), // 32: signalservice.AccountRecord.NotificationProfileManualOverride + (*AccountRecord_PinnedConversation_Contact)(nil), // 33: signalservice.AccountRecord.PinnedConversation.Contact + (*AccountRecord_NotificationProfileManualOverride_ManuallyEnabled)(nil), // 34: signalservice.AccountRecord.NotificationProfileManualOverride.ManuallyEnabled + (*Recipient_Contact)(nil), // 35: signalservice.Recipient.Contact } var file_StorageService_proto_depIdxs = []int32{ - 9, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem - 8, // 1: signalservice.WriteOperation.manifest:type_name -> signalservice.StorageManifest - 9, // 2: signalservice.WriteOperation.insertItem:type_name -> signalservice.StorageItem - 23, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier - 15, // 4: signalservice.StorageRecord.contact:type_name -> signalservice.ContactRecord - 16, // 5: signalservice.StorageRecord.groupV1:type_name -> signalservice.GroupV1Record - 17, // 6: signalservice.StorageRecord.groupV2:type_name -> signalservice.GroupV2Record - 19, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord - 20, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord - 21, // 9: signalservice.StorageRecord.callLink:type_name -> signalservice.CallLinkRecord - 22, // 10: signalservice.StorageRecord.chatFolder:type_name -> signalservice.ChatFolderRecord - 3, // 11: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState - 24, // 12: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name - 1, // 13: signalservice.ContactRecord.avatarColor:type_name -> signalservice.AvatarColor - 4, // 14: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode - 1, // 15: signalservice.GroupV2Record.avatarColor:type_name -> signalservice.AvatarColor - 5, // 16: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode - 25, // 17: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation - 18, // 18: signalservice.AccountRecord.payments:type_name -> signalservice.Payments - 0, // 19: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool - 26, // 20: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink - 27, // 21: signalservice.AccountRecord.backupSubscriberData:type_name -> signalservice.AccountRecord.IAPSubscriberData - 1, // 22: signalservice.AccountRecord.avatarColor:type_name -> signalservice.AvatarColor - 7, // 23: signalservice.ChatFolderRecord.folderType:type_name -> signalservice.ChatFolderRecord.FolderType - 29, // 24: signalservice.ChatFolderRecord.includedRecipients:type_name -> signalservice.ChatFolderRecord.Recipient - 29, // 25: signalservice.ChatFolderRecord.excludedRecipients:type_name -> signalservice.ChatFolderRecord.Recipient - 2, // 26: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type - 28, // 27: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact - 6, // 28: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color - 30, // 29: signalservice.ChatFolderRecord.Recipient.contact:type_name -> signalservice.ChatFolderRecord.Recipient.Contact - 30, // [30:30] is the sub-list for method output_type - 30, // [30:30] is the sub-list for method input_type - 30, // [30:30] is the sub-list for extension type_name - 30, // [30:30] is the sub-list for extension extendee - 0, // [0:30] is the sub-list for field type_name + 10, // 0: signalservice.StorageItems.items:type_name -> signalservice.StorageItem + 9, // 1: signalservice.WriteOperation.manifest:type_name -> signalservice.StorageManifest + 10, // 2: signalservice.WriteOperation.insertItem:type_name -> signalservice.StorageItem + 26, // 3: signalservice.ManifestRecord.identifiers:type_name -> signalservice.ManifestRecord.Identifier + 16, // 4: signalservice.StorageRecord.contact:type_name -> signalservice.ContactRecord + 17, // 5: signalservice.StorageRecord.groupV1:type_name -> signalservice.GroupV1Record + 18, // 6: signalservice.StorageRecord.groupV2:type_name -> signalservice.GroupV2Record + 20, // 7: signalservice.StorageRecord.account:type_name -> signalservice.AccountRecord + 21, // 8: signalservice.StorageRecord.storyDistributionList:type_name -> signalservice.StoryDistributionListRecord + 22, // 9: signalservice.StorageRecord.callLink:type_name -> signalservice.CallLinkRecord + 24, // 10: signalservice.StorageRecord.chatFolder:type_name -> signalservice.ChatFolderRecord + 25, // 11: signalservice.StorageRecord.notificationProfile:type_name -> signalservice.NotificationProfile + 3, // 12: signalservice.ContactRecord.identityState:type_name -> signalservice.ContactRecord.IdentityState + 27, // 13: signalservice.ContactRecord.nickname:type_name -> signalservice.ContactRecord.Name + 1, // 14: signalservice.ContactRecord.avatarColor:type_name -> signalservice.AvatarColor + 4, // 15: signalservice.GroupV2Record.storySendMode:type_name -> signalservice.GroupV2Record.StorySendMode + 1, // 16: signalservice.GroupV2Record.avatarColor:type_name -> signalservice.AvatarColor + 5, // 17: signalservice.AccountRecord.phoneNumberSharingMode:type_name -> signalservice.AccountRecord.PhoneNumberSharingMode + 28, // 18: signalservice.AccountRecord.pinnedConversations:type_name -> signalservice.AccountRecord.PinnedConversation + 19, // 19: signalservice.AccountRecord.payments:type_name -> signalservice.Payments + 0, // 20: signalservice.AccountRecord.storyViewReceiptsEnabled:type_name -> signalservice.OptionalBool + 29, // 21: signalservice.AccountRecord.usernameLink:type_name -> signalservice.AccountRecord.UsernameLink + 30, // 22: signalservice.AccountRecord.backupSubscriberData:type_name -> signalservice.AccountRecord.IAPSubscriberData + 1, // 23: signalservice.AccountRecord.avatarColor:type_name -> signalservice.AvatarColor + 31, // 24: signalservice.AccountRecord.backupTierHistory:type_name -> signalservice.AccountRecord.BackupTierHistory + 32, // 25: signalservice.AccountRecord.notificationProfileManualOverride:type_name -> signalservice.AccountRecord.NotificationProfileManualOverride + 35, // 26: signalservice.Recipient.contact:type_name -> signalservice.Recipient.Contact + 7, // 27: signalservice.ChatFolderRecord.folderType:type_name -> signalservice.ChatFolderRecord.FolderType + 23, // 28: signalservice.ChatFolderRecord.includedRecipients:type_name -> signalservice.Recipient + 23, // 29: signalservice.ChatFolderRecord.excludedRecipients:type_name -> signalservice.Recipient + 23, // 30: signalservice.NotificationProfile.allowedMembers:type_name -> signalservice.Recipient + 8, // 31: signalservice.NotificationProfile.scheduleDaysEnabled:type_name -> signalservice.NotificationProfile.DayOfWeek + 2, // 32: signalservice.ManifestRecord.Identifier.type:type_name -> signalservice.ManifestRecord.Identifier.Type + 33, // 33: signalservice.AccountRecord.PinnedConversation.contact:type_name -> signalservice.AccountRecord.PinnedConversation.Contact + 6, // 34: signalservice.AccountRecord.UsernameLink.color:type_name -> signalservice.AccountRecord.UsernameLink.Color + 34, // 35: signalservice.AccountRecord.NotificationProfileManualOverride.enabled:type_name -> signalservice.AccountRecord.NotificationProfileManualOverride.ManuallyEnabled + 36, // [36:36] is the sub-list for method output_type + 36, // [36:36] is the sub-list for method input_type + 36, // [36:36] is the sub-list for extension type_name + 36, // [36:36] is the sub-list for extension extendee + 0, // [0:36] is the sub-list for field type_name } func init() { file_StorageService_proto_init() } @@ -2975,31 +3453,38 @@ func file_StorageService_proto_init() { (*StorageRecord_StoryDistributionList)(nil), (*StorageRecord_CallLink)(nil), (*StorageRecord_ChatFolder)(nil), + (*StorageRecord_NotificationProfile)(nil), } file_StorageService_proto_msgTypes[7].OneofWrappers = []any{} file_StorageService_proto_msgTypes[9].OneofWrappers = []any{} file_StorageService_proto_msgTypes[11].OneofWrappers = []any{} - file_StorageService_proto_msgTypes[17].OneofWrappers = []any{ + file_StorageService_proto_msgTypes[14].OneofWrappers = []any{ + (*Recipient_Contact_)(nil), + (*Recipient_LegacyGroupId)(nil), + (*Recipient_GroupMasterKey)(nil), + } + file_StorageService_proto_msgTypes[16].OneofWrappers = []any{} + file_StorageService_proto_msgTypes[19].OneofWrappers = []any{ (*AccountRecord_PinnedConversation_Contact_)(nil), (*AccountRecord_PinnedConversation_LegacyGroupId)(nil), (*AccountRecord_PinnedConversation_GroupMasterKey)(nil), } - file_StorageService_proto_msgTypes[19].OneofWrappers = []any{ + file_StorageService_proto_msgTypes[21].OneofWrappers = []any{ (*AccountRecord_IAPSubscriberData_PurchaseToken)(nil), (*AccountRecord_IAPSubscriberData_OriginalTransactionId)(nil), } - file_StorageService_proto_msgTypes[21].OneofWrappers = []any{ - (*ChatFolderRecord_Recipient_Contact_)(nil), - (*ChatFolderRecord_Recipient_LegacyGroupId)(nil), - (*ChatFolderRecord_Recipient_GroupMasterKey)(nil), + file_StorageService_proto_msgTypes[22].OneofWrappers = []any{} + file_StorageService_proto_msgTypes[23].OneofWrappers = []any{ + (*AccountRecord_NotificationProfileManualOverride_DisabledAtTimestampMs)(nil), + (*AccountRecord_NotificationProfileManualOverride_Enabled)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_StorageService_proto_rawDesc), len(file_StorageService_proto_rawDesc)), - NumEnums: 8, - NumMessages: 23, + NumEnums: 9, + NumMessages: 27, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index de8517f..eaa1453 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -52,6 +52,7 @@ message ManifestRecord { STORY_DISTRIBUTION_LIST = 5; CALL_LINK = 7; CHAT_FOLDER = 8; + NOTIFICATION_PROFILE = 9; } bytes raw = 1; @@ -74,6 +75,7 @@ message StorageRecord { StoryDistributionListRecord storyDistributionList = 5; CallLinkRecord callLink = 7; ChatFolderRecord chatFolder = 8; + NotificationProfile notificationProfile = 9; } } @@ -225,48 +227,70 @@ message AccountRecord { } } - bytes profileKey = 1; - string givenName = 2; - string familyName = 3; - string avatarUrlPath = 4; - bool noteToSelfArchived = 5; - bool readReceipts = 6; - bool sealedSenderIndicators = 7; - bool typingIndicators = 8; - reserved /* proxiedLinkPreviews */ 9; - bool noteToSelfMarkedUnread = 10; - bool linkPreviews = 11; - PhoneNumberSharingMode phoneNumberSharingMode = 12; - bool unlistedPhoneNumber = 13; - repeated PinnedConversation pinnedConversations = 14; - bool preferContactAvatars = 15; - Payments payments = 16; - uint32 universalExpireTimer = 17; - bool primarySendsSms = 18; - string e164 = 19; - repeated string preferredReactionEmoji = 20; - bytes subscriberId = 21; - string subscriberCurrencyCode = 22; - bool displayBadgesOnProfile = 23; - bool subscriptionManuallyCancelled = 24; - bool keepMutedChatsArchived = 25; - bool hasSetMyStoriesPrivacy = 26; - bool hasViewedOnboardingStory = 27; - reserved /* storiesDisabled */ 28; - bool storiesDisabled = 29; - OptionalBool storyViewReceiptsEnabled = 30; - reserved /* hasReadOnboardingStory */ 31; - bool hasSeenGroupStoryEducationSheet = 32; - string username = 33; - bool hasCompletedUsernameOnboarding = 34; - UsernameLink usernameLink = 35; - reserved /* backupsSubscriberId */ 36; - reserved /* backupsSubscriberCurrencyCode */ 37; - reserved /* backupsSubscriptionManuallyCancelled */ 38; - optional bool hasBackup = 39; // Set to true after backups are enabled and one is uploaded. - optional uint64 backupTier = 40; // See zkgroup for integer particular values - IAPSubscriberData backupSubscriberData = 41; - optional AvatarColor avatarColor = 42; + message BackupTierHistory { + // See zkgroup for integer particular values. Unset if backups are not enabled. + optional uint64 backupTier = 1; + optional uint64 endedAtTimestamp = 2; + } + + message NotificationProfileManualOverride { + message ManuallyEnabled { + bytes id = 1; + + // This will be unset if no timespan was chosen in the UI. + uint64 endAtTimestampMs = 3; + } + + oneof override { + uint64 disabledAtTimestampMs = 1; + ManuallyEnabled enabled = 2; + } + } + + bytes profileKey = 1; + string givenName = 2; + string familyName = 3; + string avatarUrlPath = 4; + bool noteToSelfArchived = 5; + bool readReceipts = 6; + bool sealedSenderIndicators = 7; + bool typingIndicators = 8; + reserved /* proxiedLinkPreviews */ 9; + bool noteToSelfMarkedUnread = 10; + bool linkPreviews = 11; + PhoneNumberSharingMode phoneNumberSharingMode = 12; + bool unlistedPhoneNumber = 13; + repeated PinnedConversation pinnedConversations = 14; + bool preferContactAvatars = 15; + Payments payments = 16; + uint32 universalExpireTimer = 17; + bool primarySendsSms = 18; + reserved /* e164 */ 19; + repeated string preferredReactionEmoji = 20; + bytes subscriberId = 21; + string subscriberCurrencyCode = 22; + bool displayBadgesOnProfile = 23; + bool subscriptionManuallyCancelled = 24; + bool keepMutedChatsArchived = 25; + bool hasSetMyStoriesPrivacy = 26; + bool hasViewedOnboardingStory = 27; + reserved /* storiesDisabled */ 28; + bool storiesDisabled = 29; + OptionalBool storyViewReceiptsEnabled = 30; + reserved /* hasReadOnboardingStory */ 31; + bool hasSeenGroupStoryEducationSheet = 32; + string username = 33; + bool hasCompletedUsernameOnboarding = 34; + UsernameLink usernameLink = 35; + reserved /* backupsSubscriberId */ 36; + reserved /* backupsSubscriberCurrencyCode */ 37; + reserved /* backupsSubscriptionManuallyCancelled */ 38; + optional bool hasBackup = 39; // Set to true after backups are enabled and one is uploaded. + optional uint64 backupTier = 40; // See zkgroup for integer particular values. Unset if backups are not enabled. + IAPSubscriberData backupSubscriberData = 41; + optional AvatarColor avatarColor = 42; + BackupTierHistory backupTierHistory = 43; + NotificationProfileManualOverride notificationProfileManualOverride = 44; } message StoryDistributionListRecord { @@ -284,20 +308,20 @@ message CallLinkRecord { uint64 deletedAtTimestampMs = 3; } -message ChatFolderRecord { - message Recipient { - message Contact { - string serviceId = 1; - string e164 = 2; - } - - oneof identifier { - Contact contact = 1; - bytes legacyGroupId = 2; - bytes groupMasterKey = 3; - } +message Recipient { + message Contact { + string serviceId = 1; + string e164 = 2; } + oneof identifier { + Contact contact = 1; + bytes legacyGroupId = 2; + bytes groupMasterKey = 3; + } +} + +message ChatFolderRecord { // Represents the default "All chats" folder record vs all other custom folders enum FolderType { UNKNOWN = 0; @@ -317,3 +341,30 @@ message ChatFolderRecord { repeated Recipient excludedRecipients = 10; uint64 deletedAtTimestampMs = 11; // When non-zero, `position` should be set to -1 and includedRecipients should be empty } + +message NotificationProfile { + enum DayOfWeek { + UNKNOWN = 0; // Interpret as "Monday" + MONDAY = 1; + TUESDAY = 2; + WEDNESDAY = 3; + THURSDAY = 4; + FRIDAY = 5; + SATURDAY = 6; + SUNDAY = 7; + } + + bytes id = 1; + string name = 2; + optional string emoji = 3; + fixed32 color = 4; // 0xAARRGGBB + uint64 createdAtMs = 5; + bool allowAllCalls = 6; + bool allowAllMentions = 7; + repeated Recipient allowedMembers = 8; + bool scheduleEnabled = 9; + uint32 scheduleStartTime = 10; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + uint32 scheduleEndTime = 11; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) + repeated DayOfWeek scheduleDaysEnabled = 12; + uint64 deletedAtTimestampMs = 13; +} diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index adc1e3f..bb5b256 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -27,8 +27,10 @@ const ( type UnidentifiedSenderMessage_Message_Type int32 const ( - UnidentifiedSenderMessage_Message_PREKEY_MESSAGE UnidentifiedSenderMessage_Message_Type = 1 - UnidentifiedSenderMessage_Message_MESSAGE UnidentifiedSenderMessage_Message_Type = 2 // Further cases should line up with Envelope.Type, even though old cases don't. + // 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 ) @@ -36,14 +38,14 @@ const ( // Enum value maps for UnidentifiedSenderMessage_Message_Type. var ( UnidentifiedSenderMessage_Message_Type_name = map[int32]string{ - 1: "PREKEY_MESSAGE", 2: "MESSAGE", + 3: "PREKEY_MESSAGE", 7: "SENDERKEY_MESSAGE", 8: "PLAINTEXT_CONTENT", } UnidentifiedSenderMessage_Message_Type_value = map[string]int32{ - "PREKEY_MESSAGE": 1, "MESSAGE": 2, + "PREKEY_MESSAGE": 3, "SENDERKEY_MESSAGE": 7, "PLAINTEXT_CONTENT": 8, } @@ -493,7 +495,7 @@ func (x *UnidentifiedSenderMessage_Message) GetType() UnidentifiedSenderMessage_ if x != nil && x.Type != nil { return *x.Type } - return UnidentifiedSenderMessage_Message_PREKEY_MESSAGE + return UnidentifiedSenderMessage_Message_MESSAGE } func (x *UnidentifiedSenderMessage_Message) GetSenderCertificate() *SenderCertificate { @@ -559,9 +561,9 @@ const file_UnidentifiedDelivery_proto_rawDesc = "" + "\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\x12\n" + - "\x0ePREKEY_MESSAGE\x10\x01\x12\v\n" + - "\aMESSAGE\x10\x02\x12\x15\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" + diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.proto b/pkg/signalmeow/protobuf/UnidentifiedDelivery.proto index fb86b60..255ab6e 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.proto +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.proto @@ -34,11 +34,12 @@ message UnidentifiedSenderMessage { message Message { enum Type { - PREKEY_MESSAGE = 1; + // 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. - // Our parser does not handle reserved in enums: DESKTOP-1569 // reserved 3 to 6; SENDERKEY_MESSAGE = 7; diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index dc65ac7..06ebdea 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -4589,6 +4589,7 @@ func (x *MessageAttachment) GetClientUuid() []byte { type FilePointer struct { state protoimpl.MessageState `protogen:"open.v1"` // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. + // DEPRECATED; use locatorInfo instead. // // Types that are valid to be assigned to Locator: // @@ -4596,15 +4597,16 @@ type FilePointer struct { // *FilePointer_AttachmentLocator_ // *FilePointer_InvalidAttachmentLocator_ // *FilePointer_LocalLocator_ - Locator isFilePointer_Locator `protobuf_oneof:"locator"` - ContentType *string `protobuf:"bytes,4,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` - IncrementalMac []byte `protobuf:"bytes,5,opt,name=incrementalMac,proto3,oneof" json:"incrementalMac,omitempty"` - IncrementalMacChunkSize *uint32 `protobuf:"varint,6,opt,name=incrementalMacChunkSize,proto3,oneof" json:"incrementalMacChunkSize,omitempty"` - FileName *string `protobuf:"bytes,7,opt,name=fileName,proto3,oneof" json:"fileName,omitempty"` - Width *uint32 `protobuf:"varint,8,opt,name=width,proto3,oneof" json:"width,omitempty"` - Height *uint32 `protobuf:"varint,9,opt,name=height,proto3,oneof" json:"height,omitempty"` - Caption *string `protobuf:"bytes,10,opt,name=caption,proto3,oneof" json:"caption,omitempty"` - BlurHash *string `protobuf:"bytes,11,opt,name=blurHash,proto3,oneof" json:"blurHash,omitempty"` + Locator isFilePointer_Locator `protobuf_oneof:"locator"` + ContentType *string `protobuf:"bytes,4,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` + IncrementalMac []byte `protobuf:"bytes,5,opt,name=incrementalMac,proto3,oneof" json:"incrementalMac,omitempty"` + IncrementalMacChunkSize *uint32 `protobuf:"varint,6,opt,name=incrementalMacChunkSize,proto3,oneof" json:"incrementalMacChunkSize,omitempty"` + FileName *string `protobuf:"bytes,7,opt,name=fileName,proto3,oneof" json:"fileName,omitempty"` + Width *uint32 `protobuf:"varint,8,opt,name=width,proto3,oneof" json:"width,omitempty"` + Height *uint32 `protobuf:"varint,9,opt,name=height,proto3,oneof" json:"height,omitempty"` + Caption *string `protobuf:"bytes,10,opt,name=caption,proto3,oneof" json:"caption,omitempty"` + BlurHash *string `protobuf:"bytes,11,opt,name=blurHash,proto3,oneof" json:"blurHash,omitempty"` + LocatorInfo *FilePointer_LocatorInfo `protobuf:"bytes,13,opt,name=locatorInfo,proto3" json:"locatorInfo,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4738,6 +4740,13 @@ func (x *FilePointer) GetBlurHash() string { return "" } +func (x *FilePointer) GetLocatorInfo() *FilePointer_LocatorInfo { + if x != nil { + return x.LocatorInfo + } + return nil +} + type isFilePointer_Locator interface { isFilePointer_Locator() } @@ -7969,8 +7978,11 @@ type AccountData_AccountSettings struct { PhoneNumberSharingMode AccountData_PhoneNumberSharingMode `protobuf:"varint,17,opt,name=phoneNumberSharingMode,proto3,enum=signal.backup.AccountData_PhoneNumberSharingMode" json:"phoneNumberSharingMode,omitempty"` DefaultChatStyle *ChatStyle `protobuf:"bytes,18,opt,name=defaultChatStyle,proto3" json:"defaultChatStyle,omitempty"` CustomChatColors []*ChatStyle_CustomChatColor `protobuf:"bytes,19,rep,name=customChatColors,proto3" json:"customChatColors,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + OptimizeOnDeviceStorage bool `protobuf:"varint,20,opt,name=optimizeOnDeviceStorage,proto3" json:"optimizeOnDeviceStorage,omitempty"` + // See zkgroup for integer particular values. Unset if backups are not enabled. + BackupTier *uint64 `protobuf:"varint,21,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountData_AccountSettings) Reset() { @@ -8136,6 +8148,20 @@ func (x *AccountData_AccountSettings) GetCustomChatColors() []*ChatStyle_CustomC return nil } +func (x *AccountData_AccountSettings) GetOptimizeOnDeviceStorage() bool { + if x != nil { + return x.OptimizeOnDeviceStorage + } + return false +} + +func (x *AccountData_AccountSettings) GetBackupTier() uint64 { + if x != nil && x.BackupTier != nil { + return *x.BackupTier + } + return 0 +} + type AccountData_SubscriberData struct { state protoimpl.MessageState `protogen:"open.v1"` SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` @@ -10044,6 +10070,7 @@ func (x *ContactAttachment_PostalAddress) GetCountry() string { } // References attachments in the backup (media) storage tier. +// DEPRECATED; use LocatorInfo instead if available. type FilePointer_BackupLocator struct { state protoimpl.MessageState `protogen:"open.v1"` MediaName string `protobuf:"bytes,1,opt,name=mediaName,proto3" json:"mediaName,omitempty"` @@ -10144,6 +10171,7 @@ func (x *FilePointer_BackupLocator) GetTransitCdnNumber() uint32 { // May be downloaded or not when the backup is generated; // primarily for free-tier users who cannot copy the // attachments to the backup (media) storage tier. +// DEPRECATED; use LocatorInfo instead if available. type FilePointer_AttachmentLocator struct { state protoimpl.MessageState `protogen:"open.v1"` CdnKey string `protobuf:"bytes,1,opt,name=cdnKey,proto3" json:"cdnKey,omitempty"` @@ -10233,6 +10261,7 @@ func (x *FilePointer_AttachmentLocator) GetSize() uint32 { // CDN keys or anything else that makes download attempts impossible. // This serves as a 'tombstone' so that the UX can show that an attachment // did exist, but for whatever reason it's not retrievable. +// DEPRECATED; use LocatorInfo instead if available. type FilePointer_InvalidAttachmentLocator struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -10272,6 +10301,7 @@ func (*FilePointer_InvalidAttachmentLocator) Descriptor() ([]byte, []int) { // References attachments in a local encrypted backup. // Importers should first attempt to read the file from the local backup, // and on failure fallback to backup and transit cdn if possible. +// DEPRECATED; use LocatorInfo instead if available. type FilePointer_LocalLocator struct { state protoimpl.MessageState `protogen:"open.v1"` MediaName string `protobuf:"bytes,1,opt,name=mediaName,proto3" json:"mediaName,omitempty"` @@ -10376,6 +10406,185 @@ func (x *FilePointer_LocalLocator) GetTransitCdnNumber() uint32 { return 0 } +type FilePointer_LocatorInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Must be non-empty if transitCdnKey or plaintextHash are set/nonempty. + // Otherwise must be empty. + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // From the sender of the attachment (incl. ourselves) + // Will be reserved once all clients start reading integrityCheck + LegacyDigest []byte `protobuf:"bytes,2,opt,name=legacyDigest,proto3" json:"legacyDigest,omitempty"` + // Types that are valid to be assigned to IntegrityCheck: + // + // *FilePointer_LocatorInfo_PlaintextHash + // *FilePointer_LocatorInfo_EncryptedDigest + IntegrityCheck isFilePointer_LocatorInfo_IntegrityCheck `protobuf_oneof:"integrityCheck"` + // NB: This is the plaintext size, and empty content attachments are legal, so this + // may be zero even if transitCdnKey or mediaName are set/nonempty. + Size uint32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + // Either both transit cdn key and number are set or neither should be set. + // Upload timestamp is optional but should only be set if key/number are set. + TransitCdnKey *string `protobuf:"bytes,4,opt,name=transitCdnKey,proto3,oneof" json:"transitCdnKey,omitempty"` + TransitCdnNumber *uint32 `protobuf:"varint,5,opt,name=transitCdnNumber,proto3,oneof" json:"transitCdnNumber,omitempty"` + TransitTierUploadTimestamp *uint64 `protobuf:"varint,6,opt,name=transitTierUploadTimestamp,proto3,oneof" json:"transitTierUploadTimestamp,omitempty"` + // If present, the cdn number of the succesful upload to media tier. + // If unset, may still have been uploaded, and clients + // can discover the cdn number via the list endpoint. + // Exporting clients should set this as long as their subscription + // has not rotated since last upload; even if currently free tier. + MediaTierCdnNumber *uint32 `protobuf:"varint,7,opt,name=mediaTierCdnNumber,proto3,oneof" json:"mediaTierCdnNumber,omitempty"` + // Nonempty any time the attachment was downloaded and its + // digest validated, whether free tier or paid subscription. + // Will be reserved once all clients start reading integrityCheck, + // when mediaName will be derived from the plaintextHash and encryption key + LegacyMediaName string `protobuf:"bytes,8,opt,name=legacyMediaName,proto3" json:"legacyMediaName,omitempty"` + // Separate key used to encrypt this file for the local backup. + // Generally required for local backups. + // Missing field indicates attachment was not available locally + // when the backup was generated, but remote backup or transit + // info was available. + LocalKey []byte `protobuf:"bytes,9,opt,name=localKey,proto3,oneof" json:"localKey,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FilePointer_LocatorInfo) Reset() { + *x = FilePointer_LocatorInfo{} + mi := &file_backuppb_Backup_proto_msgTypes[117] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FilePointer_LocatorInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilePointer_LocatorInfo) ProtoMessage() {} + +func (x *FilePointer_LocatorInfo) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[117] + 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 FilePointer_LocatorInfo.ProtoReflect.Descriptor instead. +func (*FilePointer_LocatorInfo) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 4} +} + +func (x *FilePointer_LocatorInfo) GetKey() []byte { + if x != nil { + return x.Key + } + return nil +} + +func (x *FilePointer_LocatorInfo) GetLegacyDigest() []byte { + if x != nil { + return x.LegacyDigest + } + return nil +} + +func (x *FilePointer_LocatorInfo) GetIntegrityCheck() isFilePointer_LocatorInfo_IntegrityCheck { + if x != nil { + return x.IntegrityCheck + } + return nil +} + +func (x *FilePointer_LocatorInfo) GetPlaintextHash() []byte { + if x != nil { + if x, ok := x.IntegrityCheck.(*FilePointer_LocatorInfo_PlaintextHash); ok { + return x.PlaintextHash + } + } + return nil +} + +func (x *FilePointer_LocatorInfo) GetEncryptedDigest() []byte { + if x != nil { + if x, ok := x.IntegrityCheck.(*FilePointer_LocatorInfo_EncryptedDigest); ok { + return x.EncryptedDigest + } + } + return nil +} + +func (x *FilePointer_LocatorInfo) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *FilePointer_LocatorInfo) GetTransitCdnKey() string { + if x != nil && x.TransitCdnKey != nil { + return *x.TransitCdnKey + } + return "" +} + +func (x *FilePointer_LocatorInfo) GetTransitCdnNumber() uint32 { + if x != nil && x.TransitCdnNumber != nil { + return *x.TransitCdnNumber + } + return 0 +} + +func (x *FilePointer_LocatorInfo) GetTransitTierUploadTimestamp() uint64 { + if x != nil && x.TransitTierUploadTimestamp != nil { + return *x.TransitTierUploadTimestamp + } + return 0 +} + +func (x *FilePointer_LocatorInfo) GetMediaTierCdnNumber() uint32 { + if x != nil && x.MediaTierCdnNumber != nil { + return *x.MediaTierCdnNumber + } + return 0 +} + +func (x *FilePointer_LocatorInfo) GetLegacyMediaName() string { + if x != nil { + return x.LegacyMediaName + } + return "" +} + +func (x *FilePointer_LocatorInfo) GetLocalKey() []byte { + if x != nil { + return x.LocalKey + } + return nil +} + +type isFilePointer_LocatorInfo_IntegrityCheck interface { + isFilePointer_LocatorInfo_IntegrityCheck() +} + +type FilePointer_LocatorInfo_PlaintextHash struct { + // Set if file was at one point downloaded and its plaintextHash was calculated + PlaintextHash []byte `protobuf:"bytes,10,opt,name=plaintextHash,proto3,oneof"` +} + +type FilePointer_LocatorInfo_EncryptedDigest struct { + // Set if file has not been downloaded so its integrity has not been verified + // From the sender of the attachment + EncryptedDigest []byte `protobuf:"bytes,11,opt,name=encryptedDigest,proto3,oneof"` +} + +func (*FilePointer_LocatorInfo_PlaintextHash) isFilePointer_LocatorInfo_IntegrityCheck() {} + +func (*FilePointer_LocatorInfo_EncryptedDigest) isFilePointer_LocatorInfo_IntegrityCheck() {} + type Quote_QuotedAttachment struct { state protoimpl.MessageState `protogen:"open.v1"` ContentType *string `protobuf:"bytes,1,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` @@ -10387,7 +10596,7 @@ type Quote_QuotedAttachment struct { func (x *Quote_QuotedAttachment) Reset() { *x = Quote_QuotedAttachment{} - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10399,7 +10608,7 @@ func (x *Quote_QuotedAttachment) String() string { func (*Quote_QuotedAttachment) ProtoMessage() {} func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10483,7 +10692,7 @@ type GroupChangeChatUpdate_Update struct { func (x *GroupChangeChatUpdate_Update) Reset() { *x = GroupChangeChatUpdate_Update{} - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10495,7 +10704,7 @@ func (x *GroupChangeChatUpdate_Update) String() string { func (*GroupChangeChatUpdate_Update) ProtoMessage() {} func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11069,7 +11278,7 @@ type GroupInvitationRevokedUpdate_Invitee struct { func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { *x = GroupInvitationRevokedUpdate_Invitee{} - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11081,7 +11290,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) String() string { func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11129,7 +11338,7 @@ type ChatStyle_Gradient struct { func (x *ChatStyle_Gradient) Reset() { *x = ChatStyle_Gradient{} - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11141,7 +11350,7 @@ func (x *ChatStyle_Gradient) String() string { func (*ChatStyle_Gradient) ProtoMessage() {} func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11194,7 +11403,7 @@ type ChatStyle_CustomChatColor struct { func (x *ChatStyle_CustomChatColor) Reset() { *x = ChatStyle_CustomChatColor{} - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11206,7 +11415,7 @@ func (x *ChatStyle_CustomChatColor) String() string { func (*ChatStyle_CustomChatColor) ProtoMessage() {} func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11278,7 +11487,7 @@ type ChatStyle_AutomaticBubbleColor struct { func (x *ChatStyle_AutomaticBubbleColor) Reset() { *x = ChatStyle_AutomaticBubbleColor{} - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11290,7 +11499,7 @@ func (x *ChatStyle_AutomaticBubbleColor) String() string { func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11329,7 +11538,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "chatFolder\x18\b \x01(\v2\x19.signal.backup.ChatFolderH\x00R\n" + "chatFolderB\x06\n" + - "\x04item\"\xf1\x12\n" + + "\x04item\"\xdf\x13\n" + "\vAccountData\x12\x1e\n" + "\n" + "profileKey\x18\x01 \x01(\fR\n" + @@ -11361,7 +11570,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x06ORANGE\x10\x06\x12\b\n" + "\x04PINK\x10\a\x12\n" + "\n" + - "\x06PURPLE\x10\b\x1a\xb4\t\n" + + "\x06PURPLE\x10\b\x1a\xa2\n" + + "\n" + "\x0fAccountSettings\x12\"\n" + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x126\n" + "\x16sealedSenderIndicators\x18\x02 \x01(\bR\x16sealedSenderIndicators\x12*\n" + @@ -11382,8 +11592,13 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x1ehasCompletedUsernameOnboarding\x18\x10 \x01(\bR\x1ehasCompletedUsernameOnboarding\x12i\n" + "\x16phoneNumberSharingMode\x18\x11 \x01(\x0e21.signal.backup.AccountData.PhoneNumberSharingModeR\x16phoneNumberSharingMode\x12D\n" + "\x10defaultChatStyle\x18\x12 \x01(\v2\x18.signal.backup.ChatStyleR\x10defaultChatStyle\x12T\n" + - "\x10customChatColors\x18\x13 \x03(\v2(.signal.backup.ChatStyle.CustomChatColorR\x10customChatColorsB\x1b\n" + - "\x19_storyViewReceiptsEnabled\x1a\x86\x01\n" + + "\x10customChatColors\x18\x13 \x03(\v2(.signal.backup.ChatStyle.CustomChatColorR\x10customChatColors\x128\n" + + "\x17optimizeOnDeviceStorage\x18\x14 \x01(\bR\x17optimizeOnDeviceStorage\x12#\n" + + "\n" + + "backupTier\x18\x15 \x01(\x04H\x01R\n" + + "backupTier\x88\x01\x01B\x1b\n" + + "\x19_storyViewReceiptsEnabledB\r\n" + + "\v_backupTier\x1a\x86\x01\n" + "\x0eSubscriberData\x12\"\n" + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12\"\n" + "\fcurrencyCode\x18\x02 \x01(\tR\fcurrencyCode\x12,\n" + @@ -11829,7 +12044,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "BORDERLESS\x10\x02\x12\a\n" + "\x03GIF\x10\x03B\r\n" + - "\v_clientUuid\"\xb4\r\n" + + "\v_clientUuid\"\xc9\x12\n" + "\vFilePointer\x12P\n" + "\rbackupLocator\x18\x01 \x01(\v2(.signal.backup.FilePointer.BackupLocatorH\x00R\rbackupLocator\x12\\\n" + "\x11attachmentLocator\x18\x02 \x01(\v2,.signal.backup.FilePointer.AttachmentLocatorH\x00R\x11attachmentLocator\x12q\n" + @@ -11843,7 +12058,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x06height\x18\t \x01(\rH\x06R\x06height\x88\x01\x01\x12\x1d\n" + "\acaption\x18\n" + " \x01(\tH\aR\acaption\x88\x01\x01\x12\x1f\n" + - "\bblurHash\x18\v \x01(\tH\bR\bblurHash\x88\x01\x01\x1a\x9f\x02\n" + + "\bblurHash\x18\v \x01(\tH\bR\bblurHash\x88\x01\x01\x12H\n" + + "\vlocatorInfo\x18\r \x01(\v2&.signal.backup.FilePointer.LocatorInfoR\vlocatorInfo\x1a\x9f\x02\n" + "\rBackupLocator\x12\x1c\n" + "\tmediaName\x18\x01 \x01(\tR\tmediaName\x12!\n" + "\tcdnNumber\x18\x02 \x01(\rH\x00R\tcdnNumber\x88\x01\x01\x12\x10\n" + @@ -11877,7 +12093,26 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\t_localKeyB\x12\n" + "\x10_backupCdnNumberB\x10\n" + "\x0e_transitCdnKeyB\x13\n" + - "\x11_transitCdnNumberB\t\n" + + "\x11_transitCdnNumber\x1a\xc8\x04\n" + + "\vLocatorInfo\x12\x10\n" + + "\x03key\x18\x01 \x01(\fR\x03key\x12\"\n" + + "\flegacyDigest\x18\x02 \x01(\fR\flegacyDigest\x12&\n" + + "\rplaintextHash\x18\n" + + " \x01(\fH\x00R\rplaintextHash\x12*\n" + + "\x0fencryptedDigest\x18\v \x01(\fH\x00R\x0fencryptedDigest\x12\x12\n" + + "\x04size\x18\x03 \x01(\rR\x04size\x12)\n" + + "\rtransitCdnKey\x18\x04 \x01(\tH\x01R\rtransitCdnKey\x88\x01\x01\x12/\n" + + "\x10transitCdnNumber\x18\x05 \x01(\rH\x02R\x10transitCdnNumber\x88\x01\x01\x12C\n" + + "\x1atransitTierUploadTimestamp\x18\x06 \x01(\x04H\x03R\x1atransitTierUploadTimestamp\x88\x01\x01\x123\n" + + "\x12mediaTierCdnNumber\x18\a \x01(\rH\x04R\x12mediaTierCdnNumber\x88\x01\x01\x12(\n" + + "\x0flegacyMediaName\x18\b \x01(\tR\x0flegacyMediaName\x12\x1f\n" + + "\blocalKey\x18\t \x01(\fH\x05R\blocalKey\x88\x01\x01B\x10\n" + + "\x0eintegrityCheckB\x10\n" + + "\x0e_transitCdnKeyB\x13\n" + + "\x11_transitCdnNumberB\x1d\n" + + "\x1b_transitTierUploadTimestampB\x15\n" + + "\x13_mediaTierCdnNumberB\v\n" + + "\t_localKeyB\t\n" + "\alocatorB\x0e\n" + "\f_contentTypeB\x11\n" + "\x0f_incrementalMacB\x1a\n" + @@ -12406,7 +12641,7 @@ func file_backuppb_Backup_proto_rawDescGZIP() []byte { } var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 31) -var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 123) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 124) var file_backuppb_Backup_proto_goTypes = []any{ (AvatarColor)(0), // 0: signal.backup.AvatarColor (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel @@ -12556,12 +12791,13 @@ var file_backuppb_Backup_proto_goTypes = []any{ (*FilePointer_AttachmentLocator)(nil), // 145: signal.backup.FilePointer.AttachmentLocator (*FilePointer_InvalidAttachmentLocator)(nil), // 146: signal.backup.FilePointer.InvalidAttachmentLocator (*FilePointer_LocalLocator)(nil), // 147: signal.backup.FilePointer.LocalLocator - (*Quote_QuotedAttachment)(nil), // 148: signal.backup.Quote.QuotedAttachment - (*GroupChangeChatUpdate_Update)(nil), // 149: signal.backup.GroupChangeChatUpdate.Update - (*GroupInvitationRevokedUpdate_Invitee)(nil), // 150: signal.backup.GroupInvitationRevokedUpdate.Invitee - (*ChatStyle_Gradient)(nil), // 151: signal.backup.ChatStyle.Gradient - (*ChatStyle_CustomChatColor)(nil), // 152: signal.backup.ChatStyle.CustomChatColor - (*ChatStyle_AutomaticBubbleColor)(nil), // 153: signal.backup.ChatStyle.AutomaticBubbleColor + (*FilePointer_LocatorInfo)(nil), // 148: signal.backup.FilePointer.LocatorInfo + (*Quote_QuotedAttachment)(nil), // 149: signal.backup.Quote.QuotedAttachment + (*GroupChangeChatUpdate_Update)(nil), // 150: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 151: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 152: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 153: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 154: signal.backup.ChatStyle.AutomaticBubbleColor } var file_backuppb_Backup_proto_depIdxs = []int32{ 33, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData @@ -12647,104 +12883,105 @@ var file_backuppb_Backup_proto_depIdxs = []int32{ 145, // 80: signal.backup.FilePointer.attachmentLocator:type_name -> signal.backup.FilePointer.AttachmentLocator 146, // 81: signal.backup.FilePointer.invalidAttachmentLocator:type_name -> signal.backup.FilePointer.InvalidAttachmentLocator 147, // 82: signal.backup.FilePointer.localLocator:type_name -> signal.backup.FilePointer.LocalLocator - 46, // 83: signal.backup.Quote.text:type_name -> signal.backup.Text - 148, // 84: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 20, // 85: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 21, // 86: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 66, // 87: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 72, // 88: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 67, // 89: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 68, // 90: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 70, // 91: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 71, // 92: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 64, // 93: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 65, // 94: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 69, // 95: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 22, // 96: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 23, // 97: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 24, // 98: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 25, // 99: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 26, // 100: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 149, // 101: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 1, // 102: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 1, // 103: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 150, // 104: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 27, // 105: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 59, // 106: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 153, // 107: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 28, // 108: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 29, // 109: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 30, // 110: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 3, // 111: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 2, // 112: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 108, // 113: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 152, // 114: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 119, // 115: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 116: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 117: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 124, // 118: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 120, // 119: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 121, // 120: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 122, // 121: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 123, // 122: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 7, // 123: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 120, // 124: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 8, // 125: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 126: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 127: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 45, // 128: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 12, // 129: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 46, // 130: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 59, // 131: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 139, // 132: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 138, // 133: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 13, // 134: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 14, // 135: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 137, // 136: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 16, // 137: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 17, // 138: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 18, // 139: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 58, // 140: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 73, // 141: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 74, // 142: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 75, // 143: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 76, // 144: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 77, // 145: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 78, // 146: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 79, // 147: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 80, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 81, // 149: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 82, // 150: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 83, // 151: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 84, // 152: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 85, // 153: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 86, // 154: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 87, // 155: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 88, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 89, // 157: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 90, // 158: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 91, // 159: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 92, // 160: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 93, // 161: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 94, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 95, // 163: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 97, // 164: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 98, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 99, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 100, // 167: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 101, // 168: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 102, // 169: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 103, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 104, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 105, // 172: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 96, // 173: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 106, // 174: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 151, // 175: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 176, // [176:176] is the sub-list for method output_type - 176, // [176:176] is the sub-list for method input_type - 176, // [176:176] is the sub-list for extension type_name - 176, // [176:176] is the sub-list for extension extendee - 0, // [0:176] is the sub-list for field type_name + 148, // 83: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo + 46, // 84: signal.backup.Quote.text:type_name -> signal.backup.Text + 149, // 85: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 20, // 86: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 21, // 87: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 66, // 88: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 72, // 89: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 67, // 90: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 68, // 91: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 70, // 92: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 71, // 93: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 64, // 94: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 65, // 95: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 69, // 96: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 22, // 97: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 23, // 98: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 24, // 99: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 25, // 100: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 26, // 101: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 150, // 102: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 103: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 104: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 151, // 105: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 27, // 106: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 59, // 107: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 154, // 108: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 28, // 109: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 29, // 110: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 30, // 111: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 3, // 112: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 2, // 113: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 108, // 114: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 153, // 115: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 119, // 116: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 117: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 118: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 124, // 119: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 120, // 120: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 121, // 121: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 122, // 122: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 123, // 123: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 7, // 124: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 120, // 125: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 8, // 126: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 127: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 128: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 45, // 129: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 12, // 130: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 46, // 131: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 59, // 132: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 139, // 133: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 138, // 134: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 13, // 135: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 14, // 136: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 137, // 137: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 16, // 138: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 17, // 139: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 18, // 140: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 58, // 141: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 73, // 142: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 74, // 143: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 75, // 144: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 76, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 77, // 146: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 78, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 79, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 80, // 149: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 81, // 150: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 82, // 151: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 83, // 152: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 84, // 153: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 85, // 154: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 86, // 155: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 87, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 88, // 157: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 89, // 158: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 90, // 159: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 91, // 160: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 92, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 93, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 94, // 163: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 95, // 164: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 97, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 98, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 99, // 167: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 100, // 168: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 101, // 169: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 102, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 103, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 104, // 172: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 105, // 173: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 96, // 174: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 106, // 175: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 152, // 176: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 177, // [177:177] is the sub-list for method output_type + 177, // [177:177] is the sub-list for method input_type + 177, // [177:177] is the sub-list for extension type_name + 177, // [177:177] is the sub-list for extension extendee + 0, // [0:177] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -12895,8 +13132,12 @@ func file_backuppb_Backup_proto_init() { file_backuppb_Backup_proto_msgTypes[113].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{ + (*FilePointer_LocatorInfo_PlaintextHash)(nil), + (*FilePointer_LocatorInfo_EncryptedDigest)(nil), + } + file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{ (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), @@ -12932,8 +13173,8 @@ func file_backuppb_Backup_proto_init() { (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), } - file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[121].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[122].OneofWrappers = []any{ (*ChatStyle_CustomChatColor_Solid)(nil), (*ChatStyle_CustomChatColor_Gradient)(nil), } @@ -12943,7 +13184,7 @@ func file_backuppb_Backup_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), NumEnums: 31, - NumMessages: 123, + NumMessages: 124, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 3840f93..0dd3e89 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -87,6 +87,9 @@ message AccountData { PhoneNumberSharingMode phoneNumberSharingMode = 17; ChatStyle defaultChatStyle = 18; repeated ChatStyle.CustomChatColor customChatColors = 19; + bool optimizeOnDeviceStorage = 20; + // See zkgroup for integer particular values. Unset if backups are not enabled. + optional uint64 backupTier = 21; } message SubscriberData { @@ -689,6 +692,7 @@ message MessageAttachment { message FilePointer { // References attachments in the backup (media) storage tier. + // DEPRECATED; use LocatorInfo instead if available. message BackupLocator { string mediaName = 1; // If present, the cdn number of the succesful upload. @@ -698,6 +702,7 @@ message FilePointer { bytes key = 3; bytes digest = 4; uint32 size = 5; + // Fallback in case backup tier upload failed. optional string transitCdnKey = 6; optional uint32 transitCdnNumber = 7; @@ -707,6 +712,7 @@ message FilePointer { // May be downloaded or not when the backup is generated; // primarily for free-tier users who cannot copy the // attachments to the backup (media) storage tier. + // DEPRECATED; use LocatorInfo instead if available. message AttachmentLocator { string cdnKey = 1; uint32 cdnNumber = 2; @@ -721,12 +727,14 @@ message FilePointer { // CDN keys or anything else that makes download attempts impossible. // This serves as a 'tombstone' so that the UX can show that an attachment // did exist, but for whatever reason it's not retrievable. + // DEPRECATED; use LocatorInfo instead if available. message InvalidAttachmentLocator { } // References attachments in a local encrypted backup. // Importers should first attempt to read the file from the local backup, // and on failure fallback to backup and transit cdn if possible. + // DEPRECATED; use LocatorInfo instead if available. message LocalLocator { string mediaName = 1; // Separate key used to encrypt this file for the local backup. @@ -742,7 +750,57 @@ message FilePointer { optional uint32 transitCdnNumber = 8; } + message LocatorInfo { + // Must be non-empty if transitCdnKey or plaintextHash are set/nonempty. + // Otherwise must be empty. + bytes key = 1; + + // From the sender of the attachment (incl. ourselves) + // Will be reserved once all clients start reading integrityCheck + bytes legacyDigest = 2; + + oneof integrityCheck { + // Set if file was at one point downloaded and its plaintextHash was calculated + bytes plaintextHash = 10; + + // Set if file has not been downloaded so its integrity has not been verified + // From the sender of the attachment + bytes encryptedDigest = 11; + } + + // NB: This is the plaintext size, and empty content attachments are legal, so this + // may be zero even if transitCdnKey or mediaName are set/nonempty. + uint32 size = 3; + + // Either both transit cdn key and number are set or neither should be set. + // Upload timestamp is optional but should only be set if key/number are set. + optional string transitCdnKey = 4; + optional uint32 transitCdnNumber = 5; + optional uint64 transitTierUploadTimestamp = 6; + + // If present, the cdn number of the succesful upload to media tier. + // If unset, may still have been uploaded, and clients + // can discover the cdn number via the list endpoint. + // Exporting clients should set this as long as their subscription + // has not rotated since last upload; even if currently free tier. + optional uint32 mediaTierCdnNumber = 7; + + // Nonempty any time the attachment was downloaded and its + // digest validated, whether free tier or paid subscription. + // Will be reserved once all clients start reading integrityCheck, + // when mediaName will be derived from the plaintextHash and encryption key + string legacyMediaName = 8; + + // Separate key used to encrypt this file for the local backup. + // Generally required for local backups. + // Missing field indicates attachment was not available locally + // when the backup was generated, but remote backup or transit + // info was available. + optional bytes localKey = 9; + } + // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. + // DEPRECATED; use locatorInfo instead. oneof locator { BackupLocator backupLocator = 1; AttachmentLocator attachmentLocator = 2; @@ -758,6 +816,7 @@ message FilePointer { optional uint32 height = 9; optional string caption = 10; optional string blurHash = 11; + LocatorInfo locatorInfo = 13; } message Quote { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index c95420d..c3d85c0 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-23669c3c372284d42db486a218d9f29bef247abf} -DESKTOP_GIT_REVISION=${1:-010c38ae9bce84c676a9c464a04f7c26e7a2c9e0} +ANDROID_GIT_REVISION=${1:-4b9cac43a82b5b907de53696b93eaf521943d15c} +DESKTOP_GIT_REVISION=${1:-ffc34d5080b8b8aec1bbebf11a13227e224dffe0} update_proto() { case "$1" in From bd5cc56cfc01e2fef3bf6d66f66d405b94f76a8f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 7 Jul 2025 15:35:45 +0300 Subject: [PATCH 503/718] signalmeow/web: make SendRequest nil-safe --- pkg/signalmeow/web/signalwebsocket.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index c4030d6..ed60103 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -561,6 +561,9 @@ func (s *SignalWebsocket) SendRequest( ctx context.Context, request *signalpb.WebSocketRequestMessage, ) (*signalpb.WebSocketResponseMessage, error) { + if s == nil { + return nil, errors.New("websocket is nil") + } startTime := time.Now() return s.sendRequestInternal(ctx, request, startTime, 0) } From 23b2496ac950b49ffb4bb26fd6d6093a5042a49e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 7 Jul 2025 15:36:06 +0300 Subject: [PATCH 504/718] handlematrix: move viewing chat handler to correct file --- pkg/connector/client.go | 33 --------------------------------- pkg/connector/handlematrix.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 5a0b740..925747e 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -339,36 +339,3 @@ func (s *SignalClient) IsLoggedIn() bool { } return s.Client.IsLoggedIn() } - -func (s *SignalClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { - if msg.Portal == nil || msg.Portal.OtherUserID == "" { - // Group chat changes are sent by Signal so no need to fetch them on view - return nil - } - - // Sync other user ghost info in DM rooms - ghost, err := s.Main.Bridge.GetExistingGhostByID(ctx, msg.Portal.OtherUserID) - if err != nil { - return fmt.Errorf("failed to get ghost for sync: %w", err) - } else if ghost == nil { - zerolog.Ctx(ctx).Warn(). - Str("other_user_id", string(msg.Portal.OtherUserID)). - Msg("No ghost found for other user in portal") - return nil - } - - meta := ghost.Metadata.(*signalid.GhostMetadata) - if meta.ProfileFetchedAt.Time.Add(5 * time.Minute).After(time.Now()) { - // Limit profile fetches to max one per 5 minutes - return nil - } - - // Reset, but don't save, portal last sync time for immediate sync now - meta.ProfileFetchedAt.Time = time.Time{} - info, err := s.GetUserInfoWithRefreshAfter(ctx, ghost, 5*time.Minute) - if err != nil { - return fmt.Errorf("failed to get user info: %w", err) - } - ghost.UpdateInfo(ctx, info) - return nil -} diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 8137c84..09daaa2 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -562,3 +562,36 @@ func (s *SignalClient) HandleMatrixPowerLevels(ctx context.Context, msg *bridgev msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision return true, nil } + +func (s *SignalClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { + if msg.Portal == nil || msg.Portal.OtherUserID == "" { + // Group chat changes are sent by Signal so no need to fetch them on view + return nil + } + + // Sync other user ghost info in DM rooms + ghost, err := s.Main.Bridge.GetExistingGhostByID(ctx, msg.Portal.OtherUserID) + if err != nil { + return fmt.Errorf("failed to get ghost for sync: %w", err) + } else if ghost == nil { + zerolog.Ctx(ctx).Warn(). + Str("other_user_id", string(msg.Portal.OtherUserID)). + Msg("No ghost found for other user in portal") + return nil + } + + meta := ghost.Metadata.(*signalid.GhostMetadata) + if meta.ProfileFetchedAt.Time.Add(5 * time.Minute).After(time.Now()) { + // Limit profile fetches to max one per 5 minutes + return nil + } + + // Reset, but don't save, portal last sync time for immediate sync now + meta.ProfileFetchedAt.Time = time.Time{} + info, err := s.GetUserInfoWithRefreshAfter(ctx, ghost, 5*time.Minute) + if err != nil { + return fmt.Errorf("failed to get user info: %w", err) + } + ghost.UpdateInfo(ctx, info) + return nil +} From 1e6f84962e4099bdb08b7abca22285d6065089bc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 8 Jul 2025 13:28:25 +0300 Subject: [PATCH 505/718] chatsync: stop processing chats if queueing event fails --- pkg/connector/chatsync.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/connector/chatsync.go b/pkg/connector/chatsync.go index 5d982e7..5211270 100644 --- a/pkg/connector/chatsync.go +++ b/pkg/connector/chatsync.go @@ -147,7 +147,9 @@ func (s *SignalClient) syncChats(ctx context.Context) { } continue } - s.UserLogin.QueueRemoteEvent(resyncEvt) + if !s.UserLogin.QueueRemoteEvent(resyncEvt).Success { + return + } } s.UserLogin.Metadata.(*signalid.UserLoginMetadata).ChatsSynced = true err = s.UserLogin.Save(ctx) From 31164440c61d9fecf7fc2a77d13acce1fca81901 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 8 Jul 2025 19:12:33 +0300 Subject: [PATCH 506/718] signalmeow/receiving: don't send decryption errors for context cancellations --- pkg/signalmeow/receiving.go | 5 +++++ pkg/signalmeow/web/signalwebsocket.go | 3 +++ 2 files changed, 8 insertions(+) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 5b9f212..4656fd1 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -385,6 +385,11 @@ func (cli *Client) handleDecryptedResult( envelope *signalpb.Envelope, destinationServiceID libsignalgo.ServiceID, ) error { + if errors.Is(result.Err, context.Canceled) { + return result.Err + } else if ctx.Err() != nil { + return ctx.Err() + } log := zerolog.Ctx(ctx) if result.CiphertextHash != nil { defer func() { diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index ed60103..c4572d6 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -135,6 +135,9 @@ func (s *SignalWebsocket) pushStatus(ctx context.Context, status SignalWebsocket } func (s *SignalWebsocket) pushOutgoing(ctx context.Context, send SignalWebsocketSendMessage) error { + if ctx.Err() != nil { + return ctx.Err() + } s.closeLock.RLock() defer s.closeLock.RUnlock() if s.sendChannel == nil { From 7d5ba58d241e63096bd70b56c96cc0cc6a13f773 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 16 Jul 2025 11:44:44 +0300 Subject: [PATCH 507/718] Bump version to v0.8.5 --- CHANGELOG.md | 4 ++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 16 ++++++++-------- go.sum | 28 ++++++++++++++-------------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f314ccf..220f3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v0.8.5 (2025-07-16) + +* Updated libsignal to v0.76.1. + # v0.8.4 (2025-06-16) * Updated libsignal to v0.74.1. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 565e9bf..78f696e 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -38,7 +38,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.4", + Version: "0.8.5", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 54e1fd9..29aa21d 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.23.0 -toolchain go1.24.4 +toolchain go1.24.5 require ( github.com/coder/websocket v1.8.13 @@ -14,11 +14,11 @@ require ( github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 go.mau.fi/util v0.8.8 - golang.org/x/crypto v0.39.0 - golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 - golang.org/x/net v0.41.0 + golang.org/x/crypto v0.40.0 + golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc + golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.2-0.20250617163829-26da46dbbf6e + maunium.net/go/mautrix v0.24.2 ) require ( @@ -41,9 +41,9 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.12 // indirect go.mau.fi/zeroconfig v0.1.3 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index b0dbd1c..1f8d1a9 100644 --- a/go.sum +++ b/go.sum @@ -73,21 +73,21 @@ go.mau.fi/util v0.8.8 h1:OnuEEc/sIJFhnq4kFggiImUpcmnmL/xpvQMRu5Fiy5c= go.mau.fi/util v0.8.8/go.mod h1:Y/kS3loxTEhy8Vill513EtPXr+CRDdae+Xj2BXXMy/c= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= -golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -99,5 +99,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.24.2-0.20250617163829-26da46dbbf6e h1:Y8kbRpPcKMZn2gIjUFd15xzMB5GJ2bS6ZcOfvlx4KnE= -maunium.net/go/mautrix v0.24.2-0.20250617163829-26da46dbbf6e/go.mod h1:Xy6o+pXmbqmgWsUWh15EQ1eozjC+k/VT/7kloByv9PI= +maunium.net/go/mautrix v0.24.2 h1:+AVT5kbcA/QuT5svrJKp4ivwoUmz+RRplMp3DnfpheI= +maunium.net/go/mautrix v0.24.2/go.mod h1:1ut900w++eE9by9yqCR2dQdMqwsHwZG5L+1bKB1EvSA= From 9e6b701ad858fe46e4879753848c467c95c85432 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 17 Jul 2025 11:28:46 +0300 Subject: [PATCH 508/718] .github: update issue templates [skip ci] --- .github/ISSUE_TEMPLATE/bug.md | 10 ++++++---- .github/ISSUE_TEMPLATE/enhancement.md | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 18862a5..3703df9 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -1,14 +1,16 @@ --- name: Bug report about: If something is definitely wrong in the bridge (rather than just a setup issue), - file a bug report. Remember to include relevant logs. -labels: bug + file a bug report. Remember to include relevant logs. Asking in the Matrix room first + is strongly recommended. +type: Bug --- diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md index 264e67f..a04fe58 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.md +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -1,6 +1,6 @@ --- name: Enhancement request about: Submit a feature request or other suggestion -labels: enhancement +type: Feature --- From 69d54526b4b63ce5c79cccf8baa277a21f90acf1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 18 Jul 2025 15:24:16 +0300 Subject: [PATCH 509/718] capabilities: remove delete max age in note to self room --- pkg/connector/capabilities.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 072c6fa..f0f71ff 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -160,7 +160,8 @@ var signalCapsNoteToSelf *event.RoomFeatures func init() { signalCapsNoteToSelf = ptr.Clone(signalCaps) signalCapsNoteToSelf.EditMaxAge = nil - signalCapsNoteToSelf.ID = capID() + "+note_to_self" + signalCapsNoteToSelf.DeleteMaxAge = nil + signalCapsNoteToSelf.ID = capID() + "+note_to_self.2" } func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { @@ -180,5 +181,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 3 + return 1, 4 } From c245fa474f7437d0cb0b6b27b49af25271f2b787 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 18 Jul 2025 15:58:17 +0300 Subject: [PATCH 510/718] handlesignal: add support for delete for me --- pkg/connector/handlesignal.go | 142 +++++++++++++++++++++++++++ pkg/libsignalgo/groupsecretparams.go | 11 ++- pkg/signalmeow/events/message.go | 9 +- pkg/signalmeow/groups.go | 4 +- pkg/signalmeow/receiving.go | 9 +- pkg/signalmeow/store/backup_store.go | 2 +- pkg/signalmeow/types/identifer.go | 4 + 7 files changed, 174 insertions(+), 7 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 634c5ca..f77d87d 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -18,6 +18,7 @@ package connector import ( "context" + "encoding/base64" "fmt" "strings" "time" @@ -31,6 +32,7 @@ import ( "maunium.net/go/mautrix/bridgev2/simplevent" "maunium.net/go/mautrix/event" + "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -47,6 +49,8 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) bool { return s.handleSignalReceipt(evt) case *events.ReadSelf: return s.handleSignalReadSelf(evt) + case *events.DeleteForMe: + return s.handleSignalDeleteForMe(evt) case *events.Call: return s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapCallEvent(evt)).Success case *events.ContactList: @@ -469,6 +473,144 @@ func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) bool { return s.dispatchReceipts(s.Client.Store.ACI, signalpb.ReceiptMessage_READ, receipts) } +func (s *SignalClient) conversationIDToPortalKey(ctx context.Context, cid *signalpb.ConversationIdentifier) (networkid.PortalKey, bool) { + log := zerolog.Ctx(ctx) + switch ident := cid.GetIdentifier().(type) { + case *signalpb.ConversationIdentifier_ThreadServiceId: + serviceID, err := libsignalgo.ServiceIDFromString(ident.ThreadServiceId) + if err != nil { + log.Err(err).Str("chat_id", ident.ThreadServiceId).Msg("Failed to parse delete for me conversation ID") + return networkid.PortalKey{}, false + } + return s.makeDMPortalKey(serviceID), true + case *signalpb.ConversationIdentifier_ThreadGroupId: + if len(ident.ThreadGroupId) != libsignalgo.GroupIdentifierLength { + log.Error(). + Str("chat_id", base64.StdEncoding.EncodeToString(ident.ThreadGroupId)). + Msg("Invalid group ID length in delete for me conversation") + return networkid.PortalKey{}, false + } + return s.makePortalKey((*libsignalgo.GroupIdentifier)(ident.ThreadGroupId).String()), true + case *signalpb.ConversationIdentifier_ThreadE164: + log.Warn().Str("chat_id", ident.ThreadE164).Msg("Unsupported E164 conversation ID in delete for me") + return networkid.PortalKey{}, false + default: + log.Warn(). + Type("chat_id_type", ident). + Msg("Unsupported conversation ID protobuf type in delete for me") + return networkid.PortalKey{}, false + } +} + +func (s *SignalClient) addressableMessageToID(ctx context.Context, portalKey networkid.PortalKey, am *signalpb.AddressableMessage) networkid.MessageID { + log := zerolog.Ctx(ctx) + switch typedAuthor := am.GetAuthor().(type) { + case *signalpb.AddressableMessage_AuthorServiceId: + serviceID, err := libsignalgo.ServiceIDFromString(typedAuthor.AuthorServiceId) + if err != nil { + log.Err(err). + Object("portal_key", portalKey). + Str("author_service_id", typedAuthor.AuthorServiceId). + Msg("Failed to parse delete for me message author service ID") + return "" + } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { + log.Warn(). + Object("portal_key", portalKey). + Str("author_service_id", typedAuthor.AuthorServiceId). + Msg("Dropping delete for me message with unsupported service ID type") + return "" + } + return signalid.MakeMessageID(serviceID.UUID, am.GetSentTimestamp()) + case *signalpb.AddressableMessage_AuthorE164: + log.Warn(). + Object("portal_key", portalKey). + Str("author_e164", typedAuthor.AuthorE164). + Msg("Dropping delete for me message with unsupported E164 author") + return "" + default: + log.Warn(). + Object("portal_key", portalKey). + Type("author_type", typedAuthor). + Msg("Dropping delete for me message with unrecognized author protobuf type") + return "" + } +} + +func (s *SignalClient) handleSignalDeleteForMe(evt *events.DeleteForMe) bool { + log := s.UserLogin.Log.With(). + Str("action", "handle signal delete for me"). + Logger() + ctx := log.WithContext(s.Main.Bridge.BackgroundCtx) + for _, conv := range evt.GetConversationDeletes() { + if !conv.GetIsFullDelete() { + // Non-full deletes might mean clearing chats? + continue + } + portalKey, ok := s.conversationIDToPortalKey(ctx, conv.GetConversation()) + if !ok { + continue + } + + res := s.UserLogin.QueueRemoteEvent(&simplevent.ChatDelete{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatDelete, + PortalKey: portalKey, + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + StreamOrder: int64(evt.Timestamp), + }, + OnlyForMe: true, + }) + if !res.Success { + return false + } + } + for _, conv := range evt.GetLocalOnlyConversationDeletes() { + portalKey, ok := s.conversationIDToPortalKey(ctx, conv.GetConversation()) + if !ok { + continue + } + + res := s.UserLogin.QueueRemoteEvent(&simplevent.ChatDelete{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatDelete, + PortalKey: portalKey, + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + StreamOrder: int64(evt.Timestamp), + }, + OnlyForMe: true, + }) + if !res.Success { + return false + } + } + for _, conv := range evt.GetMessageDeletes() { + portalKey, ok := s.conversationIDToPortalKey(ctx, conv.GetConversation()) + if !ok { + continue + } + for _, msg := range conv.GetMessages() { + msgID := s.addressableMessageToID(ctx, portalKey, msg) + if msgID == "" { + continue + } + res := s.UserLogin.QueueRemoteEvent(&simplevent.MessageRemove{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventMessageRemove, + PortalKey: portalKey, + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + StreamOrder: int64(evt.Timestamp), + }, + OnlyForMe: true, + TargetMessage: msgID, + }) + if !res.Success { + return false + } + } + } + return true +} + func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { log := s.UserLogin.Log.With(). Str("action", "handle aci found"). diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index c6189af..5ad11fd 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -23,6 +23,7 @@ package libsignalgo import "C" import ( "crypto/rand" + "encoding/base64" "fmt" "runtime" "unsafe" @@ -42,11 +43,19 @@ func GenerateRandomness() Randomness { } const GroupMasterKeyLength = C.SignalGROUP_MASTER_KEY_LEN +const GroupIdentifierLength = C.SignalGROUP_IDENTIFIER_LEN type GroupMasterKey [GroupMasterKeyLength]byte type GroupSecretParams [C.SignalGROUP_SECRET_PARAMS_LEN]byte type GroupPublicParams [C.SignalGROUP_PUBLIC_PARAMS_LEN]byte -type GroupIdentifier [C.SignalGROUP_IDENTIFIER_LEN]byte +type GroupIdentifier [GroupIdentifierLength]byte + +func (gid *GroupIdentifier) String() string { + if gid == nil { + return "" + } + return base64.StdEncoding.EncodeToString(gid[:]) +} type UUIDCiphertext [C.SignalUUID_CIPHERTEXT_LEN]byte type ProfileKeyCiphertext [C.SignalPROFILE_KEY_CIPHERTEXT_LEN]byte diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 9b8e79d..8a13329 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -35,6 +35,7 @@ func (*ReadSelf) isSignalEvent() {} func (*Call) isSignalEvent() {} func (*ContactList) isSignalEvent() {} func (*ACIFound) isSignalEvent() {} +func (*DeleteForMe) isSignalEvent() {} func (*QueueEmpty) isSignalEvent() {} type MessageInfo struct { @@ -62,7 +63,8 @@ type Receipt struct { } type ReadSelf struct { - Messages []*signalpb.SyncMessage_Read + Timestamp uint64 + Messages []*signalpb.SyncMessage_Read } type Call struct { @@ -80,4 +82,9 @@ type ACIFound struct { ACI libsignalgo.ServiceID } +type DeleteForMe struct { + Timestamp uint64 + *signalpb.SyncMessage_DeleteForMe +} + type QueueEmpty struct{} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 35544f7..8c0a841 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -452,9 +452,7 @@ func groupIdentifierFromMasterKey(masterKey types.SerializedGroupMasterKey) (typ if err != nil { return "", err } - base64GroupIdentifier := base64.StdEncoding.EncodeToString(groupIdentifier[:]) - gid := types.GroupIdentifier(base64GroupIdentifier) - return gid, nil + return types.BytesToGroupIdentifier(groupIdentifier), nil } func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 4656fd1..49ed0f3 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -631,7 +631,14 @@ func (cli *Client) handleDecryptedResult( } if content.SyncMessage.Read != nil { handlerSuccess = cli.handleEvent(&events.ReadSelf{ - Messages: content.SyncMessage.GetRead(), + Timestamp: envelope.GetTimestamp(), + Messages: content.SyncMessage.GetRead(), + }) + } + if content.SyncMessage.DeleteForMe != nil { + handlerSuccess = cli.handleEvent(&events.DeleteForMe{ + Timestamp: envelope.GetTimestamp(), + SyncMessage_DeleteForMe: content.SyncMessage.DeleteForMe, }) } diff --git a/pkg/signalmeow/store/backup_store.go b/pkg/signalmeow/store/backup_store.go index edcb658..4575b05 100644 --- a/pkg/signalmeow/store/backup_store.go +++ b/pkg/signalmeow/store/backup_store.go @@ -183,7 +183,7 @@ func (s *sqlStore) AddBackupRecipient(ctx context.Context, recipient *backuppb.R zerolog.Ctx(ctx).Err(err). Uint64("recipient_id", recipient.Id). Msg("Failed to get group identifier from master key") - } else if err = s.StoreMasterKey(ctx, types.GroupIdentifier(base64.StdEncoding.EncodeToString(gid[:])), groupMasterKey); err != nil { + } else if err = s.StoreMasterKey(ctx, types.BytesToGroupIdentifier(gid), groupMasterKey); err != nil { return fmt.Errorf("failed to save group master key for recipient %d: %w", recipient.Id, err) } } else { diff --git a/pkg/signalmeow/types/identifer.go b/pkg/signalmeow/types/identifer.go index 87ed647..f1c02dc 100644 --- a/pkg/signalmeow/types/identifer.go +++ b/pkg/signalmeow/types/identifer.go @@ -25,6 +25,10 @@ import ( type GroupIdentifier string +func BytesToGroupIdentifier(raw *libsignalgo.GroupIdentifier) GroupIdentifier { + return GroupIdentifier(raw.String()) +} + func (gid GroupIdentifier) String() string { return string(gid) } From 8201f9b1af45b9d89b91d551337ba1a2f3a26467 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 23 Jul 2025 11:17:36 +0300 Subject: [PATCH 511/718] libsignal: update to v0.76.7 --- pkg/libsignalgo/error.go | 2 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 35 +++++++++++++++++++++------------ pkg/libsignalgo/version.go | 2 +- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/pkg/libsignalgo/error.go b/pkg/libsignalgo/error.go index 8b83a48..b0d79c8 100644 --- a/pkg/libsignalgo/error.go +++ b/pkg/libsignalgo/error.go @@ -92,7 +92,7 @@ func wrapError(signalError *C.SignalFfiError) error { func wrapSignalError(signalError *C.SignalFfiError, errorType C.uint32_t) error { var messageBytes *C.char - getMessageError := C.signal_error_get_message(signalError, &messageBytes) + getMessageError := C.signal_error_get_message(&messageBytes, signalError) if getMessageError != nil { // Ignore any errors from this, it will just end up being an empty string. C.signal_error_free(getMessageError) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 6dc0f85..9fc4534 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 6dc0f85b07d890fd02e727a0f8484a1f3f864f7e +Subproject commit 9fc4534b29fc488beeba082dd739aeae73032908 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 0288e34..d52782d 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -864,6 +864,11 @@ typedef struct { const SignalDecryptionErrorMessage *raw; } SignalConstPointerDecryptionErrorMessage; +/** + * Like [`std::panic::AssertUnwindSafe`], but FFI-compatible. + */ +typedef const SignalFfiError *SignalUnwindSafeArgSignalFfiError; + typedef struct { SignalFingerprint *raw; } SignalMutPointerFingerprint; @@ -1588,31 +1593,31 @@ SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, S void signal_error_free(SignalFfiError *err); -SignalFfiError *signal_error_get_address(const SignalFfiError *err, SignalMutPointerProtocolAddress *out); +SignalFfiError *signal_error_get_address(SignalMutPointerProtocolAddress *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_invalid_protocol_address(const SignalFfiError *err, const char **name_out, uint32_t *device_id_out); +SignalFfiError *signal_error_get_invalid_protocol_address(const char **name_out, uint32_t *device_id_out, const SignalFfiError *err); -SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out); +SignalFfiError *signal_error_get_message(const char **out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_our_fingerprint_version(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_our_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_rate_limit_challenge(const SignalFfiError *err, const char **out_token, SignalOwnedBuffer *out_options); +SignalFfiError *signal_error_get_rate_limit_challenge(const char **out_token, SignalOwnedBuffer *out_options, const SignalFfiError *err); -SignalFfiError *signal_error_get_registration_error_not_deliverable(const SignalFfiError *err, const char **out_reason, bool *out_permanent); +SignalFfiError *signal_error_get_registration_error_not_deliverable(const char **out_reason, bool *out_permanent, const SignalFfiError *err); -SignalFfiError *signal_error_get_registration_lock(const SignalFfiError *err, uint64_t *out_time_remaining_seconds, const char **out_svr2_username, const char **out_svr2_password); +SignalFfiError *signal_error_get_registration_lock(uint64_t *out_time_remaining_seconds, const char **out_svr2_username, const char **out_svr2_password, const SignalFfiError *err); -SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_retry_after_seconds(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_their_fingerprint_version(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_their_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out); +SignalFfiError *signal_error_get_tries_remaining(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); uint32_t signal_error_get_type(const SignalFfiError *err); -SignalFfiError *signal_error_get_unknown_fields(const SignalFfiError *err, SignalStringArray *out); +SignalFfiError *signal_error_get_unknown_fields(SignalStringArray *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_uuid(const SignalFfiError *err, uint8_t (*out)[16]); +SignalFfiError *signal_error_get_uuid(uint8_t (*out)[16], SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); @@ -1998,6 +2003,8 @@ SignalFfiError *signal_privatekey_generate(SignalMutPointerPrivateKey *out); SignalFfiError *signal_privatekey_get_public_key(SignalMutPointerPublicKey *out, SignalConstPointerPrivateKey k); +SignalFfiError *signal_privatekey_hpke_open(SignalOwnedBuffer *out, SignalConstPointerPrivateKey sk, SignalBorrowedBuffer ciphertext, SignalBorrowedBuffer info, SignalBorrowedBuffer associated_data); + SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstPointerPrivateKey obj); SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); @@ -2042,6 +2049,8 @@ SignalFfiError *signal_publickey_equals(bool *out, SignalConstPointerPublicKey l SignalFfiError *signal_publickey_get_public_key_bytes(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); +SignalFfiError *signal_publickey_hpke_seal(SignalOwnedBuffer *out, SignalConstPointerPublicKey pk, SignalBorrowedBuffer plaintext, SignalBorrowedBuffer info, SignalBorrowedBuffer associated_data); + SignalFfiError *signal_publickey_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey obj); SignalFfiError *signal_publickey_verify(bool *out, SignalConstPointerPublicKey key, SignalBorrowedBuffer message, SignalBorrowedBuffer signature); @@ -2118,7 +2127,7 @@ SignalFfiError *signal_registration_service_register_account(SignalCPromiseMutPo SignalFfiError *signal_registration_service_registration_session(SignalMutPointerRegistrationSession *out, SignalConstPointerRegistrationService service); -SignalFfiError *signal_registration_service_request_push_challenge(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *push_token, const void *push_token_type); +SignalFfiError *signal_registration_service_request_push_challenge(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *push_token); SignalFfiError *signal_registration_service_request_verification_code(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerRegistrationService service, const char *transport, const char *client, SignalBorrowedBytestringArray languages); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index e9ce0db..90264fd 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.76.1" +const Version = "v0.76.7" From 0833cb544052a4455cf91e6c2199a15ee7300afd Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 23 Jul 2025 11:18:43 +0300 Subject: [PATCH 512/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/SignalService.pb.go | 15 ++++++++--- pkg/signalmeow/protobuf/SignalService.proto | 1 + pkg/signalmeow/protobuf/StorageService.pb.go | 13 ++++++++-- pkg/signalmeow/protobuf/StorageService.proto | 1 + pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 26 ++++++++++++++++--- pkg/signalmeow/protobuf/backuppb/Backup.proto | 2 ++ pkg/signalmeow/protobuf/update-protos.sh | 4 +-- 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index 46214d7..fd875ac 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -6660,6 +6660,7 @@ type SyncMessage_CallLinkUpdate struct { RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey" json:"adminPasskey,omitempty"` Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` // defaults to UPDATE + Epoch []byte `protobuf:"bytes,4,opt,name=epoch" json:"epoch,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -6715,6 +6716,13 @@ func (x *SyncMessage_CallLinkUpdate) GetType() SyncMessage_CallLinkUpdate_Type { return SyncMessage_CallLinkUpdate_UPDATE } +func (x *SyncMessage_CallLinkUpdate) GetEpoch() []byte { + if x != nil { + return x.Epoch + } + return nil +} + type SyncMessage_CallLogEvent struct { state protoimpl.MessageState `protogen:"open.v1"` Type *SyncMessage_CallLogEvent_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_CallLogEvent_Type" json:"type,omitempty"` @@ -8082,7 +8090,7 @@ const file_SignalService_proto_rawDesc = "" + "\aDEFAULT\x10\x00\x12\f\n" + "\bVERIFIED\x10\x01\x12\x0e\n" + "\n" + - "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\xf1C\n" + + "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\x87D\n" + "\vSyncMessage\x123\n" + "\x04sent\x18\x01 \x01(\v2\x1f.signalservice.SyncMessage.SentR\x04sent\x12?\n" + "\bcontacts\x18\x02 \x01(\v2#.signalservice.SyncMessage.ContactsR\bcontacts\x12<\n" + @@ -8247,11 +8255,12 @@ const file_SignalService_proto_rawDesc = "" + "\fNOT_ACCEPTED\x10\x02\x12\n" + "\n" + "\x06DELETE\x10\x03\x12\f\n" + - "\bOBSERVED\x10\x04\x1a\xac\x01\n" + + "\bOBSERVED\x10\x04\x1a\xc2\x01\n" + "\x0eCallLinkUpdate\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x12B\n" + - "\x04type\x18\x03 \x01(\x0e2..signalservice.SyncMessage.CallLinkUpdate.TypeR\x04type\"\x18\n" + + "\x04type\x18\x03 \x01(\x0e2..signalservice.SyncMessage.CallLinkUpdate.TypeR\x04type\x12\x14\n" + + "\x05epoch\x18\x04 \x01(\fR\x05epoch\"\x18\n" + "\x04Type\x12\n" + "\n" + "\x06UPDATE\x10\x00\"\x04\b\x01\x10\x01\x1a\x94\x02\n" + diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 51213ca..a1fa8f9 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -628,6 +628,7 @@ message SyncMessage { optional bytes rootKey = 1; optional bytes adminPasskey = 2; optional Type type = 3; // defaults to UPDATE + optional bytes epoch = 4; } message CallLogEvent { diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index c6ce93e..3bfa1c1 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -1962,6 +1962,7 @@ type CallLinkRecord struct { RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` + Epoch []byte `protobuf:"bytes,4,opt,name=epoch,proto3" json:"epoch,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2017,6 +2018,13 @@ func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 { return 0 } +func (x *CallLinkRecord) GetEpoch() []byte { + if x != nil { + return x.Epoch + } + return nil +} + type Recipient struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Identifier: @@ -3259,11 +3267,12 @@ const file_StorageService_proto_rawDesc = "" + "\x13recipientServiceIds\x18\x03 \x03(\tR\x13recipientServiceIds\x12.\n" + "\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" + - "\visBlockList\x18\x06 \x01(\bR\visBlockList\"\x82\x01\n" + + "\visBlockList\x18\x06 \x01(\bR\visBlockList\"\x98\x01\n" + "\x0eCallLinkRecord\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + - "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\"\xe6\x01\n" + + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\x12\x14\n" + + "\x05epoch\x18\x04 \x01(\fR\x05epoch\"\xe6\x01\n" + "\tRecipient\x12<\n" + "\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index eaa1453..2229805 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -306,6 +306,7 @@ message CallLinkRecord { bytes rootKey = 1; bytes adminPasskey = 2; uint64 deletedAtTimestampMs = 3; + bytes epoch = 4; } message Recipient { diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 06ebdea..cc4b279 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1861,6 +1861,7 @@ type BackupInfo struct { MediaRootBackupKey []byte `protobuf:"bytes,3,opt,name=mediaRootBackupKey,proto3" json:"mediaRootBackupKey,omitempty"` // 32-byte random value generated when the backup is uploaded for the first time. CurrentAppVersion string `protobuf:"bytes,4,opt,name=currentAppVersion,proto3" json:"currentAppVersion,omitempty"` FirstAppVersion string `protobuf:"bytes,5,opt,name=firstAppVersion,proto3" json:"firstAppVersion,omitempty"` + DebugInfo []byte `protobuf:"bytes,6,opt,name=debugInfo,proto3" json:"debugInfo,omitempty"` // Client-specific data field for debug info during testing unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1930,6 +1931,13 @@ func (x *BackupInfo) GetFirstAppVersion() string { return "" } +func (x *BackupInfo) GetDebugInfo() []byte { + if x != nil { + return x.DebugInfo + } + return nil +} + // Frames must follow in the following ordering rules: // // 1. There is exactly one AccountData and it is the first frame. @@ -2936,6 +2944,7 @@ type CallLink struct { Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Restrictions CallLink_Restrictions `protobuf:"varint,4,opt,name=restrictions,proto3,enum=signal.backup.CallLink_Restrictions" json:"restrictions,omitempty"` ExpirationMs uint64 `protobuf:"varint,5,opt,name=expirationMs,proto3" json:"expirationMs,omitempty"` + Epoch []byte `protobuf:"bytes,6,opt,name=epoch,proto3" json:"epoch,omitempty"` // May be absent/empty for older links unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3005,6 +3014,13 @@ func (x *CallLink) GetExpirationMs() uint64 { return 0 } +func (x *CallLink) GetEpoch() []byte { + if x != nil { + return x.Epoch + } + return nil +} + type AdHocCall struct { state protoimpl.MessageState `protogen:"open.v1"` CallId uint64 `protobuf:"varint,1,opt,name=callId,proto3" json:"callId,omitempty"` @@ -11519,14 +11535,15 @@ var File_backuppb_Backup_proto protoreflect.FileDescriptor const file_backuppb_Backup_proto_rawDesc = "" + "\n" + - "\x15backuppb/Backup.proto\x12\rsignal.backup\"\xd2\x01\n" + + "\x15backuppb/Backup.proto\x12\rsignal.backup\"\xf0\x01\n" + "\n" + "BackupInfo\x12\x18\n" + "\aversion\x18\x01 \x01(\x04R\aversion\x12\"\n" + "\fbackupTimeMs\x18\x02 \x01(\x04R\fbackupTimeMs\x12.\n" + "\x12mediaRootBackupKey\x18\x03 \x01(\fR\x12mediaRootBackupKey\x12,\n" + "\x11currentAppVersion\x18\x04 \x01(\tR\x11currentAppVersion\x12(\n" + - "\x0ffirstAppVersion\x18\x05 \x01(\tR\x0ffirstAppVersion\"\xf2\x03\n" + + "\x0ffirstAppVersion\x18\x05 \x01(\tR\x0ffirstAppVersion\x12\x1c\n" + + "\tdebugInfo\x18\x06 \x01(\fR\tdebugInfo\"\xf2\x03\n" + "\x05Frame\x126\n" + "\aaccount\x18\x01 \x01(\v2\x1a.signal.backup.AccountDataH\x00R\aaccount\x128\n" + "\trecipient\x18\x02 \x01(\v2\x18.signal.backup.RecipientH\x00R\trecipient\x12)\n" + @@ -11763,13 +11780,14 @@ const file_backuppb_Backup_proto_rawDesc = "" + " \x01(\rR\x12expireTimerVersionB\x0e\n" + "\f_pinnedOrderB\x14\n" + "\x12_expirationTimerMsB\x0e\n" + - "\f_muteUntilMs\"\x8f\x02\n" + + "\f_muteUntilMs\"\xa5\x02\n" + "\bCallLink\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\x1f\n" + "\badminKey\x18\x02 \x01(\fH\x00R\badminKey\x88\x01\x01\x12\x12\n" + "\x04name\x18\x03 \x01(\tR\x04name\x12H\n" + "\frestrictions\x18\x04 \x01(\x0e2$.signal.backup.CallLink.RestrictionsR\frestrictions\x12\"\n" + - "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\"9\n" + + "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\x12\x14\n" + + "\x05epoch\x18\x06 \x01(\fR\x05epoch\"9\n" + "\fRestrictions\x12\v\n" + "\aUNKNOWN\x10\x00\x12\b\n" + "\x04NONE\x10\x01\x12\x12\n" + diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 0dd3e89..f88c6ae 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -11,6 +11,7 @@ message BackupInfo { bytes mediaRootBackupKey = 3; // 32-byte random value generated when the backup is uploaded for the first time. string currentAppVersion = 4; string firstAppVersion = 5; + bytes debugInfo = 6; // Client-specific data field for debug info during testing } // Frames must follow in the following ordering rules: @@ -343,6 +344,7 @@ message CallLink { string name = 3; Restrictions restrictions = 4; uint64 expirationMs = 5; + bytes epoch = 6; // May be absent/empty for older links } message AdHocCall { diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index c3d85c0..21503c1 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-4b9cac43a82b5b907de53696b93eaf521943d15c} -DESKTOP_GIT_REVISION=${1:-ffc34d5080b8b8aec1bbebf11a13227e224dffe0} +ANDROID_GIT_REVISION=${1:-dbd79cd0a52d7d1594f70a4ba5a68c8fc3efa5e8} +DESKTOP_GIT_REVISION=${1:-07a05f3dd6f7fd07a1faebd8dd046d2b87da6c07} update_proto() { case "$1" in From 1f08ab883c3618c874dfc54d1d052b02faf356b3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 15:59:10 +0300 Subject: [PATCH 513/718] legacyprovision: switch to standard http mux --- cmd/mautrix-signal/legacyprovision.go | 3 +-- cmd/mautrix-signal/main.go | 14 ++++++-------- go.mod | 10 ++++------ go.sum | 20 ++++++++------------ 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/cmd/mautrix-signal/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go index 8bad469..6bd6882 100644 --- a/cmd/mautrix-signal/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -25,7 +25,6 @@ import ( "sync" "sync/atomic" - "github.com/gorilla/mux" "github.com/rs/zerolog" "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridgev2" @@ -215,7 +214,7 @@ func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, return } api := login.Client.(bridgev2.IdentifierResolvingNetworkAPI) - phonenum := mux.Vars(r)["phonenum"] + phonenum := r.PathValue("phonenum") resp, err := api.ResolveIdentifier(r.Context(), phonenum, create) if err != nil { zerolog.Ctx(r.Context()).Err(err).Msg("Failed to resolve identifier") diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 78f696e..dc1a25a 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -17,8 +17,6 @@ package main import ( - "net/http" - "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix/mxmain" @@ -57,12 +55,12 @@ func main() { } m.PostStart = func() { if m.Matrix.Provisioning != nil { - m.Matrix.Provisioning.Router.HandleFunc("/v2/link/new", legacyProvLinkNew).Methods(http.MethodPost) - m.Matrix.Provisioning.Router.HandleFunc("/v2/link/wait/scan", legacyProvLinkWaitScan).Methods(http.MethodPost) - m.Matrix.Provisioning.Router.HandleFunc("/v2/link/wait/account", legacyProvLinkWaitAccount).Methods(http.MethodPost) - m.Matrix.Provisioning.Router.HandleFunc("/v2/logout", legacyProvLogout).Methods(http.MethodPost) - m.Matrix.Provisioning.Router.HandleFunc("/v2/resolve_identifier/{phonenum}", legacyProvResolveIdentifier).Methods(http.MethodGet) - m.Matrix.Provisioning.Router.HandleFunc("/v2/pm/{phonenum}", legacyProvPM).Methods(http.MethodPost) + m.Matrix.Provisioning.Router.HandleFunc("POST /v2/link/new", legacyProvLinkNew) + m.Matrix.Provisioning.Router.HandleFunc("POST /v2/link/wait/scan", legacyProvLinkWaitScan) + m.Matrix.Provisioning.Router.HandleFunc("POST /v2/link/wait/account", legacyProvLinkWaitAccount) + m.Matrix.Provisioning.Router.HandleFunc("POST /v2/logout", legacyProvLogout) + m.Matrix.Provisioning.Router.HandleFunc("GET /v2/resolve_identifier/{phonenum}", legacyProvResolveIdentifier) + m.Matrix.Provisioning.Router.HandleFunc("POST /v2/pm/{phonenum}", legacyProvPM) } } m.InitVersion(Tag, Commit, BuildTime) diff --git a/go.mod b/go.mod index 29aa21d..579302a 100644 --- a/go.mod +++ b/go.mod @@ -8,30 +8,28 @@ require ( github.com/coder/websocket v1.8.13 github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 - github.com/gorilla/mux v1.8.0 github.com/mattn/go-pointer v0.0.1 github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.8 + go.mau.fi/util v0.8.9-0.20250723171559-474867266038 golang.org/x/crypto v0.40.0 - golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc + golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.2 + maunium.net/go/mautrix v0.24.3-0.20250728125317-74ab3b118e10 ) require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gorilla/websocket v1.5.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/lib/pq v1.10.9 // 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.28 // indirect - github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb // indirect + github.com/petermattis/goid v0.0.0-20250721140440-ea1c0173183e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect diff --git a/go.sum b/go.sum index 1f8d1a9..dda20d8 100644 --- a/go.sum +++ b/go.sum @@ -16,10 +16,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -40,8 +36,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb h1:3PrKuO92dUTMrQ9dx0YNejC6U/Si6jqKmyQ9vWjwqR4= -github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20250721140440-ea1c0173183e h1:D0bJD+4O3G4izvrQUmzCL80zazlN7EwJ0PPDhpJWC/I= +github.com/petermattis/goid v0.0.0-20250721140440-ea1c0173183e/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -69,14 +65,14 @@ 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.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.8.8 h1:OnuEEc/sIJFhnq4kFggiImUpcmnmL/xpvQMRu5Fiy5c= -go.mau.fi/util v0.8.8/go.mod h1:Y/kS3loxTEhy8Vill513EtPXr+CRDdae+Xj2BXXMy/c= +go.mau.fi/util v0.8.9-0.20250723171559-474867266038 h1:RVL8TVaYc3LTBBopfjCNDtD+6eZks0O+qgXN/9hsz7k= +go.mau.fi/util v0.8.9-0.20250723171559-474867266038/go.mod h1:GZZp5f9r2MgEu4GDvtB0XxCF7i6Z7Z8fM0w9a5oZH3Y= go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4= +golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= @@ -99,5 +95,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.24.2 h1:+AVT5kbcA/QuT5svrJKp4ivwoUmz+RRplMp3DnfpheI= -maunium.net/go/mautrix v0.24.2/go.mod h1:1ut900w++eE9by9yqCR2dQdMqwsHwZG5L+1bKB1EvSA= +maunium.net/go/mautrix v0.24.3-0.20250728125317-74ab3b118e10 h1:IMOGeYKTOzHNnBx1ksVCVCw3t6joQRqDOSI2Ou4Xr/U= +maunium.net/go/mautrix v0.24.3-0.20250728125317-74ab3b118e10/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= From d4d9687ef242025350ceeb58015c038e67855510 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 16:10:20 +0300 Subject: [PATCH 514/718] signalid/media: remove pointless use of bufio --- pkg/signalid/media.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go index 533463c..6190c89 100644 --- a/pkg/signalid/media.go +++ b/pkg/signalid/media.go @@ -17,7 +17,6 @@ package signalid import ( - "bufio" "bytes" "crypto/sha256" "encoding/binary" @@ -127,7 +126,7 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err return nil, fmt.Errorf("empty media ID") } - buf := bufio.NewReader(bytes.NewBuffer(mediaID)) + buf := bytes.NewReader(mediaID) // type byte var mediaType directMediaType @@ -169,7 +168,7 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err if err = binary.Read(buf, binary.BigEndian, &info.UserID); err != nil { return info, fmt.Errorf("failed to read user id: %w", err) - } else if binary.Read(buf, binary.BigEndian, &info.GroupID); err != nil { + } else if err = binary.Read(buf, binary.BigEndian, &info.GroupID); err != nil { return info, fmt.Errorf("failed to read group id: %w", err) } if groupAvatarPath, err := readByteSlice(buf, mediaIDLen); err != nil { @@ -215,7 +214,12 @@ func writeByteSlice(w io.Writer, b []byte) error { return err } -func readByteSlice(r *bufio.Reader, maxLength int) ([]byte, error) { +type byteReader interface { + io.ByteReader + io.Reader +} + +func readByteSlice(r byteReader, maxLength int) ([]byte, error) { length, err := binary.ReadUvarint(r) if err != nil { return nil, fmt.Errorf("reading uvarint failed: %w", err) From 7c89794bb29e98db446d738885b17695eb96e3ae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 15:59:44 +0300 Subject: [PATCH 515/718] msgconv,signalmeow: switch to using LocatorInfo in backups --- pkg/msgconv/from-signal-backup.go | 40 +++++++++++++++++++++---------- pkg/msgconv/from-signal.go | 23 ++++++++++++------ pkg/signalid/media.go | 6 ++--- pkg/signalmeow/provisioning.go | 2 +- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index d5532cd..e5cb316 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -34,7 +34,7 @@ func boolToInt(b bool) int { return 0 } -type AttachmentMap map[uuid.UUID]*backuppb.FilePointer_BackupLocator +type AttachmentMap map[uuid.UUID]*backuppb.FilePointer_LocatorInfo func BackupToDataMessage(ci *backuppb.ChatItem, attMap AttachmentMap) (*signalpb.DataMessage, []*backuppb.Reaction) { var dm signalpb.DataMessage @@ -186,7 +186,7 @@ func backupToSignalAttachment( fp *backuppb.FilePointer, flag backuppb.MessageAttachment_Flag, clientUUID uuid.UUID, - atts map[uuid.UUID]*backuppb.FilePointer_BackupLocator, + atts AttachmentMap, ) *signalpb.AttachmentPointer { sig := &signalpb.AttachmentPointer{ //IncrementalMacChunkSize: fp.IncrementalMacChunkSize, @@ -200,17 +200,31 @@ func backupToSignalAttachment( BlurHash: fp.BlurHash, ClientUuid: clientUUID[:], } - switch loc := fp.Locator.(type) { - case *backuppb.FilePointer_AttachmentLocator_: - sig.AttachmentIdentifier = &signalpb.AttachmentPointer_CdnKey{CdnKey: loc.AttachmentLocator.CdnKey} - sig.Key = loc.AttachmentLocator.Key - sig.Size = &loc.AttachmentLocator.Size - sig.Digest = loc.AttachmentLocator.Digest - sig.CdnNumber = &loc.AttachmentLocator.CdnNumber - case *backuppb.FilePointer_BackupLocator_: - atts[clientUUID] = loc.BackupLocator - case *backuppb.FilePointer_InvalidAttachmentLocator_: - atts[clientUUID] = nil + if fp.LocatorInfo != nil { + if fp.LocatorInfo.TransitCdnKey != nil { + sig.AttachmentIdentifier = &signalpb.AttachmentPointer_CdnKey{CdnKey: *fp.LocatorInfo.TransitCdnKey} + sig.Size = &fp.LocatorInfo.Size + sig.Digest = fp.LocatorInfo.GetEncryptedDigest() // Note: may be nil if plaintextHash is set instead + if sig.Digest == nil { + sig.Digest = fp.LocatorInfo.LegacyDigest + } + sig.CdnNumber = fp.LocatorInfo.TransitCdnNumber + } + sig.Key = fp.LocatorInfo.Key + atts[clientUUID] = fp.LocatorInfo + } else { + switch loc := fp.Locator.(type) { + case *backuppb.FilePointer_AttachmentLocator_: + sig.AttachmentIdentifier = &signalpb.AttachmentPointer_CdnKey{CdnKey: loc.AttachmentLocator.CdnKey} + sig.Key = loc.AttachmentLocator.Key + sig.Size = &loc.AttachmentLocator.Size + sig.Digest = loc.AttachmentLocator.Digest + sig.CdnNumber = &loc.AttachmentLocator.CdnNumber + case *backuppb.FilePointer_BackupLocator_: + //atts[clientUUID] = loc.BackupLocator + case *backuppb.FilePointer_InvalidAttachmentLocator_: + atts[clientUUID] = nil + } } return sig } diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index da5becb..73663f9 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -463,21 +463,28 @@ func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *sig return &longBody, nil } -func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) ([]byte, error) { +func checkIfAttachmentExists(att *signalpb.AttachmentPointer, attMap AttachmentMap) error { if att.AttachmentIdentifier == nil { if len(att.GetClientUuid()) != 16 { - return nil, fmt.Errorf("no attachment identifier found") + return fmt.Errorf("no attachment identifier found") } target, ok := attMap[uuid.UUID(att.GetClientUuid())] if !ok { - return nil, fmt.Errorf("no attachment identifier and attachment not found in map") - } else if target == nil { - return nil, ErrAttachmentNotInBackup + return fmt.Errorf("no attachment identifier and attachment not found in map") + } else if target == nil || target.MediaTierCdnNumber == nil { + return ErrAttachmentNotInBackup } else { // TODO add support for downloading attachments from backup - return nil, ErrBackupNotSupported + return ErrBackupNotSupported } } + return nil +} + +func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) ([]byte, error) { + if err := checkIfAttachmentExists(att, attMap); err != nil { + return nil, err + } return signalmeow.DownloadAttachmentWithPointer(ctx, att) } @@ -491,7 +498,9 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp }, } mimeType := att.GetContentType() - if mc.DirectMedia { + if err := checkIfAttachmentExists(att, attMap); err != nil { + return nil, err + } else if mc.DirectMedia { mediaID, err := signalid.DirectMediaAttachment{ CDNID: att.GetCdnId(), CDNKey: att.GetCdnKey(), diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go index 6190c89..d060628 100644 --- a/pkg/signalid/media.go +++ b/pkg/signalid/media.go @@ -30,9 +30,9 @@ import ( type directMediaType byte const ( - directMediaTypeAttachment directMediaType = iota - directMediaTypeGroupAvatar - directMediaTypeProfileAvatar + directMediaTypeAttachment directMediaType = 0 + directMediaTypeGroupAvatar directMediaType = 1 + directMediaTypeProfileAvatar directMediaType = 2 ) type DirectMediaInfo interface { diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 94a4176..07697d1 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -299,7 +299,7 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) } - linkCapabilities := []string{"backup3"} + linkCapabilities := []string{"backup4"} if !allowBackup { linkCapabilities = []string{} } From 47e4284fea419fdb99bd500e88762b5763170540 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 16:17:55 +0300 Subject: [PATCH 516/718] msgconv,signalmeow: add support for plaintext attachment hashes in backup --- pkg/connector/directmedia.go | 5 ++++- pkg/msgconv/from-signal.go | 31 ++++++++++++++++++++++++------- pkg/signalid/media.go | 30 +++++++++++++++++++----------- pkg/signalmeow/attachments.go | 33 ++++++++++++++++++++++++--------- pkg/signalmeow/receiving.go | 2 +- 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go index 8507626..6f31e15 100644 --- a/pkg/connector/directmedia.go +++ b/pkg/connector/directmedia.go @@ -37,12 +37,15 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI Uint32("cdn_number", info.CDNNumber). Int("key_len", len(info.Key)). Int("digest_len", len(info.Digest)). + Bool("plaintext_digest", info.PlaintextDigest). Uint32("size", info.Size). Msg("Direct downloading attachment") return &mediaproxy.GetMediaResponseCallback{ Callback: func(w io.Writer) (int64, error) { - data, err := signalmeow.DownloadAttachment(ctx, info.CDNID, info.CDNKey, info.CDNNumber, info.Key, info.Digest, info.Size) + data, err := signalmeow.DownloadAttachment( + ctx, info.CDNID, info.CDNKey, info.CDNNumber, info.Key, info.Digest, info.PlaintextDigest, info.Size, + ) if err != nil { log.Err(err).Msg("Direct download failed") return 0, err diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 73663f9..18e8de4 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -485,7 +485,14 @@ func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalp if err := checkIfAttachmentExists(att, attMap); err != nil { return nil, err } - return signalmeow.DownloadAttachmentWithPointer(ctx, att) + var plaintextHash []byte + if len(att.GetClientUuid()) == 16 { + target, ok := attMap[uuid.UUID(att.GetClientUuid())] + if ok { + plaintextHash = target.GetPlaintextHash() + } + } + return signalmeow.DownloadAttachmentWithPointer(ctx, att, plaintextHash) } func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*bridgev2.ConvertedMessagePart, error) { @@ -501,13 +508,23 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp if err := checkIfAttachmentExists(att, attMap); err != nil { return nil, err } else if mc.DirectMedia { + digest := att.Digest + var plaintextDigest bool + if digest == nil && len(att.GetClientUuid()) == 16 { + locatorInfo, ok := attMap[uuid.UUID(att.GetClientUuid())] + if ok { + digest = locatorInfo.GetPlaintextHash() + plaintextDigest = true + } + } mediaID, err := signalid.DirectMediaAttachment{ - CDNID: att.GetCdnId(), - CDNKey: att.GetCdnKey(), - CDNNumber: att.GetCdnNumber(), - Key: att.Key, - Digest: att.Digest, - Size: att.GetSize(), + CDNID: att.GetCdnId(), + CDNKey: att.GetCdnKey(), + CDNNumber: att.GetCdnNumber(), + Key: att.Key, + Digest: digest, + PlaintextDigest: plaintextDigest, + Size: att.GetSize(), }.AsMediaID() if err != nil { return nil, err diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go index d060628..8c91b6a 100644 --- a/pkg/signalid/media.go +++ b/pkg/signalid/media.go @@ -30,9 +30,10 @@ import ( type directMediaType byte const ( - directMediaTypeAttachment directMediaType = 0 - directMediaTypeGroupAvatar directMediaType = 1 - directMediaTypeProfileAvatar directMediaType = 2 + directMediaTypeAttachment directMediaType = 0 + directMediaTypeGroupAvatar directMediaType = 1 + directMediaTypeProfileAvatar directMediaType = 2 + directMediaTypePlaintextDigestAttachment directMediaType = 3 ) type DirectMediaInfo interface { @@ -46,18 +47,24 @@ var ( ) type DirectMediaAttachment struct { - CDNID uint64 - CDNKey string - CDNNumber uint32 - Key []byte - Digest []byte - Size uint32 + CDNID uint64 + CDNKey string + CDNNumber uint32 + Key []byte + PlaintextDigest bool + Digest []byte + Size uint32 } func (m DirectMediaAttachment) AsMediaID() (mediaID networkid.MediaID, err error) { buf := &bytes.Buffer{} - if err = binary.Write(buf, binary.BigEndian, directMediaTypeAttachment); err != nil { + attType := directMediaTypeAttachment + if m.PlaintextDigest { + attType = directMediaTypePlaintextDigestAttachment + } + + if err = binary.Write(buf, binary.BigEndian, attType); err != nil { return } else if err = writeUvarint(buf, m.CDNID); err != nil { return @@ -135,8 +142,9 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err } switch mediaType { - case directMediaTypeAttachment: + case directMediaTypeAttachment, directMediaTypePlaintextDigestAttachment: var info DirectMediaAttachment + info.PlaintextDigest = mediaType == directMediaTypePlaintextDigestAttachment if info.CDNID, err = binary.ReadUvarint(buf); err != nil { return info, fmt.Errorf("failed to read cdn id: %w", err) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 386d9cc..e321f57 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -59,11 +59,17 @@ var ErrInvalidMACForAttachment = errors.New("invalid MAC for attachment") var ErrInvalidDigestForAttachment = errors.New("invalid digest for attachment") var ErrAttachmentNotFound = errors.New("attachment not found on server") -func DownloadAttachmentWithPointer(ctx context.Context, a *signalpb.AttachmentPointer) ([]byte, error) { - return DownloadAttachment(ctx, a.GetCdnId(), a.GetCdnKey(), a.GetCdnNumber(), a.Key, a.Digest, a.GetSize()) +func DownloadAttachmentWithPointer(ctx context.Context, a *signalpb.AttachmentPointer, plaintextHash []byte) ([]byte, error) { + digest := a.GetDigest() + plaintextDigest := false + if digest == nil && plaintextHash != nil { + digest = plaintextHash + plaintextDigest = true + } + return DownloadAttachment(ctx, a.GetCdnId(), a.GetCdnKey(), a.GetCdnNumber(), a.Key, digest, plaintextDigest, a.GetSize()) } -func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNumber uint32, key, digest []byte, size uint32) ([]byte, error) { +func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNumber uint32, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) { path := getAttachmentPath(cdnID, cdnKey) resp, err := web.GetAttachment(ctx, path, cdnNumber, nil) if err != nil { @@ -88,16 +94,18 @@ func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNum return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } - return decryptAttachment(body, key, digest, size) + return decryptAttachment(body, key, digest, plaintextDigest, size) } const MACLength = 32 const IVLength = 16 -func decryptAttachment(body, key, digest []byte, size uint32) ([]byte, error) { - hash := sha256.Sum256(body) - if !hmac.Equal(hash[:], digest) { - return nil, ErrInvalidDigestForAttachment +func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) { + if !plaintextDigest { + hash := sha256.Sum256(body) + if !hmac.Equal(hash[:], digest) { + return nil, ErrInvalidDigestForAttachment + } } l := len(body) - MACLength if !verifyMAC(key[MACLength:], body[:l], body[l:]) { @@ -111,7 +119,14 @@ func decryptAttachment(body, key, digest []byte, size uint32) ([]byte, error) { if len(decrypted) < int(size) { return nil, fmt.Errorf("decrypted attachment length %v < expected %v", len(decrypted), size) } - return decrypted[:size], nil + decrypted = decrypted[:size] + if plaintextDigest { + hash := sha256.Sum256(decrypted) + if !hmac.Equal(hash[:], digest) { + return nil, fmt.Errorf("%w (plaintext hash)", ErrInvalidDigestForAttachment) + } + } + return decrypted, nil } type attachmentV4UploadAttributes struct { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 49ed0f3..6c97a69 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -592,7 +592,7 @@ func (cli *Client) handleDecryptedResult( log.Debug().Msg("Recieved sync message contacts") blob := content.SyncMessage.Contacts.Blob if blob != nil { - contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob) + contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil) if err != nil { log.Err(err).Msg("Contacts Sync DownloadAttachment error") } From fb5ff7dd74df79b17d12d7778d278b0e55c9cde3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 16:52:46 +0300 Subject: [PATCH 517/718] msgconv/from-signal: remove hack for gif flag --- pkg/msgconv/from-matrix.go | 2 +- pkg/msgconv/from-signal-backup.go | 2 +- pkg/msgconv/from-signal.go | 9 +-------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 36391f3..26bb492 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -192,7 +192,7 @@ func (mc *MessageConverter) convertFileToSignal(ctx context.Context, evt *event. att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_VOICE_MESSAGE)) } if content.Info.MauGIF { - att.Flags = proto.Uint32(uint32(compatFlagGIF)) + att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_GIF)) } att.ContentType = proto.String(mime) att.FileName = &fileName diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index e5cb316..5f7f12b 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -236,7 +236,7 @@ func backupToSignalAttachmentFlag(flag backuppb.MessageAttachment_Flag) signalpb case backuppb.MessageAttachment_BORDERLESS: return signalpb.AttachmentPointer_BORDERLESS case backuppb.MessageAttachment_GIF: - return compatFlagGIF + return signalpb.AttachmentPointer_GIF case backuppb.MessageAttachment_NONE: fallthrough default: diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 18e8de4..815954a 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -76,13 +76,6 @@ func CanConvertSignal(dm *signalpb.DataMessage) bool { const ViewOnceDisappearTimer = 5 * time.Minute -// Why does signal have two different flags for gifs?? -// https://github.com/signalapp/Signal-Android/blob/v7.29.4/libsignal-service/src/main/protowire/SignalService.proto#L745 -// https://github.com/signalapp/Signal-Desktop/blob/v7.38.0-beta.1/protos/SignalService.proto#L740 -// https://github.com/signalapp/Signal-iOS/blob/7.42.0.545-beta/SignalServiceKit/protobuf/SignalService.proto#L756 -// Apparently the android one is a lie and doesn't work? -const compatFlagGIF = 8 - func (mc *MessageConverter) ToMatrix( ctx context.Context, client *signalmeow.Client, @@ -569,7 +562,7 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp content.MsgType = event.MsgFile } var extra map[string]any - if att.GetFlags()&uint32(compatFlagGIF) != 0 { + if att.GetFlags()&uint32(signalpb.AttachmentPointer_GIF) != 0 { content.Info.MauGIF = true extra = map[string]any{ "info": map[string]any{ From d85a48abeb12d4a3accdee8af11bfa76626c2f2a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 17:34:59 +0300 Subject: [PATCH 518/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 579302a..cff8080 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.3-0.20250728125317-74ab3b118e10 + maunium.net/go/mautrix v0.24.3-0.20250728143428-ae2c07fb863a ) require ( diff --git a/go.sum b/go.sum index dda20d8..e8d87ed 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.24.3-0.20250728125317-74ab3b118e10 h1:IMOGeYKTOzHNnBx1ksVCVCw3t6joQRqDOSI2Ou4Xr/U= -maunium.net/go/mautrix v0.24.3-0.20250728125317-74ab3b118e10/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= +maunium.net/go/mautrix v0.24.3-0.20250728143428-ae2c07fb863a h1:3lQKIbNLbHKxMLjwoChuCstvfJ8LT9+So4+QabIjKI8= +maunium.net/go/mautrix v0.24.3-0.20250728143428-ae2c07fb863a/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= From 1350339213519b3c54542961262055fff2d6d4c7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 28 Jul 2025 22:04:08 +0300 Subject: [PATCH 519/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cff8080..2bf4ecb 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.3-0.20250728143428-ae2c07fb863a + maunium.net/go/mautrix v0.24.3-0.20250728190343-2e7ff3fedd4c ) require ( diff --git a/go.sum b/go.sum index e8d87ed..9d298f2 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.24.3-0.20250728143428-ae2c07fb863a h1:3lQKIbNLbHKxMLjwoChuCstvfJ8LT9+So4+QabIjKI8= -maunium.net/go/mautrix v0.24.3-0.20250728143428-ae2c07fb863a/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= +maunium.net/go/mautrix v0.24.3-0.20250728190343-2e7ff3fedd4c h1:ciLyRuYMrqQK8Y0Rp06QcUz5YOnuieNlEbLg65ERLe8= +maunium.net/go/mautrix v0.24.3-0.20250728190343-2e7ff3fedd4c/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= From 7704fcc6f03aa9d2b5db8937119ee9e6f1cd06f4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 29 Jul 2025 16:19:32 +0300 Subject: [PATCH 520/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2bf4ecb..d174260 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.3-0.20250728190343-2e7ff3fedd4c + maunium.net/go/mautrix v0.24.3-0.20250729131536-26e66f293e6a ) require ( diff --git a/go.sum b/go.sum index 9d298f2..6f18389 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.24.3-0.20250728190343-2e7ff3fedd4c h1:ciLyRuYMrqQK8Y0Rp06QcUz5YOnuieNlEbLg65ERLe8= -maunium.net/go/mautrix v0.24.3-0.20250728190343-2e7ff3fedd4c/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= +maunium.net/go/mautrix v0.24.3-0.20250729131536-26e66f293e6a h1:+tnOE+D2F7wOQVY/SpBdssD9U45uvpfe2yYZ1FuXuIM= +maunium.net/go/mautrix v0.24.3-0.20250729131536-26e66f293e6a/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= From 1636355668a583eec266e7f8774e75f33e1df9d9 Mon Sep 17 00:00:00 2001 From: "Skip R." Date: Wed, 30 Jul 2025 08:47:33 -0700 Subject: [PATCH 521/718] build: use `serviceid_clang.go` when building for arm64 windows (#606) --- pkg/libsignalgo/serviceid_clang.go | 2 +- pkg/libsignalgo/serviceid_gcc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/serviceid_clang.go b/pkg/libsignalgo/serviceid_clang.go index 72c9ed3..89197b6 100644 --- a/pkg/libsignalgo/serviceid_clang.go +++ b/pkg/libsignalgo/serviceid_clang.go @@ -1,4 +1,4 @@ -//go:build darwin || android || ios +//go:build darwin || android || ios || (windows && arm64) package libsignalgo diff --git a/pkg/libsignalgo/serviceid_gcc.go b/pkg/libsignalgo/serviceid_gcc.go index b8dbbee..0feb627 100644 --- a/pkg/libsignalgo/serviceid_gcc.go +++ b/pkg/libsignalgo/serviceid_gcc.go @@ -1,4 +1,4 @@ -//go:build !(darwin || android || ios) +//go:build !(darwin || android || ios || (windows && arm64)) package libsignalgo From a17e60e3925464222b436a0c4cd618850f34e104 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 31 Jul 2025 14:25:09 +0300 Subject: [PATCH 522/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d174260..534e2c7 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.3-0.20250729131536-26e66f293e6a + maunium.net/go/mautrix v0.24.3-0.20250731110000-94f53c5853c6 ) require ( diff --git a/go.sum b/go.sum index 6f18389..c8a420f 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.24.3-0.20250729131536-26e66f293e6a h1:+tnOE+D2F7wOQVY/SpBdssD9U45uvpfe2yYZ1FuXuIM= -maunium.net/go/mautrix v0.24.3-0.20250729131536-26e66f293e6a/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= +maunium.net/go/mautrix v0.24.3-0.20250731110000-94f53c5853c6 h1:27wTzsIxqJ+xzqcGGSXfe3MGXHPgzmWHO2+lw7V8Tdk= +maunium.net/go/mautrix v0.24.3-0.20250731110000-94f53c5853c6/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= From 456a69ff410345674c4ce1ca2e4b58203283bf97 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 1 Aug 2025 11:49:19 +0300 Subject: [PATCH 523/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 534e2c7..9609350 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 golang.org/x/net v0.42.0 google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.3-0.20250731110000-94f53c5853c6 + maunium.net/go/mautrix v0.24.3-0.20250801084753-196164ed6749 ) require ( diff --git a/go.sum b/go.sum index c8a420f..33b1d29 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.24.3-0.20250731110000-94f53c5853c6 h1:27wTzsIxqJ+xzqcGGSXfe3MGXHPgzmWHO2+lw7V8Tdk= -maunium.net/go/mautrix v0.24.3-0.20250731110000-94f53c5853c6/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= +maunium.net/go/mautrix v0.24.3-0.20250801084753-196164ed6749 h1:eEIsN9CufSHs4SeRjUwIpJo3n8QaX0rfO2sEERjPkKY= +maunium.net/go/mautrix v0.24.3-0.20250801084753-196164ed6749/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= From 80f2d2b87baa07ca83afd7ba2515f743263c5e9f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 5 Aug 2025 10:45:52 +0300 Subject: [PATCH 524/718] signalmeow/contactdiscovery: update enclave ID --- pkg/signalmeow/contactdiscovery.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/contactdiscovery.go b/pkg/signalmeow/contactdiscovery.go index 2360457..07d9b49 100644 --- a/pkg/signalmeow/contactdiscovery.go +++ b/pkg/signalmeow/contactdiscovery.go @@ -40,7 +40,7 @@ import ( ) const ProdContactDiscoveryServer = "cdsi.signal.org" -const ProdContactDiscoveryMrenclave = "c6ff0682219217f7045624be472a077c0d4b06193fe71632eb0adb50051d5da1" +const ProdContactDiscoveryMrenclave = "ee9503070127120074612b6688e593b67e486b1541449f54d71e387484eb40a3" const ContactDiscoveryAuthTTL = 23 * time.Hour const rateLimitCloseCode = websocket.StatusCode(4008) From 31e390734bfca6f3d9c7bf692e1b4d0fb35b3765 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 12 Aug 2025 23:31:43 +0300 Subject: [PATCH 525/718] libsignal: update to v0.78.2 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 79 ++++++++++++++++++++++++++++- pkg/libsignalgo/messagebackupkey.go | 2 + pkg/libsignalgo/version.go | 2 +- 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 9fc4534..36916db 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 9fc4534b29fc488beeba082dd739aeae73032908 +Subproject commit 36916db152747b1a176527ceab4f826bf2d432fb diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index d52782d..0ed572f 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -23,6 +23,8 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalMEDIA_ID_LEN 15 +#define SignalBACKUP_FORWARD_SECRECY_TOKEN_LEN 32 + #define SignalMEDIA_ENCRYPTION_KEY_LEN (32 + 32) #define SignalBackupId_LEN 16 @@ -234,6 +236,7 @@ typedef enum { SignalErrorCodeSvrDataMissing = 160, SignalErrorCodeSvrRestoreFailed = 161, SignalErrorCodeSvrRotationMachineTooManySteps = 162, + SignalErrorCodeSvrRequestFailed = 163, SignalErrorCodeAppExpired = 170, SignalErrorCodeDeviceDeregistered = 171, SignalErrorCodeConnectionInvalidated = 172, @@ -276,6 +279,10 @@ typedef struct SignalAes256GcmSiv SignalAes256GcmSiv; typedef struct SignalAuthenticatedChatConnection SignalAuthenticatedChatConnection; +typedef struct SignalBackupRestoreResponse SignalBackupRestoreResponse; + +typedef struct SignalBackupStoreResponse SignalBackupStoreResponse; + typedef struct SignalBridgedStringMap SignalBridgedStringMap; typedef struct SignalCdsiLookup SignalCdsiLookup; @@ -612,6 +619,22 @@ typedef struct { SignalPrivateKey *raw; } SignalMutPointerPrivateKey; +typedef struct { + SignalBackupRestoreResponse *raw; +} SignalMutPointerBackupRestoreResponse; + +typedef struct { + const SignalBackupRestoreResponse *raw; +} SignalConstPointerBackupRestoreResponse; + +typedef struct { + SignalBackupStoreResponse *raw; +} SignalMutPointerBackupStoreResponse; + +typedef struct { + const SignalBackupStoreResponse *raw; +} SignalConstPointerBackupStoreResponse; + typedef struct { SignalBridgedStringMap *raw; } SignalMutPointerBridgedStringMap; @@ -1252,6 +1275,38 @@ typedef struct { SignalUnidentifiedSenderMessageContent *raw; } SignalMutPointerUnidentifiedSenderMessageContent; +typedef uint8_t SignalBackupKeyBytes[SignalBACKUP_KEY_LEN]; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerBackupRestoreResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerBackupRestoreResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerBackupStoreResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerBackupStoreResponse; + typedef struct { SignalSenderCertificate *raw; } SignalMutPointerSenderCertificate; @@ -1451,6 +1506,20 @@ SignalFfiError *signal_backup_key_derive_media_id(uint8_t (*out)[SignalMEDIA_ID_ SignalFfiError *signal_backup_key_derive_thumbnail_transit_encryption_key(uint8_t (*out)[SignalMEDIA_ENCRYPTION_KEY_LEN], const uint8_t (*backup_key)[SignalBACKUP_KEY_LEN], const uint8_t (*media_id)[SignalMEDIA_ID_LEN]); +SignalFfiError *signal_backup_restore_response_destroy(SignalMutPointerBackupRestoreResponse p); + +SignalFfiError *signal_backup_restore_response_get_forward_secrecy_token(uint8_t (*out)[SignalBACKUP_FORWARD_SECRECY_TOKEN_LEN], SignalConstPointerBackupRestoreResponse response); + +SignalFfiError *signal_backup_restore_response_get_next_backup_secret_data(SignalOwnedBuffer *out, SignalConstPointerBackupRestoreResponse response); + +SignalFfiError *signal_backup_store_response_destroy(SignalMutPointerBackupStoreResponse p); + +SignalFfiError *signal_backup_store_response_get_forward_secrecy_token(uint8_t (*out)[SignalBACKUP_FORWARD_SECRECY_TOKEN_LEN], SignalConstPointerBackupStoreResponse response); + +SignalFfiError *signal_backup_store_response_get_next_backup_secret_data(SignalOwnedBuffer *out, SignalConstPointerBackupStoreResponse response); + +SignalFfiError *signal_backup_store_response_get_opaque_metadata(SignalOwnedBuffer *out, SignalConstPointerBackupStoreResponse response); + SignalFfiError *signal_bridged_string_map_clone(SignalMutPointerBridgedStringMap *new_obj, SignalConstPointerBridgedStringMap obj); SignalFfiError *signal_bridged_string_map_destroy(SignalMutPointerBridgedStringMap p); @@ -1843,9 +1912,9 @@ SignalFfiError *signal_lookup_request_set_token(SignalConstPointerLookupRequest SignalFfiError *signal_message_backup_key_destroy(SignalMutPointerMessageBackupKey p); -SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMutPointerMessageBackupKey *out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_message_backup_key_from_account_entropy_pool(SignalMutPointerMessageBackupKey *out, const char *account_entropy, const SignalServiceIdFixedWidthBinaryBytes *aci, const uint8_t (*forward_secrecy_token)[SignalBACKUP_FORWARD_SECRECY_TOKEN_LEN]); -SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMutPointerMessageBackupKey *out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16]); +SignalFfiError *signal_message_backup_key_from_backup_key_and_backup_id(SignalMutPointerMessageBackupKey *out, const uint8_t (*backup_key)[32], const uint8_t (*backup_id)[16], const uint8_t (*forward_secrecy_token)[SignalBACKUP_FORWARD_SECRECY_TOKEN_LEN]); SignalFfiError *signal_message_backup_key_get_aes_key(uint8_t (*out)[32], SignalConstPointerMessageBackupKey key); @@ -2185,6 +2254,12 @@ SignalFfiError *signal_sealed_session_cipher_decrypt_to_usmc(SignalMutPointerUni SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress destination, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); +SignalFfiError *signal_secure_value_recovery_for_backups_create_new_backup_chain(SignalOwnedBuffer *out, uint8_t environment, const SignalBackupKeyBytes *backup_key); + +SignalFfiError *signal_secure_value_recovery_for_backups_restore_backup_from_server(SignalCPromiseMutPointerBackupRestoreResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, const SignalBackupKeyBytes *backup_key, SignalBorrowedBuffer metadata, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password); + +SignalFfiError *signal_secure_value_recovery_for_backups_store_backup(SignalCPromiseMutPointerBackupStoreResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, const SignalBackupKeyBytes *backup_key, SignalBorrowedBuffer previous_secret_data, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password); + SignalFfiError *signal_sender_certificate_clone(SignalMutPointerSenderCertificate *new_obj, SignalConstPointerSenderCertificate obj); SignalFfiError *signal_sender_certificate_deserialize(SignalMutPointerSenderCertificate *out, SignalBorrowedBuffer data); diff --git a/pkg/libsignalgo/messagebackupkey.go b/pkg/libsignalgo/messagebackupkey.go index 87f2b4f..65b4136 100644 --- a/pkg/libsignalgo/messagebackupkey.go +++ b/pkg/libsignalgo/messagebackupkey.go @@ -42,6 +42,7 @@ func MessageBackupKeyFromAccountEntropyPool(aep AccountEntropyPool, aci ServiceI &bk, C.CString(string(aep)), aci.CFixedBytes(), + nil, // TODO what's a forward secrecy token? ) runtime.KeepAlive(aep) if signalFfiError != nil { @@ -56,6 +57,7 @@ func MessageBackupKeyFromBackupKeyAndID(backupKey *BackupKey, backupID *BackupID &bk, (*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(backupKey)), (*[BackupIDLength]C.uint8_t)(unsafe.Pointer(backupID)), + nil, // TODO what's a forward secrecy token? ) runtime.KeepAlive(backupKey) runtime.KeepAlive(backupID) diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 90264fd..1db5dfc 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.76.7" +const Version = "v0.78.2" From 04fd88da5e00d3dd2a145e2581656ab54e52ba33 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 12 Aug 2025 23:32:31 +0300 Subject: [PATCH 526/718] changelog: update --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 220f3ab..b81dfbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v0.8.6 (unreleased) + +* Updated libsignal to v0.78.2. +* Added support for "delete to me" of chats and messages. +* Added support for latest Signal backup/transfer protocol. + # v0.8.5 (2025-07-16) * Updated libsignal to v0.76.1. From ee8a019a78f42133d4b7e15ae03afc5eca6f2bb6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 16 Aug 2025 13:52:57 +0300 Subject: [PATCH 527/718] Bump version to v0.8.6 --- .github/workflows/go.yml | 8 +++---- .pre-commit-config.yaml | 4 ++-- CHANGELOG.md | 5 +++- cmd/mautrix-signal/main.go | 2 +- go.mod | 28 +++++++++++----------- go.sum | 48 +++++++++++++++++++------------------- 6 files changed, 49 insertions(+), 46 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6bbfaef..3913002 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,8 +11,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.23", "1.24"] - name: Lint ${{ matrix.go-version == '1.24' && '(latest)' || '(old)' }} + go-version: ["1.24", "1.25"] + name: Lint ${{ matrix.go-version == '1.25' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 @@ -40,8 +40,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.23", "1.24"] - name: Test ${{ matrix.go-version == '1.24' && '(latest)' || '(old)' }} + go-version: ["1.24", "1.25"] + name: Test ${{ matrix.go-version == '1.25' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1f3f910..f6b3302 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace exclude_types: [markdown] @@ -9,7 +9,7 @@ repos: - id: check-added-large-files - repo: https://github.com/tekwizely/pre-commit-golang - rev: v1.0.0-rc.1 + rev: v1.0.0-rc.2 hooks: - id: go-imports exclude: "pb\\.go$" diff --git a/CHANGELOG.md b/CHANGELOG.md index b81dfbd..3cf3475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ -# v0.8.6 (unreleased) +# v0.8.6 (2025-08-16) +* Deprecated legacy provisioning API. The `/_matrix/provision/v2` endpoints will + be deleted in the next release. +* Bumped minimum Go version to 1.24. * Updated libsignal to v0.78.2. * Added support for "delete to me" of chats and messages. * Added support for latest Signal backup/transfer protocol. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index dc1a25a..d96283f 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -36,7 +36,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.5", + Version: "0.8.6", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 9609350..b66294a 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module go.mau.fi/mautrix-signal -go 1.23.0 +go 1.24.0 -toolchain go1.24.5 +toolchain go1.25.0 require ( github.com/coder/websocket v1.8.13 @@ -12,12 +12,12 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.8.9-0.20250723171559-474867266038 - golang.org/x/crypto v0.40.0 - golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 - golang.org/x/net v0.42.0 - google.golang.org/protobuf v1.36.6 - maunium.net/go/mautrix v0.24.3-0.20250801084753-196164ed6749 + go.mau.fi/util v0.9.0 + golang.org/x/crypto v0.41.0 + golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 + golang.org/x/net v0.43.0 + google.golang.org/protobuf v1.36.7 + maunium.net/go/mautrix v0.25.0 ) require ( @@ -28,8 +28,8 @@ require ( github.com/lib/pq v1.10.9 // 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.28 // indirect - github.com/petermattis/goid v0.0.0-20250721140440-ea1c0173183e // indirect + github.com/mattn/go-sqlite3 v1.14.32 // indirect + github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -37,11 +37,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.12 // indirect - go.mau.fi/zeroconfig v0.1.3 // indirect + github.com/yuin/goldmark v1.7.13 // indirect + go.mau.fi/zeroconfig v0.2.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 33b1d29..9fd93bc 100644 --- a/go.sum +++ b/go.sum @@ -34,10 +34,10 @@ 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.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= -github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20250721140440-ea1c0173183e h1:D0bJD+4O3G4izvrQUmzCL80zazlN7EwJ0PPDhpJWC/I= -github.com/petermattis/goid v0.0.0-20250721140440-ea1c0173183e/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= +github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe h1:vHpqOnPlnkba8iSxU4j/CvDSS9J4+F4473esQsYLGoE= +github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -63,29 +63,29 @@ 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.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= -github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.8.9-0.20250723171559-474867266038 h1:RVL8TVaYc3LTBBopfjCNDtD+6eZks0O+qgXN/9hsz7k= -go.mau.fi/util v0.8.9-0.20250723171559-474867266038/go.mod h1:GZZp5f9r2MgEu4GDvtB0XxCF7i6Z7Z8fM0w9a5oZH3Y= -go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM= -go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= -golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4= -golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= +github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +go.mau.fi/util v0.9.0 h1:ya3s3pX+Y8R2fgp0DbE7a0o3FwncoelDX5iyaeVE8ls= +go.mau.fi/util v0.9.0/go.mod h1:pdL3lg2aaeeHIreGXNnPwhJPXkXdc3ZxsI6le8hOWEA= +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.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 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= @@ -95,5 +95,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.24.3-0.20250801084753-196164ed6749 h1:eEIsN9CufSHs4SeRjUwIpJo3n8QaX0rfO2sEERjPkKY= -maunium.net/go/mautrix v0.24.3-0.20250801084753-196164ed6749/go.mod h1:KrE/TdIeAo6cfAUICmbaiZ18UgHimTOozAGOrioK9SU= +maunium.net/go/mautrix v0.25.0 h1:dhYoXIXSxI9A+kEPwBceuRP0wcpho15dVLucUF8k2eE= +maunium.net/go/mautrix v0.25.0/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= From 6900cc9d3d32a1b621bf49c6c814f86698a1a4e7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 19 Aug 2025 12:32:38 +0300 Subject: [PATCH 528/718] signalmeow/keys: dispatch logged out event on prekey 422 error --- pkg/connector/handlesignal.go | 3 +++ pkg/signalmeow/events/message.go | 3 +++ pkg/signalmeow/keys.go | 2 ++ 3 files changed, 8 insertions(+) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index f77d87d..803d481 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -30,6 +30,7 @@ import ( "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/bridgev2/simplevent" + "maunium.net/go/mautrix/bridgev2/status" "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -59,6 +60,8 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) bool { s.handleSignalACIFound(evt) case *events.QueueEmpty: s.queueEmptyWaiter.Set() + case *events.LoggedOut: + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: evt.Error.Error()}) default: s.UserLogin.Log.Warn().Type("event_type", evt).Msg("Unrecognized signalmeow event type") } diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 8a13329..cc7d62c 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -37,6 +37,7 @@ func (*ContactList) isSignalEvent() {} func (*ACIFound) isSignalEvent() {} func (*DeleteForMe) isSignalEvent() {} func (*QueueEmpty) isSignalEvent() {} +func (*LoggedOut) isSignalEvent() {} type MessageInfo struct { Sender uuid.UUID @@ -88,3 +89,5 @@ type DeleteForMe struct { } type QueueEmpty struct{} + +type LoggedOut struct{ Error error } diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index bc86789..a3f2690 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -30,6 +30,7 @@ import ( "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/events" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -630,6 +631,7 @@ func (cli *Client) keyCheckLoop(ctx context.Context) { if disconnectErr != nil { log.Err(disconnectErr).Msg("ClearKeysAndDisconnect error") } + cli.handleEvent(&events.LoggedOut{Error: err}) return } log.Err(err).Msg("Error checking and uploading new prekeys for PNI identity") From dcb4b0c99e80feada5a0582214d4ce90532d0b26 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 21 Aug 2025 17:13:50 +0300 Subject: [PATCH 529/718] msgconv/from-signal: don't use different logins for mention in split portals --- pkg/msgconv/msgconv.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/msgconv/msgconv.go b/pkg/msgconv/msgconv.go index 01d46a6..86e7e2d 100644 --- a/pkg/msgconv/msgconv.go +++ b/pkg/msgconv/msgconv.go @@ -65,7 +65,8 @@ func NewMessageConverter(br *bridgev2.Bridge) *MessageConverter { Name: ghost.Name, } userLogin := br.GetCachedUserLoginByID(networkid.UserLoginID(uuid.String())) - if userLogin != nil { + portal := getPortal(ctx) + if userLogin != nil && (portal.Receiver == "" || portal.Receiver == userLogin.ID) { userInfo.MXID = userLogin.UserMXID // TODO find matrix user displayname? } From 2390b6e70f82fff66f05c28383d2a33cef33c652 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Aug 2025 16:26:27 +0300 Subject: [PATCH 530/718] libsignal: update to v0.79.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 10 ++++------ pkg/libsignalgo/version.go | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 36916db..83690bd 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 36916db152747b1a176527ceab4f826bf2d432fb +Subproject commit 83690bdf1130c514e51d573ad0da7b3802aabb6e diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 0ed572f..dc7fc18 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1626,10 +1626,6 @@ SignalFfiError *signal_create_call_link_credential_request_issue_deterministic(S SignalFfiError *signal_create_call_link_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_create_otp(const char **out, const char *username, SignalBorrowedBuffer secret); - -SignalFfiError *signal_create_otp_from_base64(const char **out, const char *username, const char *secret); - SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store, bool use_pq_ratchet); @@ -1792,7 +1788,7 @@ SignalFfiError *signal_group_send_token_check_valid_contents(SignalBorrowedBuffe SignalFfiError *signal_group_send_token_to_full_token(SignalOwnedBuffer *out, SignalBorrowedBuffer token, uint64_t expiration); -SignalFfiError *signal_hex_encode(char *output, size_t output_len, const uint8_t *input, size_t input_len); +SignalFfiError *signal_hex_encode(SignalBorrowedMutableBuffer output, SignalBorrowedBuffer input); SignalFfiError *signal_hkdf_derive(SignalBorrowedMutableBuffer output, SignalBorrowedBuffer ikm, SignalBorrowedBuffer label, SignalBorrowedBuffer salt); @@ -1842,7 +1838,7 @@ SignalFfiError *signal_key_transparency_distinguished(SignalCPromiseOwnedBufferO SignalFfiError *signal_key_transparency_e164_search_key(SignalOwnedBuffer *out, const char *e164); -SignalFfiError *signal_key_transparency_monitor(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head); +SignalFfiError *signal_key_transparency_monitor(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head, bool is_self_monitor); SignalFfiError *signal_key_transparency_search(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head); @@ -2256,6 +2252,8 @@ SignalFfiError *signal_sealed_session_cipher_encrypt(SignalOwnedBuffer *out, Sig SignalFfiError *signal_secure_value_recovery_for_backups_create_new_backup_chain(SignalOwnedBuffer *out, uint8_t environment, const SignalBackupKeyBytes *backup_key); +SignalFfiError *signal_secure_value_recovery_for_backups_remove_backup(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password); + SignalFfiError *signal_secure_value_recovery_for_backups_restore_backup_from_server(SignalCPromiseMutPointerBackupRestoreResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, const SignalBackupKeyBytes *backup_key, SignalBorrowedBuffer metadata, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password); SignalFfiError *signal_secure_value_recovery_for_backups_store_backup(SignalCPromiseMutPointerBackupStoreResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, const SignalBackupKeyBytes *backup_key, SignalBorrowedBuffer previous_secret_data, SignalConstPointerConnectionManager connection_manager, const char *username, const char *password); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 1db5dfc..04012e8 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.78.2" +const Version = "v0.79.0" From dff8052be315c5e1608b9b9934c32d54293da3f8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 22 Aug 2025 16:28:48 +0300 Subject: [PATCH 531/718] signalmeow: update protobufs --- pkg/msgconv/from-signal-backup.go | 16 - pkg/signalmeow/protobuf/Provisioning.pb.go | 38 +- pkg/signalmeow/protobuf/Provisioning.proto | 60 +- pkg/signalmeow/protobuf/StorageService.pb.go | 10 +- pkg/signalmeow/protobuf/StorageService.proto | 2 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 813 ++++-------------- pkg/signalmeow/protobuf/backuppb/Backup.proto | 84 +- pkg/signalmeow/protobuf/update-protos.sh | 4 +- 8 files changed, 244 insertions(+), 783 deletions(-) diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index 5f7f12b..7e8d4e1 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -205,26 +205,10 @@ func backupToSignalAttachment( sig.AttachmentIdentifier = &signalpb.AttachmentPointer_CdnKey{CdnKey: *fp.LocatorInfo.TransitCdnKey} sig.Size = &fp.LocatorInfo.Size sig.Digest = fp.LocatorInfo.GetEncryptedDigest() // Note: may be nil if plaintextHash is set instead - if sig.Digest == nil { - sig.Digest = fp.LocatorInfo.LegacyDigest - } sig.CdnNumber = fp.LocatorInfo.TransitCdnNumber } sig.Key = fp.LocatorInfo.Key atts[clientUUID] = fp.LocatorInfo - } else { - switch loc := fp.Locator.(type) { - case *backuppb.FilePointer_AttachmentLocator_: - sig.AttachmentIdentifier = &signalpb.AttachmentPointer_CdnKey{CdnKey: loc.AttachmentLocator.CdnKey} - sig.Key = loc.AttachmentLocator.Key - sig.Size = &loc.AttachmentLocator.Size - sig.Digest = loc.AttachmentLocator.Digest - sig.CdnNumber = &loc.AttachmentLocator.CdnNumber - case *backuppb.FilePointer_BackupLocator_: - //atts[clientUUID] = loc.BackupLocator - case *backuppb.FilePointer_InvalidAttachmentLocator_: - atts[clientUUID] = nil - } } return sig } diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index e2fbf7c..9e75ec2 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -1,7 +1,6 @@ -//* -// Copyright (C) 2014-2016 Open Whisper Systems // -// Licensed according to the LICENSE file in this repository. +// Copyright 2020 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only // Code generated by protoc-gen-go. DO NOT EDIT. // versions: @@ -85,9 +84,14 @@ func (ProvisioningVersion) EnumDescriptor() ([]byte, []int) { return file_Provisioning_proto_rawDescGZIP(), []int{0} } +// An opaque address sent by the server when clients first open a provisioning +// WebSocket type ProvisioningAddress struct { - state protoimpl.MessageState `protogen:"open.v1"` - Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + // The opaque provisioning address for the active provisioning WebSocket + // session; clients should not attempt to interpret or modify the contents + // of the address string + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -195,10 +199,12 @@ type ProvisionMessage struct { ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"` ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` - MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` + MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` // Deprecated, but required by linked devices EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes + AciBinary []byte `protobuf:"bytes,17,opt,name=aciBinary" json:"aciBinary,omitempty"` // 16-byte UUID + PniBinary []byte `protobuf:"bytes,18,opt,name=pniBinary" json:"pniBinary,omitempty"` // 16-byte UUID unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -345,6 +351,20 @@ func (x *ProvisionMessage) GetMediaRootBackupKey() []byte { return nil } +func (x *ProvisionMessage) GetAciBinary() []byte { + if x != nil { + return x.AciBinary + } + return nil +} + +func (x *ProvisionMessage) GetPniBinary() []byte { + if x != nil { + return x.PniBinary + } + return nil +} + var File_Provisioning_proto protoreflect.FileDescriptor const file_Provisioning_proto_rawDesc = "" + @@ -354,7 +374,7 @@ const file_Provisioning_proto_rawDesc = "" + "\aaddress\x18\x01 \x01(\tR\aaddress\"E\n" + "\x11ProvisionEnvelope\x12\x1c\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x12\n" + - "\x04body\x18\x02 \x01(\fR\x04body\"\x90\x05\n" + + "\x04body\x18\x02 \x01(\fR\x04body\"\xcc\x05\n" + "\x10ProvisionMessage\x122\n" + "\x14aciIdentityKeyPublic\x18\x01 \x01(\fR\x14aciIdentityKeyPublic\x124\n" + "\x15aciIdentityKeyPrivate\x18\x02 \x01(\fR\x15aciIdentityKeyPrivate\x122\n" + @@ -374,7 +394,9 @@ const file_Provisioning_proto_rawDesc = "" + "\tmasterKey\x18\r \x01(\fR\tmasterKey\x12.\n" + "\x12ephemeralBackupKey\x18\x0e \x01(\fR\x12ephemeralBackupKey\x12.\n" + "\x12accountEntropyPool\x18\x0f \x01(\tR\x12accountEntropyPool\x12.\n" + - "\x12mediaRootBackupKey\x18\x10 \x01(\fR\x12mediaRootBackupKey*G\n" + + "\x12mediaRootBackupKey\x18\x10 \x01(\fR\x12mediaRootBackupKey\x12\x1c\n" + + "\taciBinary\x18\x11 \x01(\fR\taciBinary\x12\x1c\n" + + "\tpniBinary\x18\x12 \x01(\fR\tpniBinary*G\n" + "\x13ProvisioningVersion\x12\v\n" + "\aINITIAL\x10\x00\x12\x12\n" + "\x0eTABLET_SUPPORT\x10\x01\x12\v\n" + diff --git a/pkg/signalmeow/protobuf/Provisioning.proto b/pkg/signalmeow/protobuf/Provisioning.proto index e18829a..2fde938 100644 --- a/pkg/signalmeow/protobuf/Provisioning.proto +++ b/pkg/signalmeow/protobuf/Provisioning.proto @@ -1,48 +1,56 @@ -/** - * Copyright (C) 2014-2016 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. +/* + * Copyright 2020 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only */ + syntax = "proto2"; package signalservice; -option java_package = "org.whispersystems.signalservice.internal.push"; +option java_package = "org.whispersystems.signalservice.internal.push"; option java_outer_classname = "ProvisioningProtos"; +// An opaque address sent by the server when clients first open a provisioning +// WebSocket message ProvisioningAddress { + + // The opaque provisioning address for the active provisioning WebSocket + // session; clients should not attempt to interpret or modify the contents + // of the address string optional string address = 1; } message ProvisionEnvelope { optional bytes publicKey = 1; - optional bytes body = 2; // Encrypted ProvisionMessage + optional bytes body = 2; // Encrypted ProvisionMessage } message ProvisionMessage { - optional bytes aciIdentityKeyPublic = 1; - optional bytes aciIdentityKeyPrivate = 2; - optional bytes pniIdentityKeyPublic = 11; - optional bytes pniIdentityKeyPrivate = 12; - optional string aci = 8; - optional string pni = 10; - optional string number = 3; - optional string provisioningCode = 4; - optional string userAgent = 5; - optional bytes profileKey = 6; - optional bool readReceipts = 7; - optional uint32 provisioningVersion = 9; - optional bytes masterKey = 13; - optional bytes ephemeralBackupKey = 14; // 32 bytes - optional string accountEntropyPool = 15; - optional bytes mediaRootBackupKey = 16; // 32-bytes - // NEXT ID: 17 + optional bytes aciIdentityKeyPublic = 1; + optional bytes aciIdentityKeyPrivate = 2; + optional bytes pniIdentityKeyPublic = 11; + optional bytes pniIdentityKeyPrivate = 12; + optional string aci = 8; + optional string pni = 10; + optional string number = 3; + optional string provisioningCode = 4; + optional string userAgent = 5; + optional bytes profileKey = 6; + optional bool readReceipts = 7; + optional uint32 provisioningVersion = 9; + optional bytes masterKey = 13; // Deprecated, but required by linked devices + optional bytes ephemeralBackupKey = 14; // 32 bytes + optional string accountEntropyPool = 15; + optional bytes mediaRootBackupKey = 16; // 32-bytes + optional bytes aciBinary = 17; // 16-byte UUID + optional bytes pniBinary = 18; // 16-byte UUID + // NEXT ID: 19 } enum ProvisioningVersion { option allow_alias = true; - INITIAL = 0; - TABLET_SUPPORT = 1; - CURRENT = 1; + INITIAL = 0; + TABLET_SUPPORT = 1; + CURRENT = 1; } diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 3bfa1c1..33804f6 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -1962,7 +1962,7 @@ type CallLinkRecord struct { RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` - Epoch []byte `protobuf:"bytes,4,opt,name=epoch,proto3" json:"epoch,omitempty"` + Epoch []byte `protobuf:"bytes,4,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3267,12 +3267,13 @@ const file_StorageService_proto_rawDesc = "" + "\x13recipientServiceIds\x18\x03 \x03(\tR\x13recipientServiceIds\x12.\n" + "\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" + - "\visBlockList\x18\x06 \x01(\bR\visBlockList\"\x98\x01\n" + + "\visBlockList\x18\x06 \x01(\bR\visBlockList\"\xa7\x01\n" + "\x0eCallLinkRecord\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + - "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\x12\x14\n" + - "\x05epoch\x18\x04 \x01(\fR\x05epoch\"\xe6\x01\n" + + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\x12\x19\n" + + "\x05epoch\x18\x04 \x01(\fH\x00R\x05epoch\x88\x01\x01B\b\n" + + "\x06_epoch\"\xe6\x01\n" + "\tRecipient\x12<\n" + "\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + @@ -3467,6 +3468,7 @@ func file_StorageService_proto_init() { file_StorageService_proto_msgTypes[7].OneofWrappers = []any{} file_StorageService_proto_msgTypes[9].OneofWrappers = []any{} file_StorageService_proto_msgTypes[11].OneofWrappers = []any{} + file_StorageService_proto_msgTypes[13].OneofWrappers = []any{} file_StorageService_proto_msgTypes[14].OneofWrappers = []any{ (*Recipient_Contact_)(nil), (*Recipient_LegacyGroupId)(nil), diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index 2229805..4258fba 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -306,7 +306,7 @@ message CallLinkRecord { bytes rootKey = 1; bytes adminPasskey = 2; uint64 deletedAtTimestampMs = 3; - bytes epoch = 4; + optional bytes epoch = 4; } message Recipient { diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index cc4b279..3eaaed0 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -2944,7 +2944,7 @@ type CallLink struct { Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Restrictions CallLink_Restrictions `protobuf:"varint,4,opt,name=restrictions,proto3,enum=signal.backup.CallLink_Restrictions" json:"restrictions,omitempty"` ExpirationMs uint64 `protobuf:"varint,5,opt,name=expirationMs,proto3" json:"expirationMs,omitempty"` - Epoch []byte `protobuf:"bytes,6,opt,name=epoch,proto3" json:"epoch,omitempty"` // May be absent/empty for older links + Epoch []byte `protobuf:"bytes,6,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"` // May be absent/empty for older links unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4603,17 +4603,7 @@ func (x *MessageAttachment) GetClientUuid() []byte { } type FilePointer struct { - state protoimpl.MessageState `protogen:"open.v1"` - // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. - // DEPRECATED; use locatorInfo instead. - // - // Types that are valid to be assigned to Locator: - // - // *FilePointer_BackupLocator_ - // *FilePointer_AttachmentLocator_ - // *FilePointer_InvalidAttachmentLocator_ - // *FilePointer_LocalLocator_ - Locator isFilePointer_Locator `protobuf_oneof:"locator"` + state protoimpl.MessageState `protogen:"open.v1"` ContentType *string `protobuf:"bytes,4,opt,name=contentType,proto3,oneof" json:"contentType,omitempty"` IncrementalMac []byte `protobuf:"bytes,5,opt,name=incrementalMac,proto3,oneof" json:"incrementalMac,omitempty"` IncrementalMacChunkSize *uint32 `protobuf:"varint,6,opt,name=incrementalMacChunkSize,proto3,oneof" json:"incrementalMacChunkSize,omitempty"` @@ -4657,49 +4647,6 @@ func (*FilePointer) Descriptor() ([]byte, []int) { return file_backuppb_Backup_proto_rawDescGZIP(), []int{28} } -func (x *FilePointer) GetLocator() isFilePointer_Locator { - if x != nil { - return x.Locator - } - return nil -} - -func (x *FilePointer) GetBackupLocator() *FilePointer_BackupLocator { - if x != nil { - if x, ok := x.Locator.(*FilePointer_BackupLocator_); ok { - return x.BackupLocator - } - } - return nil -} - -func (x *FilePointer) GetAttachmentLocator() *FilePointer_AttachmentLocator { - if x != nil { - if x, ok := x.Locator.(*FilePointer_AttachmentLocator_); ok { - return x.AttachmentLocator - } - } - return nil -} - -func (x *FilePointer) GetInvalidAttachmentLocator() *FilePointer_InvalidAttachmentLocator { - if x != nil { - if x, ok := x.Locator.(*FilePointer_InvalidAttachmentLocator_); ok { - return x.InvalidAttachmentLocator - } - } - return nil -} - -func (x *FilePointer) GetLocalLocator() *FilePointer_LocalLocator { - if x != nil { - if x, ok := x.Locator.(*FilePointer_LocalLocator_); ok { - return x.LocalLocator - } - } - return nil -} - func (x *FilePointer) GetContentType() string { if x != nil && x.ContentType != nil { return *x.ContentType @@ -4763,34 +4710,6 @@ func (x *FilePointer) GetLocatorInfo() *FilePointer_LocatorInfo { return nil } -type isFilePointer_Locator interface { - isFilePointer_Locator() -} - -type FilePointer_BackupLocator_ struct { - BackupLocator *FilePointer_BackupLocator `protobuf:"bytes,1,opt,name=backupLocator,proto3,oneof"` -} - -type FilePointer_AttachmentLocator_ struct { - AttachmentLocator *FilePointer_AttachmentLocator `protobuf:"bytes,2,opt,name=attachmentLocator,proto3,oneof"` -} - -type FilePointer_InvalidAttachmentLocator_ struct { - InvalidAttachmentLocator *FilePointer_InvalidAttachmentLocator `protobuf:"bytes,3,opt,name=invalidAttachmentLocator,proto3,oneof"` -} - -type FilePointer_LocalLocator_ struct { - LocalLocator *FilePointer_LocalLocator `protobuf:"bytes,12,opt,name=localLocator,proto3,oneof"` -} - -func (*FilePointer_BackupLocator_) isFilePointer_Locator() {} - -func (*FilePointer_AttachmentLocator_) isFilePointer_Locator() {} - -func (*FilePointer_InvalidAttachmentLocator_) isFilePointer_Locator() {} - -func (*FilePointer_LocalLocator_) isFilePointer_Locator() {} - type Quote struct { state protoimpl.MessageState `protogen:"open.v1"` TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp,proto3,oneof" json:"targetSentTimestamp,omitempty"` // null if the target message could not be found at time of quote insert @@ -9074,6 +8993,7 @@ func (x *ChatItem_IncomingMessageDetails) GetSealedSender() bool { type ChatItem_OutgoingMessageDetails struct { state protoimpl.MessageState `protogen:"open.v1"` SendStatus []*SendStatus `protobuf:"bytes,1,rep,name=sendStatus,proto3" json:"sendStatus,omitempty"` + DateReceived uint64 `protobuf:"varint,2,opt,name=dateReceived,proto3" json:"dateReceived,omitempty"` // may be different from dateSent for sync messages unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -9115,6 +9035,13 @@ func (x *ChatItem_OutgoingMessageDetails) GetSendStatus() []*SendStatus { return nil } +func (x *ChatItem_OutgoingMessageDetails) GetDateReceived() uint64 { + if x != nil { + return x.DateReceived + } + return 0 +} + type ChatItem_DirectionlessMessageDetails struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -10085,351 +10012,11 @@ func (x *ContactAttachment_PostalAddress) GetCountry() string { return "" } -// References attachments in the backup (media) storage tier. -// DEPRECATED; use LocatorInfo instead if available. -type FilePointer_BackupLocator struct { - state protoimpl.MessageState `protogen:"open.v1"` - MediaName string `protobuf:"bytes,1,opt,name=mediaName,proto3" json:"mediaName,omitempty"` - // If present, the cdn number of the succesful upload. - // If empty/0, may still have been uploaded, and clients - // can discover the cdn number via the list endpoint. - CdnNumber *uint32 `protobuf:"varint,2,opt,name=cdnNumber,proto3,oneof" json:"cdnNumber,omitempty"` - Key []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` - Digest []byte `protobuf:"bytes,4,opt,name=digest,proto3" json:"digest,omitempty"` - Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` - // Fallback in case backup tier upload failed. - TransitCdnKey *string `protobuf:"bytes,6,opt,name=transitCdnKey,proto3,oneof" json:"transitCdnKey,omitempty"` - TransitCdnNumber *uint32 `protobuf:"varint,7,opt,name=transitCdnNumber,proto3,oneof" json:"transitCdnNumber,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *FilePointer_BackupLocator) Reset() { - *x = FilePointer_BackupLocator{} - mi := &file_backuppb_Backup_proto_msgTypes[113] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *FilePointer_BackupLocator) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FilePointer_BackupLocator) ProtoMessage() {} - -func (x *FilePointer_BackupLocator) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[113] - 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 FilePointer_BackupLocator.ProtoReflect.Descriptor instead. -func (*FilePointer_BackupLocator) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 0} -} - -func (x *FilePointer_BackupLocator) GetMediaName() string { - if x != nil { - return x.MediaName - } - return "" -} - -func (x *FilePointer_BackupLocator) GetCdnNumber() uint32 { - if x != nil && x.CdnNumber != nil { - return *x.CdnNumber - } - return 0 -} - -func (x *FilePointer_BackupLocator) GetKey() []byte { - if x != nil { - return x.Key - } - return nil -} - -func (x *FilePointer_BackupLocator) GetDigest() []byte { - if x != nil { - return x.Digest - } - return nil -} - -func (x *FilePointer_BackupLocator) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *FilePointer_BackupLocator) GetTransitCdnKey() string { - if x != nil && x.TransitCdnKey != nil { - return *x.TransitCdnKey - } - return "" -} - -func (x *FilePointer_BackupLocator) GetTransitCdnNumber() uint32 { - if x != nil && x.TransitCdnNumber != nil { - return *x.TransitCdnNumber - } - return 0 -} - -// References attachments in the transit storage tier. -// May be downloaded or not when the backup is generated; -// primarily for free-tier users who cannot copy the -// attachments to the backup (media) storage tier. -// DEPRECATED; use LocatorInfo instead if available. -type FilePointer_AttachmentLocator struct { - state protoimpl.MessageState `protogen:"open.v1"` - CdnKey string `protobuf:"bytes,1,opt,name=cdnKey,proto3" json:"cdnKey,omitempty"` - CdnNumber uint32 `protobuf:"varint,2,opt,name=cdnNumber,proto3" json:"cdnNumber,omitempty"` - UploadTimestamp *uint64 `protobuf:"varint,3,opt,name=uploadTimestamp,proto3,oneof" json:"uploadTimestamp,omitempty"` - Key []byte `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"` - Digest []byte `protobuf:"bytes,5,opt,name=digest,proto3" json:"digest,omitempty"` - Size uint32 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *FilePointer_AttachmentLocator) Reset() { - *x = FilePointer_AttachmentLocator{} - mi := &file_backuppb_Backup_proto_msgTypes[114] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *FilePointer_AttachmentLocator) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FilePointer_AttachmentLocator) ProtoMessage() {} - -func (x *FilePointer_AttachmentLocator) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[114] - 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 FilePointer_AttachmentLocator.ProtoReflect.Descriptor instead. -func (*FilePointer_AttachmentLocator) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 1} -} - -func (x *FilePointer_AttachmentLocator) GetCdnKey() string { - if x != nil { - return x.CdnKey - } - return "" -} - -func (x *FilePointer_AttachmentLocator) GetCdnNumber() uint32 { - if x != nil { - return x.CdnNumber - } - return 0 -} - -func (x *FilePointer_AttachmentLocator) GetUploadTimestamp() uint64 { - if x != nil && x.UploadTimestamp != nil { - return *x.UploadTimestamp - } - return 0 -} - -func (x *FilePointer_AttachmentLocator) GetKey() []byte { - if x != nil { - return x.Key - } - return nil -} - -func (x *FilePointer_AttachmentLocator) GetDigest() []byte { - if x != nil { - return x.Digest - } - return nil -} - -func (x *FilePointer_AttachmentLocator) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -// References attachments that are invalid in such a way where download -// cannot be attempted. Could range from missing digests to missing -// CDN keys or anything else that makes download attempts impossible. -// This serves as a 'tombstone' so that the UX can show that an attachment -// did exist, but for whatever reason it's not retrievable. -// DEPRECATED; use LocatorInfo instead if available. -type FilePointer_InvalidAttachmentLocator struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *FilePointer_InvalidAttachmentLocator) Reset() { - *x = FilePointer_InvalidAttachmentLocator{} - mi := &file_backuppb_Backup_proto_msgTypes[115] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *FilePointer_InvalidAttachmentLocator) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FilePointer_InvalidAttachmentLocator) ProtoMessage() {} - -func (x *FilePointer_InvalidAttachmentLocator) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[115] - 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 FilePointer_InvalidAttachmentLocator.ProtoReflect.Descriptor instead. -func (*FilePointer_InvalidAttachmentLocator) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 2} -} - -// References attachments in a local encrypted backup. -// Importers should first attempt to read the file from the local backup, -// and on failure fallback to backup and transit cdn if possible. -// DEPRECATED; use LocatorInfo instead if available. -type FilePointer_LocalLocator struct { - state protoimpl.MessageState `protogen:"open.v1"` - MediaName string `protobuf:"bytes,1,opt,name=mediaName,proto3" json:"mediaName,omitempty"` - // Separate key used to encrypt this file for the local backup. - // Generally required. Missing field indicates attachment was not - // available locally when the backup was generated, but remote - // backup or transit info was available. - LocalKey []byte `protobuf:"bytes,2,opt,name=localKey,proto3,oneof" json:"localKey,omitempty"` - RemoteKey []byte `protobuf:"bytes,3,opt,name=remoteKey,proto3" json:"remoteKey,omitempty"` - RemoteDigest []byte `protobuf:"bytes,4,opt,name=remoteDigest,proto3" json:"remoteDigest,omitempty"` - Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` - BackupCdnNumber *uint32 `protobuf:"varint,6,opt,name=backupCdnNumber,proto3,oneof" json:"backupCdnNumber,omitempty"` - TransitCdnKey *string `protobuf:"bytes,7,opt,name=transitCdnKey,proto3,oneof" json:"transitCdnKey,omitempty"` - TransitCdnNumber *uint32 `protobuf:"varint,8,opt,name=transitCdnNumber,proto3,oneof" json:"transitCdnNumber,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *FilePointer_LocalLocator) Reset() { - *x = FilePointer_LocalLocator{} - mi := &file_backuppb_Backup_proto_msgTypes[116] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *FilePointer_LocalLocator) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FilePointer_LocalLocator) ProtoMessage() {} - -func (x *FilePointer_LocalLocator) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[116] - 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 FilePointer_LocalLocator.ProtoReflect.Descriptor instead. -func (*FilePointer_LocalLocator) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 3} -} - -func (x *FilePointer_LocalLocator) GetMediaName() string { - if x != nil { - return x.MediaName - } - return "" -} - -func (x *FilePointer_LocalLocator) GetLocalKey() []byte { - if x != nil { - return x.LocalKey - } - return nil -} - -func (x *FilePointer_LocalLocator) GetRemoteKey() []byte { - if x != nil { - return x.RemoteKey - } - return nil -} - -func (x *FilePointer_LocalLocator) GetRemoteDigest() []byte { - if x != nil { - return x.RemoteDigest - } - return nil -} - -func (x *FilePointer_LocalLocator) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *FilePointer_LocalLocator) GetBackupCdnNumber() uint32 { - if x != nil && x.BackupCdnNumber != nil { - return *x.BackupCdnNumber - } - return 0 -} - -func (x *FilePointer_LocalLocator) GetTransitCdnKey() string { - if x != nil && x.TransitCdnKey != nil { - return *x.TransitCdnKey - } - return "" -} - -func (x *FilePointer_LocalLocator) GetTransitCdnNumber() uint32 { - if x != nil && x.TransitCdnNumber != nil { - return *x.TransitCdnNumber - } - return 0 -} - type FilePointer_LocatorInfo struct { state protoimpl.MessageState `protogen:"open.v1"` // Must be non-empty if transitCdnKey or plaintextHash are set/nonempty. // Otherwise must be empty. Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - // From the sender of the attachment (incl. ourselves) - // Will be reserved once all clients start reading integrityCheck - LegacyDigest []byte `protobuf:"bytes,2,opt,name=legacyDigest,proto3" json:"legacyDigest,omitempty"` // Types that are valid to be assigned to IntegrityCheck: // // *FilePointer_LocatorInfo_PlaintextHash @@ -10449,11 +10036,6 @@ type FilePointer_LocatorInfo struct { // Exporting clients should set this as long as their subscription // has not rotated since last upload; even if currently free tier. MediaTierCdnNumber *uint32 `protobuf:"varint,7,opt,name=mediaTierCdnNumber,proto3,oneof" json:"mediaTierCdnNumber,omitempty"` - // Nonempty any time the attachment was downloaded and its - // digest validated, whether free tier or paid subscription. - // Will be reserved once all clients start reading integrityCheck, - // when mediaName will be derived from the plaintextHash and encryption key - LegacyMediaName string `protobuf:"bytes,8,opt,name=legacyMediaName,proto3" json:"legacyMediaName,omitempty"` // Separate key used to encrypt this file for the local backup. // Generally required for local backups. // Missing field indicates attachment was not available locally @@ -10466,7 +10048,7 @@ type FilePointer_LocatorInfo struct { func (x *FilePointer_LocatorInfo) Reset() { *x = FilePointer_LocatorInfo{} - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10478,7 +10060,7 @@ func (x *FilePointer_LocatorInfo) String() string { func (*FilePointer_LocatorInfo) ProtoMessage() {} func (x *FilePointer_LocatorInfo) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10491,7 +10073,7 @@ func (x *FilePointer_LocatorInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use FilePointer_LocatorInfo.ProtoReflect.Descriptor instead. func (*FilePointer_LocatorInfo) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 4} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{28, 0} } func (x *FilePointer_LocatorInfo) GetKey() []byte { @@ -10501,13 +10083,6 @@ func (x *FilePointer_LocatorInfo) GetKey() []byte { return nil } -func (x *FilePointer_LocatorInfo) GetLegacyDigest() []byte { - if x != nil { - return x.LegacyDigest - } - return nil -} - func (x *FilePointer_LocatorInfo) GetIntegrityCheck() isFilePointer_LocatorInfo_IntegrityCheck { if x != nil { return x.IntegrityCheck @@ -10568,13 +10143,6 @@ func (x *FilePointer_LocatorInfo) GetMediaTierCdnNumber() uint32 { return 0 } -func (x *FilePointer_LocatorInfo) GetLegacyMediaName() string { - if x != nil { - return x.LegacyMediaName - } - return "" -} - func (x *FilePointer_LocatorInfo) GetLocalKey() []byte { if x != nil { return x.LocalKey @@ -10612,7 +10180,7 @@ type Quote_QuotedAttachment struct { func (x *Quote_QuotedAttachment) Reset() { *x = Quote_QuotedAttachment{} - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10624,7 +10192,7 @@ func (x *Quote_QuotedAttachment) String() string { func (*Quote_QuotedAttachment) ProtoMessage() {} func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10708,7 +10276,7 @@ type GroupChangeChatUpdate_Update struct { func (x *GroupChangeChatUpdate_Update) Reset() { *x = GroupChangeChatUpdate_Update{} - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10720,7 +10288,7 @@ func (x *GroupChangeChatUpdate_Update) String() string { func (*GroupChangeChatUpdate_Update) ProtoMessage() {} func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11294,7 +10862,7 @@ type GroupInvitationRevokedUpdate_Invitee struct { func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { *x = GroupInvitationRevokedUpdate_Invitee{} - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11306,7 +10874,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) String() string { func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11354,7 +10922,7 @@ type ChatStyle_Gradient struct { func (x *ChatStyle_Gradient) Reset() { *x = ChatStyle_Gradient{} - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11366,7 +10934,7 @@ func (x *ChatStyle_Gradient) String() string { func (*ChatStyle_Gradient) ProtoMessage() {} func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11419,7 +10987,7 @@ type ChatStyle_CustomChatColor struct { func (x *ChatStyle_CustomChatColor) Reset() { *x = ChatStyle_CustomChatColor{} - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11431,7 +10999,7 @@ func (x *ChatStyle_CustomChatColor) String() string { func (*ChatStyle_CustomChatColor) ProtoMessage() {} func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11503,7 +11071,7 @@ type ChatStyle_AutomaticBubbleColor struct { func (x *ChatStyle_AutomaticBubbleColor) Reset() { *x = ChatStyle_AutomaticBubbleColor{} - mi := &file_backuppb_Backup_proto_msgTypes[123] + mi := &file_backuppb_Backup_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11515,7 +11083,7 @@ func (x *ChatStyle_AutomaticBubbleColor) String() string { func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[123] + mi := &file_backuppb_Backup_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11780,19 +11348,20 @@ const file_backuppb_Backup_proto_rawDesc = "" + " \x01(\rR\x12expireTimerVersionB\x0e\n" + "\f_pinnedOrderB\x14\n" + "\x12_expirationTimerMsB\x0e\n" + - "\f_muteUntilMs\"\xa5\x02\n" + + "\f_muteUntilMs\"\xb4\x02\n" + "\bCallLink\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\x1f\n" + "\badminKey\x18\x02 \x01(\fH\x00R\badminKey\x88\x01\x01\x12\x12\n" + "\x04name\x18\x03 \x01(\tR\x04name\x12H\n" + "\frestrictions\x18\x04 \x01(\x0e2$.signal.backup.CallLink.RestrictionsR\frestrictions\x12\"\n" + - "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\x12\x14\n" + - "\x05epoch\x18\x06 \x01(\fR\x05epoch\"9\n" + + "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\x12\x19\n" + + "\x05epoch\x18\x06 \x01(\fH\x01R\x05epoch\x88\x01\x01\"9\n" + "\fRestrictions\x12\v\n" + "\aUNKNOWN\x10\x00\x12\b\n" + "\x04NONE\x10\x01\x12\x12\n" + "\x0eADMIN_APPROVAL\x10\x02B\v\n" + - "\t_adminKey\"\xca\x01\n" + + "\t_adminKeyB\b\n" + + "\x06_epoch\"\xca\x01\n" + "\tAdHocCall\x12\x16\n" + "\x06callId\x18\x01 \x01(\x04R\x06callId\x12 \n" + "\vrecipientId\x18\x02 \x01(\x04R\vrecipientId\x124\n" + @@ -11816,7 +11385,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tONLY_WITH\x10\x01\x12\x0e\n" + "\n" + "ALL_EXCEPT\x10\x02\x12\a\n" + - "\x03ALL\x10\x03\"\xa4\f\n" + + "\x03ALL\x10\x03\"\xc8\f\n" + "\bChatItem\x12\x16\n" + "\x06chatId\x18\x01 \x01(\x04R\x06chatId\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12\x1a\n" + @@ -11843,11 +11412,12 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x0edateServerSent\x18\x02 \x01(\x04H\x00R\x0edateServerSent\x88\x01\x01\x12\x12\n" + "\x04read\x18\x03 \x01(\bR\x04read\x12\"\n" + "\fsealedSender\x18\x04 \x01(\bR\fsealedSenderB\x11\n" + - "\x0f_dateServerSent\x1aS\n" + + "\x0f_dateServerSent\x1aw\n" + "\x16OutgoingMessageDetails\x129\n" + "\n" + "sendStatus\x18\x01 \x03(\v2\x19.signal.backup.SendStatusR\n" + - "sendStatus\x1a\x1d\n" + + "sendStatus\x12\"\n" + + "\fdateReceived\x18\x02 \x01(\x04R\fdateReceived\x1a\x1d\n" + "\x1bDirectionlessMessageDetailsB\x14\n" + "\x12directionalDetailsB\x06\n" + "\x04itemB\x12\n" + @@ -12062,59 +11632,20 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "BORDERLESS\x10\x02\x12\a\n" + "\x03GIF\x10\x03B\r\n" + - "\v_clientUuid\"\xc9\x12\n" + - "\vFilePointer\x12P\n" + - "\rbackupLocator\x18\x01 \x01(\v2(.signal.backup.FilePointer.BackupLocatorH\x00R\rbackupLocator\x12\\\n" + - "\x11attachmentLocator\x18\x02 \x01(\v2,.signal.backup.FilePointer.AttachmentLocatorH\x00R\x11attachmentLocator\x12q\n" + - "\x18invalidAttachmentLocator\x18\x03 \x01(\v23.signal.backup.FilePointer.InvalidAttachmentLocatorH\x00R\x18invalidAttachmentLocator\x12M\n" + - "\flocalLocator\x18\f \x01(\v2'.signal.backup.FilePointer.LocalLocatorH\x00R\flocalLocator\x12%\n" + - "\vcontentType\x18\x04 \x01(\tH\x01R\vcontentType\x88\x01\x01\x12+\n" + - "\x0eincrementalMac\x18\x05 \x01(\fH\x02R\x0eincrementalMac\x88\x01\x01\x12=\n" + - "\x17incrementalMacChunkSize\x18\x06 \x01(\rH\x03R\x17incrementalMacChunkSize\x88\x01\x01\x12\x1f\n" + - "\bfileName\x18\a \x01(\tH\x04R\bfileName\x88\x01\x01\x12\x19\n" + - "\x05width\x18\b \x01(\rH\x05R\x05width\x88\x01\x01\x12\x1b\n" + - "\x06height\x18\t \x01(\rH\x06R\x06height\x88\x01\x01\x12\x1d\n" + + "\v_clientUuid\"\x9e\b\n" + + "\vFilePointer\x12%\n" + + "\vcontentType\x18\x04 \x01(\tH\x00R\vcontentType\x88\x01\x01\x12+\n" + + "\x0eincrementalMac\x18\x05 \x01(\fH\x01R\x0eincrementalMac\x88\x01\x01\x12=\n" + + "\x17incrementalMacChunkSize\x18\x06 \x01(\rH\x02R\x17incrementalMacChunkSize\x88\x01\x01\x12\x1f\n" + + "\bfileName\x18\a \x01(\tH\x03R\bfileName\x88\x01\x01\x12\x19\n" + + "\x05width\x18\b \x01(\rH\x04R\x05width\x88\x01\x01\x12\x1b\n" + + "\x06height\x18\t \x01(\rH\x05R\x06height\x88\x01\x01\x12\x1d\n" + "\acaption\x18\n" + - " \x01(\tH\aR\acaption\x88\x01\x01\x12\x1f\n" + - "\bblurHash\x18\v \x01(\tH\bR\bblurHash\x88\x01\x01\x12H\n" + - "\vlocatorInfo\x18\r \x01(\v2&.signal.backup.FilePointer.LocatorInfoR\vlocatorInfo\x1a\x9f\x02\n" + - "\rBackupLocator\x12\x1c\n" + - "\tmediaName\x18\x01 \x01(\tR\tmediaName\x12!\n" + - "\tcdnNumber\x18\x02 \x01(\rH\x00R\tcdnNumber\x88\x01\x01\x12\x10\n" + - "\x03key\x18\x03 \x01(\fR\x03key\x12\x16\n" + - "\x06digest\x18\x04 \x01(\fR\x06digest\x12\x12\n" + - "\x04size\x18\x05 \x01(\rR\x04size\x12)\n" + - "\rtransitCdnKey\x18\x06 \x01(\tH\x01R\rtransitCdnKey\x88\x01\x01\x12/\n" + - "\x10transitCdnNumber\x18\a \x01(\rH\x02R\x10transitCdnNumber\x88\x01\x01B\f\n" + - "\n" + - "_cdnNumberB\x10\n" + - "\x0e_transitCdnKeyB\x13\n" + - "\x11_transitCdnNumber\x1a\xca\x01\n" + - "\x11AttachmentLocator\x12\x16\n" + - "\x06cdnKey\x18\x01 \x01(\tR\x06cdnKey\x12\x1c\n" + - "\tcdnNumber\x18\x02 \x01(\rR\tcdnNumber\x12-\n" + - "\x0fuploadTimestamp\x18\x03 \x01(\x04H\x00R\x0fuploadTimestamp\x88\x01\x01\x12\x10\n" + - "\x03key\x18\x04 \x01(\fR\x03key\x12\x16\n" + - "\x06digest\x18\x05 \x01(\fR\x06digest\x12\x12\n" + - "\x04size\x18\x06 \x01(\rR\x04sizeB\x12\n" + - "\x10_uploadTimestamp\x1a\x1a\n" + - "\x18InvalidAttachmentLocator\x1a\xf6\x02\n" + - "\fLocalLocator\x12\x1c\n" + - "\tmediaName\x18\x01 \x01(\tR\tmediaName\x12\x1f\n" + - "\blocalKey\x18\x02 \x01(\fH\x00R\blocalKey\x88\x01\x01\x12\x1c\n" + - "\tremoteKey\x18\x03 \x01(\fR\tremoteKey\x12\"\n" + - "\fremoteDigest\x18\x04 \x01(\fR\fremoteDigest\x12\x12\n" + - "\x04size\x18\x05 \x01(\rR\x04size\x12-\n" + - "\x0fbackupCdnNumber\x18\x06 \x01(\rH\x01R\x0fbackupCdnNumber\x88\x01\x01\x12)\n" + - "\rtransitCdnKey\x18\a \x01(\tH\x02R\rtransitCdnKey\x88\x01\x01\x12/\n" + - "\x10transitCdnNumber\x18\b \x01(\rH\x03R\x10transitCdnNumber\x88\x01\x01B\v\n" + - "\t_localKeyB\x12\n" + - "\x10_backupCdnNumberB\x10\n" + - "\x0e_transitCdnKeyB\x13\n" + - "\x11_transitCdnNumber\x1a\xc8\x04\n" + + " \x01(\tH\x06R\acaption\x88\x01\x01\x12\x1f\n" + + "\bblurHash\x18\v \x01(\tH\aR\bblurHash\x88\x01\x01\x12H\n" + + "\vlocatorInfo\x18\r \x01(\v2&.signal.backup.FilePointer.LocatorInfoR\vlocatorInfo\x1a\x86\x04\n" + "\vLocatorInfo\x12\x10\n" + - "\x03key\x18\x01 \x01(\fR\x03key\x12\"\n" + - "\flegacyDigest\x18\x02 \x01(\fR\flegacyDigest\x12&\n" + + "\x03key\x18\x01 \x01(\fR\x03key\x12&\n" + "\rplaintextHash\x18\n" + " \x01(\fH\x00R\rplaintextHash\x12*\n" + "\x0fencryptedDigest\x18\v \x01(\fH\x00R\x0fencryptedDigest\x12\x12\n" + @@ -12122,16 +11653,14 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\rtransitCdnKey\x18\x04 \x01(\tH\x01R\rtransitCdnKey\x88\x01\x01\x12/\n" + "\x10transitCdnNumber\x18\x05 \x01(\rH\x02R\x10transitCdnNumber\x88\x01\x01\x12C\n" + "\x1atransitTierUploadTimestamp\x18\x06 \x01(\x04H\x03R\x1atransitTierUploadTimestamp\x88\x01\x01\x123\n" + - "\x12mediaTierCdnNumber\x18\a \x01(\rH\x04R\x12mediaTierCdnNumber\x88\x01\x01\x12(\n" + - "\x0flegacyMediaName\x18\b \x01(\tR\x0flegacyMediaName\x12\x1f\n" + + "\x12mediaTierCdnNumber\x18\a \x01(\rH\x04R\x12mediaTierCdnNumber\x88\x01\x01\x12\x1f\n" + "\blocalKey\x18\t \x01(\fH\x05R\blocalKey\x88\x01\x01B\x10\n" + "\x0eintegrityCheckB\x10\n" + "\x0e_transitCdnKeyB\x13\n" + "\x11_transitCdnNumberB\x1d\n" + "\x1b_transitTierUploadTimestampB\x15\n" + "\x13_mediaTierCdnNumberB\v\n" + - "\t_localKeyB\t\n" + - "\alocatorB\x0e\n" + + "\t_localKeyJ\x04\b\x02\x10\x03J\x04\b\b\x10\tB\x0e\n" + "\f_contentTypeB\x11\n" + "\x0f_incrementalMacB\x1a\n" + "\x18_incrementalMacChunkSizeB\v\n" + @@ -12140,7 +11669,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\a_heightB\n" + "\n" + "\b_captionB\v\n" + - "\t_blurHash\"\xae\x04\n" + + "\t_blurHashJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03J\x04\b\x03\x10\x04J\x04\b\f\x10\r\"\xae\x04\n" + "\x05Quote\x125\n" + "\x13targetSentTimestamp\x18\x01 \x01(\x04H\x00R\x13targetSentTimestamp\x88\x01\x01\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12,\n" + @@ -12659,7 +12188,7 @@ func file_backuppb_Backup_proto_rawDescGZIP() []byte { } var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 31) -var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 124) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 120) var file_backuppb_Backup_proto_goTypes = []any{ (AvatarColor)(0), // 0: signal.backup.AvatarColor (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel @@ -12805,17 +12334,13 @@ var file_backuppb_Backup_proto_goTypes = []any{ (*ContactAttachment_Phone)(nil), // 141: signal.backup.ContactAttachment.Phone (*ContactAttachment_Email)(nil), // 142: signal.backup.ContactAttachment.Email (*ContactAttachment_PostalAddress)(nil), // 143: signal.backup.ContactAttachment.PostalAddress - (*FilePointer_BackupLocator)(nil), // 144: signal.backup.FilePointer.BackupLocator - (*FilePointer_AttachmentLocator)(nil), // 145: signal.backup.FilePointer.AttachmentLocator - (*FilePointer_InvalidAttachmentLocator)(nil), // 146: signal.backup.FilePointer.InvalidAttachmentLocator - (*FilePointer_LocalLocator)(nil), // 147: signal.backup.FilePointer.LocalLocator - (*FilePointer_LocatorInfo)(nil), // 148: signal.backup.FilePointer.LocatorInfo - (*Quote_QuotedAttachment)(nil), // 149: signal.backup.Quote.QuotedAttachment - (*GroupChangeChatUpdate_Update)(nil), // 150: signal.backup.GroupChangeChatUpdate.Update - (*GroupInvitationRevokedUpdate_Invitee)(nil), // 151: signal.backup.GroupInvitationRevokedUpdate.Invitee - (*ChatStyle_Gradient)(nil), // 152: signal.backup.ChatStyle.Gradient - (*ChatStyle_CustomChatColor)(nil), // 153: signal.backup.ChatStyle.CustomChatColor - (*ChatStyle_AutomaticBubbleColor)(nil), // 154: signal.backup.ChatStyle.AutomaticBubbleColor + (*FilePointer_LocatorInfo)(nil), // 144: signal.backup.FilePointer.LocatorInfo + (*Quote_QuotedAttachment)(nil), // 145: signal.backup.Quote.QuotedAttachment + (*GroupChangeChatUpdate_Update)(nil), // 146: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 147: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 148: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 149: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 150: signal.backup.ChatStyle.AutomaticBubbleColor } var file_backuppb_Backup_proto_depIdxs = []int32{ 33, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData @@ -12897,109 +12422,105 @@ var file_backuppb_Backup_proto_depIdxs = []int32{ 59, // 76: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer 59, // 77: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer 19, // 78: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag - 144, // 79: signal.backup.FilePointer.backupLocator:type_name -> signal.backup.FilePointer.BackupLocator - 145, // 80: signal.backup.FilePointer.attachmentLocator:type_name -> signal.backup.FilePointer.AttachmentLocator - 146, // 81: signal.backup.FilePointer.invalidAttachmentLocator:type_name -> signal.backup.FilePointer.InvalidAttachmentLocator - 147, // 82: signal.backup.FilePointer.localLocator:type_name -> signal.backup.FilePointer.LocalLocator - 148, // 83: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo - 46, // 84: signal.backup.Quote.text:type_name -> signal.backup.Text - 149, // 85: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 20, // 86: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 21, // 87: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 66, // 88: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 72, // 89: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 67, // 90: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 68, // 91: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 70, // 92: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 71, // 93: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 64, // 94: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 65, // 95: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 69, // 96: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 22, // 97: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 23, // 98: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 24, // 99: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 25, // 100: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 26, // 101: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 150, // 102: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 1, // 103: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 1, // 104: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 151, // 105: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 27, // 106: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 59, // 107: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 154, // 108: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 28, // 109: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 29, // 110: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 30, // 111: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 3, // 112: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 2, // 113: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 108, // 114: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 153, // 115: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 119, // 116: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 117: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 118: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 124, // 119: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 120, // 120: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 121, // 121: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 122, // 122: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 123, // 123: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 7, // 124: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 120, // 125: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 8, // 126: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 127: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 128: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 45, // 129: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 12, // 130: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 46, // 131: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 59, // 132: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 139, // 133: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 138, // 134: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 13, // 135: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 14, // 136: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 137, // 137: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 16, // 138: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 17, // 139: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 18, // 140: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 58, // 141: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 73, // 142: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 74, // 143: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 75, // 144: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 76, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 77, // 146: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 78, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 79, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 80, // 149: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 81, // 150: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 82, // 151: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 83, // 152: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 84, // 153: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 85, // 154: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 86, // 155: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 87, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 88, // 157: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 89, // 158: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 90, // 159: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 91, // 160: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 92, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 93, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 94, // 163: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 95, // 164: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 97, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 98, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 99, // 167: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 100, // 168: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 101, // 169: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 102, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 103, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 104, // 172: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 105, // 173: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 96, // 174: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 106, // 175: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 152, // 176: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 177, // [177:177] is the sub-list for method output_type - 177, // [177:177] is the sub-list for method input_type - 177, // [177:177] is the sub-list for extension type_name - 177, // [177:177] is the sub-list for extension extendee - 0, // [0:177] is the sub-list for field type_name + 144, // 79: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo + 46, // 80: signal.backup.Quote.text:type_name -> signal.backup.Text + 145, // 81: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 20, // 82: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 21, // 83: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 66, // 84: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 72, // 85: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 67, // 86: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 68, // 87: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 70, // 88: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 71, // 89: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 64, // 90: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 65, // 91: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 69, // 92: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 22, // 93: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 23, // 94: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 24, // 95: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 25, // 96: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 26, // 97: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 146, // 98: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 99: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 100: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 147, // 101: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 27, // 102: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 59, // 103: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 150, // 104: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 28, // 105: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 29, // 106: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 30, // 107: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 3, // 108: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 2, // 109: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 108, // 110: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 149, // 111: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 119, // 112: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 113: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 119, // 114: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 124, // 115: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 120, // 116: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 121, // 117: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 122, // 118: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 123, // 119: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 7, // 120: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 120, // 121: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 8, // 122: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 123: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 124: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 45, // 125: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 12, // 126: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 46, // 127: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 59, // 128: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 139, // 129: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 138, // 130: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 13, // 131: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 14, // 132: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 137, // 133: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 16, // 134: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 17, // 135: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 18, // 136: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 58, // 137: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 73, // 138: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 74, // 139: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 75, // 140: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 76, // 141: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 77, // 142: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 78, // 143: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 79, // 144: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 80, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 81, // 146: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 82, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 83, // 148: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 84, // 149: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 85, // 150: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 86, // 151: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 87, // 152: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 88, // 153: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 89, // 154: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 90, // 155: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 91, // 156: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 92, // 157: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 93, // 158: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 94, // 159: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 95, // 160: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 97, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 98, // 162: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 99, // 163: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 100, // 164: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 101, // 165: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 102, // 166: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 103, // 167: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 104, // 168: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 105, // 169: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 96, // 170: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 106, // 171: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 148, // 172: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 173, // [173:173] is the sub-list for method output_type + 173, // [173:173] is the sub-list for method input_type + 173, // [173:173] is the sub-list for extension type_name + 173, // [173:173] is the sub-list for extension extendee + 0, // [0:173] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -13071,12 +12592,7 @@ func file_backuppb_Backup_proto_init() { file_backuppb_Backup_proto_msgTypes[25].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[26].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[27].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[28].OneofWrappers = []any{ - (*FilePointer_BackupLocator_)(nil), - (*FilePointer_AttachmentLocator_)(nil), - (*FilePointer_InvalidAttachmentLocator_)(nil), - (*FilePointer_LocalLocator_)(nil), - } + file_backuppb_Backup_proto_msgTypes[28].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[29].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[30].OneofWrappers = []any{ (*BodyRange_MentionAci)(nil), @@ -13147,15 +12663,12 @@ func file_backuppb_Backup_proto_init() { (*PaymentNotification_TransactionDetails_FailedTransaction_)(nil), } file_backuppb_Backup_proto_msgTypes[108].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[113].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[113].OneofWrappers = []any{ (*FilePointer_LocatorInfo_PlaintextHash)(nil), (*FilePointer_LocatorInfo_EncryptedDigest)(nil), } - file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[115].OneofWrappers = []any{ (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), @@ -13191,8 +12704,8 @@ func file_backuppb_Backup_proto_init() { (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), } - file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[122].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{ (*ChatStyle_CustomChatColor_Solid)(nil), (*ChatStyle_CustomChatColor_Gradient)(nil), } @@ -13202,7 +12715,7 @@ func file_backuppb_Backup_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), NumEnums: 31, - NumMessages: 124, + NumMessages: 120, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index f88c6ae..464301d 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -344,7 +344,7 @@ message CallLink { string name = 3; Restrictions restrictions = 4; uint64 expirationMs = 5; - bytes epoch = 6; // May be absent/empty for older links + optional bytes epoch = 6; // May be absent/empty for older links } message AdHocCall { @@ -396,6 +396,7 @@ message ChatItem { message OutgoingMessageDetails { repeated SendStatus sendStatus = 1; + uint64 dateReceived = 2; // may be different from dateSent for sync messages } message DirectionlessMessageDetails { @@ -693,73 +694,12 @@ message MessageAttachment { } message FilePointer { - // References attachments in the backup (media) storage tier. - // DEPRECATED; use LocatorInfo instead if available. - message BackupLocator { - string mediaName = 1; - // If present, the cdn number of the succesful upload. - // If empty/0, may still have been uploaded, and clients - // can discover the cdn number via the list endpoint. - optional uint32 cdnNumber = 2; - bytes key = 3; - bytes digest = 4; - uint32 size = 5; - - // Fallback in case backup tier upload failed. - optional string transitCdnKey = 6; - optional uint32 transitCdnNumber = 7; - } - - // References attachments in the transit storage tier. - // May be downloaded or not when the backup is generated; - // primarily for free-tier users who cannot copy the - // attachments to the backup (media) storage tier. - // DEPRECATED; use LocatorInfo instead if available. - message AttachmentLocator { - string cdnKey = 1; - uint32 cdnNumber = 2; - optional uint64 uploadTimestamp = 3; - bytes key = 4; - bytes digest = 5; - uint32 size = 6; - } - - // References attachments that are invalid in such a way where download - // cannot be attempted. Could range from missing digests to missing - // CDN keys or anything else that makes download attempts impossible. - // This serves as a 'tombstone' so that the UX can show that an attachment - // did exist, but for whatever reason it's not retrievable. - // DEPRECATED; use LocatorInfo instead if available. - message InvalidAttachmentLocator { - } - - // References attachments in a local encrypted backup. - // Importers should first attempt to read the file from the local backup, - // and on failure fallback to backup and transit cdn if possible. - // DEPRECATED; use LocatorInfo instead if available. - message LocalLocator { - string mediaName = 1; - // Separate key used to encrypt this file for the local backup. - // Generally required. Missing field indicates attachment was not - // available locally when the backup was generated, but remote - // backup or transit info was available. - optional bytes localKey = 2; - bytes remoteKey = 3; - bytes remoteDigest = 4; - uint32 size = 5; - optional uint32 backupCdnNumber = 6; - optional string transitCdnKey = 7; - optional uint32 transitCdnNumber = 8; - } - message LocatorInfo { // Must be non-empty if transitCdnKey or plaintextHash are set/nonempty. // Otherwise must be empty. bytes key = 1; - // From the sender of the attachment (incl. ourselves) - // Will be reserved once all clients start reading integrityCheck - bytes legacyDigest = 2; + reserved /*legacyDigest*/ 2; oneof integrityCheck { // Set if file was at one point downloaded and its plaintextHash was calculated @@ -787,11 +727,7 @@ message FilePointer { // has not rotated since last upload; even if currently free tier. optional uint32 mediaTierCdnNumber = 7; - // Nonempty any time the attachment was downloaded and its - // digest validated, whether free tier or paid subscription. - // Will be reserved once all clients start reading integrityCheck, - // when mediaName will be derived from the plaintextHash and encryption key - string legacyMediaName = 8; + reserved /*legacyMediaName*/ 8; // Separate key used to encrypt this file for the local backup. // Generally required for local backups. @@ -801,14 +737,10 @@ message FilePointer { optional bytes localKey = 9; } - // If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error. - // DEPRECATED; use locatorInfo instead. - oneof locator { - BackupLocator backupLocator = 1; - AttachmentLocator attachmentLocator = 2; - InvalidAttachmentLocator invalidAttachmentLocator = 3; - LocalLocator localLocator = 12; - } + reserved /*backupLocator*/ 1; + reserved /*attachmentLocator*/ 2; + reserved /*invalidAttachmentLocator*/ 3; + reserved /*localLocator*/ 12; optional string contentType = 4; optional bytes incrementalMac = 5; diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index 21503c1..bcdd71b 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-dbd79cd0a52d7d1594f70a4ba5a68c8fc3efa5e8} -DESKTOP_GIT_REVISION=${1:-07a05f3dd6f7fd07a1faebd8dd046d2b87da6c07} +ANDROID_GIT_REVISION=${1:-62fdf3d1aa9f637729ae67b55aadcc24f38f0117} +DESKTOP_GIT_REVISION=${1:-203a1cc5e3f9c1533a58caff72e13aa6eaeeddc7} update_proto() { case "$1" in From 8ee190a1e72baf682f1ad9e112873e105c53cb27 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 26 Aug 2025 17:23:55 +0300 Subject: [PATCH 532/718] all: enable mautrix-go's new disappearing message features --- go.mod | 2 +- go.sum | 4 +-- pkg/connector/capabilities.go | 32 +++++++++++-------- pkg/connector/chatinfo.go | 14 ++++++++ pkg/connector/client.go | 17 ++-------- pkg/connector/groupinfo.go | 5 +-- pkg/connector/handlematrix.go | 12 +++++++ pkg/connector/handlesignal.go | 8 ++++- pkg/msgconv/from-matrix.go | 6 +++- pkg/msgconv/from-signal.go | 60 +++++++++++++++++------------------ 10 files changed, 94 insertions(+), 66 deletions(-) diff --git a/go.mod b/go.mod index b66294a..940c9b0 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 golang.org/x/net v0.43.0 google.golang.org/protobuf v1.36.7 - maunium.net/go/mautrix v0.25.0 + maunium.net/go/mautrix v0.25.1-0.20250826140716-0345a5356de1 ) require ( diff --git a/go.sum b/go.sum index 9fd93bc..c053158 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.0 h1:dhYoXIXSxI9A+kEPwBceuRP0wcpho15dVLucUF8k2eE= -maunium.net/go/mautrix v0.25.0/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= +maunium.net/go/mautrix v0.25.1-0.20250826140716-0345a5356de1 h1:8U8dwv4dxhMLrtqjf9LoDuQ6daGj9qdw1/62HIvK2cY= +maunium.net/go/mautrix v0.25.1-0.20250826140716-0345a5356de1/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index f0f71ff..144bda5 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -37,7 +37,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_01_16" + base := "fi.mau.signal.capabilities.2025_08_25" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -136,17 +136,21 @@ var signalCaps = &event.RoomFeatures{ MaxSize: MaxFileSize, }, }, - MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files - LocationMessage: event.CapLevelPartialSupport, - Poll: event.CapLevelRejected, - 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)), + MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files + LocationMessage: event.CapLevelPartialSupport, + Poll: event.CapLevelRejected, + 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: &event.DisappearingTimerCapability{ + Types: []event.DisappearingType{event.DisappearingTypeAfterRead}, + }, + Reaction: event.CapLevelFullySupported, ReactionCount: 1, AllowedReactions: nil, @@ -161,7 +165,7 @@ func init() { signalCapsNoteToSelf = ptr.Clone(signalCaps) signalCapsNoteToSelf.EditMaxAge = nil signalCapsNoteToSelf.DeleteMaxAge = nil - signalCapsNoteToSelf.ID = capID() + "+note_to_self.2" + signalCapsNoteToSelf.ID = capID() + "+note_to_self" } func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { @@ -181,5 +185,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 4 + return 1, 5 } diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 1937318..d4d1013 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -40,6 +40,12 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) +var ( + _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) +) + const PrivateChatTopic = "Signal private chat" const NoteToSelfName = "Signal Note to Self" @@ -278,6 +284,14 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type PowerLevel: &moderatorPL, }, }, + PowerLevels: &bridgev2.PowerLevelOverrides{ + Events: map[event.Type]int{ + event.StateRoomName: 0, + event.StateTopic: 0, + event.StateRoomAvatar: 0, + event.StateBeeperDisappearingTimer: 0, + }, + }, } if s.Main.Config.NumberInTopic && recipient.E164 != "" { topic = fmt.Sprintf("%s with %s", PrivateChatTopic, recipient.E164) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 925747e..27cea14 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -42,21 +42,8 @@ type SignalClient struct { } var ( - _ bridgev2.NetworkAPI = (*SignalClient)(nil) - _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.NetworkAPI = (*SignalClient)(nil) + _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) ) var pushCfg = &bridgev2.PushConfig{ diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index dfd4faf..3b5fbcd 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -66,6 +66,7 @@ func applyAttributesAccess(plc *bridgev2.PowerLevelOverrides, attributeAccess si plc.Events[event.StateRoomName] = attributePL plc.Events[event.StateRoomAvatar] = attributePL plc.Events[event.StateTopic] = attributePL + plc.Events[event.StateBeeperDisappearingTimer] = attributePL } func applyMembersAccess(plc *bridgev2.PowerLevelOverrides, memberAccess signalmeow.AccessControl) { @@ -170,7 +171,7 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden Topic: &groupInfo.Description, Avatar: avatar, Disappear: &database.DisappearingSetting{ - Type: database.DisappearingTypeAfterRead, + Type: event.DisappearingTypeAfterRead, Timer: time.Duration(groupInfo.DisappearingMessagesDuration) * time.Second, }, Members: members, @@ -245,7 +246,7 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, groupID } if groupChange.ModifyDisappearingMessagesDuration != nil { ic.ChatInfo.Disappear = &database.DisappearingSetting{ - Type: database.DisappearingTypeAfterRead, + Type: event.DisappearingTypeAfterRead, Timer: time.Duration(*groupChange.ModifyDisappearingMessagesDuration) * time.Second, } } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 09daaa2..af5cb55 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -39,6 +39,18 @@ import ( signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) +var ( + _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) +) + func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { userID, groupID, err := signalid.ParsePortalID(portalID) if err != nil { diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 803d481..fe11f88 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -331,7 +331,13 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po if converted.Disappear.Type != "" { evtTS := evt.GetTimestamp() if !dataMsg.GetIsViewOnce() { - portal.UpdateDisappearingSetting(ctx, converted.Disappear, nil, evtTS, true, true) + portal.UpdateDisappearingSetting(ctx, converted.Disappear, bridgev2.UpdateDisappearingSettingOpts{ + Sender: intent, + Timestamp: evtTS, + Implicit: true, + Save: true, + SendNotice: true, + }) } if evt.Info.Sender == evt.s.Client.Store.ACI { converted.Disappear.DisappearAt = evtTS.Add(converted.Disappear.Timer) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 26bb492..9af4dc5 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -71,8 +71,12 @@ func (mc *MessageConverter) ToSignal( } } } - if portal.Disappear.Timer > 0 { + if content.BeeperDisappearingTimer != nil { + dm.ExpireTimer = proto.Uint32(uint32(content.BeeperDisappearingTimer.Timer.Seconds())) + } else if portal.Disappear.Timer > 0 { dm.ExpireTimer = proto.Uint32(uint32(portal.Disappear.Timer.Seconds())) + } + if dm.ExpireTimer != nil && *dm.ExpireTimer != 0 { timerVersion := portal.Metadata.(*signalid.PortalMetadata).ExpirationTimerVersion if timerVersion > 0 { dm.ExpireTimerVersion = &timerVersion diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 815954a..b4f1b56 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -93,12 +93,12 @@ func (mc *MessageConverter) ToMatrix( Parts: make([]*bridgev2.ConvertedMessagePart, 0, calculateLength(dm)), } if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { - cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), dm.ExpireTimerVersion, true)) + cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), dm.ExpireTimerVersion, time.UnixMilli(int64(dm.GetTimestamp())))) // Don't allow any other parts in a disappearing timer change message return cm } if dm.GetExpireTimer() > 0 { - cm.Disappear.Type = database.DisappearingTypeAfterRead + cm.Disappear.Type = event.DisappearingTypeAfterRead cm.Disappear.Timer = time.Duration(dm.GetExpireTimer()) * time.Second } if dm.Sticker != nil { @@ -140,7 +140,7 @@ func (mc *MessageConverter) ToMatrix( }) } if dm.GetIsViewOnce() && mc.DisappearViewOnce && (cm.Disappear.Timer == 0 || cm.Disappear.Timer > ViewOnceDisappearTimer) { - cm.Disappear.Type = database.DisappearingTypeAfterRead + cm.Disappear.Type = event.DisappearingTypeAfterRead cm.Disappear.Timer = ViewOnceDisappearTimer cm.Parts = append(cm.Parts, &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, @@ -170,38 +170,38 @@ func (mc *MessageConverter) ToMatrix( return cm } -func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, timerVersion *uint32, updatePortal bool) *bridgev2.ConvertedMessagePart { +func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, timerVersion *uint32, ts time.Time) *bridgev2.ConvertedMessagePart { part := &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: bridgev2.DisappearingMessageNotice(time.Duration(timer)*time.Second, false), } - if updatePortal { - portal := getPortal(ctx) - portalMeta := portal.Metadata.(*signalid.PortalMetadata) - if timerVersion != nil && portalMeta.ExpirationTimerVersion > *timerVersion { - zerolog.Ctx(ctx).Warn(). - Uint32("current_version", portalMeta.ExpirationTimerVersion). - Uint32("new_version", *timerVersion). - Msg("Ignoring outdated disappearing timer change") - part.Content.Body += " (change ignored)" - return part - } - portal.Disappear.Timer = time.Duration(timer) * time.Second - if timer == 0 { - portal.Disappear.Type = "" - } else { - portal.Disappear.Type = database.DisappearingTypeAfterRead - } - if timerVersion != nil { - portalMeta.ExpirationTimerVersion = *timerVersion - } else { - portalMeta.ExpirationTimerVersion = 1 - } - err := portal.Save(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to update portal disappearing timer in database") - } + portal := getPortal(ctx) + portalMeta := portal.Metadata.(*signalid.PortalMetadata) + if timerVersion != nil && portalMeta.ExpirationTimerVersion > *timerVersion { + zerolog.Ctx(ctx).Warn(). + Uint32("current_version", portalMeta.ExpirationTimerVersion). + Uint32("new_version", *timerVersion). + Msg("Ignoring outdated disappearing timer change") + part.Content.Body += " (change ignored)" + return part } + setting := database.DisappearingSetting{ + Timer: time.Duration(timer) * time.Second, + Type: event.DisappearingTypeAfterRead, + } + if timer == 0 { + portal.Disappear.Type = "" + } + if timerVersion != nil { + portalMeta.ExpirationTimerVersion = *timerVersion + } else { + portalMeta.ExpirationTimerVersion = 1 + } + portal.UpdateDisappearingSetting(ctx, setting, bridgev2.UpdateDisappearingSettingOpts{ + Sender: getIntent(ctx), + Timestamp: ts, + Save: true, + }) return part } From 9e31917222f506bd8cf313d01f9048dd913634aa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 29 Aug 2025 12:12:00 +0300 Subject: [PATCH 533/718] signalmeow: update capability flags --- pkg/signalmeow/provisioning.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 07697d1..8957018 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -359,9 +359,8 @@ func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningC } var signalCapabilities = map[string]any{ - "deleteSync": true, - "versionedExpirationTimer": true, - "ssre2": true, + "attachmentBackfill": true, + "sqpr": true, } var signalCapabilitiesBody = exerrors.Must(json.Marshal(signalCapabilities)) From 676ad03905abe733f7e496fc72939e7784de75aa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 29 Aug 2025 16:10:41 +0300 Subject: [PATCH 534/718] handlematrix: add support for changing disappearing timer --- pkg/connector/handlematrix.go | 56 +++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index af5cb55..977e22f 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -26,6 +26,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/ptr" "go.mau.fi/util/variationselector" "google.golang.org/protobuf/proto" "maunium.net/go/mautrix/bridgev2" @@ -40,15 +41,16 @@ import ( ) var ( - _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.DisappearTimerChangingNetworkAPI = (*SignalClient)(nil) ) func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { @@ -607,3 +609,39 @@ func (s *SignalClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev ghost.UpdateInfo(ctx, info) return nil } + +func (s *SignalClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *bridgev2.MatrixDisappearingTimer) (bool, error) { + if msg.Content.Type != event.DisappearingTypeAfterRead && msg.Content.Timer.Duration != 0 { + return false, fmt.Errorf("unsupported disappearing timer type: %s", msg.Content.Type) + } + userID, groupID, err := signalid.ParsePortalID(msg.Portal.ID) + if err != nil { + return false, err + } + newSetting := database.DisappearingSetting{ + Type: event.DisappearingTypeAfterRead, + Timer: msg.Content.Timer.Duration, + } + if newSetting.Timer == 0 { + newSetting.Type = event.DisappearingTypeNone + } + if groupID != "" { + return s.handleMatrixRoomMeta(ctx, msg.Portal, &signalmeow.GroupChange{ + ModifyDisappearingMessagesDuration: ptr.Ptr(uint32(msg.Content.Timer.Seconds())), + }, func() { + msg.Portal.Disappear = newSetting + }) + } else { + res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Flags: ptr.Ptr(uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE)), + ExpireTimer: ptr.Ptr(uint32(msg.Content.Timer.Seconds())), + }, + }) + if !res.WasSuccessful { + return false, res.Error + } + msg.Portal.Disappear = newSetting + return true, nil + } +} From f80af12c9b8e28c2974d897f89efbce255a9b82e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Sep 2025 16:40:35 +0300 Subject: [PATCH 535/718] signalmeow/store: save signal-specific nicknames --- pkg/connector/config.go | 2 ++ pkg/connector/example-config.yaml | 1 + pkg/signalmeow/storageservice.go | 4 ++++ pkg/signalmeow/store/recipient_store.go | 7 ++++++- pkg/signalmeow/store/upgrades/00-latest.sql | 3 ++- pkg/signalmeow/store/upgrades/22-recipient-nickname.sql | 2 ++ pkg/signalmeow/types/contact.go | 1 + 7 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/22-recipient-nickname.sql diff --git a/pkg/connector/config.go b/pkg/connector/config.go index 1f583c5..e210b65 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -47,6 +47,7 @@ type SignalConfig struct { type DisplaynameParams struct { ProfileName string ContactName string + Nickname string Username string PhoneNumber string UUID string @@ -60,6 +61,7 @@ func (c *SignalConfig) FormatDisplayname(contact *types.Recipient) string { err := c.displaynameTemplate.Execute(&nameBuf, &DisplaynameParams{ ProfileName: contact.Profile.Name, ContactName: contact.ContactName, + Nickname: contact.Nickname, Username: "", PhoneNumber: contact.E164, UUID: contact.ACI.String(), diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml index 8c0a61e..e9ff6b4 100644 --- a/pkg/connector/example-config.yaml +++ b/pkg/connector/example-config.yaml @@ -1,6 +1,7 @@ # Displayname template for Signal users. # {{.ProfileName}} - The Signal profile name set by the user. # {{.ContactName}} - The name for the user from your phone's contact list. This is not safe on multi-user instances. +# {{.Nickname}} - The nickname set for the user in the native Signal app. This is not safe on multi-user instances. # {{.PhoneNumber}} - The phone number of the user. # {{.UUID}} - The UUID of the Signal user. # {{.AboutEmoji}} - The emoji set by the user in their profile. diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 26d52ff..38a17d9 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -88,6 +88,10 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat changed = true recipient.ContactName = strings.TrimSpace(fmt.Sprintf("%s %s", contact.SystemGivenName, contact.SystemFamilyName)) } + if contact.Nickname != nil { + changed = true + recipient.Nickname = strings.TrimSpace(fmt.Sprintf("%s %s", contact.Nickname.Given, contact.Nickname.Family)) + } if contact.E164 != "" { changed = changed || recipient.E164 != contact.E164 recipient.E164 = contact.E164 diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 03608a2..9e2bb8e 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -55,6 +55,7 @@ const ( e164_number, contact_name, contact_avatar_hash, + nickname, profile_key, profile_name, profile_about, @@ -79,6 +80,7 @@ const ( e164_number, contact_name, contact_avatar_hash, + nickname, profile_key, profile_name, profile_about, @@ -87,12 +89,13 @@ const ( profile_fetched_at, needs_pni_signature ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ON CONFLICT (account_id, aci_uuid) DO UPDATE SET pni_uuid = excluded.pni_uuid, e164_number = excluded.e164_number, contact_name = excluded.contact_name, contact_avatar_hash = excluded.contact_avatar_hash, + nickname = excluded.nickname, profile_key = excluded.profile_key, profile_name = excluded.profile_name, profile_about = excluded.profile_about, @@ -128,6 +131,7 @@ func scanRecipient(row dbutil.Scannable) (*types.Recipient, error) { &recipient.E164, &recipient.ContactName, &recipient.ContactAvatar.Hash, + &recipient.Nickname, &profileKey, &recipient.Profile.Name, &recipient.Profile.About, @@ -329,6 +333,7 @@ func (s *sqlStore) StoreRecipient(ctx context.Context, recipient *types.Recipien recipient.E164, recipient.ContactName, recipient.ContactAvatar.Hash, + recipient.Nickname, recipient.Profile.Key.Slice(), recipient.Profile.Name, recipient.Profile.About, diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index cb7e693..2c550c9 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v21 (compatible with v13+): Latest revision +-- v0 -> v22 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -109,6 +109,7 @@ CREATE TABLE signalmeow_recipients ( e164_number TEXT NOT NULL DEFAULT '', contact_name TEXT NOT NULL DEFAULT '', contact_avatar_hash TEXT NOT NULL DEFAULT '', + nickname TEXT NOT NULL DEFAULT '', profile_key bytea, profile_name TEXT NOT NULL DEFAULT '', profile_about TEXT NOT NULL DEFAULT '', diff --git a/pkg/signalmeow/store/upgrades/22-recipient-nickname.sql b/pkg/signalmeow/store/upgrades/22-recipient-nickname.sql new file mode 100644 index 0000000..437cb33 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/22-recipient-nickname.sql @@ -0,0 +1,2 @@ +-- v22 (compatible with v13+): Store Signal-specific nickname of contacts +ALTER TABLE signalmeow_recipients ADD COLUMN nickname TEXT NOT NULL DEFAULT ''; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index fea6fa5..53852aa 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -51,6 +51,7 @@ type Recipient struct { E164 string ContactName string ContactAvatar ContactAvatar + Nickname string Profile Profile NeedsPNISignature bool From c71d417ccc8691b8bdfdbad8d208a6ab83790d62 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Sep 2025 16:48:30 +0300 Subject: [PATCH 536/718] signalmeow/storageservice: send contact list event on storage sync --- pkg/connector/handlesignal.go | 13 ++++++++----- pkg/signalmeow/events/message.go | 1 + pkg/signalmeow/storageservice.go | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index fe11f88..d60acc0 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -651,12 +651,15 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { if contact.ACI == uuid.Nil { continue } - fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) - if err != nil { - log.Err(err).Msg("Failed to get full contact info from store") - continue + if !evt.IsFromDB { + fullContact, err := s.Client.ContactByACI(ctx, contact.ACI) + if err != nil { + log.Err(err).Msg("Failed to get full contact info from store") + continue + } + fullContact.ContactAvatar = contact.ContactAvatar + contact = fullContact } - fullContact.ContactAvatar = contact.ContactAvatar ghost, err := s.Main.Bridge.GetGhostByID(ctx, signalid.MakeUserID(contact.ACI)) if err != nil { log.Err(err).Msg("Failed to get ghost to update contact info") diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index cc7d62c..0642c33 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -76,6 +76,7 @@ type Call struct { type ContactList struct { Contacts []*types.Recipient + IsFromDB bool } type ACIFound struct { diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 38a17d9..06b0283 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -35,6 +35,7 @@ import ( "google.golang.org/protobuf/proto" "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/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" @@ -59,6 +60,7 @@ func (cli *Client) SyncStorage(ctx context.Context) { func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdate) error { log := zerolog.Ctx(ctx) + var changedContacts []*types.Recipient for _, record := range update.NewRecords { switch data := record.StorageRecord.GetRecord().(type) { case *signalpb.StorageRecord_Contact: @@ -74,7 +76,8 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat continue } contact := data.Contact - _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (changed bool, err error) { + topLevelChanged := false + recipient, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (changed bool, err error) { if len(contact.ProfileKey) == libsignalgo.ProfileKeyLength { newProfileKey := libsignalgo.ProfileKey(contact.ProfileKey) changed = changed || recipient.Profile.Key != newProfileKey @@ -96,11 +99,15 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat changed = changed || recipient.E164 != contact.E164 recipient.E164 = contact.E164 } + topLevelChanged = changed return }) if err != nil { return fmt.Errorf("failed to update contact %s/%s: %w", aci, pni, err) } + if topLevelChanged { + changedContacts = append(changedContacts, recipient) + } case *signalpb.StorageRecord_GroupV2: if len(data.GroupV2.MasterKey) != libsignalgo.GroupMasterKeyLength { log.Warn().Msg("Invalid group master key length") @@ -126,6 +133,12 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat log.Warn().Type("type", data).Str("item_id", record.StorageID).Msg("Unknown storage record type") } } + if len(changedContacts) > 0 { + go cli.handleEvent(&events.ContactList{ + Contacts: changedContacts, + IsFromDB: true, + }) + } return nil } From 06ac834ac32db08118b437923ef87c97fb43ba41 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 1 Sep 2025 17:06:25 +0300 Subject: [PATCH 537/718] config: parse displayname template at config parse time --- pkg/connector/config.go | 18 ++++++++++++++++++ pkg/connector/connector.go | 7 ------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/pkg/connector/config.go b/pkg/connector/config.go index e210b65..4e42186 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -22,6 +22,8 @@ import ( "text/template" up "go.mau.fi/util/configupgrade" + "gopkg.in/yaml.v3" + "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" @@ -44,6 +46,22 @@ type SignalConfig struct { displaynameTemplate *template.Template `yaml:"-"` } +type umConfig SignalConfig + +func (c *SignalConfig) UnmarshalYAML(node *yaml.Node) error { + err := node.Decode((*umConfig)(c)) + if err != nil { + return err + } + return c.PostProcess() +} + +func (c *SignalConfig) PostProcess() error { + var err error + c.displaynameTemplate, err = template.New("displayname").Parse(c.DisplaynameTemplate) + return err +} + type DisplaynameParams struct { ProfileName string ContactName string diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 00032b8..e81ef7a 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "strconv" - "text/template" "time" "github.com/google/uuid" @@ -59,12 +58,6 @@ func (s *SignalConnector) GetName() bridgev2.BridgeName { } func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { - var err error - s.Config.displaynameTemplate, err = template.New("displayname").Parse(s.Config.DisplaynameTemplate) - if err != nil { - // TODO return error or do this later? - panic(err) - } s.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "signalmeow").Logger())) s.Bridge = bridge s.MsgConv = msgconv.NewMessageConverter(bridge) From ffd170f0f11d3565302875a39bce5f66827f5174 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 4 Sep 2025 12:13:58 +0200 Subject: [PATCH 538/718] startchat: add support for creating groups (#607) --- go.mod | 4 +- go.sum | 4 +- pkg/connector/capabilities.go | 48 +++++++++++----- pkg/connector/chatinfo.go | 105 +++++++++++++++++++++++++++++++++- pkg/connector/groupinfo.go | 9 ++- pkg/connector/handlematrix.go | 3 +- pkg/signalmeow/attachments.go | 22 +++---- pkg/signalmeow/groups.go | 52 +++++++++-------- pkg/signalmeow/profile.go | 5 +- 9 files changed, 189 insertions(+), 63 deletions(-) diff --git a/go.mod b/go.mod index 940c9b0..bf104b0 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,8 @@ require ( golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 golang.org/x/net v0.43.0 google.golang.org/protobuf v1.36.7 - maunium.net/go/mautrix v0.25.1-0.20250826140716-0345a5356de1 + gopkg.in/yaml.v3 v3.0.1 + maunium.net/go/mautrix v0.25.1-0.20250902152424-709f48f2b370 ) require ( @@ -44,6 +45,5 @@ require ( golang.org/x/text v0.28.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index c053158..e4402d2 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.1-0.20250826140716-0345a5356de1 h1:8U8dwv4dxhMLrtqjf9LoDuQ6daGj9qdw1/62HIvK2cY= -maunium.net/go/mautrix v0.25.1-0.20250826140716-0345a5356de1/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= +maunium.net/go/mautrix v0.25.1-0.20250902152424-709f48f2b370 h1:1rz6V3P38i2qSJKEe0QBXozfI/9yaM/zWrZPDrtKVYQ= +maunium.net/go/mautrix v0.25.1-0.20250902152424-709f48f2b370/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 144bda5..129c75c 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -136,20 +136,18 @@ var signalCaps = &event.RoomFeatures{ MaxSize: MaxFileSize, }, }, - MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files - LocationMessage: event.CapLevelPartialSupport, - Poll: event.CapLevelRejected, - 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: &event.DisappearingTimerCapability{ - Types: []event.DisappearingType{event.DisappearingTypeAfterRead}, - }, + MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files + LocationMessage: event.CapLevelPartialSupport, + Poll: event.CapLevelRejected, + 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, @@ -159,6 +157,10 @@ var signalCaps = &event.RoomFeatures{ TypingNotifications: true, } +var signalDisappearingCap = &event.DisappearingTimerCapability{ + Types: []event.DisappearingType{event.DisappearingTypeAfterRead}, +} + var signalCapsNoteToSelf *event.RoomFeatures func init() { @@ -178,6 +180,24 @@ func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Por var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ DisappearingMessages: true, AggressiveUpdateInfo: true, + Provisioning: bridgev2.ProvisioningCapabilities{ + ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{ + CreateDM: true, + LookupPhone: true, + LookupUsername: false, // TODO implement + ContactList: true, + }, + GroupCreation: map[string]bridgev2.GroupTypeCapabilities{ + "group": { + TypeDescription: "a group chat", + + Name: bridgev2.GroupFieldCapability{Allowed: true, Required: true, MaxLength: 32}, + Avatar: bridgev2.GroupFieldCapability{Allowed: true}, + Disappear: bridgev2.GroupFieldCapability{Allowed: true, DisappearSettings: signalDisappearingCap}, + Participants: bridgev2.GroupFieldCapability{Allowed: true}, + }, + }, + }, } func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index d4d1013..4b72ad0 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -32,6 +32,7 @@ import ( "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalid" @@ -236,9 +237,107 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre } } -func (s *SignalClient) CreateGroup(ctx context.Context, name string, users ...networkid.UserID) (*bridgev2.CreateChatResponse, error) { - //TODO implement me - return nil, fmt.Errorf("not implemented") +func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCreateParams) (*bridgev2.CreateChatResponse, error) { + group := &signalmeow.Group{ + Title: ptr.Val(params.Name).Name, + Members: make([]*signalmeow.GroupMember, len(params.Participants)+1), + Description: ptr.Val(params.Topic).Topic, + AnnouncementsOnly: false, + DisappearingMessagesDuration: uint32(ptr.Val(params.Disappear).Timer.Seconds()), + AccessControl: &signalmeow.GroupAccessControl{ + Members: signalmeow.AccessControl_MEMBER, + AddFromInviteLink: signalmeow.AccessControl_UNSATISFIABLE, + Attributes: signalmeow.AccessControl_ADMINISTRATOR, + }, + } + var pl *event.PowerLevelsEventContent + // TODO actually get PLs + if pl != nil { + if pl.EventsDefault > pl.UsersDefault { + group.AnnouncementsOnly = true + } + if pl.Invite() > pl.UsersDefault { + group.AccessControl.Members = signalmeow.AccessControl_ADMINISTRATOR + } + if pl.GetEventLevel(event.StateRoomName) <= pl.UsersDefault { + group.AccessControl.Attributes = signalmeow.AccessControl_MEMBER + } + } + group.Members[0] = &signalmeow.GroupMember{ + ACI: s.Client.Store.ACI, + Role: signalmeow.GroupMember_ADMINISTRATOR, + } + for i, member := range params.Participants { + userID, err := signalid.ParseUserID(member) + if err != nil { + return nil, fmt.Errorf("invalid user ID %q: %w", member, err) + } + group.Members[i+1] = &signalmeow.GroupMember{ + ACI: userID, + Role: signalmeow.GroupMember_DEFAULT, // TODO set proper role from power levels + } + } + _, err := signalmeow.PrepareGroupCreation(group) + if err != nil { + return nil, fmt.Errorf("failed to prepare group creation: %w", err) + } + var avatarBytes []byte + var avatarMXC id.ContentURIString + if params.Avatar != nil { + avatarMXC = params.Avatar.URL + avatarBytes, err = s.Main.Bridge.Bot.DownloadMedia(ctx, params.Avatar.URL, params.Avatar.MSC3414File) + if err != nil { + return nil, fmt.Errorf("failed to download avatar: %w", err) + } + group.AvatarPath, err = s.Client.UploadGroupAvatar(ctx, avatarBytes, group.GroupIdentifier) + if err != nil { + return nil, fmt.Errorf("failed to upload avatar: %w", err) + } + } + portal, err := s.Main.Bridge.GetPortalByKey(ctx, s.makePortalKey(string(group.GroupIdentifier))) + if err != nil { + return nil, fmt.Errorf("failed to get portal: %w", err) + } + if params.RoomID != "" { + err = portal.UpdateMatrixRoomID(ctx, params.RoomID, bridgev2.UpdateMatrixRoomIDParams{SyncDBMetadata: func() { + portal.Name = group.Title + portal.NameSet = true + portal.Topic = group.Description + portal.TopicSet = true + portal.AvatarHash = sha256.Sum256(avatarBytes) + portal.AvatarSet = true + portal.AvatarMXC = avatarMXC + portal.AvatarID = makeAvatarPathID(group.AvatarPath) + if group.DisappearingMessagesDuration > 0 { + portal.Disappear = database.DisappearingSetting{ + Type: event.DisappearingTypeAfterRead, + Timer: time.Duration(group.DisappearingMessagesDuration) * time.Second, + } + } + }}) + if err != nil { + return nil, fmt.Errorf("failed to set portal room ID: %w", err) + } + } + resp, err := s.Client.CreateGroup(ctx, group, avatarBytes) + if err != nil { + return nil, fmt.Errorf("failed to create group: %w", err) + } + if params.RoomID != "" { + // UpdateMatrixRoomID could do this for us if we passed ChatInfoSource to it, + // but we only want to do it after the group is successfully created + portal.UpdateBridgeInfo(ctx) + portal.UpdateCapabilities(ctx, s.UserLogin, true) + } + wrappedInfo, err := s.wrapGroupInfo(ctx, resp, nil) + if err != nil { + return nil, fmt.Errorf("failed to wrap group info for sync: %w", err) + } + return &bridgev2.CreateChatResponse{ + PortalKey: portal.PortalKey, + Portal: portal, + PortalInfo: wrappedInfo, + }, nil } func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveIdentifierResponse, error) { diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 3b5fbcd..857031f 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -101,6 +101,10 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden if err != nil { return nil, fmt.Errorf("failed to retrieve group by id: %w", err) } + return s.wrapGroupInfo(ctx, groupInfo, backupChat) +} + +func (s *SignalClient) wrapGroupInfo(ctx context.Context, groupInfo *signalmeow.Group, backupChat *store.BackupChat) (*bridgev2.ChatInfo, error) { members := &bridgev2.ChatMemberList{ IsFull: true, MemberMap: make(map[networkid.UserID]bridgev2.ChatMember, len(groupInfo.Members)+len(groupInfo.PendingMembers)+len(groupInfo.RequestingMembers)+len(groupInfo.BannedMembers)), @@ -156,13 +160,14 @@ func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIden } } if backupChat == nil { + var err error // TODO allow using backup chat for data too instead of asking server? - backupChat, err = s.Client.Store.BackupStore.GetBackupChatByGroupID(ctx, groupID) + backupChat, err = s.Client.Store.BackupStore.GetBackupChatByGroupID(ctx, groupInfo.GroupIdentifier) if err != nil { zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get backup chat for group") } } - avatar, err := s.makeGroupAvatar(ctx, groupID, &groupInfo.AvatarPath, groupInfo.GroupMasterKey) + avatar, err := s.makeGroupAvatar(ctx, groupInfo.GroupIdentifier, &groupInfo.AvatarPath, groupInfo.GroupMasterKey) if err != nil { return nil, fmt.Errorf("failed to make group avatar: %w", err) } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 977e22f..614795a 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -365,11 +365,10 @@ func (s *SignalClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2 return false, fmt.Errorf("failed to download avatar: %w", err) } avatarHash = sha256.Sum256(data) - avatarPathPtr, err := s.Client.UploadGroupAvatar(ctx, data, groupID) + avatarPath, err = s.Client.UploadGroupAvatar(ctx, data, groupID) if err != nil { return false, fmt.Errorf("failed to reupload avatar: %w", err) } - avatarPath = *avatarPathPtr } return s.handleMatrixRoomMeta(ctx, msg.Portal, &signalmeow.GroupChange{ ModifyAvatar: &avatarPath, diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index e321f57..ea03c21 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -280,28 +280,28 @@ func (cli *Client) uploadAttachmentTUS( return nil } -func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier) (*string, error) { +func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier) (string, error) { log := zerolog.Ctx(ctx) groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { log.Err(err).Msg("Could not get master key from group id") - return nil, err + return "", err } groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyToBytes(groupMasterKey)) if err != nil { log.Err(err).Msg("Failed to get Authorization for today") - return nil, err + return "", err } groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyToBytes(groupMasterKey)) if err != nil { log.Err(err).Msg("Could not get groupSecretParams from master key") - return nil, err + return "", err } attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Avatar{Avatar: avatarBytes}} encryptedAvatar, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) if err != nil { log.Err(err).Msg("Could not encrypt avatar into Group Property") - return nil, err + return "", err } // Get upload form from Signal server @@ -310,18 +310,18 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi resp, err := web.SendHTTPRequest(ctx, http.MethodGet, formPath, opts) if err != nil { log.Err(err).Msg("Error sending request fetching avatar upload form") - return nil, err + return "", err } body, err := io.ReadAll(resp.Body) if err != nil { log.Err(err).Msg("Error decoding response body fetching upload attributes") - return nil, err + return "", err } uploadForm := signalpb.AvatarUploadAttributes{} err = proto.Unmarshal(body, &uploadForm) if err != nil { log.Err(err).Msg("failed to unmarshal group avatar upload form") - return nil, err + return "", err } requestBody := &bytes.Buffer{} w := multipart.NewWriter(requestBody) @@ -345,14 +345,14 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi }) if err != nil { log.Err(err).Msg("Error sending request uploading attachment") - return nil, err + return "", err } if resp.StatusCode < 200 || resp.StatusCode >= 300 { log.Error().Int("status_code", resp.StatusCode).Msg("Error uploading attachment") - return nil, fmt.Errorf("error uploading attachment: %s", resp.Status) + return "", fmt.Errorf("error uploading attachment: %s", resp.Status) } - return &uploadForm.Key, nil + return uploadForm.Key, nil } func verifyMAC(key, body, mac []byte) bool { diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 8c0a841..865de3f 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -18,7 +18,6 @@ package signalmeow import ( "context" - "crypto/rand" "encoding/base64" "encoding/hex" "encoding/json" @@ -32,6 +31,8 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/ptr" + "go.mau.fi/util/random" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -1558,10 +1559,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi log.Err(err).Msg("Failed to retrieve Group") } if group.InviteLinkPassword == nil && groupChange.ModifyAddFromInviteLinkAccess != nil && groupChange.ModifyInviteLinkPassword != nil { - inviteLinkPasswordBytes := make([]byte, 16) - rand.Read(inviteLinkPasswordBytes) - inviteLinkPassword := InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) - groupChange.ModifyInviteLinkPassword = &inviteLinkPassword + groupChange.ModifyInviteLinkPassword = ptr.Ptr(GenerateInviteLinkPassword()) } groupChange.Revision = group.Revision + 1 for attempt := 0; attempt < 5; attempt++ { @@ -1644,9 +1642,7 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou AddFromInviteLink: signalpb.AccessControl_AccessRequired(decryptedGroup.AccessControl.AddFromInviteLink), } if decryptedGroup.AccessControl.AddFromInviteLink != AccessControl_UNSATISFIABLE { - inviteLinkPasswordBytes := make([]byte, 16) - rand.Read(inviteLinkPasswordBytes) - encryptedGroup.InviteLinkPassword = inviteLinkPasswordBytes + encryptedGroup.InviteLinkPassword = random.Bytes(16) } } for _, member := range decryptedGroup.Members { @@ -1671,41 +1667,52 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou return encryptedGroup, nil } +func PrepareGroupCreation(decryptedGroup *Group) (libsignalgo.GroupMasterKey, error) { + var masterKeyBytes libsignalgo.GroupMasterKey + if decryptedGroup.GroupMasterKey == "" { + masterKeyBytes = libsignalgo.GroupMasterKey(random.Bytes(32)) + decryptedGroup.GroupMasterKey = masterKeyFromBytes(masterKeyBytes) + } else { + masterKeyBytes = masterKeyToBytes(decryptedGroup.GroupMasterKey) + } + if decryptedGroup.GroupIdentifier == "" { + var err error + decryptedGroup.GroupIdentifier, err = groupIdentifierFromMasterKey(decryptedGroup.GroupMasterKey) + if err != nil { + return masterKeyBytes, err + } + } + return masterKeyBytes, nil +} + func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { log := zerolog.Ctx(ctx).With().Str("action", "CreateGroupOnServer").Logger() - masterKeyByteArray := make([]byte, 32) - rand.Read(masterKeyByteArray) - masterKeyBytes := libsignalgo.GroupMasterKey(masterKeyByteArray) - groupMasterKey := masterKeyFromBytes(masterKeyBytes) - groupId, err := groupIdentifierFromMasterKey(groupMasterKey) + masterKeyBytes, err := PrepareGroupCreation(decryptedGroup) if err != nil { - log.Err(err).Msg("Couldn't get gid from masterkey") return nil, err } - err = cli.Store.GroupStore.StoreMasterKey(ctx, groupId, groupMasterKey) + err = cli.Store.GroupStore.StoreMasterKey(ctx, decryptedGroup.GroupIdentifier, decryptedGroup.GroupMasterKey) if err != nil { return nil, fmt.Errorf("StoreMasterKey error: %w", err) } - log.Debug().Msg(string(groupMasterKey)) groupSecretParams, err := libsignalgo.DeriveGroupSecretParamsFromMasterKey(masterKeyBytes) if err != nil { log.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") return nil, err } if len(avatarBytes) > 0 { - avatarPath, err := cli.UploadGroupAvatar(ctx, avatarBytes, groupId) + avatarPath, err := cli.UploadGroupAvatar(ctx, avatarBytes, decryptedGroup.GroupIdentifier) if err != nil { log.Err(err).Msg("Failed to upload group avatar") return nil, err } - decryptedGroup.AvatarPath = *avatarPath + decryptedGroup.AvatarPath = avatarPath } encryptedGroup, err := cli.EncryptGroup(ctx, decryptedGroup, groupSecretParams) if err != nil { log.Err(err).Msg("Failed to encrypt group") return nil, err } - log.Debug().Stringer("groupID", groupId) groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) if err != nil { log.Err(err).Msg("Failed to get Authorization for today") @@ -1744,18 +1751,15 @@ func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Grou case http.StatusBadRequest: return nil, fmt.Errorf("failed to put new group: bad request") } - group, err := cli.fetchGroupWithMasterKey(ctx, groupMasterKey) + group, err := cli.fetchGroupWithMasterKey(ctx, decryptedGroup.GroupMasterKey) if err != nil { return nil, fmt.Errorf("failed to get new group: %w", err) } - log.Debug().Stringer("group id", group.GroupIdentifier).Msg("new group created") return group, nil } func GenerateInviteLinkPassword() types.SerializedInviteLinkPassword { - inviteLinkPasswordBytes := make([]byte, 16) - rand.Read(inviteLinkPasswordBytes) - return InviteLinkPasswordFromBytes(inviteLinkPasswordBytes) + return InviteLinkPasswordFromBytes(random.Bytes(16)) } func (cli *Client) CreateGroup(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 3aa88ff..81f1ed8 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -21,7 +21,6 @@ import ( "context" "crypto/aes" "crypto/cipher" - "crypto/rand" "encoding/base64" "encoding/hex" "encoding/json" @@ -35,6 +34,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/random" "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" @@ -338,8 +338,7 @@ func encryptString(key libsignalgo.ProfileKey, plaintext string, paddedLength in return nil, errors.New("plaintext longer than paddedLength") } padded := append([]byte(plaintext), make([]byte, paddedLength-inputLength)...) - nonce := make([]byte, NONCE_LENGTH) - rand.Read(nonce) + nonce := random.Bytes(NONCE_LENGTH) keyBytes := key[:] ciphertext, err := AesgcmEncrypt(keyBytes, nonce, padded) if err != nil { From b2c6eaf6f9fa900858aa045de8a05086b05e1915 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Sep 2025 16:00:27 +0300 Subject: [PATCH 539/718] msgconv/from-signal: don't bridge redundant disappear timer changes --- pkg/msgconv/from-signal.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index b4f1b56..41ad2ec 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -190,8 +190,9 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C Type: event.DisappearingTypeAfterRead, } if timer == 0 { - portal.Disappear.Type = "" + setting.Type = "" } + part.DontBridge = setting == portal.Disappear if timerVersion != nil { portalMeta.ExpirationTimerVersion = *timerVersion } else { From e3ecc7c0b201546b39521945f427b9f3ae5fde69 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Sep 2025 16:27:03 +0300 Subject: [PATCH 540/718] msgconv/from-signal: add action message metadata to disappearing notices --- go.mod | 2 +- go.sum | 4 ++-- pkg/msgconv/from-signal.go | 26 +++++++++++++++++--------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index bf104b0..00b8bdc 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.43.0 google.golang.org/protobuf v1.36.7 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.1-0.20250902152424-709f48f2b370 + maunium.net/go/mautrix v0.25.1-0.20250909132418-41bbe4ace4c7 ) require ( diff --git a/go.sum b/go.sum index e4402d2..390cf40 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.1-0.20250902152424-709f48f2b370 h1:1rz6V3P38i2qSJKEe0QBXozfI/9yaM/zWrZPDrtKVYQ= -maunium.net/go/mautrix v0.25.1-0.20250902152424-709f48f2b370/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= +maunium.net/go/mautrix v0.25.1-0.20250909132418-41bbe4ace4c7 h1:TywnMUPZakwE9oU1jPC8pVZk3q5dP66LkyOQ5Z+e7cI= +maunium.net/go/mautrix v0.25.1-0.20250909132418-41bbe4ace4c7/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 41ad2ec..1606245 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -171,11 +171,27 @@ func (mc *MessageConverter) ToMatrix( } func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, timerVersion *uint32, ts time.Time) *bridgev2.ConvertedMessagePart { + portal := getPortal(ctx) + setting := database.DisappearingSetting{ + Timer: time.Duration(timer) * time.Second, + Type: event.DisappearingTypeAfterRead, + } + if timer == 0 { + setting.Type = "" + } part := &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: bridgev2.DisappearingMessageNotice(time.Duration(timer)*time.Second, false), + Extra: map[string]any{ + "com.beeper.action_message": map[string]any{ + "type": "disappearing_timer", + "timer": setting.Timer.Milliseconds(), + "timer_type": setting.Type, + "implicit": false, + }, + }, + DontBridge: setting == portal.Disappear, } - portal := getPortal(ctx) portalMeta := portal.Metadata.(*signalid.PortalMetadata) if timerVersion != nil && portalMeta.ExpirationTimerVersion > *timerVersion { zerolog.Ctx(ctx).Warn(). @@ -185,14 +201,6 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C part.Content.Body += " (change ignored)" return part } - setting := database.DisappearingSetting{ - Timer: time.Duration(timer) * time.Second, - Type: event.DisappearingTypeAfterRead, - } - if timer == 0 { - setting.Type = "" - } - part.DontBridge = setting == portal.Disappear if timerVersion != nil { portalMeta.ExpirationTimerVersion = *timerVersion } else { From 09846af725e3580f3c7f1008acd10d315ad3e7f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 12 Sep 2025 13:38:50 +0300 Subject: [PATCH 541/718] legacy{migrate,provision}: delete Except keep start chat endpoints --- cmd/mautrix-signal/legacymigrate.go | 49 ------ cmd/mautrix-signal/legacymigrate.sql | 181 ---------------------- cmd/mautrix-signal/legacyprovision.go | 211 -------------------------- cmd/mautrix-signal/main.go | 17 --- go.mod | 2 +- go.sum | 4 +- 6 files changed, 3 insertions(+), 461 deletions(-) delete mode 100644 cmd/mautrix-signal/legacymigrate.go delete mode 100644 cmd/mautrix-signal/legacymigrate.sql diff --git a/cmd/mautrix-signal/legacymigrate.go b/cmd/mautrix-signal/legacymigrate.go deleted file mode 100644 index 377b5af..0000000 --- a/cmd/mautrix-signal/legacymigrate.go +++ /dev/null @@ -1,49 +0,0 @@ -// mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2024 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package main - -import ( - _ "embed" - - up "go.mau.fi/util/configupgrade" - - "maunium.net/go/mautrix/bridgev2/bridgeconfig" -) - -const legacyMigrateRenameTables = ` -ALTER TABLE portal RENAME TO portal_old; -ALTER TABLE puppet RENAME TO puppet_old; -ALTER TABLE "user" RENAME TO user_old; -ALTER TABLE user_portal RENAME TO user_portal_old; -ALTER TABLE message RENAME TO message_old; -ALTER TABLE reaction RENAME TO reaction_old; -ALTER TABLE disappearing_message RENAME TO disappearing_message_old; -` - -//go:embed legacymigrate.sql -var legacyMigrateCopyData string - -func migrateLegacyConfig(helper up.Helper) { - helper.Set(up.Str, "mautrix.bridge.e2ee", "encryption", "pickle_key") - bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "displayname_template"}, []string{"network", "displayname_template"}) - bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "note_to_self_avatar"}, []string{"network", "note_to_self_avatar"}) - bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "location_format"}, []string{"network", "location_format"}) - bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "use_contact_avatars"}, []string{"network", "use_contact_avatars"}) - bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "use_outdated_profiles"}, []string{"network", "use_outdated_profiles"}) - bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "number_in_topic"}, []string{"network", "number_in_topic"}) - bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"signal", "device_name"}, []string{"network", "device_name"}) -} diff --git a/cmd/mautrix-signal/legacymigrate.sql b/cmd/mautrix-signal/legacymigrate.sql deleted file mode 100644 index cbf06e3..0000000 --- a/cmd/mautrix-signal/legacymigrate.sql +++ /dev/null @@ -1,181 +0,0 @@ -INSERT INTO "user" (bridge_id, mxid, management_room, access_token) -SELECT '', mxid, management_room, NULL -FROM user_old; - -INSERT INTO user_login (bridge_id, user_mxid, id, remote_name, space_room, metadata) -SELECT - '', - mxid, - cast(uuid AS TEXT), - phone, -- remote_name - space_room, - CAST( - '{"phone":"' || phone || '"}' - -- only: postgres - AS jsonb - -- only: sqlite (line commented) --- AS text - ) -FROM user_old WHERE uuid IS NOT NULL AND phone IS NOT NULL; - -INSERT INTO portal ( - bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, other_user_id, - name, topic, avatar_id, avatar_hash, avatar_mxc, - name_set, avatar_set, topic_set, name_is_custom, in_space, - room_type, disappear_type, disappear_timer, metadata -) -SELECT - '', -- bridge_id - chat_id, -- id - CASE - WHEN receiver='00000000-0000-0000-0000-000000000000' THEN '' - ELSE CAST(receiver AS TEXT) - END, -- receiver - mxid, - NULL, -- parent_id - '', -- parent_receiver - CASE WHEN portal_old.relay_user_id<>'' THEN '' END, -- relay_bridge_id - CASE WHEN portal_old.relay_user_id<>'' THEN (SELECT id FROM user_login WHERE user_mxid=portal_old.relay_user_id) END, -- relay_login_id - CASE WHEN LENGTH(chat_id)=44 THEN NULL ELSE chat_id END, -- other_user_id - name, - topic, - CASE - WHEN avatar_path='notetoself' THEN avatar_url - WHEN avatar_path<>'' THEN ('path:' || avatar_path) - WHEN avatar_hash<>'' THEN ('hash:' || avatar_hash) - ELSE '' - END, -- avatar_id - avatar_hash, -- avatar_hash - avatar_url, -- avatar_mxc - name_set, - avatar_set, - topic_set, - CASE WHEN LENGTH(chat_id)=44 THEN true ELSE false END, -- name_is_custom - false, -- in_space - CASE WHEN LENGTH(chat_id)=44 THEN '' ELSE 'dm' END, -- room_type - CASE WHEN expiration_time<>0 THEN 'after_read' END, - CASE WHEN expiration_time<>0 THEN expiration_time * 1000000000 END, - CAST( - '{"revision":' || revision || '}' - -- only: postgres - AS jsonb - -- only: sqlite (line commented) --- AS text - ) -- metadata -FROM portal_old; - -INSERT INTO ghost ( - bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, - name_set, avatar_set, contact_info_set, - is_bot, identifiers, metadata -) -SELECT - '', -- bridge_id - cast(uuid AS TEXT), -- id - name, - CASE - WHEN avatar_path<>'' THEN ('path:' || avatar_path) - WHEN avatar_hash<>'' THEN ('hash:' || avatar_hash) - ELSE '' - END, -- avatar_id - avatar_hash, -- avatar_hash - avatar_url, -- avatar_mxc - name_set, - avatar_set, - contact_info_set, - false, -- is_bot - '[]', -- identifiers - CAST( - CASE - WHEN profile_fetched_at IS NOT NULL THEN ('{"profile_fetched_at":' || profile_fetched_at || '}') - ELSE '{}' - END - -- only: postgres - AS jsonb - -- only: sqlite (line commented) --- AS text - ) -- metadata -FROM puppet_old; - -INSERT INTO message ( - bridge_id, id, part_id, mxid, room_id, room_receiver, - sender_id, sender_mxid, timestamp, edit_count, metadata -) -SELECT - '', -- bridge_id - cast(sender AS TEXT) || '|' || timestamp, -- id - CASE WHEN part_index=0 THEN '' ELSE CAST(part_index AS TEXT) END, -- part_id - mxid, - signal_chat_id, -- room_id - CASE - WHEN signal_receiver='00000000-0000-0000-0000-000000000000' THEN '' - ELSE cast(signal_receiver AS TEXT) - END, -- room_receiver - cast(sender AS TEXT), -- sender_id - '', -- sender_mxid - timestamp * 1000000, - 0, -- edit_count - '{}' -- metadata -FROM message_old; - -INSERT INTO disappearing_message ( - bridge_id, mx_room, mxid, type, timer, disappear_at -) -SELECT - '', -- bridge_id - room_id, -- mx_room - mxid, - 'after_read', -- type - expiration_seconds * 1000000000, -- timer - CASE WHEN expiration_ts IS NOT NULL THEN expiration_ts * 1000000000 END -- disappear_at -FROM disappearing_message_old -WHERE expiration_ts < 9000000000 - AND room_id IN (SELECT mxid FROM portal WHERE mxid IS NOT NULL); - -INSERT INTO reaction ( - bridge_id, message_id, message_part_id, sender_id, emoji_id, emoji, - room_id, room_receiver, mxid, timestamp, metadata -) -SELECT - '', -- bridge_id - cast(msg_author AS TEXT) || '|' || msg_timestamp, -- message_id - '', -- message_part_id - cast(author AS TEXT), -- sender_id - '', -- emoji_id - emoji, - signal_chat_id, -- room_id - CASE - WHEN signal_receiver='00000000-0000-0000-0000-000000000000' THEN '' - ELSE cast(signal_receiver AS TEXT) - END, -- room_receiver - mxid, - msg_timestamp * 1000000, -- timestamp (actual reaction timestamp not available) - '{}' -- metadata -FROM reaction_old; - -INSERT INTO user_portal ( - bridge_id, user_mxid, login_id, portal_id, portal_receiver, in_space, preferred, last_read -) -SELECT - '', -- bridge_id - user_mxid, - cast(user_old.uuid AS TEXT), -- login_id - portal_chat_id, -- portal_id - CASE - WHEN portal_receiver='00000000-0000-0000-0000-000000000000' THEN '' - ELSE cast(portal_receiver AS TEXT) - END, -- portal_receiver - in_space, - false, -- preferred - CASE WHEN last_read_ts = 0 THEN NULL ELSE last_read_ts * 1000000 END -- last_read -FROM user_portal_old -LEFT JOIN user_old ON user_old.mxid = user_portal_old.user_mxid -WHERE user_old.uuid IS NOT NULL; - -DROP TABLE disappearing_message_old; -DROP TABLE reaction_old; -DROP TABLE user_portal_old; -DROP TABLE message_old; -DROP TABLE puppet_old; -DROP TABLE portal_old; -DROP TABLE user_old; diff --git a/cmd/mautrix-signal/legacyprovision.go b/cmd/mautrix-signal/legacyprovision.go index 6bd6882..c9061ac 100644 --- a/cmd/mautrix-signal/legacyprovision.go +++ b/cmd/mautrix-signal/legacyprovision.go @@ -17,197 +17,16 @@ package main import ( - "context" "encoding/json" "fmt" "net/http" - "strconv" - "sync" - "sync/atomic" "github.com/rs/zerolog" "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/status" "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/pkg/connector" ) -var legacyProvisionHandleID atomic.Uint32 -var loginSessions = make(map[uint32]*legacyLoginProcess) -var loginSessionsLock sync.Mutex - -type legacyLoginProcess struct { - ID uint32 - Login bridgev2.LoginProcess - User *bridgev2.User -} - -func (llp *legacyLoginProcess) Delete() { - loginSessionsLock.Lock() - delete(loginSessions, llp.ID) - loginSessionsLock.Unlock() -} - -func legacyProvLinkNew(w http.ResponseWriter, r *http.Request) { - handleID := legacyProvisionHandleID.Add(1) - user := m.Matrix.Provisioning.GetUser(r) - defLogin := user.GetDefaultLogin() - if defLogin != nil && defLogin.Client != nil && defLogin.Client.IsLoggedIn() { - JSONResponse(w, http.StatusConflict, &Error{ - Error: "Already logged in", - ErrCode: "FI.MAU.ALREADY_LOGGED_IN", - }) - return - } - log := zerolog.Ctx(r.Context()) - login, err := m.Connector.CreateLogin(r.Context(), user, "qr") - if err != nil { - log.Err(err).Msg("Failed to create login") - JSONResponse(w, http.StatusInternalServerError, &Error{ - Error: "Internal error starting login", - ErrCode: "M_UNKNOWN", - }) - return - } - firstStep, err := login.Start(r.Context()) - if err != nil { - log.Err(err).Msg("Failed to start login") - JSONResponse(w, http.StatusInternalServerError, &Error{ - Error: "Internal error starting login", - ErrCode: "M_UNKNOWN", - }) - return - } else if firstStep.StepID != connector.LoginStepQR || firstStep.Type != bridgev2.LoginStepTypeDisplayAndWait || firstStep.DisplayAndWaitParams.Type != bridgev2.LoginDisplayTypeQR { - log.Error().Any("first_step", firstStep).Msg("Unexpected first step") - JSONResponse(w, http.StatusInternalServerError, &Error{ - Error: "Unexpected first login step", - ErrCode: "M_UNKNOWN", - }) - return - } - loginSessionsLock.Lock() - loginSessions[handleID] = &legacyLoginProcess{ - ID: handleID, - Login: login, - User: user, - } - loginSessionsLock.Unlock() - JSONResponse(w, http.StatusOK, Response{ - Success: true, - Status: "provisioning_url_received", - SessionID: strconv.Itoa(int(handleID)), - URI: firstStep.DisplayAndWaitParams.Data, - }) -} - -func getLoginProcess(w http.ResponseWriter, r *http.Request) *legacyLoginProcess { - var body LinkWaitForAccountRequest - err := json.NewDecoder(r.Body).Decode(&body) - if err != nil { - JSONResponse(w, http.StatusBadRequest, Error{ - Success: false, - Error: "Error decoding JSON body", - ErrCode: mautrix.MBadJSON.ErrCode, - }) - return nil - } - sessionID, err := strconv.Atoi(body.SessionID) - if err != nil { - JSONResponse(w, http.StatusBadRequest, Error{ - Success: false, - Error: "Error decoding session ID in JSON body", - ErrCode: mautrix.MBadJSON.ErrCode, - }) - return nil - } - process, ok := loginSessions[uint32(sessionID)] - user := m.Matrix.Provisioning.GetUser(r) - if !ok || process.User != user { - JSONResponse(w, http.StatusNotFound, Error{ - Success: false, - Error: "No session found", - ErrCode: mautrix.MNotFound.ErrCode, - }) - return nil - } - return process -} - -func legacyProvLinkWaitScan(w http.ResponseWriter, r *http.Request) { - login := getLoginProcess(w, r) - if login == nil { - return - } - res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) - if err != nil { - zerolog.Ctx(r.Context()).Err(err).Msg("Failed to log in") - JSONResponse(w, http.StatusInternalServerError, Error{ - Error: "Failed to log in", - ErrCode: "M_UNKNOWN", - }) - login.Delete() - return - } else if res.StepID != connector.LoginStepProcess { - zerolog.Ctx(r.Context()).Error().Any("first_step", res).Msg("Unexpected login step") - JSONResponse(w, http.StatusInternalServerError, Error{ - Error: "Unexpected login step", - ErrCode: "M_UNKNOWN", - }) - login.Delete() - return - } - JSONResponse(w, http.StatusOK, Response{ - Success: true, - Status: "provisioning_data_received", - }) -} - -func legacyProvLinkWaitAccount(w http.ResponseWriter, r *http.Request) { - login := getLoginProcess(w, r) - if login == nil { - return - } - res, err := login.Login.(bridgev2.LoginProcessDisplayAndWait).Wait(r.Context()) - if err != nil { - zerolog.Ctx(r.Context()).Err(err).Msg("Failed to log in") - JSONResponse(w, http.StatusInternalServerError, Error{ - Error: "Failed to log in", - ErrCode: "M_UNKNOWN", - }) - } else if res.StepID != connector.LoginStepComplete || res.Type != bridgev2.LoginStepTypeComplete { - zerolog.Ctx(r.Context()).Error().Any("first_step", res).Msg("Unexpected login step") - JSONResponse(w, http.StatusInternalServerError, Error{ - Error: "Unexpected login step", - ErrCode: "M_UNKNOWN", - }) - } else { - JSONResponse(w, http.StatusOK, Response{ - Success: true, - Status: "prekeys_registered", - UUID: string(res.CompleteParams.UserLogin.ID), - Number: res.CompleteParams.UserLogin.RemoteName, - }) - go handleLoginComplete(context.WithoutCancel(r.Context()), login.User, res.CompleteParams.UserLogin) - } - login.Delete() -} - -func handleLoginComplete(ctx context.Context, user *bridgev2.User, newLogin *bridgev2.UserLogin) { - allLogins := user.GetCachedUserLogins() - for _, login := range allLogins { - if login.ID != newLogin.ID { - login.Delete(ctx, status.BridgeState{StateEvent: status.StateLoggedOut, Reason: "LOGIN_OVERRIDDEN"}, bridgev2.DeleteOpts{}) - } - } -} - -func legacyProvLogout(w http.ResponseWriter, r *http.Request) { - // No-op for backwards compatibility - JSONResponse(w, http.StatusOK, nil) -} - func legacyResolveIdentifierOrStartChat(w http.ResponseWriter, r *http.Request, create bool) { login := m.Matrix.Provisioning.GetLoginForRequest(w, r) if login == nil { @@ -305,31 +124,10 @@ type Response struct { Success bool `json:"success"` Status string `json:"status"` - // For response in LinkNew - SessionID string `json:"session_id,omitempty"` - URI string `json:"uri,omitempty"` - - // For response in LinkWaitForAccount - UUID string `json:"uuid,omitempty"` - Number string `json:"number,omitempty"` - // For response in ResolveIdentifier *ResolveIdentifierResponse } -type WhoAmIResponse struct { - Permissions int `json:"permissions"` - MXID string `json:"mxid"` - Signal *WhoAmIResponseSignal `json:"signal,omitempty"` -} - -type WhoAmIResponseSignal struct { - Number string `json:"number"` - UUID string `json:"uuid"` - Name string `json:"name"` - Ok bool `json:"ok"` -} - type ResolveIdentifierResponse struct { RoomID id.RoomID `json:"room_id"` ChatID ResolveIdentifierResponseChatID `json:"chat_id"` @@ -347,12 +145,3 @@ type ResolveIdentifierResponseOtherUser struct { DisplayName string `json:"displayname"` AvatarURL id.ContentURI `json:"avatar_url"` } - -type LinkWaitForScanRequest struct { - SessionID string `json:"session_id"` -} - -type LinkWaitForAccountRequest struct { - SessionID string `json:"session_id"` - DeviceName string `json:"device_name"` // TODO this seems to not be used anywhere -} diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index d96283f..16093b5 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -17,11 +17,9 @@ package main import ( - "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix/mxmain" "go.mau.fi/mautrix-signal/pkg/connector" - "go.mau.fi/mautrix-signal/pkg/signalmeow" ) // Information to find out exactly which commit the bridge was built from. @@ -42,23 +40,8 @@ var m = mxmain.BridgeMain{ } func main() { - bridgeconfig.HackyMigrateLegacyNetworkConfig = migrateLegacyConfig - m.PostInit = func() { - signalmeow.SetLogger(m.Log.With().Str("component", "signalmeow").Logger()) - m.CheckLegacyDB( - 20, - "v0.5.1", - "v0.7.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 21), - true, - ) - } m.PostStart = func() { if m.Matrix.Provisioning != nil { - m.Matrix.Provisioning.Router.HandleFunc("POST /v2/link/new", legacyProvLinkNew) - m.Matrix.Provisioning.Router.HandleFunc("POST /v2/link/wait/scan", legacyProvLinkWaitScan) - m.Matrix.Provisioning.Router.HandleFunc("POST /v2/link/wait/account", legacyProvLinkWaitAccount) - m.Matrix.Provisioning.Router.HandleFunc("POST /v2/logout", legacyProvLogout) m.Matrix.Provisioning.Router.HandleFunc("GET /v2/resolve_identifier/{phonenum}", legacyProvResolveIdentifier) m.Matrix.Provisioning.Router.HandleFunc("POST /v2/pm/{phonenum}", legacyProvPM) } diff --git a/go.mod b/go.mod index 00b8bdc..7136fa1 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.43.0 google.golang.org/protobuf v1.36.7 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.1-0.20250909132418-41bbe4ace4c7 + maunium.net/go/mautrix v0.25.1-0.20250911181014-4603a344ce1d ) require ( diff --git a/go.sum b/go.sum index 390cf40..345ff89 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.1-0.20250909132418-41bbe4ace4c7 h1:TywnMUPZakwE9oU1jPC8pVZk3q5dP66LkyOQ5Z+e7cI= -maunium.net/go/mautrix v0.25.1-0.20250909132418-41bbe4ace4c7/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= +maunium.net/go/mautrix v0.25.1-0.20250911181014-4603a344ce1d h1:jKAn+2wwFC3aLdgE7IBSxhVjB4JisBOz2oCLzj928+c= +maunium.net/go/mautrix v0.25.1-0.20250911181014-4603a344ce1d/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= From 7a81e7bcf5c7e44b0f9b0204bce4fc04fbda9cde Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 12 Sep 2025 13:57:26 +0300 Subject: [PATCH 542/718] libsignal: update to v0.80.3 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 24 +++++++++++++++++++++++- pkg/libsignalgo/sendercertificate.go | 15 ++++++++++++--- pkg/libsignalgo/version.go | 2 +- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 83690bd..43a23ef 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 83690bdf1130c514e51d573ad0da7b3802aabb6e +Subproject commit 43a23efa1118ac32a1434ab317025adfa2b91e4a diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index dc7fc18..ead3cb4 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1323,6 +1323,11 @@ typedef struct { const SignalServerCertificate *raw; } SignalConstPointerServerCertificate; +typedef struct { + const SignalConstPointerPublicKey *base; + size_t length; +} SignalBorrowedSliceOfConstPointerPublicKey; + typedef struct { SignalSenderKeyDistributionMessage *raw; } SignalMutPointerSenderKeyDistributionMessage; @@ -1378,6 +1383,21 @@ typedef struct { SignalCancellationId cancellation_id; } SignalCPromiseMutPointerUnauthenticatedChatConnection; +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalOptionalUuid *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseOptionalUuid; + typedef struct { SignalValidatingMac *raw; } SignalMutPointerValidatingMac; @@ -2284,7 +2304,7 @@ SignalFfiError *signal_sender_certificate_get_signature(SignalOwnedBuffer *out, SignalFfiError *signal_sender_certificate_new(SignalMutPointerSenderCertificate *out, const char *sender_uuid, const char *sender_e164, uint32_t sender_device_id, SignalConstPointerPublicKey sender_key, uint64_t expiration, SignalConstPointerServerCertificate signer_cert, SignalConstPointerPrivateKey signer_key); -SignalFfiError *signal_sender_certificate_validate(bool *out, SignalConstPointerSenderCertificate cert, SignalConstPointerPublicKey key, uint64_t time); +SignalFfiError *signal_sender_certificate_validate(bool *out, SignalConstPointerSenderCertificate cert, SignalBorrowedSliceOfConstPointerPublicKey trust_roots, uint64_t time); SignalFfiError *signal_sender_key_distribution_message_clone(SignalMutPointerSenderKeyDistributionMessage *new_obj, SignalConstPointerSenderKeyDistributionMessage obj); @@ -2488,6 +2508,8 @@ SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChat SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); +SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_hash(SignalCPromiseOptionalUuid *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer hash); + SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); diff --git a/pkg/libsignalgo/sendercertificate.go b/pkg/libsignalgo/sendercertificate.go index 1d7422f..47cf958 100644 --- a/pkg/libsignalgo/sendercertificate.go +++ b/pkg/libsignalgo/sendercertificate.go @@ -24,6 +24,7 @@ import "C" import ( "runtime" "time" + "unsafe" "github.com/google/uuid" ) @@ -186,16 +187,24 @@ func (sc *SenderCertificate) GetKey() (*PublicKey, error) { return wrapPublicKey(key.raw), nil } -func (sc *SenderCertificate) Validate(trustRoot *PublicKey, ts time.Time) (bool, error) { +func (sc *SenderCertificate) Validate(trustRoots []*PublicKey, ts time.Time) (bool, error) { var valid C.bool + constRoots := make([]C.SignalConstPointerPublicKey, len(trustRoots)) + for i, root := range trustRoots { + constRoots[i] = root.constPtr() + } signalFfiError := C.signal_sender_certificate_validate( &valid, sc.constPtr(), - trustRoot.constPtr(), + // TODO this might not be correct + C.SignalBorrowedSliceOfConstPointerPublicKey{ + base: unsafe.SliceData(constRoots), + length: C.size_t(len(constRoots)), + }, C.uint64_t(ts.UnixMilli()), ) runtime.KeepAlive(sc) - runtime.KeepAlive(trustRoot) + runtime.KeepAlive(constRoots) if signalFfiError != nil { return false, wrapError(signalFfiError) } diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 04012e8..334f82a 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.79.0" +const Version = "v0.80.3" From 0d77884ce4459ac7e56de3895ca34087580eec78 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 12 Sep 2025 14:03:08 +0300 Subject: [PATCH 543/718] changelog: update --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cf3475..0b0e5b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# v0.8.7 (unreleased) + +* Removed legacy provisioning API and database legacy migration. + Upgrading directly from versions prior to v0.7.0 is not supported. + * If you've been using the bridge since before v0.7.0 and have prevented the + bridge from writing to the config, you must either update the config + manually or allow the bridge to update it for you **before** upgrading to + this release (i.e. run v0.8.6 once with config writing allowed). +* Updated libsignal to v0.80.3. +* Added support for `com.beeper.disappearing_timer` state event, which stores + the disappearing setting of chats and allows changing the setting from Matrix. +* Added support for nicknames in displayname templates. + * Like contact list names, nicknames are not safe to use on multi-user instances. +* Added support for creating Signal groups. +* Fixed certain types of logouts not being detected properly. + # v0.8.6 (2025-08-16) * Deprecated legacy provisioning API. The `/_matrix/provision/v2` endpoints will From 6d218d8853a54a69a859f19bb4f2edb9e4a6ebcf Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 16 Sep 2025 15:05:20 +0300 Subject: [PATCH 544/718] Bump version to v0.8.7 --- CHANGELOG.md | 2 +- cmd/mautrix-signal/main.go | 2 +- go.mod | 26 ++++++++++----------- go.sum | 48 +++++++++++++++++++------------------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b0e5b4..b548abd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v0.8.7 (unreleased) +# v0.8.7 (2025-09-16) * Removed legacy provisioning API and database legacy migration. Upgrading directly from versions prior to v0.7.0 is not supported. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 16093b5..01e3793 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -34,7 +34,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.6", + Version: "0.8.7", Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 7136fa1..503059c 100644 --- a/go.mod +++ b/go.mod @@ -2,23 +2,23 @@ module go.mau.fi/mautrix-signal go 1.24.0 -toolchain go1.25.0 +toolchain go1.25.1 require ( - github.com/coder/websocket v1.8.13 + github.com/coder/websocket v1.8.14 github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 github.com/mattn/go-pointer v0.0.1 github.com/rs/zerolog v1.34.0 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.0 - golang.org/x/crypto v0.41.0 - golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 - golang.org/x/net v0.43.0 - google.golang.org/protobuf v1.36.7 + go.mau.fi/util v0.9.1 + golang.org/x/crypto v0.42.0 + golang.org/x/exp v0.0.0-20250911091902-df9299821621 + golang.org/x/net v0.44.0 + google.golang.org/protobuf v1.36.9 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.1-0.20250911181014-4603a344ce1d + maunium.net/go/mautrix v0.25.1 ) require ( @@ -30,7 +30,7 @@ require ( 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.32 // indirect - github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect + github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -40,9 +40,9 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.13 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // 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 diff --git a/go.sum b/go.sum index 345ff89..d410473 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 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/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= -github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -36,8 +36,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe h1:vHpqOnPlnkba8iSxU4j/CvDSS9J4+F4473esQsYLGoE= -github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 h1:QTvNkZ5ylY0PGgA+Lih+GdboMLY/G9SEGLMEGVjTVA4= +github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -51,8 +51,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -65,27 +65,27 @@ 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.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.0 h1:ya3s3pX+Y8R2fgp0DbE7a0o3FwncoelDX5iyaeVE8ls= -go.mau.fi/util v0.9.0/go.mod h1:pdL3lg2aaeeHIreGXNnPwhJPXkXdc3ZxsI6le8hOWEA= +go.mau.fi/util v0.9.1 h1:A+XKHRsjKkFi2qOm4RriR1HqY2hoOXNS3WFHaC89r2Y= +go.mau.fi/util v0.9.1/go.mod h1:M0bM9SyaOWJniaHs9hxEzz91r5ql6gYq6o1q5O1SsjQ= 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.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= -golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= +golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= -google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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= @@ -95,5 +95,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.25.1-0.20250911181014-4603a344ce1d h1:jKAn+2wwFC3aLdgE7IBSxhVjB4JisBOz2oCLzj928+c= -maunium.net/go/mautrix v0.25.1-0.20250911181014-4603a344ce1d/go.mod h1:pDd6Ppg+1PbWrw/rg4ZQQfVYZICRGzH+DcliZ/BODvU= +maunium.net/go/mautrix v0.25.1 h1:+xe3eXtQNcDPU/HoWzvSOA5YX57iqlYI1TXf/fM0KWs= +maunium.net/go/mautrix v0.25.1/go.mod h1:iSueLJ/2fBaNrsTObGqi1j0cl/loxrtAjmjay1scYD8= From 979bf338020869102103977d4c73747aef03930e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Sep 2025 12:50:59 +0300 Subject: [PATCH 545/718] handlematrix: fix changing disappearing timer --- pkg/connector/handlematrix.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 614795a..4443fad 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -631,8 +631,10 @@ func (s *SignalClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *b msg.Portal.Disappear = newSetting }) } else { + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ DataMessage: &signalpb.DataMessage{ + Timestamp: ptr.Ptr(ts), Flags: ptr.Ptr(uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE)), ExpireTimer: ptr.Ptr(uint32(msg.Content.Timer.Seconds())), }, From 96b1aae14ece3a5d8fc84c25f003316da09906f1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Sep 2025 15:04:27 +0300 Subject: [PATCH 546/718] msgconv/from-signal: ignore disappearing timers in backfill --- pkg/msgconv/from-signal.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 1606245..277e2a5 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -93,7 +93,9 @@ func (mc *MessageConverter) ToMatrix( Parts: make([]*bridgev2.ConvertedMessagePart, 0, calculateLength(dm)), } if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { - cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix(ctx, dm.GetExpireTimer(), dm.ExpireTimerVersion, time.UnixMilli(int64(dm.GetTimestamp())))) + cm.Parts = append(cm.Parts, mc.ConvertDisappearingTimerChangeToMatrix( + ctx, dm.GetExpireTimer(), dm.ExpireTimerVersion, time.UnixMilli(int64(dm.GetTimestamp())), attMap != nil, + )) // Don't allow any other parts in a disappearing timer change message return cm } @@ -170,7 +172,9 @@ func (mc *MessageConverter) ToMatrix( return cm } -func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.Context, timer uint32, timerVersion *uint32, ts time.Time) *bridgev2.ConvertedMessagePart { +func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix( + ctx context.Context, timer uint32, timerVersion *uint32, ts time.Time, isBackfill bool, +) *bridgev2.ConvertedMessagePart { portal := getPortal(ctx) setting := database.DisappearingSetting{ Timer: time.Duration(timer) * time.Second, @@ -188,10 +192,14 @@ func (mc *MessageConverter) ConvertDisappearingTimerChangeToMatrix(ctx context.C "timer": setting.Timer.Milliseconds(), "timer_type": setting.Type, "implicit": false, + "backfill": isBackfill, }, }, DontBridge: setting == portal.Disappear, } + if isBackfill { + return part + } portalMeta := portal.Metadata.(*signalid.PortalMetadata) if timerVersion != nil && portalMeta.ExpirationTimerVersion > *timerVersion { zerolog.Ctx(ctx).Warn(). From 88b2378fd9ca7538c900fd831464274c5bff9805 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 17 Sep 2025 15:04:37 +0300 Subject: [PATCH 547/718] signalmeow: remove unused data message wrapper functions --- pkg/signalmeow/sending.go | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 69545d9..5c3612e 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -531,32 +531,6 @@ func ReadReceptMessageForTimestamps(timestamps []uint64) *signalpb.Content { } } -func DataMessageForReaction(reaction string, targetMessageSender uuid.UUID, targetMessageTimestamp uint64, removing bool) *signalpb.Content { - timestamp := currentMessageTimestamp() - dm := &signalpb.DataMessage{ - Timestamp: ×tamp, - RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), - Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(reaction), - Remove: proto.Bool(removing), - TargetAuthorAci: proto.String(targetMessageSender.String()), - TargetSentTimestamp: proto.Uint64(targetMessageTimestamp), - }, - } - return wrapDataMessageInContent(dm) -} - -func DataMessageForDelete(targetMessageTimestamp uint64) *signalpb.Content { - timestamp := currentMessageTimestamp() - dm := &signalpb.DataMessage{ - Timestamp: ×tamp, - Delete: &signalpb.DataMessage_Delete{ - TargetSentTimestamp: proto.Uint64(targetMessageTimestamp), - }, - } - return wrapDataMessageInContent(dm) -} - func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { return &signalpb.Content{ DataMessage: dm, From 250975a622459f2c949eff3ad315fad8a52ff90c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 19 Sep 2025 14:32:26 +0300 Subject: [PATCH 548/718] capabilities: enable implicit read receipts --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/capabilities.go | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 503059c..d31d7ec 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.44.0 google.golang.org/protobuf v1.36.9 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.1 + maunium.net/go/mautrix v0.25.2-0.20250919113047-b760023dcaa3 ) require ( diff --git a/go.sum b/go.sum index d410473..a0e7676 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.1 h1:+xe3eXtQNcDPU/HoWzvSOA5YX57iqlYI1TXf/fM0KWs= -maunium.net/go/mautrix v0.25.1/go.mod h1:iSueLJ/2fBaNrsTObGqi1j0cl/loxrtAjmjay1scYD8= +maunium.net/go/mautrix v0.25.2-0.20250919113047-b760023dcaa3 h1:MU7lyDtxVAsd1Mh+WGJOFD5PsGLRRl3Xv67zizxLkgc= +maunium.net/go/mautrix v0.25.2-0.20250919113047-b760023dcaa3/go.mod h1:iSueLJ/2fBaNrsTObGqi1j0cl/loxrtAjmjay1scYD8= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 129c75c..329a81d 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -180,6 +180,7 @@ func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Por var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ DisappearingMessages: true, AggressiveUpdateInfo: true, + ImplicitReadReceipts: true, Provisioning: bridgev2.ProvisioningCapabilities{ ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{ CreateDM: true, From 546230ec40ccc44758ad22fc34882bda3644c327 Mon Sep 17 00:00:00 2001 From: Adam Van Ymeren Date: Thu, 25 Sep 2025 12:31:18 -0700 Subject: [PATCH 549/718] handlematrix: resync portals upon viewieng if they haven't synced in the last 24h (#608) Co-authored-by: Tulir Asokan --- pkg/connector/chatinfo.go | 2 ++ pkg/connector/groupinfo.go | 9 +++++- pkg/connector/handlematrix.go | 55 +++++++++++++++++++++-------------- pkg/signalid/dbmeta.go | 2 ++ 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 4b72ad0..18ffb36 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -438,6 +438,8 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type Type: ptr.Ptr(database.RoomTypeDM), CanBackfill: backupChat != nil, + + ExtraUpdates: updatePortalSyncMeta, }, } } diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 857031f..6baa3d6 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -23,6 +23,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/jsontime" "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -182,11 +183,17 @@ func (s *SignalClient) wrapGroupInfo(ctx context.Context, groupInfo *signalmeow. Members: members, Type: ptr.Ptr(database.RoomTypeDefault), JoinRule: &event.JoinRulesEventContent{JoinRule: joinRule}, - ExtraUpdates: makeRevisionUpdater(groupInfo.Revision), + ExtraUpdates: bridgev2.MergeExtraUpdaters(makeRevisionUpdater(groupInfo.Revision), updatePortalSyncMeta), CanBackfill: backupChat != nil, }, nil } +func updatePortalSyncMeta(ctx context.Context, portal *bridgev2.Portal) bool { + meta := portal.Metadata.(*signalid.PortalMetadata) + meta.LastSync = jsontime.UnixNow() + return true +} + func (s *SignalClient) makeGroupAvatar(ctx context.Context, groupID types.GroupIdentifier, path *string, groupMasterKey types.SerializedGroupMasterKey) (*bridgev2.Avatar, error) { if path == nil { return nil, nil diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 4443fad..1a10773 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -32,6 +32,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/bridgev2/simplevent" "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -577,35 +578,45 @@ func (s *SignalClient) HandleMatrixPowerLevels(ctx context.Context, msg *bridgev } func (s *SignalClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { - if msg.Portal == nil || msg.Portal.OtherUserID == "" { - // Group chat changes are sent by Signal so no need to fetch them on view + if msg.Portal == nil { return nil } - // Sync other user ghost info in DM rooms - ghost, err := s.Main.Bridge.GetExistingGhostByID(ctx, msg.Portal.OtherUserID) - if err != nil { - return fmt.Errorf("failed to get ghost for sync: %w", err) - } else if ghost == nil { - zerolog.Ctx(ctx).Warn(). - Str("other_user_id", string(msg.Portal.OtherUserID)). - Msg("No ghost found for other user in portal") - return nil + // Sync the other users ghost in DMs + if msg.Portal.OtherUserID != "" { + ghost, err := s.Main.Bridge.GetExistingGhostByID(ctx, msg.Portal.OtherUserID) + if err != nil { + return fmt.Errorf("failed to get ghost for sync: %w", err) + } else if ghost == nil { + zerolog.Ctx(ctx).Warn(). + Str("other_user_id", string(msg.Portal.OtherUserID)). + Msg("No ghost found for other user in portal") + } else { + meta := ghost.Metadata.(*signalid.GhostMetadata) + if meta.ProfileFetchedAt.Time.Add(5 * time.Minute).Before(time.Now()) { + // Reset, but don't save, portal last sync time for immediate sync now + meta.ProfileFetchedAt.Time = time.Time{} + info, err := s.GetUserInfoWithRefreshAfter(ctx, ghost, 5*time.Minute) + if err != nil { + return fmt.Errorf("failed to get user info: %w", err) + } + ghost.UpdateInfo(ctx, info) + } + } } - meta := ghost.Metadata.(*signalid.GhostMetadata) - if meta.ProfileFetchedAt.Time.Add(5 * time.Minute).After(time.Now()) { - // Limit profile fetches to max one per 5 minutes - return nil + // always resync the portal if its stale + portalMeta := msg.Portal.Metadata.(*signalid.PortalMetadata) + if portalMeta.LastSync.Add(24 * time.Hour).Before(time.Now()) { + s.UserLogin.QueueRemoteEvent(&simplevent.ChatResync{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatResync, + PortalKey: msg.Portal.PortalKey, + }, + GetChatInfoFunc: s.GetChatInfo, + }) } - // Reset, but don't save, portal last sync time for immediate sync now - meta.ProfileFetchedAt.Time = time.Time{} - info, err := s.GetUserInfoWithRefreshAfter(ctx, ghost, 5*time.Minute) - if err != nil { - return fmt.Errorf("failed to get user info: %w", err) - } - ghost.UpdateInfo(ctx, info) return nil } diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index 76ee217..72112a8 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -23,6 +23,8 @@ import ( type PortalMetadata struct { Revision uint32 `json:"revision,omitempty"` ExpirationTimerVersion uint32 `json:"expiration_timer_version,omitempty"` + // Lazy resync tracking + LastSync jsontime.Unix `json:"last_sync,omitempty"` } type MessageMetadata struct { From 7459cb38b3fdb8c2f2ddb64929bc05737f67ad50 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 25 Sep 2025 23:59:08 +0300 Subject: [PATCH 550/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d31d7ec..9ead914 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.44.0 google.golang.org/protobuf v1.36.9 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.2-0.20250919113047-b760023dcaa3 + maunium.net/go/mautrix v0.25.2-0.20250924172949-cf29b07f32ce ) require ( diff --git a/go.sum b/go.sum index a0e7676..1e05243 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.2-0.20250919113047-b760023dcaa3 h1:MU7lyDtxVAsd1Mh+WGJOFD5PsGLRRl3Xv67zizxLkgc= -maunium.net/go/mautrix v0.25.2-0.20250919113047-b760023dcaa3/go.mod h1:iSueLJ/2fBaNrsTObGqi1j0cl/loxrtAjmjay1scYD8= +maunium.net/go/mautrix v0.25.2-0.20250924172949-cf29b07f32ce h1:sRBScG2xa66ERjgrX+7D//HorAhmNHwxB2Kzltg+aUg= +maunium.net/go/mautrix v0.25.2-0.20250924172949-cf29b07f32ce/go.mod h1:iSueLJ/2fBaNrsTObGqi1j0cl/loxrtAjmjay1scYD8= From 0fb7252230e78a424410132dd9b5d8f22e2b9aee Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 26 Sep 2025 19:56:40 +0300 Subject: [PATCH 551/718] libsignalgo: add docker version of update-ffi.sh [skip cd] --- pkg/libsignalgo/update-ffi-docker-inner.sh | 11 +++++++++++ pkg/libsignalgo/update-ffi-docker.sh | 9 +++++++++ 2 files changed, 20 insertions(+) create mode 100755 pkg/libsignalgo/update-ffi-docker-inner.sh create mode 100755 pkg/libsignalgo/update-ffi-docker.sh diff --git a/pkg/libsignalgo/update-ffi-docker-inner.sh b/pkg/libsignalgo/update-ffi-docker-inner.sh new file mode 100755 index 0000000..7641701 --- /dev/null +++ b/pkg/libsignalgo/update-ffi-docker-inner.sh @@ -0,0 +1,11 @@ +#!/bin/sh +cd /data +export RUSTFLAGS="-Ctarget-feature=-crt-static" RUSTC_WRAPPER="" +apk add --no-cache git make cmake protoc musl-dev g++ clang-dev cbindgen +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 diff --git a/pkg/libsignalgo/update-ffi-docker.sh b/pkg/libsignalgo/update-ffi-docker.sh new file mode 100755 index 0000000..5fb6dda --- /dev/null +++ b/pkg/libsignalgo/update-ffi-docker.sh @@ -0,0 +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 +cd libsignal +echo "const Version = \"$(git describe --tags --always)\"" >> ../version.go From 01d1472750150a53440551f0c0503dfbf31b323a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 30 Sep 2025 15:36:25 +0300 Subject: [PATCH 552/718] libsignal: update to v0.82.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 2 +- pkg/libsignalgo/version.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 43a23ef..42ff946 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 43a23efa1118ac32a1434ab317025adfa2b91e4a +Subproject commit 42ff946228be177c33c147359178455b411d3628 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index ead3cb4..0111718 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -866,7 +866,7 @@ typedef struct { typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, SignalConstPointerKyberPreKeyRecord record); -typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id); +typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id, uint32_t signed_prekey_id, SignalConstPointerPublicKey base_key); typedef struct { void *ctx; diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 334f82a..b137e61 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.80.3" +const Version = "v0.82.0" From 527cd4ec0be42dd2d57a0af50556dc1573da3583 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 30 Sep 2025 16:14:13 +0300 Subject: [PATCH 553/718] signalmeow/groups: update to v2 api --- pkg/signalmeow/groups.go | 83 ++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 865de3f..de6e054 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -192,7 +192,7 @@ type GroupChange struct { ModifyInviteLinkPassword *types.SerializedInviteLinkPassword } -func (groupChange *GroupChange) isEmptpy() bool { +func (groupChange *GroupChange) isEmpty() bool { return len(groupChange.AddMembers) == 0 && len(groupChange.DeleteMembers) == 0 && len(groupChange.ModifyMemberRoles) == 0 && @@ -638,6 +638,7 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier } return cli.fetchGroupWithMasterKey(ctx, groupMasterKey) } + func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey types.SerializedGroupMasterKey) (*Group, error) { masterKeyBytes := masterKeyToBytes(groupMasterKey) groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) @@ -650,24 +651,28 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t ContentType: web.ContentTypeProtobuf, Host: web.StorageHostname, } - response, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/groups", opts) + response, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v2/groups", opts) if err != nil { return nil, err } if response.StatusCode != 200 { return nil, fmt.Errorf("fetchGroupByID SendHTTPRequest bad status: %d", response.StatusCode) } - var encryptedGroup signalpb.Group + return cli.parseGroupResponse(ctx, response, groupMasterKey) +} + +func (cli *Client) parseGroupResponse(ctx context.Context, response *http.Response, masterKey types.SerializedGroupMasterKey) (*Group, error) { + var groupResponse signalpb.GroupResponse groupBytes, err := io.ReadAll(response.Body) if err != nil { return nil, err } - err = proto.Unmarshal(groupBytes, &encryptedGroup) + err = proto.Unmarshal(groupBytes, &groupResponse) if err != nil { return nil, fmt.Errorf("failed to unmarshal group: %w", err) } - group, err := decryptGroup(ctx, &encryptedGroup, groupMasterKey) + group, err := decryptGroup(ctx, groupResponse.Group, masterKey) if err != nil { return nil, fmt.Errorf("failed to decrypt group: %w", err) } @@ -1196,7 +1201,7 @@ func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.Req }, nil } -func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroupChange *GroupChange, gid types.GroupIdentifier) (*signalpb.GroupChange, error) { +func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroupChange *GroupChange) (*signalpb.GroupChangeResponse, error) { log := zerolog.Ctx(ctx).With().Str("action", "EncryptGroupChange").Logger() groupMasterKey := decryptedGroupChange.GroupMasterKey masterKeyBytes := masterKeyToBytes(groupMasterKey) @@ -1479,7 +1484,7 @@ func (e RespError) Error() string { return e.Err } -func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupChange_Actions, groupMasterKey types.SerializedGroupMasterKey, groupLinkPassword []byte) (*signalpb.GroupChange, error) { +func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupChange_Actions, groupMasterKey types.SerializedGroupMasterKey, groupLinkPassword []byte) (*signalpb.GroupChangeResponse, error) { log := zerolog.Ctx(ctx).With().Str("action", "patchGroup").Logger() groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyToBytes(groupMasterKey)) if err != nil { @@ -1488,9 +1493,9 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh } var path string if groupLinkPassword == nil { - path = "/v1/groups/" + path = "/v2/groups/" } else { - path = fmt.Sprintf("/v1/groups/?inviteLinkPassword=%s", base64.StdEncoding.EncodeToString(groupLinkPassword)) + path = fmt.Sprintf("/v2/groups/?inviteLinkPassword=%s", base64.StdEncoding.EncodeToString(groupLinkPassword)) } requestBody, err := proto.Marshal(groupChange) if err != nil { @@ -1535,70 +1540,78 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh if err != nil { return nil, fmt.Errorf("failed to read storage manifest response: %w", err) } - signedGroupChange := signalpb.GroupChange{} - err = proto.Unmarshal(body, &signedGroupChange) + var changeResp signalpb.GroupChangeResponse + err = proto.Unmarshal(body, &changeResp) if err != nil { return nil, fmt.Errorf("failed to unmarshal signed groupChange: %w", err) } - return &signedGroupChange, nil + return &changeResp, nil } func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) (uint32, error) { log := zerolog.Ctx(ctx).With().Str("action", "UpdateGroup").Logger() groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { - log.Err(err).Msg("Could not get master key from group id") - return 0, err + return 0, fmt.Errorf("failed to get master key for group: %w", err) } groupChange.GroupMasterKey = groupMasterKey masterKeyBytes := masterKeyToBytes(groupMasterKey) var refetchedAddMemberCredentials bool - var signedGroupChange *signalpb.GroupChange + var signedGroupChange *signalpb.GroupChangeResponse group, err := cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { - log.Err(err).Msg("Failed to retrieve Group") + return 0, fmt.Errorf("failed to fetch group info to update: %w", err) } if group.InviteLinkPassword == nil && groupChange.ModifyAddFromInviteLinkAccess != nil && groupChange.ModifyInviteLinkPassword != nil { groupChange.ModifyInviteLinkPassword = ptr.Ptr(GenerateInviteLinkPassword()) } groupChange.Revision = group.Revision + 1 - for attempt := 0; attempt < 5; attempt++ { - signedGroupChange, err = cli.EncryptAndSignGroupChange(ctx, groupChange, gid) - if errors.Is(err, GroupPatchNotAcceptedError) { - log.Warn().Str("Error applying GroupChange, retrying...", err.Error()) + for attempt := 0; ; attempt++ { + signedGroupChange, err = cli.EncryptAndSignGroupChange(ctx, groupChange) + if err == nil { + break + } else if attempt >= 5 { + return 0, fmt.Errorf("failed to encrypt and sign group change after multiple retries: %w", err) + } else if errors.Is(err, GroupPatchNotAcceptedError) { + log.Err(err).Msg("Failed to apply group change, retrying...") if len(groupChange.AddMembers) > 0 && !refetchedAddMemberCredentials { refetchedAddMemberCredentials = true // change = refetchAddMemberCredentials(change); TODO } else { - return 0, fmt.Errorf("Group Change Failed: %w", err) + return 0, fmt.Errorf("failed to update group: %w", err) } } else if errors.Is(err, ConflictError) { delete(cli.GroupCache.groups, gid) delete(cli.GroupCache.lastFetched, gid) delete(cli.GroupCache.activeCalls, gid) group, err = cli.RetrieveGroupByID(ctx, gid, 0) + if err != nil { + return 0, fmt.Errorf("failed to fetch group after conflict: %w", err) + } groupChange.resolveConflict(group) - if groupChange.isEmptpy() { + if groupChange.isEmpty() { log.Debug().Msg("Change is empty after conflict resolution") } groupChange.Revision = group.Revision + 1 } else { - break + return 0, fmt.Errorf("unknown error encrypting and signing group change: %w", err) } } delete(cli.GroupCache.groups, gid) delete(cli.GroupCache.lastFetched, gid) delete(cli.GroupCache.activeCalls, gid) - if err != nil { - log.Err(err).Msg("couldn't patch group on server") - return 0, err + if signedGroupChange == nil { + return 0, fmt.Errorf("no signed group change returned: %w", err) } - groupChangeBytes, err := proto.Marshal(signedGroupChange) + groupChangeBytes, err := proto.Marshal(signedGroupChange.GroupChange) if err != nil { - log.Err(err).Msg("Error marshalling signed GroupChange") - return 0, err + return 0, fmt.Errorf("failed to marshal signed group change: %w", err) + } + groupContext := &signalpb.GroupContextV2{ + Revision: &groupChange.Revision, + GroupChange: groupChangeBytes, + MasterKey: masterKeyBytes[:], } - groupContext := &signalpb.GroupContextV2{Revision: &groupChange.Revision, GroupChange: groupChangeBytes, MasterKey: masterKeyBytes[:]} _, err = cli.SendGroupUpdate(ctx, group, groupContext, groupChange) if err != nil { log.Err(err).Msg("Error sending GroupChange to group members") @@ -1718,7 +1731,7 @@ func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Grou log.Err(err).Msg("Failed to get Authorization for today") return nil, err } - path := "/v1/groups/" + path := "/v2/groups/" requestBody, err := proto.Marshal(encryptedGroup) if err != nil { log.Err(err).Msg("Failed to marshal request") @@ -1751,11 +1764,7 @@ func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Grou case http.StatusBadRequest: return nil, fmt.Errorf("failed to put new group: bad request") } - group, err := cli.fetchGroupWithMasterKey(ctx, decryptedGroup.GroupMasterKey) - if err != nil { - return nil, fmt.Errorf("failed to get new group: %w", err) - } - return group, nil + return cli.parseGroupResponse(ctx, resp, decryptedGroup.GroupMasterKey) } func GenerateInviteLinkPassword() types.SerializedInviteLinkPassword { @@ -1801,7 +1810,7 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent Host: web.StorageHostname, } // highest known epoch seems to always be 5, but that may change in the future. includeLastState is always false - path := fmt.Sprintf("/v1/groups/logs/%d?maxSupportedChangeEpoch=%d&includeFirstState=%t&includeLastState=false", fromRevision, 5, includeFirstState) + path := fmt.Sprintf("/v2/groups/logs/%d?maxSupportedChangeEpoch=%d&includeFirstState=%t&includeLastState=false", fromRevision, 5, includeFirstState) response, err := web.SendHTTPRequest(ctx, http.MethodGet, path, opts) if err != nil { return nil, err From 4843285488d5b2c6b422dd3eec2da068e9b092ff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 30 Sep 2025 16:56:37 +0300 Subject: [PATCH 554/718] dependencies: update mautrix-go --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 9ead914..3366ff4 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.1 + go.mau.fi/util v0.9.2-0.20250928173307-c0b5f4ee5899 golang.org/x/crypto v0.42.0 golang.org/x/exp v0.0.0-20250911091902-df9299821621 golang.org/x/net v0.44.0 google.golang.org/protobuf v1.36.9 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.2-0.20250924172949-cf29b07f32ce + maunium.net/go/mautrix v0.25.2-0.20250930123525-329da10584ba ) require ( diff --git a/go.sum b/go.sum index 1e05243..6e3dcca 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.1 h1:A+XKHRsjKkFi2qOm4RriR1HqY2hoOXNS3WFHaC89r2Y= -go.mau.fi/util v0.9.1/go.mod h1:M0bM9SyaOWJniaHs9hxEzz91r5ql6gYq6o1q5O1SsjQ= +go.mau.fi/util v0.9.2-0.20250928173307-c0b5f4ee5899 h1:GoPWdX45WrJG/NC+/6u4km9X9UvrzqGGG78z4VlXI7o= +go.mau.fi/util v0.9.2-0.20250928173307-c0b5f4ee5899/go.mod h1:M0bM9SyaOWJniaHs9hxEzz91r5ql6gYq6o1q5O1SsjQ= 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.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= @@ -95,5 +95,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.25.2-0.20250924172949-cf29b07f32ce h1:sRBScG2xa66ERjgrX+7D//HorAhmNHwxB2Kzltg+aUg= -maunium.net/go/mautrix v0.25.2-0.20250924172949-cf29b07f32ce/go.mod h1:iSueLJ/2fBaNrsTObGqi1j0cl/loxrtAjmjay1scYD8= +maunium.net/go/mautrix v0.25.2-0.20250930123525-329da10584ba h1:IDm8LrL7PJCPqcKeGgBRTCMotz9DCRA1Ru6RWRVAfCQ= +maunium.net/go/mautrix v0.25.2-0.20250930123525-329da10584ba/go.mod h1:nDkJOInK+FbqroUE7j0M1W0PAmAV+03YZYJKWqpx1/0= From 031ef4d2ddc824b73bf3665959b3cbf4968e7c6b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 1 Oct 2025 13:12:51 +0300 Subject: [PATCH 555/718] libsignalgo: add zlib to ldflags --- pkg/libsignalgo/cflags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/libsignalgo/cflags.go b/pkg/libsignalgo/cflags.go index b86e973..12c1e0c 100644 --- a/pkg/libsignalgo/cflags.go +++ b/pkg/libsignalgo/cflags.go @@ -1,6 +1,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm +#cgo LDFLAGS: -lsignal_ffi -ldl -lm -lz */ import "C" From a0e596496ceee20282aefa2fcec2fd35d58b2c7b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 1 Oct 2025 14:49:22 +0300 Subject: [PATCH 556/718] groupinfo: add exclude from timeline flag for group resyncs --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/connector/groupinfo.go | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 3366ff4..bfd23cc 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.2-0.20250928173307-c0b5f4ee5899 + go.mau.fi/util v0.9.2-0.20251001114608-d99877b9cc10 golang.org/x/crypto v0.42.0 golang.org/x/exp v0.0.0-20250911091902-df9299821621 golang.org/x/net v0.44.0 google.golang.org/protobuf v1.36.9 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.2-0.20250930123525-329da10584ba + maunium.net/go/mautrix v0.25.2-0.20251001115535-dd778ae0cdaf ) require ( diff --git a/go.sum b/go.sum index 6e3dcca..7cc4a8a 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.2-0.20250928173307-c0b5f4ee5899 h1:GoPWdX45WrJG/NC+/6u4km9X9UvrzqGGG78z4VlXI7o= -go.mau.fi/util v0.9.2-0.20250928173307-c0b5f4ee5899/go.mod h1:M0bM9SyaOWJniaHs9hxEzz91r5ql6gYq6o1q5O1SsjQ= +go.mau.fi/util v0.9.2-0.20251001114608-d99877b9cc10 h1:EvX/di02gOriKN0xGDJuQ5mgiNdAF4LJc8moffI7Svo= +go.mau.fi/util v0.9.2-0.20251001114608-d99877b9cc10/go.mod h1:M0bM9SyaOWJniaHs9hxEzz91r5ql6gYq6o1q5O1SsjQ= 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.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= @@ -95,5 +95,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.25.2-0.20250930123525-329da10584ba h1:IDm8LrL7PJCPqcKeGgBRTCMotz9DCRA1Ru6RWRVAfCQ= -maunium.net/go/mautrix v0.25.2-0.20250930123525-329da10584ba/go.mod h1:nDkJOInK+FbqroUE7j0M1W0PAmAV+03YZYJKWqpx1/0= +maunium.net/go/mautrix v0.25.2-0.20251001115535-dd778ae0cdaf h1:prmIYgiziW4A8H2v/TliQ7fis8uTWblabxyPIeLFlNg= +maunium.net/go/mautrix v0.25.2-0.20251001115535-dd778ae0cdaf/go.mod h1:eWXuX2UAGye4AU7i/8Fv2L2Nh7L9kZtuv3R0O0n1KaM= diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 6baa3d6..56256c5 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -114,6 +114,7 @@ func (s *SignalClient) wrapGroupInfo(ctx context.Context, groupInfo *signalmeow. event.StatePowerLevels: moderatorPL, }, }, + ExcludeChangesFromTimeline: true, } applyAnnouncementsOnly(members.PowerLevels, groupInfo.AnnouncementsOnly) joinRule := event.JoinRuleInvite @@ -185,6 +186,8 @@ func (s *SignalClient) wrapGroupInfo(ctx context.Context, groupInfo *signalmeow. JoinRule: &event.JoinRulesEventContent{JoinRule: joinRule}, ExtraUpdates: bridgev2.MergeExtraUpdaters(makeRevisionUpdater(groupInfo.Revision), updatePortalSyncMeta), CanBackfill: backupChat != nil, + + ExcludeChangesFromTimeline: true, }, nil } From 89638a95ab355f3fe5f91fbf2358965f3f8a4cb9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 5 Oct 2025 00:28:12 +0300 Subject: [PATCH 557/718] signalmeow/provisioning: fix typo in capability name --- pkg/signalmeow/provisioning.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 8957018..d0aeb59 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -360,7 +360,7 @@ func continueProvisioning(ctx context.Context, ws *websocket.Conn, provisioningC var signalCapabilities = map[string]any{ "attachmentBackfill": true, - "sqpr": true, + "spqr": true, } var signalCapabilitiesBody = exerrors.Must(json.Marshal(signalCapabilities)) From 40a0d8525c3282e608fa3d1f92f13817aa101de8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 5 Oct 2025 00:47:57 +0300 Subject: [PATCH 558/718] libsignal: update to v0.83.0 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 24 ++++-------------------- pkg/libsignalgo/prekey.go | 1 - pkg/libsignalgo/prekeybundle.go | 1 - pkg/libsignalgo/version.go | 2 +- 5 files changed, 6 insertions(+), 24 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 42ff946..eb7e0e7 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 42ff946228be177c33c147359178455b411d3628 +Subproject commit eb7e0e7d18c76b29a0de706ed8932730f68b677e diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 0111718..5f503ad 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1606,7 +1606,7 @@ SignalFfiError *signal_connection_manager_clear_proxy(SignalConstPointerConnecti SignalFfiError *signal_connection_manager_destroy(SignalMutPointerConnectionManager p); -SignalFfiError *signal_connection_manager_new(SignalMutPointerConnectionManager *out, uint8_t environment, const char *user_agent, SignalMutPointerBridgedStringMap remote_config); +SignalFfiError *signal_connection_manager_new(SignalMutPointerConnectionManager *out, uint8_t environment, const char *user_agent, SignalMutPointerBridgedStringMap remote_config, uint8_t build_variant); SignalFfiError *signal_connection_manager_on_network_change(SignalConstPointerConnectionManager connection_manager); @@ -1616,7 +1616,7 @@ SignalFfiError *signal_connection_manager_set_invalid_proxy(SignalConstPointerCo SignalFfiError *signal_connection_manager_set_proxy(SignalConstPointerConnectionManager connection_manager, SignalConstPointerConnectionProxyConfig proxy); -SignalFfiError *signal_connection_manager_set_remote_config(SignalConstPointerConnectionManager connection_manager, SignalMutPointerBridgedStringMap remote_config); +SignalFfiError *signal_connection_manager_set_remote_config(SignalConstPointerConnectionManager connection_manager, SignalMutPointerBridgedStringMap remote_config, uint8_t build_variant); SignalFfiError *signal_connection_proxy_config_clone(SignalMutPointerConnectionProxyConfig *new_obj, SignalConstPointerConnectionProxyConfig obj); @@ -1648,7 +1648,7 @@ SignalFfiError *signal_create_call_link_credential_response_check_valid_contents SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); -SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store, bool use_pq_ratchet); +SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); @@ -1966,9 +1966,7 @@ SignalFfiError *signal_message_new(SignalMutPointerSignalMessage *out, uint8_t m SignalFfiError *signal_message_verify_mac(bool *out, SignalConstPointerSignalMessage msg, SignalConstPointerPublicKey sender_identity_key, SignalConstPointerPublicKey receiver_identity_key, SignalBorrowedBuffer mac_key); -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_mp4_sanitizer_sanitize(SignalMutPointerSanitizedMetadata *out, SignalConstPointerFfiInputStreamStruct input, uint64_t len); -#endif SignalFfiError *signal_online_backup_validator_add_frame(SignalMutPointerOnlineBackupValidator backup, SignalBorrowedBuffer frame); @@ -2094,7 +2092,7 @@ SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstP SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); -SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now, bool use_pq_ratchet); +SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); @@ -2242,25 +2240,15 @@ SignalFfiError *signal_registration_session_get_requested_information(SignalOwne SignalFfiError *signal_registration_session_get_verified(bool *out, SignalConstPointerRegistrationSession session); -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_clone(SignalMutPointerSanitizedMetadata *new_obj, SignalConstPointerSanitizedMetadata obj); -#endif -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_destroy(SignalMutPointerSanitizedMetadata p); -#endif -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, SignalConstPointerSanitizedMetadata sanitized); -#endif -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_get_data_offset(uint64_t *out, SignalConstPointerSanitizedMetadata sanitized); -#endif -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_sanitized_metadata_get_metadata(SignalOwnedBuffer *out, SignalConstPointerSanitizedMetadata sanitized); -#endif SignalFfiError *signal_sealed_sender_multi_recipient_encrypt(SignalOwnedBuffer *out, SignalBorrowedSliceOfConstPointerProtocolAddress recipients, SignalBorrowedSliceOfConstPointerSessionRecord recipient_sessions, SignalBorrowedBuffer excluded_recipients, SignalConstPointerUnidentifiedSenderMessageContent content, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); @@ -2466,9 +2454,7 @@ SignalFfiError *signal_sgx_client_state_established_send(SignalOwnedBuffer *out, SignalFfiError *signal_sgx_client_state_initial_request(SignalOwnedBuffer *out, SignalConstPointerSgxClientState obj); -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_signal_media_check_available(void); -#endif SignalFfiError *signal_signed_pre_key_record_clone(SignalMutPointerSignedPreKeyRecord *new_obj, SignalConstPointerSignedPreKeyRecord obj); @@ -2556,8 +2542,6 @@ SignalFfiError *signal_validating_mac_initialize(SignalMutPointerValidatingMac * SignalFfiError *signal_validating_mac_update(int32_t *out, SignalMutPointerValidatingMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); -#if defined(SIGNAL_MEDIA_SUPPORTED) SignalFfiError *signal_webp_sanitizer_sanitize(SignalConstPointerFfiSyncInputStreamStruct input); -#endif #endif /* SIGNAL_FFI_H_ */ diff --git a/pkg/libsignalgo/prekey.go b/pkg/libsignalgo/prekey.go index 7713c76..4d01f89 100644 --- a/pkg/libsignalgo/prekey.go +++ b/pkg/libsignalgo/prekey.go @@ -39,7 +39,6 @@ func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddres callbackCtx.wrapPreKeyStore(preKeyStore), callbackCtx.wrapSignedPreKeyStore(signedPreKeyStore), callbackCtx.wrapKyberPreKeyStore(kyberPreKeyStore), - false, // no pq ratchets yet ) runtime.KeepAlive(preKeyMessage) runtime.KeepAlive(fromAddress) diff --git a/pkg/libsignalgo/prekeybundle.go b/pkg/libsignalgo/prekeybundle.go index 7d8536e..4cd5547 100644 --- a/pkg/libsignalgo/prekeybundle.go +++ b/pkg/libsignalgo/prekeybundle.go @@ -37,7 +37,6 @@ func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress * callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), now, - false, // no pq ratchets yet ) runtime.KeepAlive(bundle) runtime.KeepAlive(forAddress) diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index b137e61..82b7589 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.82.0" +const Version = "v0.83.0" From 58203bf921e2d7866880e3946a62065b27e230ce Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Oct 2025 17:15:51 +0300 Subject: [PATCH 559/718] signalmeow/provisioning: update link capabilities --- pkg/signalmeow/provisioning.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index d0aeb59..8e87738 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -299,7 +299,7 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) } - linkCapabilities := []string{"backup4"} + linkCapabilities := []string{"backup4", "backup5"} if !allowBackup { linkCapabilities = []string{} } From aaa4f1f00fecc8150e961ca2536077a65f2f1503 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Oct 2025 18:41:37 +0300 Subject: [PATCH 560/718] libsignal: update to v0.84.0 --- pkg/libsignalgo/identitykey.go | 7 +++---- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 28 ++++++++++++++++++++++++---- pkg/libsignalgo/version.go | 2 +- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/pkg/libsignalgo/identitykey.go b/pkg/libsignalgo/identitykey.go index 7877d22..f35d116 100644 --- a/pkg/libsignalgo/identitykey.go +++ b/pkg/libsignalgo/identitykey.go @@ -114,14 +114,13 @@ func GenerateIdentityKeyPair() (*IdentityKeyPair, error) { } func DeserializeIdentityKeyPair(bytes []byte) (*IdentityKeyPair, error) { - var privateKey C.SignalMutPointerPrivateKey - var publicKey C.SignalMutPointerPublicKey - signalFfiError := C.signal_identitykeypair_deserialize(&privateKey, &publicKey, BytesToBuffer(bytes)) + var keys C.SignalPairOfMutPointerPublicKeyMutPointerPrivateKey + signalFfiError := C.signal_identitykeypair_deserialize(&keys, BytesToBuffer(bytes)) runtime.KeepAlive(bytes) if signalFfiError != nil { return nil, wrapError(signalFfiError) } - return &IdentityKeyPair{publicKey: wrapPublicKey(publicKey.raw), privateKey: wrapPrivateKey(privateKey.raw)}, nil + return &IdentityKeyPair{publicKey: wrapPublicKey(keys.first.raw), privateKey: wrapPrivateKey(keys.second.raw)}, nil } func NewIdentityKeyPair(publicKey *PublicKey, privateKey *PrivateKey) (*IdentityKeyPair, error) { diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index eb7e0e7..c02859f 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit eb7e0e7d18c76b29a0de706ed8932730f68b677e +Subproject commit c02859f57552477680fb7928c3c3426193040313 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 5f503ad..a516a23 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -892,6 +892,21 @@ typedef struct { */ typedef const SignalFfiError *SignalUnwindSafeArgSignalFfiError; +typedef struct { + const char *first; + uint32_t second; +} SignalPairOfc_charu32; + +typedef struct { + const char *first; + SignalOwnedBuffer second; +} SignalPairOfc_charOwnedBufferOfc_uchar; + +typedef struct { + const char *first; + bool second; +} SignalPairOfc_charbool; + typedef struct { SignalFingerprint *raw; } SignalMutPointerFingerprint; @@ -973,6 +988,11 @@ typedef struct { SignalHttpRequest *raw; } SignalMutPointerHttpRequest; +typedef struct { + SignalMutPointerPublicKey first; + SignalMutPointerPrivateKey second; +} SignalPairOfMutPointerPublicKeyMutPointerPrivateKey; + typedef struct { const SignalPrivateKey *raw; } SignalConstPointerPrivateKey; @@ -1680,15 +1700,15 @@ void signal_error_free(SignalFfiError *err); SignalFfiError *signal_error_get_address(SignalMutPointerProtocolAddress *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_invalid_protocol_address(const char **name_out, uint32_t *device_id_out, const SignalFfiError *err); +SignalFfiError *signal_error_get_invalid_protocol_address(SignalPairOfc_charu32 *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_message(const char **out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_our_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_rate_limit_challenge(const char **out_token, SignalOwnedBuffer *out_options, const SignalFfiError *err); +SignalFfiError *signal_error_get_rate_limit_challenge(SignalPairOfc_charOwnedBufferOfc_uchar *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_registration_error_not_deliverable(const char **out_reason, bool *out_permanent, const SignalFfiError *err); +SignalFfiError *signal_error_get_registration_error_not_deliverable(SignalPairOfc_charbool *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_registration_lock(uint64_t *out_time_remaining_seconds, const char **out_svr2_username, const char **out_svr2_password, const SignalFfiError *err); @@ -1834,7 +1854,7 @@ SignalFfiError *signal_http_request_new_without_body(SignalMutPointerHttpRequest SignalFfiError *signal_identitykey_verify_alternate_identity(bool *out, SignalConstPointerPublicKey public_key, SignalConstPointerPublicKey other_identity, SignalBorrowedBuffer signature); -SignalFfiError *signal_identitykeypair_deserialize(SignalMutPointerPrivateKey *private_key, SignalMutPointerPublicKey *public_key, SignalBorrowedBuffer input); +SignalFfiError *signal_identitykeypair_deserialize(SignalPairOfMutPointerPublicKeyMutPointerPrivateKey *out, SignalBorrowedBuffer input); SignalFfiError *signal_identitykeypair_serialize(SignalOwnedBuffer *out, SignalConstPointerPublicKey public_key, SignalConstPointerPrivateKey private_key); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 82b7589..b859d49 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.83.0" +const Version = "v0.84.0" From 7e0f1601d2841aaf945352d1ef9883030731ad56 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Oct 2025 18:46:50 +0300 Subject: [PATCH 561/718] changelog: update --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b548abd..23bab3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v25.10 (unreleased) + +* Switched to calendar versioning. +* Updated libsignal to v0.84.0. +* Fixed backfill creating incorrect disappearing timer change notices. + # v0.8.7 (2025-09-16) * Removed legacy provisioning API and database legacy migration. From 4889eae088d3f74031b23c8f69d67b566c2eb690 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 14 Oct 2025 00:20:43 +0300 Subject: [PATCH 562/718] chatinfo: add support for PNIs in group creation --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/chatinfo.go | 23 +++++++++++++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index bfd23cc..1dcea92 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.44.0 google.golang.org/protobuf v1.36.9 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.2-0.20251001115535-dd778ae0cdaf + maunium.net/go/mautrix v0.25.2-0.20251013212004-097813c9b29b ) require ( diff --git a/go.sum b/go.sum index 7cc4a8a..eaf756c 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.2-0.20251001115535-dd778ae0cdaf h1:prmIYgiziW4A8H2v/TliQ7fis8uTWblabxyPIeLFlNg= -maunium.net/go/mautrix v0.25.2-0.20251001115535-dd778ae0cdaf/go.mod h1:eWXuX2UAGye4AU7i/8Fv2L2Nh7L9kZtuv3R0O0n1KaM= +maunium.net/go/mautrix v0.25.2-0.20251013212004-097813c9b29b h1:cRR925ki45mwOA5lb6tjWYxV8YAG00/anpTRH2SJfvA= +maunium.net/go/mautrix v0.25.2-0.20251013212004-097813c9b29b/go.mod h1:eWXuX2UAGye4AU7i/8Fv2L2Nh7L9kZtuv3R0O0n1KaM= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 18ffb36..55dcf9e 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -240,7 +240,7 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCreateParams) (*bridgev2.CreateChatResponse, error) { group := &signalmeow.Group{ Title: ptr.Val(params.Name).Name, - Members: make([]*signalmeow.GroupMember, len(params.Participants)+1), + Members: make([]*signalmeow.GroupMember, 1, len(params.Participants)+1), Description: ptr.Val(params.Topic).Topic, AnnouncementsOnly: false, DisappearingMessagesDuration: uint32(ptr.Val(params.Disappear).Timer.Seconds()), @@ -267,14 +267,25 @@ func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCr ACI: s.Client.Store.ACI, Role: signalmeow.GroupMember_ADMINISTRATOR, } - for i, member := range params.Participants { - userID, err := signalid.ParseUserID(member) + currentTS := uint64(time.Now().UnixMilli()) + for _, member := range params.Participants { + userID, err := signalid.ParseUserIDAsServiceID(member) if err != nil { return nil, fmt.Errorf("invalid user ID %q: %w", member, err) } - group.Members[i+1] = &signalmeow.GroupMember{ - ACI: userID, - Role: signalmeow.GroupMember_DEFAULT, // TODO set proper role from power levels + if userID.Type == libsignalgo.ServiceIDTypeACI { + group.Members = append(group.Members, &signalmeow.GroupMember{ + ACI: userID.UUID, + Role: signalmeow.GroupMember_DEFAULT, // TODO set proper role from power levels + }) + } else if userID.Type == libsignalgo.ServiceIDTypePNI { + // TODO check if this is correct + group.PendingMembers = append(group.PendingMembers, &signalmeow.PendingMember{ + ServiceID: userID, + Role: signalmeow.GroupMember_DEFAULT, + AddedByUserID: s.Client.Store.ACI, + Timestamp: currentTS, + }) } } _, err := signalmeow.PrepareGroupCreation(group) From 422291c80452ddbbf6760db66977220797b078e5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 16 Oct 2025 12:05:32 +0200 Subject: [PATCH 563/718] Bump version to v25.10 --- CHANGELOG.md | 2 +- cmd/mautrix-signal/main.go | 3 ++- go.mod | 18 +++++++++--------- go.sum | 36 ++++++++++++++++++------------------ 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23bab3b..9135702 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v25.10 (unreleased) +# v25.10 * Switched to calendar versioning. * Updated libsignal to v0.84.0. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 01e3793..73a2921 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -34,7 +34,8 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "0.8.7", + Version: "25.10", + SemCalVer: true, Connector: &connector.SignalConnector{}, } diff --git a/go.mod b/go.mod index 1dcea92..d57b356 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.24.0 -toolchain go1.25.1 +toolchain go1.25.3 require ( github.com/coder/websocket v1.8.14 @@ -12,13 +12,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.2-0.20251001114608-d99877b9cc10 - golang.org/x/crypto v0.42.0 - golang.org/x/exp v0.0.0-20250911091902-df9299821621 - golang.org/x/net v0.44.0 - google.golang.org/protobuf v1.36.9 + go.mau.fi/util v0.9.2 + golang.org/x/crypto v0.43.0 + golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b + golang.org/x/net v0.46.0 + google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.2-0.20251013212004-097813c9b29b + maunium.net/go/mautrix v0.25.2 ) require ( @@ -41,8 +41,8 @@ require ( github.com/yuin/goldmark v1.7.13 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.36.0 // indirect - golang.org/x/text v0.29.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 // 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 diff --git a/go.sum b/go.sum index eaf756c..da6cc5e 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -65,27 +65,27 @@ 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.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.2-0.20251001114608-d99877b9cc10 h1:EvX/di02gOriKN0xGDJuQ5mgiNdAF4LJc8moffI7Svo= -go.mau.fi/util v0.9.2-0.20251001114608-d99877b9cc10/go.mod h1:M0bM9SyaOWJniaHs9hxEzz91r5ql6gYq6o1q5O1SsjQ= +go.mau.fi/util v0.9.2 h1:+S4Z03iCsGqU2WY8X2gySFsFjaLlUHFRDVCYvVwynKM= +go.mau.fi/util v0.9.2/go.mod h1:055elBBCJSdhRsmub7ci9hXZPgGr1U6dYg44cSgRgoU= 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.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= -golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= -golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= -golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA= +golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/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= @@ -95,5 +95,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.25.2-0.20251013212004-097813c9b29b h1:cRR925ki45mwOA5lb6tjWYxV8YAG00/anpTRH2SJfvA= -maunium.net/go/mautrix v0.25.2-0.20251013212004-097813c9b29b/go.mod h1:eWXuX2UAGye4AU7i/8Fv2L2Nh7L9kZtuv3R0O0n1KaM= +maunium.net/go/mautrix v0.25.2 h1:CUG23zp754yGOTMh9Q4mVSENS9FyweE/G+6ZsPDMCUU= +maunium.net/go/mautrix v0.25.2/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= From 11e0e970675a5ead29047518f1fa038365476bfc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 20 Oct 2025 11:22:33 +0300 Subject: [PATCH 564/718] client: use transient disconnect for all network errors --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/client.go | 17 ++++++++--------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index d57b356..0613f9b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.46.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.2 + maunium.net/go/mautrix v0.25.3-0.20251020084845-56b182f85d04 ) require ( diff --git a/go.sum b/go.sum index da6cc5e..560e1b9 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.2 h1:CUG23zp754yGOTMh9Q4mVSENS9FyweE/G+6ZsPDMCUU= -maunium.net/go/mautrix v0.25.2/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.25.3-0.20251020084845-56b182f85d04 h1:OPcp3Bh6PyF282Siq7/d84XZHaNSm74N9VINAeYEQys= +maunium.net/go/mautrix v0.25.3-0.20251020084845-56b182f85d04/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 27cea14..8da1723 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -189,7 +189,7 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec case signalmeow.SignalConnectionEventError: s.UserLogin.Log.Debug().Msg("Sending UnknownError BridgeState") - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) case signalmeow.SignalConnectionCleanShutdown: if s.Client.IsLoggedIn() { @@ -303,15 +303,14 @@ func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bo ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") - if retryCount < 6 { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) - retryInSeconds := 2 << retryCount - zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") - time.Sleep(time.Duration(retryInSeconds) * time.Second) - s.tryConnect(ctx, retryCount+1, doSync) - } else { - s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) + retryInSeconds := 2 << retryCount + if retryInSeconds > 150 { + retryInSeconds = 150 } + zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") + time.Sleep(time.Duration(retryInSeconds) * time.Second) + s.tryConnect(ctx, retryCount+1, doSync) } else { go s.bridgeStateLoop(ch) if doSync { From 08d70602e195719e6a5d9c8943d13d56c4d3c21b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 20 Oct 2025 11:52:14 +0300 Subject: [PATCH 565/718] signalmeow/web: split non-retrying errors into different type --- pkg/connector/client.go | 10 +++++++--- pkg/signalmeow/receiving.go | 11 +++++++++++ pkg/signalmeow/web/signalwebsocket.go | 4 +++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 8da1723..0ff578f 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -188,9 +188,13 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } case signalmeow.SignalConnectionEventError: - s.UserLogin.Log.Debug().Msg("Sending UnknownError BridgeState") + s.UserLogin.Log.Debug().Msg("Sending TransientDisconnect BridgeState") s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateTransientDisconnect, Error: "unknown-websocket-error", Message: err.Error()}) + case signalmeow.SignalConnectionEventFatalError: + s.UserLogin.Log.Debug().Msg("Sending UnknownError BridgeState") + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateUnknownError, Error: "unknown-websocket-error", Message: err.Error()}) + case signalmeow.SignalConnectionCleanShutdown: if s.Client.IsLoggedIn() { s.UserLogin.Log.Debug().Msg("Clean Shutdown - sending no BridgeState") @@ -233,7 +237,7 @@ func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.Connec case web.SignalWebsocketConnectionEventLoggedOut: log.Err(status.Err).Msg("Authed websocket logged out") return fmt.Errorf("authed websocket logged out: %w", status.Err) - case web.SignalWebsocketConnectionEventError: + case web.SignalWebsocketConnectionEventError, web.SignalWebsocketConnectionEventFatalError: log.Err(status.Err).Msg("Authed websocket error") return fmt.Errorf("authed websocket errored: %w", status.Err) case web.SignalWebsocketConnectionEventCleanShutdown: @@ -247,7 +251,7 @@ func (s *SignalClient) ConnectBackground(ctx context.Context, _ *bridgev2.Connec log.Err(status.Err).Msg("Unauthed websocket disconnected") case web.SignalWebsocketConnectionEventLoggedOut: log.Err(status.Err).Msg("Unauthed websocket logged out") - case web.SignalWebsocketConnectionEventError: + case web.SignalWebsocketConnectionEventError, web.SignalWebsocketConnectionEventFatalError: log.Err(status.Err).Msg("Unauthed websocket error") case web.SignalWebsocketConnectionEventCleanShutdown: log.Info().Msg("Unauthed websocket clean shutdown") diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 6c97a69..d630386 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -46,6 +46,7 @@ const ( SignalConnectionEventDisconnected SignalConnectionEventLoggedOut SignalConnectionEventError + SignalConnectionEventFatalError SignalConnectionCleanShutdown ) @@ -56,6 +57,7 @@ var signalConnectionEventNames = map[SignalConnectionEvent]string{ SignalConnectionEventDisconnected: "SignalConnectionEventDisconnected", SignalConnectionEventLoggedOut: "SignalConnectionEventLoggedOut", SignalConnectionEventError: "SignalConnectionEventError", + SignalConnectionEventFatalError: "SignalConnectionEventFatalError", SignalConnectionCleanShutdown: "SignalConnectionCleanShutdown", } @@ -164,6 +166,8 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection //StopReceiveLoops(d) case web.SignalWebsocketConnectionEventError: log.Err(status.Err).Msg("Authed websocket error") + case web.SignalWebsocketConnectionEventFatalError: + log.Err(status.Err).Msg("Authed websocket fatal error") case web.SignalWebsocketConnectionEventCleanShutdown: log.Info().Msg("Authed websocket clean shutdown") } @@ -192,6 +196,8 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection log.Err(status.Err).Msg("Unauthed websocket logged out ** THIS SHOULD BE IMPOSSIBLE **") case web.SignalWebsocketConnectionEventError: log.Err(status.Err).Msg("Unauthed websocket error") + case web.SignalWebsocketConnectionEventFatalError: + log.Err(status.Err).Msg("Unauthed websocket fatal error") case web.SignalWebsocketConnectionEventCleanShutdown: log.Info().Msg("Unauthed websocket clean shutdown") } @@ -221,6 +227,11 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection Event: SignalConnectionEventError, Err: currentStatus.Err, } + } else if currentStatus.Event == web.SignalWebsocketConnectionEventFatalError { + statusToSend = SignalConnectionStatus{ + Event: SignalConnectionEventFatalError, + Err: currentStatus.Err, + } } else if currentStatus.Event == web.SignalWebsocketConnectionEventCleanShutdown { statusToSend = SignalConnectionStatus{ Event: SignalConnectionCleanShutdown, diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index c4572d6..ca09208 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -73,6 +73,7 @@ const ( SignalWebsocketConnectionEventDisconnected SignalWebsocketConnectionEventLoggedOut SignalWebsocketConnectionEventError + SignalWebsocketConnectionEventFatalError SignalWebsocketConnectionEventCleanShutdown ) @@ -83,6 +84,7 @@ var signalWebsocketConnectionEventNames = map[SignalWebsocketConnectionEvent]str SignalWebsocketConnectionEventDisconnected: "SignalWebsocketConnectionEventDisconnected", SignalWebsocketConnectionEventLoggedOut: "SignalWebsocketConnectionEventLoggedOut", SignalWebsocketConnectionEventError: "SignalWebsocketConnectionEventError", + SignalWebsocketConnectionEventFatalError: "SignalWebsocketConnectionEventFatalError", SignalWebsocketConnectionEventCleanShutdown: "SignalWebsocketConnectionEventCleanShutdown", } @@ -275,7 +277,7 @@ func (s *SignalWebsocket) connectLoop( return // NOT RETRYING, KILLING THE CONNECTION LOOP } else if resp.StatusCode > 0 && resp.StatusCode < 500 { // Unexpected status code - s.pushStatus(ctx, SignalWebsocketConnectionEventError, fmt.Errorf("unexpected status opening websocket: %v", resp.Status)) + s.pushStatus(ctx, SignalWebsocketConnectionEventFatalError, fmt.Errorf("unexpected status opening websocket: %v", resp.Status)) return // NOT RETRYING, KILLING THE CONNECTION LOOP } else { // Something is very wrong From 865642be07e1c987a7e2e7ce608c5e0d7179ac11 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 20 Oct 2025 12:36:42 +0300 Subject: [PATCH 566/718] docker: use gitlab dependency proxy for CI builds --- Dockerfile.ci | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile.ci b/Dockerfile.ci index dc554ab..7d34502 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,4 +1,6 @@ -FROM alpine:3.22 +ARG DOCKER_HUB="docker.io" + +FROM ${DOCKER_HUB}/alpine:3.22 ENV UID=1337 \ GID=1337 From d63cf0106bc47a9ff2a6202b782481a14dce3999 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 22 Oct 2025 21:49:59 +0300 Subject: [PATCH 567/718] all: add support for PNI ghosts to bridge invites/bans (#612) --- go.mod | 2 +- go.sum | 4 +- pkg/connector/chatinfo.go | 75 ++++++++---- pkg/connector/groupinfo.go | 219 ++++++++++++++++------------------ pkg/connector/handlematrix.go | 75 ++++++++---- pkg/connector/id.go | 19 +++ pkg/signalid/ids.go | 33 ++++- pkg/signalmeow/groups.go | 15 +-- 8 files changed, 261 insertions(+), 181 deletions(-) diff --git a/go.mod b/go.mod index 0613f9b..2fabdcc 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.46.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.3-0.20251020084845-56b182f85d04 + maunium.net/go/mautrix v0.25.3-0.20251022182546-33d8d658fe98 ) require ( diff --git a/go.sum b/go.sum index 560e1b9..b7850bf 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.3-0.20251020084845-56b182f85d04 h1:OPcp3Bh6PyF282Siq7/d84XZHaNSm74N9VINAeYEQys= -maunium.net/go/mautrix v0.25.3-0.20251020084845-56b182f85d04/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.25.3-0.20251022182546-33d8d658fe98 h1:0cTTVYsfTyXaoqFYz4MoHfMv+zps+Gh3dbQtDn4mtHo= +maunium.net/go/mautrix v0.25.3-0.20251022182546-33d8d658fe98/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 55dcf9e..88cf3e2 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -45,13 +45,16 @@ var ( _ bridgev2.IdentifierResolvingNetworkAPI = (*SignalClient)(nil) _ bridgev2.GroupCreatingNetworkAPI = (*SignalClient)(nil) _ bridgev2.ContactListingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.GhostDMCreatingNetworkAPI = (*SignalClient)(nil) ) +var _ bridgev2.IdentifierValidatingNetwork = (*SignalConnector)(nil) + const PrivateChatTopic = "Signal private chat" const NoteToSelfName = "Signal Note to Self" func (s *SignalClient) GetUserInfoWithRefreshAfter(ctx context.Context, ghost *bridgev2.Ghost, refreshAfter time.Duration) (*bridgev2.UserInfo, error) { - userID, err := signalid.ParseUserID(ghost.ID) + userID, err := signalid.ParseUserIDAsServiceID(ghost.ID) if err != nil { return nil, err } @@ -59,12 +62,17 @@ func (s *SignalClient) GetUserInfoWithRefreshAfter(ctx context.Context, ghost *b // Don't do unnecessary fetches in background mode return nil, nil } - contact, err := s.Client.ContactByACIWithRefreshAfter(ctx, userID, refreshAfter) + var contact *types.Recipient + if userID.Type == libsignalgo.ServiceIDTypePNI { + contact, err = s.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, uuid.Nil, userID.UUID, nil) + } else { + contact, err = s.Client.ContactByACIWithRefreshAfter(ctx, userID.UUID, refreshAfter) + } if err != nil { return nil, err } meta := ghost.Metadata.(*signalid.GhostMetadata) - if !s.Main.Config.UseOutdatedProfiles && meta.ProfileFetchedAt.After(contact.Profile.FetchedAt) { + if userID.Type != libsignalgo.ServiceIDTypePNI && (!s.Main.Config.UseOutdatedProfiles && meta.ProfileFetchedAt.After(contact.Profile.FetchedAt)) { return nil, nil } return s.contactToUserInfo(ctx, contact) @@ -157,18 +165,41 @@ func (s *SignalClient) contactToUserInfo(ctx context.Context, contact *types.Rec return ui, nil } -var _ bridgev2.IdentifierValidatingNetwork = (*SignalConnector)(nil) - func (s *SignalConnector) ValidateUserID(id networkid.UserID) bool { _, err := signalid.ParseUserIDAsServiceID(id) return err == nil } -func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { +func (s *SignalClient) CreateChatWithGhost(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.CreateChatResponse, error) { + parsedID, err := signalid.ParseUserIDAsServiceID(ghost.ID) + if err != nil { + return nil, err + } + resp, err := s.ResolveIdentifier(ctx, parsedID.String(), true) + if err != nil { + return nil, err + } else if resp == nil { + return nil, nil + } + resultID, err := signalid.ParseUserIDAsServiceID(resp.UserID) + if err != nil { + return nil, fmt.Errorf("failed to parse result user ID: %w", err) + } + if parsedID.Type == libsignalgo.ServiceIDTypePNI { + if resultID.Type == libsignalgo.ServiceIDTypeACI && !resultID.IsEmpty() { + resp.Chat.DMRedirectedTo = resp.UserID + } else { + resp.Chat.DMRedirectedTo = bridgev2.SpecialValueDMRedirectedToBot + } + } + return resp.Chat, nil +} + +func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, _ bool) (*bridgev2.ResolveIdentifierResponse, error) { var aci, pni uuid.UUID var e164Number uint64 var recipient *types.Recipient - serviceID, err := libsignalgo.ServiceIDFromString(number) + serviceID, err := signalid.ParseUserIDAsServiceID(networkid.UserID(number)) if err != nil { number, err = bridgev2.CleanPhoneNumber(number) if err != nil { @@ -216,25 +247,23 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, cre return nil, fmt.Errorf("failed to convert contact: %w", err) } - // createChat is a no-op: chats don't need to be created, and we always return chat info + var userID networkid.UserID if aci != uuid.Nil { - ghost, err := s.Main.Bridge.GetGhostByID(ctx, signalid.MakeUserID(aci)) - if err != nil { - return nil, fmt.Errorf("failed to get ghost: %w", err) - } - return &bridgev2.ResolveIdentifierResponse{ - UserID: signalid.MakeUserID(aci), - UserInfo: userInfo, - Ghost: ghost, - Chat: s.makeCreateDMResponse(ctx, recipient, nil), - }, nil + userID = signalid.MakeUserID(aci) } else { - return &bridgev2.ResolveIdentifierResponse{ - UserID: signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)), - UserInfo: userInfo, - Chat: s.makeCreateDMResponse(ctx, recipient, nil), - }, nil + userID = signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(pni)) } + // createChat is a no-op: chats don't need to be created, and we always return chat info + resp := &bridgev2.ResolveIdentifierResponse{ + UserID: userID, + UserInfo: userInfo, + Chat: s.makeCreateDMResponse(ctx, recipient, nil), + } + resp.Ghost, err = s.Main.Bridge.GetGhostByID(ctx, resp.UserID) + if err != nil { + return nil, fmt.Errorf("failed to get ghost: %w", err) + } + return resp, nil } func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCreateParams) (*bridgev2.CreateChatResponse, error) { diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index 56256c5..a025fa4 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -123,43 +123,30 @@ func (s *SignalClient) wrapGroupInfo(ctx context.Context, groupInfo *signalmeow. applyMembersAccess(members.PowerLevels, groupInfo.AccessControl.Members) joinRule = inviteLinkToJoinRule(groupInfo.AccessControl.AddFromInviteLink) } - for _, member := range groupInfo.Members { - evtSender := s.makeEventSender(member.ACI) - members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ - EventSender: evtSender, - PowerLevel: roleToPL(member.Role), - Membership: event.MembershipJoin, - } + for _, member := range groupInfo.RequestingMembers { + members.MemberMap.Set(bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipKnock, + }) } for _, member := range groupInfo.PendingMembers { - aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) - if aci == nil { - continue - } - evtSender := s.makeEventSender(*aci) - members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ - EventSender: evtSender, - PowerLevel: roleToPL(member.Role), - Membership: event.MembershipInvite, - } + s.addChatMemberWithACIQuery(ctx, members.MemberMap, member.ServiceID, bridgev2.ChatMember{ + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipInvite, + MemberSender: s.makeEventSender(member.AddedByUserID), + }) } - for _, member := range groupInfo.RequestingMembers { - evtSender := s.makeEventSender(member.ACI) - members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ - EventSender: evtSender, - Membership: event.MembershipKnock, - } + for _, member := range groupInfo.Members { + members.MemberMap.Set(bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipJoin, + }) } for _, member := range groupInfo.BannedMembers { - aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) - if aci == nil { - continue - } - evtSender := s.makeEventSender(*aci) - members.MemberMap[evtSender.Sender] = bridgev2.ChatMember{ - EventSender: evtSender, - Membership: event.MembershipBan, - } + s.addChatMemberWithACIQuery(ctx, members.MemberMap, member.ServiceID, bridgev2.ChatMember{ + Membership: event.MembershipBan, + }) } if backupChat == nil { var err error @@ -191,6 +178,10 @@ func (s *SignalClient) wrapGroupInfo(ctx context.Context, groupInfo *signalmeow. }, nil } +func addMemberToMap(mc map[networkid.UserID]bridgev2.ChatMember, member bridgev2.ChatMember) { + mc[member.EventSender.Sender] = member +} + func updatePortalSyncMeta(ctx context.Context, portal *bridgev2.Portal) bool { meta := portal.Metadata.(*signalid.PortalMetadata) meta.LastSync = jsontime.UnixNow() @@ -286,131 +277,127 @@ func (s *SignalClient) groupChangeToChatInfoChange(ctx context.Context, groupID JoinRule: inviteLinkToJoinRule(*groupChange.ModifyAddFromInviteLinkAccess), } } - var mc []bridgev2.ChatMember - for _, member := range groupChange.AddMembers { - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ACI), - PowerLevel: roleToPL(member.Role), - Membership: event.MembershipJoin, - }) - } - for _, member := range groupChange.ModifyMemberRoles { - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ACI), - PowerLevel: roleToPL(member.Role), - Membership: event.MembershipJoin, - }) - } - bannedMembers := make(map[libsignalgo.ServiceID]bool) - for _, member := range groupChange.AddBannedMembers { - aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) - if aci == nil { - continue - } - bannedMembers[member.ServiceID] = true - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), - Membership: event.MembershipBan, - }) - } - for _, memberACI := range groupChange.DeleteMembers { - if bannedMembers[libsignalgo.NewACIServiceID(*memberACI)] { - continue - } - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*memberACI), - Membership: event.MembershipLeave, - PrevMembership: event.MembershipJoin, - }) - } + mc := make(bridgev2.ChatMemberMap) for _, member := range groupChange.AddPendingMembers { - aci := s.maybeResolvePNItoACI(ctx, &member.ServiceID) - if aci == nil { - continue - } - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), - PowerLevel: roleToPL(member.Role), - Membership: event.MembershipInvite, - }) - } - for _, memberServiceID := range groupChange.DeletePendingMembers { - if bannedMembers[*memberServiceID] { - continue - } - aci := s.maybeResolvePNItoACI(ctx, memberServiceID) - if aci == nil { - continue - } - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), - Membership: event.MembershipLeave, - PrevMembership: event.MembershipInvite, + s.addChatMemberWithACIQuery(ctx, mc, member.ServiceID, bridgev2.ChatMember{ + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipInvite, + PrevMembership: event.MembershipLeave, + MemberSender: s.makeEventSender(member.AddedByUserID), }) } for _, member := range groupChange.AddRequestingMembers { - mc = append(mc, bridgev2.ChatMember{ + mc.Set(bridgev2.ChatMember{ EventSender: s.makeEventSender(member.ACI), Membership: event.MembershipKnock, }) } + for _, memberServiceID := range groupChange.DeletePendingMembers { + s.addChatMemberWithACIQuery(ctx, mc, *memberServiceID, bridgev2.ChatMember{ + Membership: event.MembershipLeave, + PrevMembership: event.MembershipInvite, + }) + } for _, memberACI := range groupChange.DeleteRequestingMembers { - if bannedMembers[libsignalgo.NewACIServiceID(*memberACI)] { - continue - } - mc = append(mc, bridgev2.ChatMember{ + mc.Set(bridgev2.ChatMember{ EventSender: s.makeEventSender(*memberACI), Membership: event.MembershipLeave, PrevMembership: event.MembershipKnock, }) } + for _, memberACI := range groupChange.DeleteMembers { + mc.Set(bridgev2.ChatMember{ + EventSender: s.makeEventSender(*memberACI), + Membership: event.MembershipLeave, + PrevMembership: event.MembershipJoin, + }) + } for _, memberServiceID := range groupChange.DeleteBannedMembers { - aci := s.maybeResolvePNItoACI(ctx, memberServiceID) - if aci == nil { - continue - } - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(*aci), + s.addChatMemberWithACIQuery(ctx, mc, *memberServiceID, bridgev2.ChatMember{ Membership: event.MembershipLeave, PrevMembership: event.MembershipBan, }) } + for _, member := range groupChange.AddBannedMembers { + s.addChatMemberWithACIQuery(ctx, mc, member.ServiceID, bridgev2.ChatMember{ + Membership: event.MembershipBan, + }) + } for _, member := range groupChange.PromotePendingMembers { - mc = append(mc, bridgev2.ChatMember{ + mc.Set(bridgev2.ChatMember{ EventSender: s.makeEventSender(member.ACI), Membership: event.MembershipJoin, PrevMembership: event.MembershipInvite, }) } for _, member := range groupChange.PromotePendingPniAciMembers { - mc = append(mc, bridgev2.ChatMember{ - EventSender: s.makeEventSender(member.ACI), - Membership: event.MembershipJoin, + mc.Set(bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + Membership: event.MembershipJoin, + }) + mc.Set(bridgev2.ChatMember{ + EventSender: s.makePNIEventSender(member.PNI), + Membership: event.MembershipLeave, PrevMembership: event.MembershipInvite, + MemberEventExtra: map[string]any{ + "com.beeper.exclude_from_timeline": true, + }, }) } for _, member := range groupChange.PromoteRequestingMembers { - mc = append(mc, bridgev2.ChatMember{ + mc.Set(bridgev2.ChatMember{ EventSender: s.makeEventSender(member.ACI), Membership: event.MembershipJoin, PrevMembership: event.MembershipKnock, }) } + for _, member := range groupChange.AddMembers { + mc.Set(bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipJoin, + }) + } + for _, member := range groupChange.ModifyMemberRoles { + mc.Set(bridgev2.ChatMember{ + EventSender: s.makeEventSender(member.ACI), + PowerLevel: roleToPL(member.Role), + Membership: event.MembershipJoin, + }) + } if len(mc) > 0 || pls != nil { - ic.MemberChanges = &bridgev2.ChatMemberList{Members: mc, PowerLevels: pls} + ic.MemberChanges = &bridgev2.ChatMemberList{MemberMap: mc, PowerLevels: pls} } return ic, nil } -func (s *SignalClient) maybeResolvePNItoACI(ctx context.Context, serviceID *libsignalgo.ServiceID) *uuid.UUID { - if serviceID.Type == libsignalgo.ServiceIDTypeACI { - return &serviceID.UUID +func (s *SignalClient) addChatMemberWithACIQuery( + ctx context.Context, mc bridgev2.ChatMemberMap, serviceID libsignalgo.ServiceID, member bridgev2.ChatMember, +) { + member.EventSender = s.makeEventSenderFromServiceID(serviceID) + mc.Set(member) + if aci := s.tryResolvePNItoLoggedInACI(ctx, serviceID); aci != nil { + member.EventSender = s.makeEventSender(*aci) + mc.Add(member) } - device, err := s.Client.Store.DeviceStore.DeviceByPNI(ctx, serviceID.UUID) - if err != nil || device == nil { +} + +func (s *SignalClient) tryResolvePNItoLoggedInACI(ctx context.Context, serviceID libsignalgo.ServiceID) *uuid.UUID { + if serviceID.Type != libsignalgo.ServiceIDTypePNI { return nil + } else if serviceID.UUID == s.Client.Store.PNI { + return &s.Client.Store.ACI + } else if s.Main.Bridge.Config.SplitPortals { + // When split portals is enabled, we don't care about anyone else's logins + return nil + } else if device, err := s.Client.Store.DeviceStore.DeviceByPNI(ctx, serviceID.UUID); err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get ACI for PNI") + return nil + } else if device == nil { + return nil + } else { + return &device.ACI } - return &device.ACI } func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal, fromRevision, toRevision uint32, ts uint64) { @@ -443,8 +430,8 @@ func (s *SignalClient) catchUpGroup(ctx context.Context, portal *bridgev2.Portal chatInfoChange, err := s.groupChangeToChatInfoChange(ctx, types.GroupIdentifier(portal.ID), gc.GroupChange.Revision, gc.GroupChange) if err != nil { log.Err(err).Msg("Failed to convert group info") - } else if gc.GroupChange.SourceServiceID.Type == libsignalgo.ServiceIDTypeACI { - portal.ProcessChatInfoChange(ctx, s.makeEventSender(gc.GroupChange.SourceServiceID.UUID), s.UserLogin, chatInfoChange, time.UnixMilli(int64(ts))) + } else { + portal.ProcessChatInfoChange(ctx, s.makeEventSenderFromServiceID(gc.GroupChange.SourceServiceID), s.UserLogin, chatInfoChange, time.UnixMilli(int64(ts))) } if gc.GroupChange.Revision == toRevision { break diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 1a10773..dec5341 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -387,7 +387,7 @@ func (s *SignalClient) HandleMatrixRoomTopic(ctx context.Context, msg *bridgev2. func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2.MatrixMembershipChange) (bool, error) { var targetIntent bridgev2.MatrixAPI - var targetSignalID uuid.UUID + var targetSignalID libsignalgo.ServiceID var err error if msg.Portal.RoomType == database.RoomTypeDM { //TODO: this probably needs to revert some changes and clean up the portal on leaves @@ -434,21 +434,35 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 } switch msg.Type { case bridgev2.AcceptInvite: + if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { + return false, fmt.Errorf("can't accept invite for non-ACI service ID") + } gc.PromotePendingMembers = []*signalmeow.PromotePendingMember{{ - ACI: targetSignalID, + ACI: targetSignalID.UUID, }} case bridgev2.RevokeInvite, bridgev2.RejectInvite: - deletePendingMember := libsignalgo.NewACIServiceID(targetSignalID) - gc.DeletePendingMembers = []*libsignalgo.ServiceID{&deletePendingMember} + gc.DeletePendingMembers = []*libsignalgo.ServiceID{&targetSignalID} case bridgev2.Leave, bridgev2.Kick: - gc.DeleteMembers = []*uuid.UUID{&targetSignalID} + if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { + return false, fmt.Errorf("can't kick non-ACI service ID") + } + gc.DeleteMembers = []*uuid.UUID{&targetSignalID.UUID} case bridgev2.Invite: - gc.AddMembers = []*signalmeow.AddMember{{ - GroupMember: signalmeow.GroupMember{ - ACI: targetSignalID, - Role: role, - }, - }} + if targetSignalID.Type == libsignalgo.ServiceIDTypeACI { + gc.AddMembers = []*signalmeow.AddMember{{ + GroupMember: signalmeow.GroupMember{ + ACI: targetSignalID.UUID, + Role: role, + }, + }} + } else { + gc.AddPendingMembers = []*signalmeow.PendingMember{{ + ServiceID: targetSignalID, + Role: role, + AddedByUserID: s.Client.Store.ACI, + Timestamp: uint64(msg.Event.Timestamp), + }} + } // TODO: joining and knocking requires a way to obtain the invite link // because the joining/knocking member doesn't have the GroupMasterKey yet // case bridgev2.Join: @@ -465,29 +479,39 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 // Timestamp: uint64(time.Now().UnixMilli()), // }} case bridgev2.AcceptKnock: + if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { + return false, fmt.Errorf("can't accept knock from non-ACI service ID") + } gc.PromoteRequestingMembers = []*signalmeow.RoleMember{{ - ACI: targetSignalID, + ACI: targetSignalID.UUID, Role: role, }} case bridgev2.RetractKnock, bridgev2.RejectKnock: - gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID} + if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { + return false, fmt.Errorf("can't reject knock from non-ACI service ID") + } + gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID.UUID} case bridgev2.BanKnocked, bridgev2.BanInvited, bridgev2.BanJoined, bridgev2.BanLeft: gc.AddBannedMembers = []*signalmeow.BannedMember{{ - ServiceID: libsignalgo.NewACIServiceID(targetSignalID), + ServiceID: targetSignalID, Timestamp: uint64(time.Now().UnixMilli()), }} switch msg.Type { case bridgev2.BanJoined: - gc.DeleteMembers = []*uuid.UUID{&targetSignalID} + if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { + return false, fmt.Errorf("can't ban joined non-ACI service ID") + } + gc.DeleteMembers = []*uuid.UUID{&targetSignalID.UUID} case bridgev2.BanInvited: - deletePendingMember := libsignalgo.NewACIServiceID(targetSignalID) - gc.DeletePendingMembers = []*libsignalgo.ServiceID{&deletePendingMember} + gc.DeletePendingMembers = []*libsignalgo.ServiceID{&targetSignalID} case bridgev2.BanKnocked: - gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID} + if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { + return false, fmt.Errorf("can't ban knocked non-ACI service ID") + } + gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID.UUID} } case bridgev2.Unban: - unbanUser := libsignalgo.NewACIServiceID(targetSignalID) - gc.DeleteBannedMembers = []*libsignalgo.ServiceID{&unbanUser} + gc.DeleteBannedMembers = []*libsignalgo.ServiceID{&targetSignalID} default: log.Debug().Msg("unsupported membership change") return false, nil @@ -501,7 +525,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 if err != nil { return false, err } - if msg.Type == bridgev2.Invite { + if msg.Type == bridgev2.Invite && targetSignalID.Type != libsignalgo.ServiceIDTypePNI { err = targetIntent.EnsureJoined(ctx, msg.Portal.MXID) if err != nil { return false, err @@ -540,18 +564,17 @@ func (s *SignalClient) HandleMatrixPowerLevels(ctx context.Context, msg *bridgev if msg.Portal.RoomType == database.RoomTypeDM { return false, nil } - log := zerolog.Ctx(ctx) gc := &signalmeow.GroupChange{} for _, plc := range msg.Users { if !hasAdminChanged(&plc.SinglePowerLevelChange) { continue } - aci, err := signalid.ParseGhostOrUserLoginID(plc.Target) - if err != nil { - log.Err(err).Msg("Couldn't parse user id") + serviceID, err := signalid.ParseGhostOrUserLoginID(plc.Target) + if err != nil || serviceID.Type != libsignalgo.ServiceIDTypeACI { + continue } gc.ModifyMemberRoles = append(gc.ModifyMemberRoles, &signalmeow.RoleMember{ - ACI: aci, + ACI: serviceID.UUID, Role: plToRole(plc.NewLevel), }) } diff --git a/pkg/connector/id.go b/pkg/connector/id.go index 16cb7dc..4c3f123 100644 --- a/pkg/connector/id.go +++ b/pkg/connector/id.go @@ -17,6 +17,8 @@ package connector import ( + "fmt" + "github.com/google/uuid" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" @@ -48,3 +50,20 @@ func (s *SignalClient) makeEventSender(sender uuid.UUID) bridgev2.EventSender { Sender: signalid.MakeUserID(sender), } } + +func (s *SignalClient) makePNIEventSender(sender uuid.UUID) bridgev2.EventSender { + return bridgev2.EventSender{ + Sender: signalid.MakeUserIDFromServiceID(libsignalgo.NewPNIServiceID(sender)), + } +} + +func (s *SignalClient) makeEventSenderFromServiceID(serviceID libsignalgo.ServiceID) bridgev2.EventSender { + switch serviceID.Type { + case libsignalgo.ServiceIDTypeACI: + return s.makeEventSender(serviceID.UUID) + case libsignalgo.ServiceIDTypePNI: + return s.makePNIEventSender(serviceID.UUID) + default: + panic(fmt.Errorf("invalid service ID type %d", serviceID.Type)) + } +} diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go index 79ba90f..daa9200 100644 --- a/pkg/signalid/ids.go +++ b/pkg/signalid/ids.go @@ -48,19 +48,33 @@ func ParseUserLoginID(userLoginID networkid.UserLoginID) (uuid.UUID, error) { return userID, nil } -func ParseGhostOrUserLoginID(ghostOrUserLogin bridgev2.GhostOrUserLogin) (uuid.UUID, error) { +func toServiceID(id uuid.UUID, err error) (libsignalgo.ServiceID, error) { + if err != nil { + return libsignalgo.ServiceID{}, err + } + return libsignalgo.NewACIServiceID(id), nil +} + +func ParseGhostOrUserLoginID(ghostOrUserLogin bridgev2.GhostOrUserLogin) (libsignalgo.ServiceID, error) { switch ghostOrUserLogin := ghostOrUserLogin.(type) { case *bridgev2.UserLogin: - return ParseUserLoginID(ghostOrUserLogin.ID) + return toServiceID(ParseUserLoginID(ghostOrUserLogin.ID)) case *bridgev2.Ghost: - return ParseUserID(ghostOrUserLogin.ID) + return ParseUserIDAsServiceID(ghostOrUserLogin.ID) default: - return uuid.Nil, fmt.Errorf("cannot parse ID: unknown type: %T", ghostOrUserLogin) + return libsignalgo.ServiceID{}, fmt.Errorf("cannot parse ID: unknown type: %T", ghostOrUserLogin) } } +const pniUserIDPrefix = "pni_" +const pniServiceIDPrefix = "PNI:" + func ParseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { - return libsignalgo.ServiceIDFromString(string(userID)) + userIDStr := string(userID) + if strings.HasPrefix(userIDStr, pniUserIDPrefix) { + userIDStr = pniServiceIDPrefix + userIDStr[len(pniUserIDPrefix):] + } + return libsignalgo.ServiceIDFromString(userIDStr) } func ParsePortalID(portalID networkid.PortalID) (userID libsignalgo.ServiceID, groupID types.GroupIdentifier, err error) { @@ -103,7 +117,14 @@ func MakeUserID(user uuid.UUID) networkid.UserID { } func MakeUserIDFromServiceID(user libsignalgo.ServiceID) networkid.UserID { - return networkid.UserID(user.String()) + switch user.Type { + case libsignalgo.ServiceIDTypeACI: + return MakeUserID(user.UUID) + case libsignalgo.ServiceIDTypePNI: + return networkid.UserID(pniUserIDPrefix + user.UUID.String()) + default: + panic(fmt.Errorf("invalid service ID type %d", user.Type)) + } } func MakeUserLoginID(user uuid.UUID) networkid.UserLoginID { diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index de6e054..d938e10 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -831,9 +831,6 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange log.Err(err).Msg("Couldn't decrypt source serviceID") return nil, err } - if sourceServiceID.Type != libsignalgo.ServiceIDTypeACI { - return nil, fmt.Errorf("wrong serviceid kind: expected aci, got pni") - } decryptedGroupChange := &GroupChange{ GroupMasterKey: groupMasterKey, Revision: encryptedActions.Revision, @@ -891,7 +888,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return nil, err } if serviceID.Type != libsignalgo.ServiceIDTypeACI { - return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + return nil, fmt.Errorf("wrong ServiceID kind for delete member: expected ACI, got PNI") } decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &serviceID.UUID) } @@ -904,7 +901,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return nil, err } if serviceID.Type != libsignalgo.ServiceIDTypeACI { - return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + return nil, fmt.Errorf("wrong ServiceID kind for modify member: expected ACI, got PNI") } decryptedGroupChange.ModifyMemberRoles = append(decryptedGroupChange.ModifyMemberRoles, &RoleMember{ ACI: serviceID.UUID, @@ -992,7 +989,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return nil, err } if pniServiceID.Type != libsignalgo.ServiceIDTypePNI { - return nil, fmt.Errorf("Wrong ServiceID kind: expected PNI, got ACI") + return nil, fmt.Errorf("wrong ServiceID kind for promote pending pni->aci: expected PNI, got ACI") } decryptedGroupChange.PromotePendingPniAciMembers = append(decryptedGroupChange.PromotePendingPniAciMembers, &PromotePendingPniAciMember{ ACI: *aci, @@ -1147,7 +1144,7 @@ func decryptPKeyAndIDorPresentation(ctx context.Context, userID []byte, profileK return nil, nil, err } if serviceID.Type == libsignalgo.ServiceIDTypePNI { - return nil, nil, fmt.Errorf("wrong serviceid kind, expected ACI, got PNI") + return nil, nil, fmt.Errorf("wrong serviceid kind for profile key: expected ACI, got PNI") } return &serviceID.UUID, profileKey, nil @@ -1808,6 +1805,10 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, Host: web.StorageHostname, + Headers: map[string]string{ + // TODO actually cache the data and provide real expiry timestamp + "Cached-Send-Endorsements": "0", + }, } // highest known epoch seems to always be 5, but that may change in the future. includeLastState is always false path := fmt.Sprintf("/v2/groups/logs/%d?maxSupportedChangeEpoch=%d&includeFirstState=%t&includeLastState=false", fromRevision, 5, includeFirstState) From 41311f917cd2a6ea0d606ada4318eae310b4808a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 22 Oct 2025 21:50:24 +0300 Subject: [PATCH 568/718] signalmeow/sending: don't clear needs PNI signature flag for typing/receipts --- pkg/signalmeow/sending.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 5c3612e..d5f7076 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -690,8 +690,9 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } else if recipientID.Type == libsignalgo.ServiceIDTypePNI { pni = recipientID.UUID } + isTypingOrReceipt := content.TypingMessage != nil || content.ReceiptMessage != nil recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { - if recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature { + if recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature && !isTypingOrReceipt { needsPNISignature = true zerolog.Ctx(ctx).Debug(). Stringer("recipient", recipientID). @@ -713,7 +714,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv zerolog.Ctx(ctx).Err(err).Msg("Failed to get message recipient data") } // Treat needs PNI signature as "this is a message request" and don't send receipts/typing - if needsPNISignature && (content.TypingMessage != nil || content.ReceiptMessage != nil) { + if needsPNISignature && isTypingOrReceipt { zerolog.Ctx(ctx).Debug().Msg("Not sending typing/receipt message to recipient as needs PNI signature flag is set") res := SuccessfulSendResult{Recipient: recipientID} if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { From 9beafc1c2f83e7bc4b763c9a35a7cb9942c1a6a6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 22 Oct 2025 22:00:54 +0300 Subject: [PATCH 569/718] signalmeow/sending: fix typing/receipts being sent to PNI --- pkg/signalmeow/sending.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index d5f7076..c1b2016 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -692,8 +692,8 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } isTypingOrReceipt := content.TypingMessage != nil || content.ReceiptMessage != nil recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { - if recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature && !isTypingOrReceipt { - needsPNISignature = true + needsPNISignature = recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature + if needsPNISignature && !isTypingOrReceipt { zerolog.Ctx(ctx).Debug(). Stringer("recipient", recipientID). Msg("Including PNI identity in message") From 69208e85683b6e680428b00aca4527fd93fe6231 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 23 Oct 2025 15:14:38 +0300 Subject: [PATCH 570/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2fabdcc..5fc3a9a 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.46.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.3-0.20251022182546-33d8d658fe98 + maunium.net/go/mautrix v0.25.3-0.20251023124911-1be49d53e4f3 ) require ( diff --git a/go.sum b/go.sum index b7850bf..f48dcac 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.3-0.20251022182546-33d8d658fe98 h1:0cTTVYsfTyXaoqFYz4MoHfMv+zps+Gh3dbQtDn4mtHo= -maunium.net/go/mautrix v0.25.3-0.20251022182546-33d8d658fe98/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.25.3-0.20251023124911-1be49d53e4f3 h1:C+inXVPJspCtjiLIP64npDR01o5Fs9bE9lg3jr0PzS4= +maunium.net/go/mautrix v0.25.3-0.20251023124911-1be49d53e4f3/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= From 5f3e2527025ea7707b1994ebbb72359978b57b60 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 23 Oct 2025 15:20:59 +0300 Subject: [PATCH 571/718] changelog: update --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9135702..4e38aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v25.11 (unreleased) + +* Added support for bridging invite state in groups for phone number invites. +* Fixed PNI signature not being sent when replying to message requests. +* Fixed unnecessary repeating error notices when Signal is down. + # v25.10 * Switched to calendar versioning. From 0ededf479433f708cb7a60f4f072cc3552b7ad7b Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Fri, 24 Oct 2025 08:51:17 -0700 Subject: [PATCH 572/718] build.sh: fail if prior steps fail (#609) --- build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sh b/build.sh index 2b51084..3ec20a6 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,5 @@ #!/bin/sh +set -e ./build-rust.sh cp -f pkg/libsignalgo/libsignal/target/release/libsignal_ffi.a . LIBRARY_PATH=.:$LIBRARY_PATH ./build-go.sh From afa38f4f9fc373f40ca8965e2ebc0a44880fe0ff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 27 Oct 2025 18:07:14 +0200 Subject: [PATCH 573/718] msgconv/from-signal: match sticker size with native desktop --- pkg/msgconv/from-signal.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 277e2a5..ac3fe65 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -441,10 +441,11 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker }, } } - // Signal stickers are 512x512, so tell Matrix clients to render them as 256x256 + // Signal stickers are 512x512, so tell Matrix clients to render them as 200x200 to match Signal + // https://github.com/signalapp/Signal-Desktop/blob/v7.77.0-beta.1/ts/components/conversation/Message.dom.tsx#L135 if converted.Content.Info.Width == 512 && converted.Content.Info.Height == 512 { - converted.Content.Info.Width = 256 - converted.Content.Info.Height = 256 + converted.Content.Info.Width = 200 + converted.Content.Info.Height = 200 } converted.Content.Body = sticker.GetEmoji() converted.Type = event.EventSticker From b3973632e5e27b6fa0cb083e9772663b084155ba Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 27 Oct 2025 19:03:38 +0200 Subject: [PATCH 574/718] capabilities: advertise supported state events and member actions Closes #614 Closes #613 --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/capabilities.go | 29 ++++++++++++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 5fc3a9a..313f1ed 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.46.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.3-0.20251023124911-1be49d53e4f3 + maunium.net/go/mautrix v0.25.3-0.20251027163910-adc035b6a555 ) require ( diff --git a/go.sum b/go.sum index f48dcac..95c60ff 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.3-0.20251023124911-1be49d53e4f3 h1:C+inXVPJspCtjiLIP64npDR01o5Fs9bE9lg3jr0PzS4= -maunium.net/go/mautrix v0.25.3-0.20251023124911-1be49d53e4f3/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.25.3-0.20251027163910-adc035b6a555 h1:6D/kRJyT+5+RRnJErNNglVwDMYU6EwQN0bRYqcdkfZw= +maunium.net/go/mautrix v0.25.3-0.20251027163910-adc035b6a555/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 329a81d..b9cb632 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -25,6 +25,7 @@ import ( "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" ) @@ -37,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_08_25" + base := "fi.mau.signal.capabilities.2025_10_27" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -136,6 +137,19 @@ var signalCaps = &event.RoomFeatures{ MaxSize: MaxFileSize, }, }, + State: event.StateFeatureMap{ + event.StateRoomName.Type: {Level: event.CapLevelFullySupported}, + event.StateRoomAvatar.Type: {Level: event.CapLevelFullySupported}, + event.StateTopic.Type: {Level: event.CapLevelFullySupported}, + event.StateBeeperDisappearingTimer.Type: {Level: event.CapLevelFullySupported}, + }, + MemberActions: event.MemberFeatureMap{ + event.MemberActionInvite: event.CapLevelFullySupported, + event.MemberActionRevokeInvite: event.CapLevelFullySupported, + event.MemberActionLeave: event.CapLevelFullySupported, + event.MemberActionBan: event.CapLevelFullySupported, + event.MemberActionKick: event.CapLevelFullySupported, + }, MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files LocationMessage: event.CapLevelPartialSupport, Poll: event.CapLevelRejected, @@ -162,9 +176,16 @@ var signalDisappearingCap = &event.DisappearingTimerCapability{ } var signalCapsNoteToSelf *event.RoomFeatures +var signalCapsDM *event.RoomFeatures func init() { - signalCapsNoteToSelf = ptr.Clone(signalCaps) + signalCapsDM = ptr.Clone(signalCaps) + signalCapsDM.ID = capID() + "+dm" + signalCapsDM.MemberActions = nil + signalCapsDM.State = event.StateFeatureMap{ + event.StateBeeperDisappearingTimer.Type: {Level: event.CapLevelFullySupported}, + } + signalCapsNoteToSelf = ptr.Clone(signalCapsDM) signalCapsNoteToSelf.EditMaxAge = nil signalCapsNoteToSelf.DeleteMaxAge = nil signalCapsNoteToSelf.ID = capID() + "+note_to_self" @@ -173,6 +194,8 @@ func init() { func (s *SignalClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { if portal.Receiver == s.UserLogin.ID && portal.ID == networkid.PortalID(s.UserLogin.ID) { return signalCapsNoteToSelf + } else if portal.RoomType == database.RoomTypeDM { + return signalCapsDM } return signalCaps } @@ -206,5 +229,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 5 + return 1, 6 } From dab89843b0ca14c0851f0b5032d38c3b29252755 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Tue, 28 Oct 2025 12:40:17 +0000 Subject: [PATCH 575/718] handlematrix: return error when handling unsupported membership changes --- pkg/connector/handlematrix.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index dec5341..65e7b7c 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -513,8 +513,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 case bridgev2.Unban: gc.DeleteBannedMembers = []*libsignalgo.ServiceID{&targetSignalID} default: - log.Debug().Msg("unsupported membership change") - return false, nil + return false, fmt.Errorf("unsupported membership change: %s -> %s", msg.Type.From, msg.Type.To) } _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) if err != nil || groupID == "" { From 6e49c340768e8f8521cf9ab4ea2e94e6fed3e1f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 28 Oct 2025 15:08:34 +0200 Subject: [PATCH 576/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 313f1ed..f61bdd1 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.46.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.3-0.20251027163910-adc035b6a555 + maunium.net/go/mautrix v0.25.3-0.20251028130646-bea28c1381cd ) require ( diff --git a/go.sum b/go.sum index 95c60ff..fa344cc 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.3-0.20251027163910-adc035b6a555 h1:6D/kRJyT+5+RRnJErNNglVwDMYU6EwQN0bRYqcdkfZw= -maunium.net/go/mautrix v0.25.3-0.20251027163910-adc035b6a555/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.25.3-0.20251028130646-bea28c1381cd h1:4OfgnwTd71vgHGc+kBwhWsb92ePZVvsDbyTLJiy+PKU= +maunium.net/go/mautrix v0.25.3-0.20251028130646-bea28c1381cd/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= From 6f840544e180794d5aa8e4d57cce0cdcaaca5fad Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 29 Oct 2025 14:10:25 +0200 Subject: [PATCH 577/718] signalmeow: update protobufs --- .../protobuf/ContactDiscovery.pb.go | 2 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 2 +- pkg/signalmeow/protobuf/Groups.pb.go | 2 +- pkg/signalmeow/protobuf/Provisioning.pb.go | 2 +- pkg/signalmeow/protobuf/SignalService.pb.go | 735 ++++++---- pkg/signalmeow/protobuf/SignalService.proto | 24 +- .../protobuf/StickerResources.pb.go | 2 +- pkg/signalmeow/protobuf/StorageService.pb.go | 2 +- .../protobuf/UnidentifiedDelivery.pb.go | 2 +- .../protobuf/WebSocketResources.pb.go | 2 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 1304 ++++++++++------- pkg/signalmeow/protobuf/backuppb/Backup.proto | 27 + pkg/signalmeow/protobuf/update-protos.sh | 7 +- 13 files changed, 1339 insertions(+), 774 deletions(-) diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 97ac6b4..5523a0e 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: ContactDiscovery.proto diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index e83e374..144428d 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: DeviceName.proto diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 7178760..3e5cc7a 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: Groups.proto diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 9e75ec2..d2f0a4d 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: Provisioning.proto diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index fd875ac..ae5bd18 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: SignalService.proto @@ -346,6 +346,7 @@ const ( DataMessage_CDN_SELECTOR_ATTACHMENTS DataMessage_ProtocolVersion = 5 DataMessage_MENTIONS DataMessage_ProtocolVersion = 6 DataMessage_PAYMENTS DataMessage_ProtocolVersion = 7 + DataMessage_POLLS DataMessage_ProtocolVersion = 8 DataMessage_CURRENT DataMessage_ProtocolVersion = 7 ) @@ -360,6 +361,7 @@ var ( 5: "CDN_SELECTOR_ATTACHMENTS", 6: "MENTIONS", 7: "PAYMENTS", + 8: "POLLS", // Duplicate value: 7: "CURRENT", } DataMessage_ProtocolVersion_value = map[string]int32{ @@ -371,6 +373,7 @@ var ( "CDN_SELECTOR_ATTACHMENTS": 5, "MENTIONS": 6, "PAYMENTS": 7, + "POLLS": 8, "CURRENT": 7, } ) @@ -473,6 +476,7 @@ type DataMessage_Quote_Type int32 const ( DataMessage_Quote_NORMAL DataMessage_Quote_Type = 0 DataMessage_Quote_GIFT_BADGE DataMessage_Quote_Type = 1 + DataMessage_Quote_POLL DataMessage_Quote_Type = 2 ) // Enum value maps for DataMessage_Quote_Type. @@ -480,10 +484,12 @@ var ( DataMessage_Quote_Type_name = map[int32]string{ 0: "NORMAL", 1: "GIFT_BADGE", + 2: "POLL", } DataMessage_Quote_Type_value = map[string]int32{ "NORMAL": 0, "GIFT_BADGE": 1, + "POLL": 2, } ) @@ -2126,7 +2132,10 @@ type DataMessage struct { GroupCallUpdate *DataMessage_GroupCallUpdate `protobuf:"bytes,19,opt,name=groupCallUpdate" json:"groupCallUpdate,omitempty"` Payment *DataMessage_Payment `protobuf:"bytes,20,opt,name=payment" json:"payment,omitempty"` StoryContext *DataMessage_StoryContext `protobuf:"bytes,21,opt,name=storyContext" json:"storyContext,omitempty"` - GiftBadge *DataMessage_GiftBadge `protobuf:"bytes,22,opt,name=giftBadge" json:"giftBadge,omitempty"` // NEXT ID: 24 + GiftBadge *DataMessage_GiftBadge `protobuf:"bytes,22,opt,name=giftBadge" json:"giftBadge,omitempty"` + PollCreate *DataMessage_PollCreate `protobuf:"bytes,24,opt,name=pollCreate" json:"pollCreate,omitempty"` + PollTerminate *DataMessage_PollTerminate `protobuf:"bytes,25,opt,name=pollTerminate" json:"pollTerminate,omitempty"` + PollVote *DataMessage_PollVote `protobuf:"bytes,26,opt,name=pollVote" json:"pollVote,omitempty"` // NEXT ID: 27 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2308,6 +2317,27 @@ func (x *DataMessage) GetGiftBadge() *DataMessage_GiftBadge { return nil } +func (x *DataMessage) GetPollCreate() *DataMessage_PollCreate { + if x != nil { + return x.PollCreate + } + return nil +} + +func (x *DataMessage) GetPollTerminate() *DataMessage_PollTerminate { + if x != nil { + return x.PollTerminate + } + return nil +} + +func (x *DataMessage) GetPollVote() *DataMessage_PollVote { + if x != nil { + return x.PollVote + } + return nil +} + type NullMessage struct { state protoimpl.MessageState `protogen:"open.v1"` Padding []byte `protobuf:"bytes,1,opt,name=padding" json:"padding,omitempty"` @@ -4843,6 +4873,178 @@ func (x *DataMessage_GiftBadge) GetReceiptCredentialPresentation() []byte { return nil } +type DataMessage_PollCreate struct { + state protoimpl.MessageState `protogen:"open.v1"` + Question *string `protobuf:"bytes,1,opt,name=question" json:"question,omitempty"` + AllowMultiple *bool `protobuf:"varint,2,opt,name=allowMultiple" json:"allowMultiple,omitempty"` + Options []string `protobuf:"bytes,3,rep,name=options" json:"options,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_PollCreate) Reset() { + *x = DataMessage_PollCreate{} + mi := &file_SignalService_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_PollCreate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_PollCreate) ProtoMessage() {} + +func (x *DataMessage_PollCreate) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[37] + 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 DataMessage_PollCreate.ProtoReflect.Descriptor instead. +func (*DataMessage_PollCreate) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 9} +} + +func (x *DataMessage_PollCreate) GetQuestion() string { + if x != nil && x.Question != nil { + return *x.Question + } + return "" +} + +func (x *DataMessage_PollCreate) GetAllowMultiple() bool { + if x != nil && x.AllowMultiple != nil { + return *x.AllowMultiple + } + return false +} + +func (x *DataMessage_PollCreate) GetOptions() []string { + if x != nil { + return x.Options + } + return nil +} + +type DataMessage_PollTerminate struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_PollTerminate) Reset() { + *x = DataMessage_PollTerminate{} + mi := &file_SignalService_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_PollTerminate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_PollTerminate) ProtoMessage() {} + +func (x *DataMessage_PollTerminate) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DataMessage_PollTerminate.ProtoReflect.Descriptor instead. +func (*DataMessage_PollTerminate) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 10} +} + +func (x *DataMessage_PollTerminate) GetTargetSentTimestamp() uint64 { + if x != nil && x.TargetSentTimestamp != nil { + return *x.TargetSentTimestamp + } + return 0 +} + +type DataMessage_PollVote struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetAuthorAciBinary []byte `protobuf:"bytes,1,opt,name=targetAuthorAciBinary" json:"targetAuthorAciBinary,omitempty"` + TargetSentTimestamp *uint64 `protobuf:"varint,2,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + OptionIndexes []uint32 `protobuf:"varint,3,rep,name=optionIndexes" json:"optionIndexes,omitempty"` // must be in the range [0, options.length) from the PollCreate + VoteCount *uint32 `protobuf:"varint,4,opt,name=voteCount" json:"voteCount,omitempty"` // increment this by 1 each time you vote on a given poll + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_PollVote) Reset() { + *x = DataMessage_PollVote{} + mi := &file_SignalService_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_PollVote) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_PollVote) ProtoMessage() {} + +func (x *DataMessage_PollVote) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[39] + 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 DataMessage_PollVote.ProtoReflect.Descriptor instead. +func (*DataMessage_PollVote) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 11} +} + +func (x *DataMessage_PollVote) GetTargetAuthorAciBinary() []byte { + if x != nil { + return x.TargetAuthorAciBinary + } + return nil +} + +func (x *DataMessage_PollVote) GetTargetSentTimestamp() uint64 { + if x != nil && x.TargetSentTimestamp != nil { + return *x.TargetSentTimestamp + } + return 0 +} + +func (x *DataMessage_PollVote) GetOptionIndexes() []uint32 { + if x != nil { + return x.OptionIndexes + } + return nil +} + +func (x *DataMessage_PollVote) GetVoteCount() uint32 { + if x != nil && x.VoteCount != nil { + return *x.VoteCount + } + return 0 +} + type DataMessage_Payment_Amount struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Amount: @@ -4855,7 +5057,7 @@ type DataMessage_Payment_Amount struct { func (x *DataMessage_Payment_Amount) Reset() { *x = DataMessage_Payment_Amount{} - mi := &file_SignalService_proto_msgTypes[37] + mi := &file_SignalService_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4867,7 +5069,7 @@ func (x *DataMessage_Payment_Amount) String() string { func (*DataMessage_Payment_Amount) ProtoMessage() {} func (x *DataMessage_Payment_Amount) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[37] + mi := &file_SignalService_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4923,7 +5125,7 @@ type DataMessage_Payment_Notification struct { func (x *DataMessage_Payment_Notification) Reset() { *x = DataMessage_Payment_Notification{} - mi := &file_SignalService_proto_msgTypes[38] + mi := &file_SignalService_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4935,7 +5137,7 @@ func (x *DataMessage_Payment_Notification) String() string { func (*DataMessage_Payment_Notification) ProtoMessage() {} func (x *DataMessage_Payment_Notification) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[38] + mi := &file_SignalService_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4994,7 +5196,7 @@ type DataMessage_Payment_Activation struct { func (x *DataMessage_Payment_Activation) Reset() { *x = DataMessage_Payment_Activation{} - mi := &file_SignalService_proto_msgTypes[39] + mi := &file_SignalService_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5006,7 +5208,7 @@ func (x *DataMessage_Payment_Activation) String() string { func (*DataMessage_Payment_Activation) ProtoMessage() {} func (x *DataMessage_Payment_Activation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[39] + mi := &file_SignalService_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5038,7 +5240,7 @@ type DataMessage_Payment_Amount_MobileCoin struct { func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { *x = DataMessage_Payment_Amount_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[40] + mi := &file_SignalService_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5050,7 +5252,7 @@ func (x *DataMessage_Payment_Amount_MobileCoin) String() string { func (*DataMessage_Payment_Amount_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Amount_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[40] + mi := &file_SignalService_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5082,7 +5284,7 @@ type DataMessage_Payment_Notification_MobileCoin struct { func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { *x = DataMessage_Payment_Notification_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[41] + mi := &file_SignalService_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5094,7 +5296,7 @@ func (x *DataMessage_Payment_Notification_MobileCoin) String() string { func (*DataMessage_Payment_Notification_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Notification_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[41] + mi := &file_SignalService_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5128,7 +5330,7 @@ type DataMessage_Quote_QuotedAttachment struct { func (x *DataMessage_Quote_QuotedAttachment) Reset() { *x = DataMessage_Quote_QuotedAttachment{} - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5140,7 +5342,7 @@ func (x *DataMessage_Quote_QuotedAttachment) String() string { func (*DataMessage_Quote_QuotedAttachment) ProtoMessage() {} func (x *DataMessage_Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5191,7 +5393,7 @@ type DataMessage_Contact_Name struct { func (x *DataMessage_Contact_Name) Reset() { *x = DataMessage_Contact_Name{} - mi := &file_SignalService_proto_msgTypes[43] + mi := &file_SignalService_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5203,7 +5405,7 @@ func (x *DataMessage_Contact_Name) String() string { func (*DataMessage_Contact_Name) ProtoMessage() {} func (x *DataMessage_Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[43] + mi := &file_SignalService_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5272,7 +5474,7 @@ type DataMessage_Contact_Phone struct { func (x *DataMessage_Contact_Phone) Reset() { *x = DataMessage_Contact_Phone{} - mi := &file_SignalService_proto_msgTypes[44] + mi := &file_SignalService_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5284,7 +5486,7 @@ func (x *DataMessage_Contact_Phone) String() string { func (*DataMessage_Contact_Phone) ProtoMessage() {} func (x *DataMessage_Contact_Phone) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[44] + mi := &file_SignalService_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5332,7 +5534,7 @@ type DataMessage_Contact_Email struct { func (x *DataMessage_Contact_Email) Reset() { *x = DataMessage_Contact_Email{} - mi := &file_SignalService_proto_msgTypes[45] + mi := &file_SignalService_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5344,7 +5546,7 @@ func (x *DataMessage_Contact_Email) String() string { func (*DataMessage_Contact_Email) ProtoMessage() {} func (x *DataMessage_Contact_Email) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[45] + mi := &file_SignalService_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5398,7 +5600,7 @@ type DataMessage_Contact_PostalAddress struct { func (x *DataMessage_Contact_PostalAddress) Reset() { *x = DataMessage_Contact_PostalAddress{} - mi := &file_SignalService_proto_msgTypes[46] + mi := &file_SignalService_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5410,7 +5612,7 @@ func (x *DataMessage_Contact_PostalAddress) String() string { func (*DataMessage_Contact_PostalAddress) ProtoMessage() {} func (x *DataMessage_Contact_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[46] + mi := &file_SignalService_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5499,7 +5701,7 @@ type DataMessage_Contact_Avatar struct { func (x *DataMessage_Contact_Avatar) Reset() { *x = DataMessage_Contact_Avatar{} - mi := &file_SignalService_proto_msgTypes[47] + mi := &file_SignalService_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5511,7 +5713,7 @@ func (x *DataMessage_Contact_Avatar) String() string { func (*DataMessage_Contact_Avatar) ProtoMessage() {} func (x *DataMessage_Contact_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[47] + mi := &file_SignalService_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5554,7 +5756,7 @@ type TextAttachment_Gradient struct { func (x *TextAttachment_Gradient) Reset() { *x = TextAttachment_Gradient{} - mi := &file_SignalService_proto_msgTypes[48] + mi := &file_SignalService_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5566,7 +5768,7 @@ func (x *TextAttachment_Gradient) String() string { func (*TextAttachment_Gradient) ProtoMessage() {} func (x *TextAttachment_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[48] + mi := &file_SignalService_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5640,7 +5842,7 @@ const ( func (x *SyncMessage_Sent) Reset() { *x = SyncMessage_Sent{} - mi := &file_SignalService_proto_msgTypes[49] + mi := &file_SignalService_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5652,7 +5854,7 @@ func (x *SyncMessage_Sent) String() string { func (*SyncMessage_Sent) ProtoMessage() {} func (x *SyncMessage_Sent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[49] + mi := &file_SignalService_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5753,7 +5955,7 @@ const ( func (x *SyncMessage_Contacts) Reset() { *x = SyncMessage_Contacts{} - mi := &file_SignalService_proto_msgTypes[50] + mi := &file_SignalService_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5765,7 +5967,7 @@ func (x *SyncMessage_Contacts) String() string { func (*SyncMessage_Contacts) ProtoMessage() {} func (x *SyncMessage_Contacts) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[50] + mi := &file_SignalService_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5806,7 +6008,7 @@ type SyncMessage_Blocked struct { func (x *SyncMessage_Blocked) Reset() { *x = SyncMessage_Blocked{} - mi := &file_SignalService_proto_msgTypes[51] + mi := &file_SignalService_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5818,7 +6020,7 @@ func (x *SyncMessage_Blocked) String() string { func (*SyncMessage_Blocked) ProtoMessage() {} func (x *SyncMessage_Blocked) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[51] + mi := &file_SignalService_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5864,7 +6066,7 @@ type SyncMessage_Request struct { func (x *SyncMessage_Request) Reset() { *x = SyncMessage_Request{} - mi := &file_SignalService_proto_msgTypes[52] + mi := &file_SignalService_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5876,7 +6078,7 @@ func (x *SyncMessage_Request) String() string { func (*SyncMessage_Request) ProtoMessage() {} func (x *SyncMessage_Request) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[52] + mi := &file_SignalService_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5909,7 +6111,7 @@ type SyncMessage_Read struct { func (x *SyncMessage_Read) Reset() { *x = SyncMessage_Read{} - mi := &file_SignalService_proto_msgTypes[53] + mi := &file_SignalService_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5921,7 +6123,7 @@ func (x *SyncMessage_Read) String() string { func (*SyncMessage_Read) ProtoMessage() {} func (x *SyncMessage_Read) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[53] + mi := &file_SignalService_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5961,7 +6163,7 @@ type SyncMessage_Viewed struct { func (x *SyncMessage_Viewed) Reset() { *x = SyncMessage_Viewed{} - mi := &file_SignalService_proto_msgTypes[54] + mi := &file_SignalService_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5973,7 +6175,7 @@ func (x *SyncMessage_Viewed) String() string { func (*SyncMessage_Viewed) ProtoMessage() {} func (x *SyncMessage_Viewed) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[54] + mi := &file_SignalService_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6016,7 +6218,7 @@ type SyncMessage_Configuration struct { func (x *SyncMessage_Configuration) Reset() { *x = SyncMessage_Configuration{} - mi := &file_SignalService_proto_msgTypes[55] + mi := &file_SignalService_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6028,7 +6230,7 @@ func (x *SyncMessage_Configuration) String() string { func (*SyncMessage_Configuration) ProtoMessage() {} func (x *SyncMessage_Configuration) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[55] + mi := &file_SignalService_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6090,7 +6292,7 @@ type SyncMessage_StickerPackOperation struct { func (x *SyncMessage_StickerPackOperation) Reset() { *x = SyncMessage_StickerPackOperation{} - mi := &file_SignalService_proto_msgTypes[56] + mi := &file_SignalService_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6102,7 +6304,7 @@ func (x *SyncMessage_StickerPackOperation) String() string { func (*SyncMessage_StickerPackOperation) ProtoMessage() {} func (x *SyncMessage_StickerPackOperation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[56] + mi := &file_SignalService_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6149,7 +6351,7 @@ type SyncMessage_ViewOnceOpen struct { func (x *SyncMessage_ViewOnceOpen) Reset() { *x = SyncMessage_ViewOnceOpen{} - mi := &file_SignalService_proto_msgTypes[57] + mi := &file_SignalService_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6161,7 +6363,7 @@ func (x *SyncMessage_ViewOnceOpen) String() string { func (*SyncMessage_ViewOnceOpen) ProtoMessage() {} func (x *SyncMessage_ViewOnceOpen) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[57] + mi := &file_SignalService_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6200,7 +6402,7 @@ type SyncMessage_FetchLatest struct { func (x *SyncMessage_FetchLatest) Reset() { *x = SyncMessage_FetchLatest{} - mi := &file_SignalService_proto_msgTypes[58] + mi := &file_SignalService_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6212,7 +6414,7 @@ func (x *SyncMessage_FetchLatest) String() string { func (*SyncMessage_FetchLatest) ProtoMessage() {} func (x *SyncMessage_FetchLatest) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[58] + mi := &file_SignalService_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6246,7 +6448,7 @@ type SyncMessage_Keys struct { func (x *SyncMessage_Keys) Reset() { *x = SyncMessage_Keys{} - mi := &file_SignalService_proto_msgTypes[59] + mi := &file_SignalService_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6258,7 +6460,7 @@ func (x *SyncMessage_Keys) String() string { func (*SyncMessage_Keys) ProtoMessage() {} func (x *SyncMessage_Keys) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[59] + mi := &file_SignalService_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6305,7 +6507,7 @@ type SyncMessage_PniIdentity struct { func (x *SyncMessage_PniIdentity) Reset() { *x = SyncMessage_PniIdentity{} - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6317,7 +6519,7 @@ func (x *SyncMessage_PniIdentity) String() string { func (*SyncMessage_PniIdentity) ProtoMessage() {} func (x *SyncMessage_PniIdentity) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6358,7 +6560,7 @@ type SyncMessage_MessageRequestResponse struct { func (x *SyncMessage_MessageRequestResponse) Reset() { *x = SyncMessage_MessageRequestResponse{} - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6370,7 +6572,7 @@ func (x *SyncMessage_MessageRequestResponse) String() string { func (*SyncMessage_MessageRequestResponse) ProtoMessage() {} func (x *SyncMessage_MessageRequestResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6421,7 +6623,7 @@ type SyncMessage_OutgoingPayment struct { func (x *SyncMessage_OutgoingPayment) Reset() { *x = SyncMessage_OutgoingPayment{} - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6433,7 +6635,7 @@ func (x *SyncMessage_OutgoingPayment) String() string { func (*SyncMessage_OutgoingPayment) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6503,7 +6705,7 @@ type SyncMessage_PniChangeNumber struct { func (x *SyncMessage_PniChangeNumber) Reset() { *x = SyncMessage_PniChangeNumber{} - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6515,7 +6717,7 @@ func (x *SyncMessage_PniChangeNumber) String() string { func (*SyncMessage_PniChangeNumber) ProtoMessage() {} func (x *SyncMessage_PniChangeNumber) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6585,7 +6787,7 @@ type SyncMessage_CallEvent struct { func (x *SyncMessage_CallEvent) Reset() { *x = SyncMessage_CallEvent{} - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6597,7 +6799,7 @@ func (x *SyncMessage_CallEvent) String() string { func (*SyncMessage_CallEvent) ProtoMessage() {} func (x *SyncMessage_CallEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6667,7 +6869,7 @@ type SyncMessage_CallLinkUpdate struct { func (x *SyncMessage_CallLinkUpdate) Reset() { *x = SyncMessage_CallLinkUpdate{} - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6679,7 +6881,7 @@ func (x *SyncMessage_CallLinkUpdate) String() string { func (*SyncMessage_CallLinkUpdate) ProtoMessage() {} func (x *SyncMessage_CallLinkUpdate) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6740,7 +6942,7 @@ type SyncMessage_CallLogEvent struct { func (x *SyncMessage_CallLogEvent) Reset() { *x = SyncMessage_CallLogEvent{} - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6752,7 +6954,7 @@ func (x *SyncMessage_CallLogEvent) String() string { func (*SyncMessage_CallLogEvent) ProtoMessage() {} func (x *SyncMessage_CallLogEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6808,7 +7010,7 @@ type SyncMessage_DeleteForMe struct { func (x *SyncMessage_DeleteForMe) Reset() { *x = SyncMessage_DeleteForMe{} - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6820,7 +7022,7 @@ func (x *SyncMessage_DeleteForMe) String() string { func (*SyncMessage_DeleteForMe) ProtoMessage() {} func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6873,7 +7075,7 @@ type SyncMessage_DeviceNameChange struct { func (x *SyncMessage_DeviceNameChange) Reset() { *x = SyncMessage_DeviceNameChange{} - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6885,7 +7087,7 @@ func (x *SyncMessage_DeviceNameChange) String() string { func (*SyncMessage_DeviceNameChange) ProtoMessage() {} func (x *SyncMessage_DeviceNameChange) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6918,7 +7120,7 @@ type SyncMessage_AttachmentBackfillRequest struct { func (x *SyncMessage_AttachmentBackfillRequest) Reset() { *x = SyncMessage_AttachmentBackfillRequest{} - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6930,7 +7132,7 @@ func (x *SyncMessage_AttachmentBackfillRequest) String() string { func (*SyncMessage_AttachmentBackfillRequest) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillRequest) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6975,7 +7177,7 @@ type SyncMessage_AttachmentBackfillResponse struct { func (x *SyncMessage_AttachmentBackfillResponse) Reset() { *x = SyncMessage_AttachmentBackfillResponse{} - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6987,7 +7189,7 @@ func (x *SyncMessage_AttachmentBackfillResponse) String() string { func (*SyncMessage_AttachmentBackfillResponse) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7071,7 +7273,7 @@ type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7083,7 +7285,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7131,7 +7333,7 @@ type SyncMessage_Sent_StoryMessageRecipient struct { func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7143,7 +7345,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7196,7 +7398,7 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7208,7 +7410,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7290,7 +7492,7 @@ type SyncMessage_DeleteForMe_MessageDeletes struct { func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { *x = SyncMessage_DeleteForMe_MessageDeletes{} - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7302,7 +7504,7 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7348,7 +7550,7 @@ type SyncMessage_DeleteForMe_AttachmentDelete struct { func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { *x = SyncMessage_DeleteForMe_AttachmentDelete{} - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7360,7 +7562,7 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7423,7 +7625,7 @@ type SyncMessage_DeleteForMe_ConversationDelete struct { func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7435,7 +7637,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7488,7 +7690,7 @@ type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7500,7 +7702,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7536,7 +7738,7 @@ type SyncMessage_AttachmentBackfillResponse_AttachmentData struct { func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) Reset() { *x = SyncMessage_AttachmentBackfillResponse_AttachmentData{} - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7548,7 +7750,7 @@ func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) String() string func (*SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7617,7 +7819,7 @@ type SyncMessage_AttachmentBackfillResponse_AttachmentDataList struct { func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) Reset() { *x = SyncMessage_AttachmentBackfillResponse_AttachmentDataList{} - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7629,7 +7831,7 @@ func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) String() str func (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7669,7 +7871,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7681,7 +7883,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7721,7 +7923,7 @@ type PaymentAddress_MobileCoin struct { func (x *PaymentAddress_MobileCoin) Reset() { *x = PaymentAddress_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[81] + mi := &file_SignalService_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7733,7 +7935,7 @@ func (x *PaymentAddress_MobileCoin) String() string { func (*PaymentAddress_MobileCoin) ProtoMessage() {} func (x *PaymentAddress_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[81] + mi := &file_SignalService_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7848,7 +8050,7 @@ const file_SignalService_proto_rawDesc = "" + "\aurgency\x18\x02 \x01(\x0e2).signalservice.CallMessage.Opaque.UrgencyR\aurgency\"0\n" + "\aUrgency\x12\r\n" + "\tDROPPABLE\x10\x00\x12\x16\n" + - "\x12HANDLE_IMMEDIATELY\x10\x01J\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"\xf7\"\n" + + "\x12HANDLE_IMMEDIATELY\x10\x01J\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"\xca'\n" + "\vDataMessage\x12\x12\n" + "\x04body\x18\x01 \x01(\tR\x04body\x12B\n" + "\vattachments\x18\x02 \x03(\v2 .signalservice.AttachmentPointerR\vattachments\x127\n" + @@ -7877,7 +8079,12 @@ const file_SignalService_proto_rawDesc = "" + "\x0fgroupCallUpdate\x18\x13 \x01(\v2*.signalservice.DataMessage.GroupCallUpdateR\x0fgroupCallUpdate\x12<\n" + "\apayment\x18\x14 \x01(\v2\".signalservice.DataMessage.PaymentR\apayment\x12K\n" + "\fstoryContext\x18\x15 \x01(\v2'.signalservice.DataMessage.StoryContextR\fstoryContext\x12B\n" + - "\tgiftBadge\x18\x16 \x01(\v2$.signalservice.DataMessage.GiftBadgeR\tgiftBadge\x1a\x9a\x05\n" + + "\tgiftBadge\x18\x16 \x01(\v2$.signalservice.DataMessage.GiftBadgeR\tgiftBadge\x12E\n" + + "\n" + + "pollCreate\x18\x18 \x01(\v2%.signalservice.DataMessage.PollCreateR\n" + + "pollCreate\x12N\n" + + "\rpollTerminate\x18\x19 \x01(\v2(.signalservice.DataMessage.PollTerminateR\rpollTerminate\x12?\n" + + "\bpollVote\x18\x1a \x01(\v2#.signalservice.DataMessage.PollVoteR\bpollVote\x1a\x9a\x05\n" + "\aPayment\x12U\n" + "\fnotification\x18\x01 \x01(\v2/.signalservice.DataMessage.Payment.NotificationH\x00R\fnotification\x12O\n" + "\n" + @@ -7906,7 +8113,7 @@ const file_SignalService_proto_rawDesc = "" + "\x04Type\x12\v\n" + "\aREQUEST\x10\x00\x12\r\n" + "\tACTIVATED\x10\x01B\x06\n" + - "\x04ItemJ\x06\b\xea\a\x10\xeb\aJ\x06\b\xeb\a\x10\xec\a\x1a\xd0\x03\n" + + "\x04ItemJ\x06\b\xea\a\x10\xeb\aJ\x06\b\xeb\a\x10\xec\a\x1a\xda\x03\n" + "\x05Quote\x12\x0e\n" + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x1c\n" + "\tauthorAci\x18\x05 \x01(\tR\tauthorAci\x12\x12\n" + @@ -7919,12 +8126,13 @@ const file_SignalService_proto_rawDesc = "" + "\x10QuotedAttachment\x12 \n" + "\vcontentType\x18\x01 \x01(\tR\vcontentType\x12\x1a\n" + "\bfileName\x18\x02 \x01(\tR\bfileName\x12>\n" + - "\tthumbnail\x18\x03 \x01(\v2 .signalservice.AttachmentPointerR\tthumbnail\"\"\n" + + "\tthumbnail\x18\x03 \x01(\v2 .signalservice.AttachmentPointerR\tthumbnail\",\n" + "\x04Type\x12\n" + "\n" + "\x06NORMAL\x10\x00\x12\x0e\n" + "\n" + - "GIFT_BADGE\x10\x01J\x04\b\x02\x10\x03\x1a\xbf\n" + + "GIFT_BADGE\x10\x01\x12\b\n" + + "\x04POLL\x10\x02J\x04\b\x02\x10\x03\x1a\xbf\n" + "\n" + "\aContact\x12;\n" + "\x04name\x18\x01 \x01(\v2'.signalservice.DataMessage.Contact.NameR\x04name\x12@\n" + @@ -8003,12 +8211,24 @@ const file_SignalService_proto_rawDesc = "" + "\tauthorAci\x18\x01 \x01(\tR\tauthorAci\x12$\n" + "\rsentTimestamp\x18\x02 \x01(\x04R\rsentTimestamp\x1aQ\n" + "\tGiftBadge\x12D\n" + - "\x1dreceiptCredentialPresentation\x18\x01 \x01(\fR\x1dreceiptCredentialPresentation\"Z\n" + + "\x1dreceiptCredentialPresentation\x18\x01 \x01(\fR\x1dreceiptCredentialPresentation\x1ah\n" + + "\n" + + "PollCreate\x12\x1a\n" + + "\bquestion\x18\x01 \x01(\tR\bquestion\x12$\n" + + "\rallowMultiple\x18\x02 \x01(\bR\rallowMultiple\x12\x18\n" + + "\aoptions\x18\x03 \x03(\tR\aoptions\x1aA\n" + + "\rPollTerminate\x120\n" + + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x1a\xb6\x01\n" + + "\bPollVote\x124\n" + + "\x15targetAuthorAciBinary\x18\x01 \x01(\fR\x15targetAuthorAciBinary\x120\n" + + "\x13targetSentTimestamp\x18\x02 \x01(\x04R\x13targetSentTimestamp\x12$\n" + + "\roptionIndexes\x18\x03 \x03(\rR\roptionIndexes\x12\x1c\n" + + "\tvoteCount\x18\x04 \x01(\rR\tvoteCount\"Z\n" + "\x05Flags\x12\x0f\n" + "\vEND_SESSION\x10\x01\x12\x1b\n" + "\x17EXPIRATION_TIMER_UPDATE\x10\x02\x12\x16\n" + "\x12PROFILE_KEY_UPDATE\x10\x04\x12\v\n" + - "\aFORWARD\x10\b\"\xb0\x01\n" + + "\aFORWARD\x10\b\"\xbb\x01\n" + "\x0fProtocolVersion\x12\v\n" + "\aINITIAL\x10\x00\x12\x12\n" + "\x0eMESSAGE_TIMERS\x10\x01\x12\r\n" + @@ -8017,7 +8237,8 @@ const file_SignalService_proto_rawDesc = "" + "\tREACTIONS\x10\x04\x12\x1c\n" + "\x18CDN_SELECTOR_ATTACHMENTS\x10\x05\x12\f\n" + "\bMENTIONS\x10\x06\x12\f\n" + - "\bPAYMENTS\x10\a\x12\v\n" + + "\bPAYMENTS\x10\a\x12\t\n" + + "\x05POLLS\x10\b\x12\v\n" + "\aCURRENT\x10\a\x1a\x02\x10\x01J\x04\b\x03\x10\x04\"'\n" + "\vNullMessage\x12\x18\n" + "\apadding\x18\x01 \x01(\fR\apadding\"\x92\x01\n" + @@ -8434,7 +8655,7 @@ func file_SignalService_proto_rawDescGZIP() []byte { } var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 28) -var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 82) +var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 85) var file_SignalService_proto_goTypes = []any{ (Envelope_Type)(0), // 0: signalservice.Envelope.Type (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type @@ -8501,51 +8722,54 @@ var file_SignalService_proto_goTypes = []any{ (*DataMessage_GroupCallUpdate)(nil), // 62: signalservice.DataMessage.GroupCallUpdate (*DataMessage_StoryContext)(nil), // 63: signalservice.DataMessage.StoryContext (*DataMessage_GiftBadge)(nil), // 64: signalservice.DataMessage.GiftBadge - (*DataMessage_Payment_Amount)(nil), // 65: signalservice.DataMessage.Payment.Amount - (*DataMessage_Payment_Notification)(nil), // 66: signalservice.DataMessage.Payment.Notification - (*DataMessage_Payment_Activation)(nil), // 67: signalservice.DataMessage.Payment.Activation - (*DataMessage_Payment_Amount_MobileCoin)(nil), // 68: signalservice.DataMessage.Payment.Amount.MobileCoin - (*DataMessage_Payment_Notification_MobileCoin)(nil), // 69: signalservice.DataMessage.Payment.Notification.MobileCoin - (*DataMessage_Quote_QuotedAttachment)(nil), // 70: signalservice.DataMessage.Quote.QuotedAttachment - (*DataMessage_Contact_Name)(nil), // 71: signalservice.DataMessage.Contact.Name - (*DataMessage_Contact_Phone)(nil), // 72: signalservice.DataMessage.Contact.Phone - (*DataMessage_Contact_Email)(nil), // 73: signalservice.DataMessage.Contact.Email - (*DataMessage_Contact_PostalAddress)(nil), // 74: signalservice.DataMessage.Contact.PostalAddress - (*DataMessage_Contact_Avatar)(nil), // 75: signalservice.DataMessage.Contact.Avatar - (*TextAttachment_Gradient)(nil), // 76: signalservice.TextAttachment.Gradient - (*SyncMessage_Sent)(nil), // 77: signalservice.SyncMessage.Sent - (*SyncMessage_Contacts)(nil), // 78: signalservice.SyncMessage.Contacts - (*SyncMessage_Blocked)(nil), // 79: signalservice.SyncMessage.Blocked - (*SyncMessage_Request)(nil), // 80: signalservice.SyncMessage.Request - (*SyncMessage_Read)(nil), // 81: signalservice.SyncMessage.Read - (*SyncMessage_Viewed)(nil), // 82: signalservice.SyncMessage.Viewed - (*SyncMessage_Configuration)(nil), // 83: signalservice.SyncMessage.Configuration - (*SyncMessage_StickerPackOperation)(nil), // 84: signalservice.SyncMessage.StickerPackOperation - (*SyncMessage_ViewOnceOpen)(nil), // 85: signalservice.SyncMessage.ViewOnceOpen - (*SyncMessage_FetchLatest)(nil), // 86: signalservice.SyncMessage.FetchLatest - (*SyncMessage_Keys)(nil), // 87: signalservice.SyncMessage.Keys - (*SyncMessage_PniIdentity)(nil), // 88: signalservice.SyncMessage.PniIdentity - (*SyncMessage_MessageRequestResponse)(nil), // 89: signalservice.SyncMessage.MessageRequestResponse - (*SyncMessage_OutgoingPayment)(nil), // 90: signalservice.SyncMessage.OutgoingPayment - (*SyncMessage_PniChangeNumber)(nil), // 91: signalservice.SyncMessage.PniChangeNumber - (*SyncMessage_CallEvent)(nil), // 92: signalservice.SyncMessage.CallEvent - (*SyncMessage_CallLinkUpdate)(nil), // 93: signalservice.SyncMessage.CallLinkUpdate - (*SyncMessage_CallLogEvent)(nil), // 94: signalservice.SyncMessage.CallLogEvent - (*SyncMessage_DeleteForMe)(nil), // 95: signalservice.SyncMessage.DeleteForMe - (*SyncMessage_DeviceNameChange)(nil), // 96: signalservice.SyncMessage.DeviceNameChange - (*SyncMessage_AttachmentBackfillRequest)(nil), // 97: signalservice.SyncMessage.AttachmentBackfillRequest - (*SyncMessage_AttachmentBackfillResponse)(nil), // 98: signalservice.SyncMessage.AttachmentBackfillResponse - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 99: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 100: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 101: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 102: signalservice.SyncMessage.DeleteForMe.MessageDeletes - (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 103: signalservice.SyncMessage.DeleteForMe.AttachmentDelete - (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 104: signalservice.SyncMessage.DeleteForMe.ConversationDelete - (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 105: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 106: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 107: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList - (*ContactDetails_Avatar)(nil), // 108: signalservice.ContactDetails.Avatar - (*PaymentAddress_MobileCoin)(nil), // 109: signalservice.PaymentAddress.MobileCoin + (*DataMessage_PollCreate)(nil), // 65: signalservice.DataMessage.PollCreate + (*DataMessage_PollTerminate)(nil), // 66: signalservice.DataMessage.PollTerminate + (*DataMessage_PollVote)(nil), // 67: signalservice.DataMessage.PollVote + (*DataMessage_Payment_Amount)(nil), // 68: signalservice.DataMessage.Payment.Amount + (*DataMessage_Payment_Notification)(nil), // 69: signalservice.DataMessage.Payment.Notification + (*DataMessage_Payment_Activation)(nil), // 70: signalservice.DataMessage.Payment.Activation + (*DataMessage_Payment_Amount_MobileCoin)(nil), // 71: signalservice.DataMessage.Payment.Amount.MobileCoin + (*DataMessage_Payment_Notification_MobileCoin)(nil), // 72: signalservice.DataMessage.Payment.Notification.MobileCoin + (*DataMessage_Quote_QuotedAttachment)(nil), // 73: signalservice.DataMessage.Quote.QuotedAttachment + (*DataMessage_Contact_Name)(nil), // 74: signalservice.DataMessage.Contact.Name + (*DataMessage_Contact_Phone)(nil), // 75: signalservice.DataMessage.Contact.Phone + (*DataMessage_Contact_Email)(nil), // 76: signalservice.DataMessage.Contact.Email + (*DataMessage_Contact_PostalAddress)(nil), // 77: signalservice.DataMessage.Contact.PostalAddress + (*DataMessage_Contact_Avatar)(nil), // 78: signalservice.DataMessage.Contact.Avatar + (*TextAttachment_Gradient)(nil), // 79: signalservice.TextAttachment.Gradient + (*SyncMessage_Sent)(nil), // 80: signalservice.SyncMessage.Sent + (*SyncMessage_Contacts)(nil), // 81: signalservice.SyncMessage.Contacts + (*SyncMessage_Blocked)(nil), // 82: signalservice.SyncMessage.Blocked + (*SyncMessage_Request)(nil), // 83: signalservice.SyncMessage.Request + (*SyncMessage_Read)(nil), // 84: signalservice.SyncMessage.Read + (*SyncMessage_Viewed)(nil), // 85: signalservice.SyncMessage.Viewed + (*SyncMessage_Configuration)(nil), // 86: signalservice.SyncMessage.Configuration + (*SyncMessage_StickerPackOperation)(nil), // 87: signalservice.SyncMessage.StickerPackOperation + (*SyncMessage_ViewOnceOpen)(nil), // 88: signalservice.SyncMessage.ViewOnceOpen + (*SyncMessage_FetchLatest)(nil), // 89: signalservice.SyncMessage.FetchLatest + (*SyncMessage_Keys)(nil), // 90: signalservice.SyncMessage.Keys + (*SyncMessage_PniIdentity)(nil), // 91: signalservice.SyncMessage.PniIdentity + (*SyncMessage_MessageRequestResponse)(nil), // 92: signalservice.SyncMessage.MessageRequestResponse + (*SyncMessage_OutgoingPayment)(nil), // 93: signalservice.SyncMessage.OutgoingPayment + (*SyncMessage_PniChangeNumber)(nil), // 94: signalservice.SyncMessage.PniChangeNumber + (*SyncMessage_CallEvent)(nil), // 95: signalservice.SyncMessage.CallEvent + (*SyncMessage_CallLinkUpdate)(nil), // 96: signalservice.SyncMessage.CallLinkUpdate + (*SyncMessage_CallLogEvent)(nil), // 97: signalservice.SyncMessage.CallLogEvent + (*SyncMessage_DeleteForMe)(nil), // 98: signalservice.SyncMessage.DeleteForMe + (*SyncMessage_DeviceNameChange)(nil), // 99: signalservice.SyncMessage.DeviceNameChange + (*SyncMessage_AttachmentBackfillRequest)(nil), // 100: signalservice.SyncMessage.AttachmentBackfillRequest + (*SyncMessage_AttachmentBackfillResponse)(nil), // 101: signalservice.SyncMessage.AttachmentBackfillResponse + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 102: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 103: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 104: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 105: signalservice.SyncMessage.DeleteForMe.MessageDeletes + (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 106: signalservice.SyncMessage.DeleteForMe.AttachmentDelete + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 107: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 108: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 109: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 110: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + (*ContactDetails_Avatar)(nil), // 111: signalservice.ContactDetails.Avatar + (*PaymentAddress_MobileCoin)(nil), // 112: signalservice.PaymentAddress.MobileCoin } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type @@ -8577,108 +8801,111 @@ var file_SignalService_proto_depIdxs = []int32{ 56, // 26: signalservice.DataMessage.payment:type_name -> signalservice.DataMessage.Payment 63, // 27: signalservice.DataMessage.storyContext:type_name -> signalservice.DataMessage.StoryContext 64, // 28: signalservice.DataMessage.giftBadge:type_name -> signalservice.DataMessage.GiftBadge - 11, // 29: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type - 12, // 30: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action - 41, // 31: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 - 40, // 32: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer - 37, // 33: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment - 47, // 34: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange - 40, // 35: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer - 13, // 36: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style - 36, // 37: signalservice.TextAttachment.preview:type_name -> signalservice.Preview - 76, // 38: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient - 14, // 39: signalservice.Verified.state:type_name -> signalservice.Verified.State - 77, // 40: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent - 78, // 41: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts - 80, // 42: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request - 81, // 43: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read - 79, // 44: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked - 38, // 45: signalservice.SyncMessage.verified:type_name -> signalservice.Verified - 83, // 46: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration - 84, // 47: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation - 85, // 48: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen - 86, // 49: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest - 87, // 50: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys - 89, // 51: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse - 90, // 52: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment - 82, // 53: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed - 91, // 54: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber - 92, // 55: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent - 93, // 56: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate - 94, // 57: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 95, // 58: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe - 96, // 59: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange - 97, // 60: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest - 98, // 61: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse - 108, // 62: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 109, // 63: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin - 31, // 64: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 27, // 65: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style - 1, // 66: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 67: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 68: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 66, // 69: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 67, // 70: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 70, // 71: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 47, // 72: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 73: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 71, // 74: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 72, // 75: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 73, // 76: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 74, // 77: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 75, // 78: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 40, // 79: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 68, // 80: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 69, // 81: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 6, // 82: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 40, // 83: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 84: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 85: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 86: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 40, // 87: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 31, // 88: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 99, // 89: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 35, // 90: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 100, // 91: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 46, // 92: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 40, // 93: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 15, // 94: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 16, // 95: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 17, // 96: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 18, // 97: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 101, // 98: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 19, // 99: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 20, // 100: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 21, // 101: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 22, // 102: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type - 23, // 103: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 102, // 104: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes - 104, // 105: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete - 105, // 106: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - 103, // 107: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete - 48, // 108: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 109: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier - 48, // 110: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 111: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier - 107, // 112: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList - 24, // 113: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error - 49, // 114: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 115: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage - 49, // 116: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 117: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 118: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 119: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage - 48, // 120: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage - 49, // 121: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier - 40, // 122: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer - 25, // 123: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status - 106, // 124: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - 106, // 125: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - 126, // [126:126] is the sub-list for method output_type - 126, // [126:126] is the sub-list for method input_type - 126, // [126:126] is the sub-list for extension type_name - 126, // [126:126] is the sub-list for extension extendee - 0, // [0:126] is the sub-list for field type_name + 65, // 29: signalservice.DataMessage.pollCreate:type_name -> signalservice.DataMessage.PollCreate + 66, // 30: signalservice.DataMessage.pollTerminate:type_name -> signalservice.DataMessage.PollTerminate + 67, // 31: signalservice.DataMessage.pollVote:type_name -> signalservice.DataMessage.PollVote + 11, // 32: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type + 12, // 33: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action + 41, // 34: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 + 40, // 35: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer + 37, // 36: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment + 47, // 37: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange + 40, // 38: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer + 13, // 39: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style + 36, // 40: signalservice.TextAttachment.preview:type_name -> signalservice.Preview + 79, // 41: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient + 14, // 42: signalservice.Verified.state:type_name -> signalservice.Verified.State + 80, // 43: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent + 81, // 44: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts + 83, // 45: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request + 84, // 46: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read + 82, // 47: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked + 38, // 48: signalservice.SyncMessage.verified:type_name -> signalservice.Verified + 86, // 49: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration + 87, // 50: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation + 88, // 51: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen + 89, // 52: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest + 90, // 53: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys + 92, // 54: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse + 93, // 55: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment + 85, // 56: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed + 94, // 57: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber + 95, // 58: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent + 96, // 59: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate + 97, // 60: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent + 98, // 61: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe + 99, // 62: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange + 100, // 63: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest + 101, // 64: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse + 111, // 65: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 112, // 66: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin + 31, // 67: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 27, // 68: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style + 1, // 69: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 70: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 71: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 69, // 72: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 70, // 73: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 73, // 74: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 47, // 75: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 76: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 74, // 77: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 75, // 78: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 76, // 79: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 77, // 80: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 78, // 81: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 82: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 71, // 83: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 72, // 84: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 6, // 85: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 40, // 86: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 87: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 88: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 89: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 40, // 90: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 31, // 91: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 102, // 92: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 93: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 103, // 94: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 46, // 95: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 96: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 15, // 97: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 16, // 98: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 17, // 99: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 18, // 100: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 104, // 101: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 19, // 102: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 20, // 103: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 21, // 104: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 22, // 105: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 23, // 106: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 105, // 107: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes + 107, // 108: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 108, // 109: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 106, // 110: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete + 48, // 111: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 112: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier + 48, // 113: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 114: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier + 110, // 115: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + 24, // 116: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error + 49, // 117: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 118: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage + 49, // 119: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 120: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 121: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 122: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage + 48, // 123: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage + 49, // 124: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 40, // 125: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer + 25, // 126: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status + 109, // 127: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 109, // 128: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 129, // [129:129] is the sub-list for method output_type + 129, // [129:129] is the sub-list for method input_type + 129, // [129:129] is the sub-list for extension type_name + 129, // [129:129] is the sub-list for extension extendee + 0, // [0:129] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -8718,20 +8945,20 @@ func file_SignalService_proto_init() { (*DataMessage_Payment_Notification_)(nil), (*DataMessage_Payment_Activation_)(nil), } - file_SignalService_proto_msgTypes[37].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[40].OneofWrappers = []any{ (*DataMessage_Payment_Amount_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[38].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[41].OneofWrappers = []any{ (*DataMessage_Payment_Notification_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[62].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[65].OneofWrappers = []any{ (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[70].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[73].OneofWrappers = []any{ (*SyncMessage_AttachmentBackfillResponse_Attachments)(nil), (*SyncMessage_AttachmentBackfillResponse_Error_)(nil), } - file_SignalService_proto_msgTypes[78].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[81].OneofWrappers = []any{ (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment)(nil), (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_)(nil), } @@ -8741,7 +8968,7 @@ func file_SignalService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_SignalService_proto_rawDesc), len(file_SignalService_proto_rawDesc)), NumEnums: 28, - NumMessages: 82, + NumMessages: 85, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index a1fa8f9..249c4eb 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -177,6 +177,7 @@ message DataMessage { enum Type { NORMAL = 0; GIFT_BADGE = 1; + POLL = 2; } message QuotedAttachment { @@ -302,6 +303,7 @@ message DataMessage { CDN_SELECTOR_ATTACHMENTS = 5; MENTIONS = 6; PAYMENTS = 7; + POLLS = 8; CURRENT = 7; } @@ -309,6 +311,23 @@ message DataMessage { optional bytes receiptCredentialPresentation = 1; } + message PollCreate { + optional string question = 1; + optional bool allowMultiple = 2; + repeated string options = 3; + } + + message PollTerminate { + optional uint64 targetSentTimestamp = 1; + } + + message PollVote { + optional bytes targetAuthorAciBinary = 1; + optional uint64 targetSentTimestamp = 2; + repeated uint32 optionIndexes = 3; // must be in the range [0, options.length) from the PollCreate + optional uint32 voteCount = 4; // increment this by 1 each time you vote on a given poll + } + optional string body = 1; repeated AttachmentPointer attachments = 2; reserved /*groupV1*/ 3; @@ -331,7 +350,10 @@ message DataMessage { optional Payment payment = 20; optional StoryContext storyContext = 21; optional GiftBadge giftBadge = 22; - // NEXT ID: 24 + optional PollCreate pollCreate = 24; + optional PollTerminate pollTerminate = 25; + optional PollVote pollVote = 26; + // NEXT ID: 27 } message NullMessage { diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index b1969bc..52905c6 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: StickerResources.proto diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 33804f6..1294a3f 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: StorageService.proto diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index bb5b256..d512960 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: UnidentifiedDelivery.proto diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index ff48cda..ef45ba0 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: WebSocketResources.proto diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 3eaaed0..86e176a 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.6 +// protoc-gen-go v1.36.10 // protoc v3.21.12 // source: backuppb/Backup.proto @@ -1098,6 +1098,7 @@ const ( Quote_NORMAL Quote_Type = 1 Quote_GIFT_BADGE Quote_Type = 2 Quote_VIEW_ONCE Quote_Type = 3 + Quote_POLL Quote_Type = 4 ) // Enum value maps for Quote_Type. @@ -1107,12 +1108,14 @@ var ( 1: "NORMAL", 2: "GIFT_BADGE", 3: "VIEW_ONCE", + 4: "POLL", } Quote_Type_value = map[string]int32{ "UNKNOWN": 0, "NORMAL": 1, "GIFT_BADGE": 2, "VIEW_ONCE": 3, + "POLL": 4, } ) @@ -1247,7 +1250,7 @@ func (x IndividualCall_Type) Number() protoreflect.EnumNumber { // Deprecated: Use IndividualCall_Type.Descriptor instead. func (IndividualCall_Type) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{33, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 0} } type IndividualCall_Direction int32 @@ -1296,7 +1299,7 @@ func (x IndividualCall_Direction) Number() protoreflect.EnumNumber { // Deprecated: Use IndividualCall_Direction.Descriptor instead. func (IndividualCall_Direction) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{33, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 1} } type IndividualCall_State int32 @@ -1355,7 +1358,7 @@ func (x IndividualCall_State) Number() protoreflect.EnumNumber { // Deprecated: Use IndividualCall_State.Descriptor instead. func (IndividualCall_State) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{33, 2} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 2} } type GroupCall_State int32 @@ -1431,7 +1434,7 @@ func (x GroupCall_State) Number() protoreflect.EnumNumber { // Deprecated: Use GroupCall_State.Descriptor instead. func (GroupCall_State) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 0} } type SimpleChatUpdate_Type int32 @@ -1522,7 +1525,7 @@ func (x SimpleChatUpdate_Type) Number() protoreflect.EnumNumber { // Deprecated: Use SimpleChatUpdate_Type.Descriptor instead. func (SimpleChatUpdate_Type) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{36, 0} } type ChatStyle_WallpaperPreset int32 @@ -1628,7 +1631,7 @@ func (x ChatStyle_WallpaperPreset) Number() protoreflect.EnumNumber { // Deprecated: Use ChatStyle_WallpaperPreset.Descriptor instead. func (ChatStyle_WallpaperPreset) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 0} } type ChatStyle_BubbleColorPreset int32 @@ -1737,7 +1740,7 @@ func (x ChatStyle_BubbleColorPreset) Number() protoreflect.EnumNumber { // Deprecated: Use ChatStyle_BubbleColorPreset.Descriptor instead. func (ChatStyle_BubbleColorPreset) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 1} } type NotificationProfile_DayOfWeek int32 @@ -1801,7 +1804,7 @@ func (x NotificationProfile_DayOfWeek) Number() protoreflect.EnumNumber { // Deprecated: Use NotificationProfile_DayOfWeek.Descriptor instead. func (NotificationProfile_DayOfWeek) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{78, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 0} } // Represents the default "All chats" folder record vs all other custom folders @@ -1851,7 +1854,7 @@ func (x ChatFolder_FolderType) Number() protoreflect.EnumNumber { // Deprecated: Use ChatFolder_FolderType.Descriptor instead. func (ChatFolder_FolderType) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{81, 0} } type BackupInfo struct { @@ -3282,6 +3285,7 @@ type ChatItem struct { // *ChatItem_GiftBadge // *ChatItem_ViewOnceMessage // *ChatItem_DirectStoryReplyMessage + // *ChatItem_Poll Item isChatItem_Item `protobuf_oneof:"item"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -3488,6 +3492,15 @@ func (x *ChatItem) GetDirectStoryReplyMessage() *DirectStoryReplyMessage { return nil } +func (x *ChatItem) GetPoll() *Poll { + if x != nil { + if x, ok := x.Item.(*ChatItem_Poll); ok { + return x.Poll + } + } + return nil +} + type isChatItem_DirectionalDetails interface { isChatItem_DirectionalDetails() } @@ -3550,6 +3563,10 @@ type ChatItem_DirectStoryReplyMessage struct { DirectStoryReplyMessage *DirectStoryReplyMessage `protobuf:"bytes,19,opt,name=directStoryReplyMessage,proto3,oneof"` // group story reply messages are not backed up } +type ChatItem_Poll struct { + Poll *Poll `protobuf:"bytes,20,opt,name=poll,proto3,oneof"` +} + func (*ChatItem_StandardMessage) isChatItem_Item() {} func (*ChatItem_ContactMessage) isChatItem_Item() {} @@ -3568,6 +3585,8 @@ func (*ChatItem_ViewOnceMessage) isChatItem_Item() {} func (*ChatItem_DirectStoryReplyMessage) isChatItem_Item() {} +func (*ChatItem_Poll) isChatItem_Item() {} + type SendStatus struct { state protoimpl.MessageState `protogen:"open.v1"` RecipientId uint64 `protobuf:"varint,1,opt,name=recipientId,proto3" json:"recipientId,omitempty"` @@ -4958,6 +4977,74 @@ func (x *Reaction) GetSortOrder() uint64 { return 0 } +type Poll struct { + state protoimpl.MessageState `protogen:"open.v1"` + Question string `protobuf:"bytes,1,opt,name=question,proto3" json:"question,omitempty"` // Between 1-100 characters + AllowMultiple bool `protobuf:"varint,2,opt,name=allowMultiple,proto3" json:"allowMultiple,omitempty"` + Options []*Poll_PollOption `protobuf:"bytes,3,rep,name=options,proto3" json:"options,omitempty"` // At least two + HasEnded bool `protobuf:"varint,4,opt,name=hasEnded,proto3" json:"hasEnded,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Poll) Reset() { + *x = Poll{} + mi := &file_backuppb_Backup_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Poll) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Poll) ProtoMessage() {} + +func (x *Poll) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[32] + 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 Poll.ProtoReflect.Descriptor instead. +func (*Poll) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{32} +} + +func (x *Poll) GetQuestion() string { + if x != nil { + return x.Question + } + return "" +} + +func (x *Poll) GetAllowMultiple() bool { + if x != nil { + return x.AllowMultiple + } + return false +} + +func (x *Poll) GetOptions() []*Poll_PollOption { + if x != nil { + return x.Options + } + return nil +} + +func (x *Poll) GetHasEnded() bool { + if x != nil { + return x.HasEnded + } + return false +} + type ChatUpdateMessage struct { state protoimpl.MessageState `protogen:"open.v1"` // If unset, importers should ignore the update message without throwing an error. @@ -4973,6 +5060,7 @@ type ChatUpdateMessage struct { // *ChatUpdateMessage_IndividualCall // *ChatUpdateMessage_GroupCall // *ChatUpdateMessage_LearnedProfileChange + // *ChatUpdateMessage_PollTerminate Update isChatUpdateMessage_Update `protobuf_oneof:"update"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -4980,7 +5068,7 @@ type ChatUpdateMessage struct { func (x *ChatUpdateMessage) Reset() { *x = ChatUpdateMessage{} - mi := &file_backuppb_Backup_proto_msgTypes[32] + mi := &file_backuppb_Backup_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4992,7 +5080,7 @@ func (x *ChatUpdateMessage) String() string { func (*ChatUpdateMessage) ProtoMessage() {} func (x *ChatUpdateMessage) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[32] + mi := &file_backuppb_Backup_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5005,7 +5093,7 @@ func (x *ChatUpdateMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatUpdateMessage.ProtoReflect.Descriptor instead. func (*ChatUpdateMessage) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{32} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{33} } func (x *ChatUpdateMessage) GetUpdate() isChatUpdateMessage_Update { @@ -5096,6 +5184,15 @@ func (x *ChatUpdateMessage) GetLearnedProfileChange() *LearnedProfileChatUpdate return nil } +func (x *ChatUpdateMessage) GetPollTerminate() *PollTerminateUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_PollTerminate); ok { + return x.PollTerminate + } + } + return nil +} + type isChatUpdateMessage_Update interface { isChatUpdateMessage_Update() } @@ -5136,6 +5233,10 @@ type ChatUpdateMessage_LearnedProfileChange struct { LearnedProfileChange *LearnedProfileChatUpdate `protobuf:"bytes,9,opt,name=learnedProfileChange,proto3,oneof"` } +type ChatUpdateMessage_PollTerminate struct { + PollTerminate *PollTerminateUpdate `protobuf:"bytes,10,opt,name=pollTerminate,proto3,oneof"` +} + func (*ChatUpdateMessage_SimpleUpdate) isChatUpdateMessage_Update() {} func (*ChatUpdateMessage_GroupChange) isChatUpdateMessage_Update() {} @@ -5154,6 +5255,8 @@ func (*ChatUpdateMessage_GroupCall) isChatUpdateMessage_Update() {} func (*ChatUpdateMessage_LearnedProfileChange) isChatUpdateMessage_Update() {} +func (*ChatUpdateMessage_PollTerminate) isChatUpdateMessage_Update() {} + type IndividualCall struct { state protoimpl.MessageState `protogen:"open.v1"` CallId *uint64 `protobuf:"varint,1,opt,name=callId,proto3,oneof" json:"callId,omitempty"` @@ -5168,7 +5271,7 @@ type IndividualCall struct { func (x *IndividualCall) Reset() { *x = IndividualCall{} - mi := &file_backuppb_Backup_proto_msgTypes[33] + mi := &file_backuppb_Backup_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5180,7 +5283,7 @@ func (x *IndividualCall) String() string { func (*IndividualCall) ProtoMessage() {} func (x *IndividualCall) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[33] + mi := &file_backuppb_Backup_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5193,7 +5296,7 @@ func (x *IndividualCall) ProtoReflect() protoreflect.Message { // Deprecated: Use IndividualCall.ProtoReflect.Descriptor instead. func (*IndividualCall) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{33} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34} } func (x *IndividualCall) GetCallId() uint64 { @@ -5253,7 +5356,7 @@ type GroupCall struct { func (x *GroupCall) Reset() { *x = GroupCall{} - mi := &file_backuppb_Backup_proto_msgTypes[34] + mi := &file_backuppb_Backup_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5265,7 +5368,7 @@ func (x *GroupCall) String() string { func (*GroupCall) ProtoMessage() {} func (x *GroupCall) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[34] + mi := &file_backuppb_Backup_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5278,7 +5381,7 @@ func (x *GroupCall) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupCall.ProtoReflect.Descriptor instead. func (*GroupCall) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{34} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35} } func (x *GroupCall) GetCallId() uint64 { @@ -5339,7 +5442,7 @@ type SimpleChatUpdate struct { func (x *SimpleChatUpdate) Reset() { *x = SimpleChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[35] + mi := &file_backuppb_Backup_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5351,7 +5454,7 @@ func (x *SimpleChatUpdate) String() string { func (*SimpleChatUpdate) ProtoMessage() {} func (x *SimpleChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[35] + mi := &file_backuppb_Backup_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5364,7 +5467,7 @@ func (x *SimpleChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SimpleChatUpdate.ProtoReflect.Descriptor instead. func (*SimpleChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{35} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{36} } func (x *SimpleChatUpdate) GetType() SimpleChatUpdate_Type { @@ -5385,7 +5488,7 @@ type ExpirationTimerChatUpdate struct { func (x *ExpirationTimerChatUpdate) Reset() { *x = ExpirationTimerChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[36] + mi := &file_backuppb_Backup_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5397,7 +5500,7 @@ func (x *ExpirationTimerChatUpdate) String() string { func (*ExpirationTimerChatUpdate) ProtoMessage() {} func (x *ExpirationTimerChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[36] + mi := &file_backuppb_Backup_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5410,7 +5513,7 @@ func (x *ExpirationTimerChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpirationTimerChatUpdate.ProtoReflect.Descriptor instead. func (*ExpirationTimerChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{36} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{37} } func (x *ExpirationTimerChatUpdate) GetExpiresInMs() uint64 { @@ -5430,7 +5533,7 @@ type ProfileChangeChatUpdate struct { func (x *ProfileChangeChatUpdate) Reset() { *x = ProfileChangeChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[37] + mi := &file_backuppb_Backup_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5442,7 +5545,7 @@ func (x *ProfileChangeChatUpdate) String() string { func (*ProfileChangeChatUpdate) ProtoMessage() {} func (x *ProfileChangeChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[37] + mi := &file_backuppb_Backup_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5455,7 +5558,7 @@ func (x *ProfileChangeChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ProfileChangeChatUpdate.ProtoReflect.Descriptor instead. func (*ProfileChangeChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{37} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{38} } func (x *ProfileChangeChatUpdate) GetPreviousName() string { @@ -5487,7 +5590,7 @@ type LearnedProfileChatUpdate struct { func (x *LearnedProfileChatUpdate) Reset() { *x = LearnedProfileChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[38] + mi := &file_backuppb_Backup_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5499,7 +5602,7 @@ func (x *LearnedProfileChatUpdate) String() string { func (*LearnedProfileChatUpdate) ProtoMessage() {} func (x *LearnedProfileChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[38] + mi := &file_backuppb_Backup_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5512,7 +5615,7 @@ func (x *LearnedProfileChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use LearnedProfileChatUpdate.ProtoReflect.Descriptor instead. func (*LearnedProfileChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{38} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{39} } func (x *LearnedProfileChatUpdate) GetPreviousName() isLearnedProfileChatUpdate_PreviousName { @@ -5565,7 +5668,7 @@ type ThreadMergeChatUpdate struct { func (x *ThreadMergeChatUpdate) Reset() { *x = ThreadMergeChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[39] + mi := &file_backuppb_Backup_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5577,7 +5680,7 @@ func (x *ThreadMergeChatUpdate) String() string { func (*ThreadMergeChatUpdate) ProtoMessage() {} func (x *ThreadMergeChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[39] + mi := &file_backuppb_Backup_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5590,7 +5693,7 @@ func (x *ThreadMergeChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ThreadMergeChatUpdate.ProtoReflect.Descriptor instead. func (*ThreadMergeChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{39} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{40} } func (x *ThreadMergeChatUpdate) GetPreviousE164() uint64 { @@ -5609,7 +5712,7 @@ type SessionSwitchoverChatUpdate struct { func (x *SessionSwitchoverChatUpdate) Reset() { *x = SessionSwitchoverChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[40] + mi := &file_backuppb_Backup_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5621,7 +5724,7 @@ func (x *SessionSwitchoverChatUpdate) String() string { func (*SessionSwitchoverChatUpdate) ProtoMessage() {} func (x *SessionSwitchoverChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[40] + mi := &file_backuppb_Backup_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5634,7 +5737,7 @@ func (x *SessionSwitchoverChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionSwitchoverChatUpdate.ProtoReflect.Descriptor instead. func (*SessionSwitchoverChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{40} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{41} } func (x *SessionSwitchoverChatUpdate) GetE164() uint64 { @@ -5655,7 +5758,7 @@ type GroupChangeChatUpdate struct { func (x *GroupChangeChatUpdate) Reset() { *x = GroupChangeChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[41] + mi := &file_backuppb_Backup_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5667,7 +5770,7 @@ func (x *GroupChangeChatUpdate) String() string { func (*GroupChangeChatUpdate) ProtoMessage() {} func (x *GroupChangeChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[41] + mi := &file_backuppb_Backup_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5680,7 +5783,7 @@ func (x *GroupChangeChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChangeChatUpdate.ProtoReflect.Descriptor instead. func (*GroupChangeChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{41} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{42} } func (x *GroupChangeChatUpdate) GetUpdates() []*GroupChangeChatUpdate_Update { @@ -5699,7 +5802,7 @@ type GenericGroupUpdate struct { func (x *GenericGroupUpdate) Reset() { *x = GenericGroupUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[42] + mi := &file_backuppb_Backup_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5711,7 +5814,7 @@ func (x *GenericGroupUpdate) String() string { func (*GenericGroupUpdate) ProtoMessage() {} func (x *GenericGroupUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[42] + mi := &file_backuppb_Backup_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5724,7 +5827,7 @@ func (x *GenericGroupUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GenericGroupUpdate.ProtoReflect.Descriptor instead. func (*GenericGroupUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{42} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{43} } func (x *GenericGroupUpdate) GetUpdaterAci() []byte { @@ -5743,7 +5846,7 @@ type GroupCreationUpdate struct { func (x *GroupCreationUpdate) Reset() { *x = GroupCreationUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[43] + mi := &file_backuppb_Backup_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5755,7 +5858,7 @@ func (x *GroupCreationUpdate) String() string { func (*GroupCreationUpdate) ProtoMessage() {} func (x *GroupCreationUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[43] + mi := &file_backuppb_Backup_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5768,7 +5871,7 @@ func (x *GroupCreationUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupCreationUpdate.ProtoReflect.Descriptor instead. func (*GroupCreationUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{43} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{44} } func (x *GroupCreationUpdate) GetUpdaterAci() []byte { @@ -5789,7 +5892,7 @@ type GroupNameUpdate struct { func (x *GroupNameUpdate) Reset() { *x = GroupNameUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[44] + mi := &file_backuppb_Backup_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5801,7 +5904,7 @@ func (x *GroupNameUpdate) String() string { func (*GroupNameUpdate) ProtoMessage() {} func (x *GroupNameUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[44] + mi := &file_backuppb_Backup_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5814,7 +5917,7 @@ func (x *GroupNameUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupNameUpdate.ProtoReflect.Descriptor instead. func (*GroupNameUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{44} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{45} } func (x *GroupNameUpdate) GetUpdaterAci() []byte { @@ -5841,7 +5944,7 @@ type GroupAvatarUpdate struct { func (x *GroupAvatarUpdate) Reset() { *x = GroupAvatarUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[45] + mi := &file_backuppb_Backup_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5853,7 +5956,7 @@ func (x *GroupAvatarUpdate) String() string { func (*GroupAvatarUpdate) ProtoMessage() {} func (x *GroupAvatarUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[45] + mi := &file_backuppb_Backup_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5866,7 +5969,7 @@ func (x *GroupAvatarUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupAvatarUpdate.ProtoReflect.Descriptor instead. func (*GroupAvatarUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{45} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{46} } func (x *GroupAvatarUpdate) GetUpdaterAci() []byte { @@ -5894,7 +5997,7 @@ type GroupDescriptionUpdate struct { func (x *GroupDescriptionUpdate) Reset() { *x = GroupDescriptionUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[46] + mi := &file_backuppb_Backup_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5906,7 +6009,7 @@ func (x *GroupDescriptionUpdate) String() string { func (*GroupDescriptionUpdate) ProtoMessage() {} func (x *GroupDescriptionUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[46] + mi := &file_backuppb_Backup_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5919,7 +6022,7 @@ func (x *GroupDescriptionUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupDescriptionUpdate.ProtoReflect.Descriptor instead. func (*GroupDescriptionUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{46} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{47} } func (x *GroupDescriptionUpdate) GetUpdaterAci() []byte { @@ -5946,7 +6049,7 @@ type GroupMembershipAccessLevelChangeUpdate struct { func (x *GroupMembershipAccessLevelChangeUpdate) Reset() { *x = GroupMembershipAccessLevelChangeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[47] + mi := &file_backuppb_Backup_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5958,7 +6061,7 @@ func (x *GroupMembershipAccessLevelChangeUpdate) String() string { func (*GroupMembershipAccessLevelChangeUpdate) ProtoMessage() {} func (x *GroupMembershipAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[47] + mi := &file_backuppb_Backup_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5971,7 +6074,7 @@ func (x *GroupMembershipAccessLevelChangeUpdate) ProtoReflect() protoreflect.Mes // Deprecated: Use GroupMembershipAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. func (*GroupMembershipAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{47} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{48} } func (x *GroupMembershipAccessLevelChangeUpdate) GetUpdaterAci() []byte { @@ -5998,7 +6101,7 @@ type GroupAttributesAccessLevelChangeUpdate struct { func (x *GroupAttributesAccessLevelChangeUpdate) Reset() { *x = GroupAttributesAccessLevelChangeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[48] + mi := &file_backuppb_Backup_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6010,7 +6113,7 @@ func (x *GroupAttributesAccessLevelChangeUpdate) String() string { func (*GroupAttributesAccessLevelChangeUpdate) ProtoMessage() {} func (x *GroupAttributesAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[48] + mi := &file_backuppb_Backup_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6023,7 +6126,7 @@ func (x *GroupAttributesAccessLevelChangeUpdate) ProtoReflect() protoreflect.Mes // Deprecated: Use GroupAttributesAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. func (*GroupAttributesAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{48} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{49} } func (x *GroupAttributesAccessLevelChangeUpdate) GetUpdaterAci() []byte { @@ -6050,7 +6153,7 @@ type GroupAnnouncementOnlyChangeUpdate struct { func (x *GroupAnnouncementOnlyChangeUpdate) Reset() { *x = GroupAnnouncementOnlyChangeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[49] + mi := &file_backuppb_Backup_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6062,7 +6165,7 @@ func (x *GroupAnnouncementOnlyChangeUpdate) String() string { func (*GroupAnnouncementOnlyChangeUpdate) ProtoMessage() {} func (x *GroupAnnouncementOnlyChangeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[49] + mi := &file_backuppb_Backup_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6075,7 +6178,7 @@ func (x *GroupAnnouncementOnlyChangeUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use GroupAnnouncementOnlyChangeUpdate.ProtoReflect.Descriptor instead. func (*GroupAnnouncementOnlyChangeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{49} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{50} } func (x *GroupAnnouncementOnlyChangeUpdate) GetUpdaterAci() []byte { @@ -6104,7 +6207,7 @@ type GroupAdminStatusUpdate struct { func (x *GroupAdminStatusUpdate) Reset() { *x = GroupAdminStatusUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[50] + mi := &file_backuppb_Backup_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6116,7 +6219,7 @@ func (x *GroupAdminStatusUpdate) String() string { func (*GroupAdminStatusUpdate) ProtoMessage() {} func (x *GroupAdminStatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[50] + mi := &file_backuppb_Backup_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6129,7 +6232,7 @@ func (x *GroupAdminStatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupAdminStatusUpdate.ProtoReflect.Descriptor instead. func (*GroupAdminStatusUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{50} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{51} } func (x *GroupAdminStatusUpdate) GetUpdaterAci() []byte { @@ -6162,7 +6265,7 @@ type GroupMemberLeftUpdate struct { func (x *GroupMemberLeftUpdate) Reset() { *x = GroupMemberLeftUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[51] + mi := &file_backuppb_Backup_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6174,7 +6277,7 @@ func (x *GroupMemberLeftUpdate) String() string { func (*GroupMemberLeftUpdate) ProtoMessage() {} func (x *GroupMemberLeftUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[51] + mi := &file_backuppb_Backup_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6187,7 +6290,7 @@ func (x *GroupMemberLeftUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberLeftUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberLeftUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{51} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{52} } func (x *GroupMemberLeftUpdate) GetAci() []byte { @@ -6207,7 +6310,7 @@ type GroupMemberRemovedUpdate struct { func (x *GroupMemberRemovedUpdate) Reset() { *x = GroupMemberRemovedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[52] + mi := &file_backuppb_Backup_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6219,7 +6322,7 @@ func (x *GroupMemberRemovedUpdate) String() string { func (*GroupMemberRemovedUpdate) ProtoMessage() {} func (x *GroupMemberRemovedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[52] + mi := &file_backuppb_Backup_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6232,7 +6335,7 @@ func (x *GroupMemberRemovedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberRemovedUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberRemovedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{52} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{53} } func (x *GroupMemberRemovedUpdate) GetRemoverAci() []byte { @@ -6258,7 +6361,7 @@ type SelfInvitedToGroupUpdate struct { func (x *SelfInvitedToGroupUpdate) Reset() { *x = SelfInvitedToGroupUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[53] + mi := &file_backuppb_Backup_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6270,7 +6373,7 @@ func (x *SelfInvitedToGroupUpdate) String() string { func (*SelfInvitedToGroupUpdate) ProtoMessage() {} func (x *SelfInvitedToGroupUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[53] + mi := &file_backuppb_Backup_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6283,7 +6386,7 @@ func (x *SelfInvitedToGroupUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SelfInvitedToGroupUpdate.ProtoReflect.Descriptor instead. func (*SelfInvitedToGroupUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{53} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{54} } func (x *SelfInvitedToGroupUpdate) GetInviterAci() []byte { @@ -6303,7 +6406,7 @@ type SelfInvitedOtherUserToGroupUpdate struct { func (x *SelfInvitedOtherUserToGroupUpdate) Reset() { *x = SelfInvitedOtherUserToGroupUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[54] + mi := &file_backuppb_Backup_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6315,7 +6418,7 @@ func (x *SelfInvitedOtherUserToGroupUpdate) String() string { func (*SelfInvitedOtherUserToGroupUpdate) ProtoMessage() {} func (x *SelfInvitedOtherUserToGroupUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[54] + mi := &file_backuppb_Backup_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6328,7 +6431,7 @@ func (x *SelfInvitedOtherUserToGroupUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use SelfInvitedOtherUserToGroupUpdate.ProtoReflect.Descriptor instead. func (*SelfInvitedOtherUserToGroupUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{54} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{55} } func (x *SelfInvitedOtherUserToGroupUpdate) GetInviteeServiceId() []byte { @@ -6349,7 +6452,7 @@ type GroupUnknownInviteeUpdate struct { func (x *GroupUnknownInviteeUpdate) Reset() { *x = GroupUnknownInviteeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[55] + mi := &file_backuppb_Backup_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6361,7 +6464,7 @@ func (x *GroupUnknownInviteeUpdate) String() string { func (*GroupUnknownInviteeUpdate) ProtoMessage() {} func (x *GroupUnknownInviteeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[55] + mi := &file_backuppb_Backup_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6374,7 +6477,7 @@ func (x *GroupUnknownInviteeUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupUnknownInviteeUpdate.ProtoReflect.Descriptor instead. func (*GroupUnknownInviteeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{55} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{56} } func (x *GroupUnknownInviteeUpdate) GetInviterAci() []byte { @@ -6401,7 +6504,7 @@ type GroupInvitationAcceptedUpdate struct { func (x *GroupInvitationAcceptedUpdate) Reset() { *x = GroupInvitationAcceptedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[56] + mi := &file_backuppb_Backup_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6413,7 +6516,7 @@ func (x *GroupInvitationAcceptedUpdate) String() string { func (*GroupInvitationAcceptedUpdate) ProtoMessage() {} func (x *GroupInvitationAcceptedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[56] + mi := &file_backuppb_Backup_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6426,7 +6529,7 @@ func (x *GroupInvitationAcceptedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInvitationAcceptedUpdate.ProtoReflect.Descriptor instead. func (*GroupInvitationAcceptedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{56} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{57} } func (x *GroupInvitationAcceptedUpdate) GetInviterAci() []byte { @@ -6454,7 +6557,7 @@ type GroupInvitationDeclinedUpdate struct { func (x *GroupInvitationDeclinedUpdate) Reset() { *x = GroupInvitationDeclinedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[57] + mi := &file_backuppb_Backup_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6466,7 +6569,7 @@ func (x *GroupInvitationDeclinedUpdate) String() string { func (*GroupInvitationDeclinedUpdate) ProtoMessage() {} func (x *GroupInvitationDeclinedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[57] + mi := &file_backuppb_Backup_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6479,7 +6582,7 @@ func (x *GroupInvitationDeclinedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInvitationDeclinedUpdate.ProtoReflect.Descriptor instead. func (*GroupInvitationDeclinedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{57} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{58} } func (x *GroupInvitationDeclinedUpdate) GetInviterAci() []byte { @@ -6505,7 +6608,7 @@ type GroupMemberJoinedUpdate struct { func (x *GroupMemberJoinedUpdate) Reset() { *x = GroupMemberJoinedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[58] + mi := &file_backuppb_Backup_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6517,7 +6620,7 @@ func (x *GroupMemberJoinedUpdate) String() string { func (*GroupMemberJoinedUpdate) ProtoMessage() {} func (x *GroupMemberJoinedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[58] + mi := &file_backuppb_Backup_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6530,7 +6633,7 @@ func (x *GroupMemberJoinedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberJoinedUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberJoinedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{58} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{59} } func (x *GroupMemberJoinedUpdate) GetNewMemberAci() []byte { @@ -6553,7 +6656,7 @@ type GroupMemberAddedUpdate struct { func (x *GroupMemberAddedUpdate) Reset() { *x = GroupMemberAddedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[59] + mi := &file_backuppb_Backup_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6565,7 +6668,7 @@ func (x *GroupMemberAddedUpdate) String() string { func (*GroupMemberAddedUpdate) ProtoMessage() {} func (x *GroupMemberAddedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[59] + mi := &file_backuppb_Backup_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6578,7 +6681,7 @@ func (x *GroupMemberAddedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberAddedUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberAddedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{59} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{60} } func (x *GroupMemberAddedUpdate) GetUpdaterAci() []byte { @@ -6619,7 +6722,7 @@ type GroupSelfInvitationRevokedUpdate struct { func (x *GroupSelfInvitationRevokedUpdate) Reset() { *x = GroupSelfInvitationRevokedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[60] + mi := &file_backuppb_Backup_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6631,7 +6734,7 @@ func (x *GroupSelfInvitationRevokedUpdate) String() string { func (*GroupSelfInvitationRevokedUpdate) ProtoMessage() {} func (x *GroupSelfInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[60] + mi := &file_backuppb_Backup_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6644,7 +6747,7 @@ func (x *GroupSelfInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupSelfInvitationRevokedUpdate.ProtoReflect.Descriptor instead. func (*GroupSelfInvitationRevokedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{60} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{61} } func (x *GroupSelfInvitationRevokedUpdate) GetRevokerAci() []byte { @@ -6670,7 +6773,7 @@ type GroupInvitationRevokedUpdate struct { func (x *GroupInvitationRevokedUpdate) Reset() { *x = GroupInvitationRevokedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[61] + mi := &file_backuppb_Backup_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6682,7 +6785,7 @@ func (x *GroupInvitationRevokedUpdate) String() string { func (*GroupInvitationRevokedUpdate) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[61] + mi := &file_backuppb_Backup_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6695,7 +6798,7 @@ func (x *GroupInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInvitationRevokedUpdate.ProtoReflect.Descriptor instead. func (*GroupInvitationRevokedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{61} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{62} } func (x *GroupInvitationRevokedUpdate) GetUpdaterAci() []byte { @@ -6721,7 +6824,7 @@ type GroupJoinRequestUpdate struct { func (x *GroupJoinRequestUpdate) Reset() { *x = GroupJoinRequestUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[62] + mi := &file_backuppb_Backup_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6733,7 +6836,7 @@ func (x *GroupJoinRequestUpdate) String() string { func (*GroupJoinRequestUpdate) ProtoMessage() {} func (x *GroupJoinRequestUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[62] + mi := &file_backuppb_Backup_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6746,7 +6849,7 @@ func (x *GroupJoinRequestUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinRequestUpdate.ProtoReflect.Descriptor instead. func (*GroupJoinRequestUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{62} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{63} } func (x *GroupJoinRequestUpdate) GetRequestorAci() []byte { @@ -6768,7 +6871,7 @@ type GroupJoinRequestApprovalUpdate struct { func (x *GroupJoinRequestApprovalUpdate) Reset() { *x = GroupJoinRequestApprovalUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[63] + mi := &file_backuppb_Backup_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6780,7 +6883,7 @@ func (x *GroupJoinRequestApprovalUpdate) String() string { func (*GroupJoinRequestApprovalUpdate) ProtoMessage() {} func (x *GroupJoinRequestApprovalUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[63] + mi := &file_backuppb_Backup_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6793,7 +6896,7 @@ func (x *GroupJoinRequestApprovalUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinRequestApprovalUpdate.ProtoReflect.Descriptor instead. func (*GroupJoinRequestApprovalUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{63} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{64} } func (x *GroupJoinRequestApprovalUpdate) GetRequestorAci() []byte { @@ -6826,7 +6929,7 @@ type GroupJoinRequestCanceledUpdate struct { func (x *GroupJoinRequestCanceledUpdate) Reset() { *x = GroupJoinRequestCanceledUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[64] + mi := &file_backuppb_Backup_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6838,7 +6941,7 @@ func (x *GroupJoinRequestCanceledUpdate) String() string { func (*GroupJoinRequestCanceledUpdate) ProtoMessage() {} func (x *GroupJoinRequestCanceledUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[64] + mi := &file_backuppb_Backup_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6851,7 +6954,7 @@ func (x *GroupJoinRequestCanceledUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinRequestCanceledUpdate.ProtoReflect.Descriptor instead. func (*GroupJoinRequestCanceledUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{64} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{65} } func (x *GroupJoinRequestCanceledUpdate) GetRequestorAci() []byte { @@ -6877,7 +6980,7 @@ type GroupSequenceOfRequestsAndCancelsUpdate struct { func (x *GroupSequenceOfRequestsAndCancelsUpdate) Reset() { *x = GroupSequenceOfRequestsAndCancelsUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[65] + mi := &file_backuppb_Backup_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6889,7 +6992,7 @@ func (x *GroupSequenceOfRequestsAndCancelsUpdate) String() string { func (*GroupSequenceOfRequestsAndCancelsUpdate) ProtoMessage() {} func (x *GroupSequenceOfRequestsAndCancelsUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[65] + mi := &file_backuppb_Backup_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6902,7 +7005,7 @@ func (x *GroupSequenceOfRequestsAndCancelsUpdate) ProtoReflect() protoreflect.Me // Deprecated: Use GroupSequenceOfRequestsAndCancelsUpdate.ProtoReflect.Descriptor instead. func (*GroupSequenceOfRequestsAndCancelsUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{65} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{66} } func (x *GroupSequenceOfRequestsAndCancelsUpdate) GetRequestorAci() []byte { @@ -6928,7 +7031,7 @@ type GroupInviteLinkResetUpdate struct { func (x *GroupInviteLinkResetUpdate) Reset() { *x = GroupInviteLinkResetUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[66] + mi := &file_backuppb_Backup_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6940,7 +7043,7 @@ func (x *GroupInviteLinkResetUpdate) String() string { func (*GroupInviteLinkResetUpdate) ProtoMessage() {} func (x *GroupInviteLinkResetUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[66] + mi := &file_backuppb_Backup_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6953,7 +7056,7 @@ func (x *GroupInviteLinkResetUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLinkResetUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkResetUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{66} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{67} } func (x *GroupInviteLinkResetUpdate) GetUpdaterAci() []byte { @@ -6973,7 +7076,7 @@ type GroupInviteLinkEnabledUpdate struct { func (x *GroupInviteLinkEnabledUpdate) Reset() { *x = GroupInviteLinkEnabledUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[67] + mi := &file_backuppb_Backup_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6985,7 +7088,7 @@ func (x *GroupInviteLinkEnabledUpdate) String() string { func (*GroupInviteLinkEnabledUpdate) ProtoMessage() {} func (x *GroupInviteLinkEnabledUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[67] + mi := &file_backuppb_Backup_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6998,7 +7101,7 @@ func (x *GroupInviteLinkEnabledUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLinkEnabledUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkEnabledUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{67} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{68} } func (x *GroupInviteLinkEnabledUpdate) GetUpdaterAci() []byte { @@ -7025,7 +7128,7 @@ type GroupInviteLinkAdminApprovalUpdate struct { func (x *GroupInviteLinkAdminApprovalUpdate) Reset() { *x = GroupInviteLinkAdminApprovalUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[68] + mi := &file_backuppb_Backup_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7037,7 +7140,7 @@ func (x *GroupInviteLinkAdminApprovalUpdate) String() string { func (*GroupInviteLinkAdminApprovalUpdate) ProtoMessage() {} func (x *GroupInviteLinkAdminApprovalUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[68] + mi := &file_backuppb_Backup_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7050,7 +7153,7 @@ func (x *GroupInviteLinkAdminApprovalUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use GroupInviteLinkAdminApprovalUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkAdminApprovalUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{68} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{69} } func (x *GroupInviteLinkAdminApprovalUpdate) GetUpdaterAci() []byte { @@ -7076,7 +7179,7 @@ type GroupInviteLinkDisabledUpdate struct { func (x *GroupInviteLinkDisabledUpdate) Reset() { *x = GroupInviteLinkDisabledUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[69] + mi := &file_backuppb_Backup_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7088,7 +7191,7 @@ func (x *GroupInviteLinkDisabledUpdate) String() string { func (*GroupInviteLinkDisabledUpdate) ProtoMessage() {} func (x *GroupInviteLinkDisabledUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[69] + mi := &file_backuppb_Backup_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7101,7 +7204,7 @@ func (x *GroupInviteLinkDisabledUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLinkDisabledUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkDisabledUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{69} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{70} } func (x *GroupInviteLinkDisabledUpdate) GetUpdaterAci() []byte { @@ -7120,7 +7223,7 @@ type GroupMemberJoinedByLinkUpdate struct { func (x *GroupMemberJoinedByLinkUpdate) Reset() { *x = GroupMemberJoinedByLinkUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[70] + mi := &file_backuppb_Backup_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7132,7 +7235,7 @@ func (x *GroupMemberJoinedByLinkUpdate) String() string { func (*GroupMemberJoinedByLinkUpdate) ProtoMessage() {} func (x *GroupMemberJoinedByLinkUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[70] + mi := &file_backuppb_Backup_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7145,7 +7248,7 @@ func (x *GroupMemberJoinedByLinkUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberJoinedByLinkUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberJoinedByLinkUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{70} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{71} } func (x *GroupMemberJoinedByLinkUpdate) GetNewMemberAci() []byte { @@ -7164,7 +7267,7 @@ type GroupV2MigrationUpdate struct { func (x *GroupV2MigrationUpdate) Reset() { *x = GroupV2MigrationUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[71] + mi := &file_backuppb_Backup_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7176,7 +7279,7 @@ func (x *GroupV2MigrationUpdate) String() string { func (*GroupV2MigrationUpdate) ProtoMessage() {} func (x *GroupV2MigrationUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[71] + mi := &file_backuppb_Backup_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7189,7 +7292,7 @@ func (x *GroupV2MigrationUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupV2MigrationUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{71} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{72} } // Another user migrated gv1->gv2 but was unable to add @@ -7202,7 +7305,7 @@ type GroupV2MigrationSelfInvitedUpdate struct { func (x *GroupV2MigrationSelfInvitedUpdate) Reset() { *x = GroupV2MigrationSelfInvitedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[72] + mi := &file_backuppb_Backup_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7214,7 +7317,7 @@ func (x *GroupV2MigrationSelfInvitedUpdate) String() string { func (*GroupV2MigrationSelfInvitedUpdate) ProtoMessage() {} func (x *GroupV2MigrationSelfInvitedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[72] + mi := &file_backuppb_Backup_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7227,7 +7330,7 @@ func (x *GroupV2MigrationSelfInvitedUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use GroupV2MigrationSelfInvitedUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationSelfInvitedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{72} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{73} } // The local user migrated gv1->gv2 but was unable to @@ -7242,7 +7345,7 @@ type GroupV2MigrationInvitedMembersUpdate struct { func (x *GroupV2MigrationInvitedMembersUpdate) Reset() { *x = GroupV2MigrationInvitedMembersUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[73] + mi := &file_backuppb_Backup_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7254,7 +7357,7 @@ func (x *GroupV2MigrationInvitedMembersUpdate) String() string { func (*GroupV2MigrationInvitedMembersUpdate) ProtoMessage() {} func (x *GroupV2MigrationInvitedMembersUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[73] + mi := &file_backuppb_Backup_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7267,7 +7370,7 @@ func (x *GroupV2MigrationInvitedMembersUpdate) ProtoReflect() protoreflect.Messa // Deprecated: Use GroupV2MigrationInvitedMembersUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationInvitedMembersUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{73} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{74} } func (x *GroupV2MigrationInvitedMembersUpdate) GetInvitedMembersCount() uint32 { @@ -7289,7 +7392,7 @@ type GroupV2MigrationDroppedMembersUpdate struct { func (x *GroupV2MigrationDroppedMembersUpdate) Reset() { *x = GroupV2MigrationDroppedMembersUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[74] + mi := &file_backuppb_Backup_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7301,7 +7404,7 @@ func (x *GroupV2MigrationDroppedMembersUpdate) String() string { func (*GroupV2MigrationDroppedMembersUpdate) ProtoMessage() {} func (x *GroupV2MigrationDroppedMembersUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[74] + mi := &file_backuppb_Backup_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7314,7 +7417,7 @@ func (x *GroupV2MigrationDroppedMembersUpdate) ProtoReflect() protoreflect.Messa // Deprecated: Use GroupV2MigrationDroppedMembersUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationDroppedMembersUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{74} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{75} } func (x *GroupV2MigrationDroppedMembersUpdate) GetDroppedMembersCount() uint32 { @@ -7335,7 +7438,7 @@ type GroupExpirationTimerUpdate struct { func (x *GroupExpirationTimerUpdate) Reset() { *x = GroupExpirationTimerUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[75] + mi := &file_backuppb_Backup_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7347,7 +7450,7 @@ func (x *GroupExpirationTimerUpdate) String() string { func (*GroupExpirationTimerUpdate) ProtoMessage() {} func (x *GroupExpirationTimerUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[75] + mi := &file_backuppb_Backup_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7360,7 +7463,7 @@ func (x *GroupExpirationTimerUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupExpirationTimerUpdate.ProtoReflect.Descriptor instead. func (*GroupExpirationTimerUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{75} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{76} } func (x *GroupExpirationTimerUpdate) GetExpiresInMs() uint64 { @@ -7377,6 +7480,58 @@ func (x *GroupExpirationTimerUpdate) GetUpdaterAci() []byte { return nil } +type PollTerminateUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetSentTimestamp uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp,proto3" json:"targetSentTimestamp,omitempty"` + Question string `protobuf:"bytes,2,opt,name=question,proto3" json:"question,omitempty"` // Between 1-100 characters + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PollTerminateUpdate) Reset() { + *x = PollTerminateUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PollTerminateUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PollTerminateUpdate) ProtoMessage() {} + +func (x *PollTerminateUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[77] + 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 PollTerminateUpdate.ProtoReflect.Descriptor instead. +func (*PollTerminateUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77} +} + +func (x *PollTerminateUpdate) GetTargetSentTimestamp() uint64 { + if x != nil { + return x.TargetSentTimestamp + } + return 0 +} + +func (x *PollTerminateUpdate) GetQuestion() string { + if x != nil { + return x.Question + } + return "" +} + type StickerPack struct { state protoimpl.MessageState `protogen:"open.v1"` PackId []byte `protobuf:"bytes,1,opt,name=packId,proto3" json:"packId,omitempty"` @@ -7387,7 +7542,7 @@ type StickerPack struct { func (x *StickerPack) Reset() { *x = StickerPack{} - mi := &file_backuppb_Backup_proto_msgTypes[76] + mi := &file_backuppb_Backup_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7399,7 +7554,7 @@ func (x *StickerPack) String() string { func (*StickerPack) ProtoMessage() {} func (x *StickerPack) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[76] + mi := &file_backuppb_Backup_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7412,7 +7567,7 @@ func (x *StickerPack) ProtoReflect() protoreflect.Message { // Deprecated: Use StickerPack.ProtoReflect.Descriptor instead. func (*StickerPack) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{76} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} } func (x *StickerPack) GetPackId() []byte { @@ -7453,7 +7608,7 @@ type ChatStyle struct { func (x *ChatStyle) Reset() { *x = ChatStyle{} - mi := &file_backuppb_Backup_proto_msgTypes[77] + mi := &file_backuppb_Backup_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7465,7 +7620,7 @@ func (x *ChatStyle) String() string { func (*ChatStyle) ProtoMessage() {} func (x *ChatStyle) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[77] + mi := &file_backuppb_Backup_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7478,7 +7633,7 @@ func (x *ChatStyle) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle.ProtoReflect.Descriptor instead. func (*ChatStyle) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} } func (x *ChatStyle) GetWallpaper() isChatStyle_Wallpaper { @@ -7610,7 +7765,7 @@ type NotificationProfile struct { func (x *NotificationProfile) Reset() { *x = NotificationProfile{} - mi := &file_backuppb_Backup_proto_msgTypes[78] + mi := &file_backuppb_Backup_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7622,7 +7777,7 @@ func (x *NotificationProfile) String() string { func (*NotificationProfile) ProtoMessage() {} func (x *NotificationProfile) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[78] + mi := &file_backuppb_Backup_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7635,7 +7790,7 @@ func (x *NotificationProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use NotificationProfile.ProtoReflect.Descriptor instead. func (*NotificationProfile) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80} } func (x *NotificationProfile) GetName() string { @@ -7741,7 +7896,7 @@ type ChatFolder struct { func (x *ChatFolder) Reset() { *x = ChatFolder{} - mi := &file_backuppb_Backup_proto_msgTypes[79] + mi := &file_backuppb_Backup_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7753,7 +7908,7 @@ func (x *ChatFolder) String() string { func (*ChatFolder) ProtoMessage() {} func (x *ChatFolder) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[79] + mi := &file_backuppb_Backup_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7766,7 +7921,7 @@ func (x *ChatFolder) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatFolder.ProtoReflect.Descriptor instead. func (*ChatFolder) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{81} } func (x *ChatFolder) GetName() string { @@ -7843,7 +7998,7 @@ type AccountData_UsernameLink struct { func (x *AccountData_UsernameLink) Reset() { *x = AccountData_UsernameLink{} - mi := &file_backuppb_Backup_proto_msgTypes[80] + mi := &file_backuppb_Backup_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7855,7 +8010,7 @@ func (x *AccountData_UsernameLink) String() string { func (*AccountData_UsernameLink) ProtoMessage() {} func (x *AccountData_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[80] + mi := &file_backuppb_Backup_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7922,7 +8077,7 @@ type AccountData_AccountSettings struct { func (x *AccountData_AccountSettings) Reset() { *x = AccountData_AccountSettings{} - mi := &file_backuppb_Backup_proto_msgTypes[81] + mi := &file_backuppb_Backup_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7934,7 +8089,7 @@ func (x *AccountData_AccountSettings) String() string { func (*AccountData_AccountSettings) ProtoMessage() {} func (x *AccountData_AccountSettings) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[81] + mi := &file_backuppb_Backup_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8108,7 +8263,7 @@ type AccountData_SubscriberData struct { func (x *AccountData_SubscriberData) Reset() { *x = AccountData_SubscriberData{} - mi := &file_backuppb_Backup_proto_msgTypes[82] + mi := &file_backuppb_Backup_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8120,7 +8275,7 @@ func (x *AccountData_SubscriberData) String() string { func (*AccountData_SubscriberData) ProtoMessage() {} func (x *AccountData_SubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[82] + mi := &file_backuppb_Backup_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8173,7 +8328,7 @@ type AccountData_IAPSubscriberData struct { func (x *AccountData_IAPSubscriberData) Reset() { *x = AccountData_IAPSubscriberData{} - mi := &file_backuppb_Backup_proto_msgTypes[83] + mi := &file_backuppb_Backup_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8185,7 +8340,7 @@ func (x *AccountData_IAPSubscriberData) String() string { func (*AccountData_IAPSubscriberData) ProtoMessage() {} func (x *AccountData_IAPSubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[83] + mi := &file_backuppb_Backup_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8261,7 +8416,7 @@ type Contact_Registered struct { func (x *Contact_Registered) Reset() { *x = Contact_Registered{} - mi := &file_backuppb_Backup_proto_msgTypes[84] + mi := &file_backuppb_Backup_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8273,7 +8428,7 @@ func (x *Contact_Registered) String() string { func (*Contact_Registered) ProtoMessage() {} func (x *Contact_Registered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[84] + mi := &file_backuppb_Backup_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8298,7 +8453,7 @@ type Contact_NotRegistered struct { func (x *Contact_NotRegistered) Reset() { *x = Contact_NotRegistered{} - mi := &file_backuppb_Backup_proto_msgTypes[85] + mi := &file_backuppb_Backup_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8310,7 +8465,7 @@ func (x *Contact_NotRegistered) String() string { func (*Contact_NotRegistered) ProtoMessage() {} func (x *Contact_NotRegistered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[85] + mi := &file_backuppb_Backup_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8343,7 +8498,7 @@ type Contact_Name struct { func (x *Contact_Name) Reset() { *x = Contact_Name{} - mi := &file_backuppb_Backup_proto_msgTypes[86] + mi := &file_backuppb_Backup_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8355,7 +8510,7 @@ func (x *Contact_Name) String() string { func (*Contact_Name) ProtoMessage() {} func (x *Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[86] + mi := &file_backuppb_Backup_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8410,7 +8565,7 @@ type Group_GroupSnapshot struct { func (x *Group_GroupSnapshot) Reset() { *x = Group_GroupSnapshot{} - mi := &file_backuppb_Backup_proto_msgTypes[87] + mi := &file_backuppb_Backup_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8422,7 +8577,7 @@ func (x *Group_GroupSnapshot) String() string { func (*Group_GroupSnapshot) ProtoMessage() {} func (x *Group_GroupSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[87] + mi := &file_backuppb_Backup_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8539,7 +8694,7 @@ type Group_GroupAttributeBlob struct { func (x *Group_GroupAttributeBlob) Reset() { *x = Group_GroupAttributeBlob{} - mi := &file_backuppb_Backup_proto_msgTypes[88] + mi := &file_backuppb_Backup_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8551,7 +8706,7 @@ func (x *Group_GroupAttributeBlob) String() string { func (*Group_GroupAttributeBlob) ProtoMessage() {} func (x *Group_GroupAttributeBlob) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[88] + mi := &file_backuppb_Backup_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8649,7 +8804,7 @@ type Group_Member struct { func (x *Group_Member) Reset() { *x = Group_Member{} - mi := &file_backuppb_Backup_proto_msgTypes[89] + mi := &file_backuppb_Backup_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8661,7 +8816,7 @@ func (x *Group_Member) String() string { func (*Group_Member) ProtoMessage() {} func (x *Group_Member) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[89] + mi := &file_backuppb_Backup_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8709,7 +8864,7 @@ type Group_MemberPendingProfileKey struct { func (x *Group_MemberPendingProfileKey) Reset() { *x = Group_MemberPendingProfileKey{} - mi := &file_backuppb_Backup_proto_msgTypes[90] + mi := &file_backuppb_Backup_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8721,7 +8876,7 @@ func (x *Group_MemberPendingProfileKey) String() string { func (*Group_MemberPendingProfileKey) ProtoMessage() {} func (x *Group_MemberPendingProfileKey) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[90] + mi := &file_backuppb_Backup_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8768,7 +8923,7 @@ type Group_MemberPendingAdminApproval struct { func (x *Group_MemberPendingAdminApproval) Reset() { *x = Group_MemberPendingAdminApproval{} - mi := &file_backuppb_Backup_proto_msgTypes[91] + mi := &file_backuppb_Backup_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8780,7 +8935,7 @@ func (x *Group_MemberPendingAdminApproval) String() string { func (*Group_MemberPendingAdminApproval) ProtoMessage() {} func (x *Group_MemberPendingAdminApproval) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[91] + mi := &file_backuppb_Backup_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8820,7 +8975,7 @@ type Group_MemberBanned struct { func (x *Group_MemberBanned) Reset() { *x = Group_MemberBanned{} - mi := &file_backuppb_Backup_proto_msgTypes[92] + mi := &file_backuppb_Backup_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8832,7 +8987,7 @@ func (x *Group_MemberBanned) String() string { func (*Group_MemberBanned) ProtoMessage() {} func (x *Group_MemberBanned) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[92] + mi := &file_backuppb_Backup_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8873,7 +9028,7 @@ type Group_AccessControl struct { func (x *Group_AccessControl) Reset() { *x = Group_AccessControl{} - mi := &file_backuppb_Backup_proto_msgTypes[93] + mi := &file_backuppb_Backup_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8885,7 +9040,7 @@ func (x *Group_AccessControl) String() string { func (*Group_AccessControl) ProtoMessage() {} func (x *Group_AccessControl) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[93] + mi := &file_backuppb_Backup_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8934,7 +9089,7 @@ type ChatItem_IncomingMessageDetails struct { func (x *ChatItem_IncomingMessageDetails) Reset() { *x = ChatItem_IncomingMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[94] + mi := &file_backuppb_Backup_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8946,7 +9101,7 @@ func (x *ChatItem_IncomingMessageDetails) String() string { func (*ChatItem_IncomingMessageDetails) ProtoMessage() {} func (x *ChatItem_IncomingMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[94] + mi := &file_backuppb_Backup_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9000,7 +9155,7 @@ type ChatItem_OutgoingMessageDetails struct { func (x *ChatItem_OutgoingMessageDetails) Reset() { *x = ChatItem_OutgoingMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[95] + mi := &file_backuppb_Backup_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9012,7 +9167,7 @@ func (x *ChatItem_OutgoingMessageDetails) String() string { func (*ChatItem_OutgoingMessageDetails) ProtoMessage() {} func (x *ChatItem_OutgoingMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[95] + mi := &file_backuppb_Backup_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9050,7 +9205,7 @@ type ChatItem_DirectionlessMessageDetails struct { func (x *ChatItem_DirectionlessMessageDetails) Reset() { *x = ChatItem_DirectionlessMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[96] + mi := &file_backuppb_Backup_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9062,7 +9217,7 @@ func (x *ChatItem_DirectionlessMessageDetails) String() string { func (*ChatItem_DirectionlessMessageDetails) ProtoMessage() {} func (x *ChatItem_DirectionlessMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[96] + mi := &file_backuppb_Backup_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9086,7 +9241,7 @@ type SendStatus_Pending struct { func (x *SendStatus_Pending) Reset() { *x = SendStatus_Pending{} - mi := &file_backuppb_Backup_proto_msgTypes[97] + mi := &file_backuppb_Backup_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9098,7 +9253,7 @@ func (x *SendStatus_Pending) String() string { func (*SendStatus_Pending) ProtoMessage() {} func (x *SendStatus_Pending) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[97] + mi := &file_backuppb_Backup_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9123,7 +9278,7 @@ type SendStatus_Sent struct { func (x *SendStatus_Sent) Reset() { *x = SendStatus_Sent{} - mi := &file_backuppb_Backup_proto_msgTypes[98] + mi := &file_backuppb_Backup_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9135,7 +9290,7 @@ func (x *SendStatus_Sent) String() string { func (*SendStatus_Sent) ProtoMessage() {} func (x *SendStatus_Sent) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[98] + mi := &file_backuppb_Backup_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9167,7 +9322,7 @@ type SendStatus_Delivered struct { func (x *SendStatus_Delivered) Reset() { *x = SendStatus_Delivered{} - mi := &file_backuppb_Backup_proto_msgTypes[99] + mi := &file_backuppb_Backup_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9179,7 +9334,7 @@ func (x *SendStatus_Delivered) String() string { func (*SendStatus_Delivered) ProtoMessage() {} func (x *SendStatus_Delivered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[99] + mi := &file_backuppb_Backup_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9211,7 +9366,7 @@ type SendStatus_Read struct { func (x *SendStatus_Read) Reset() { *x = SendStatus_Read{} - mi := &file_backuppb_Backup_proto_msgTypes[100] + mi := &file_backuppb_Backup_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9223,7 +9378,7 @@ func (x *SendStatus_Read) String() string { func (*SendStatus_Read) ProtoMessage() {} func (x *SendStatus_Read) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[100] + mi := &file_backuppb_Backup_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9255,7 +9410,7 @@ type SendStatus_Viewed struct { func (x *SendStatus_Viewed) Reset() { *x = SendStatus_Viewed{} - mi := &file_backuppb_Backup_proto_msgTypes[101] + mi := &file_backuppb_Backup_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9267,7 +9422,7 @@ func (x *SendStatus_Viewed) String() string { func (*SendStatus_Viewed) ProtoMessage() {} func (x *SendStatus_Viewed) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[101] + mi := &file_backuppb_Backup_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9299,7 +9454,7 @@ type SendStatus_Skipped struct { func (x *SendStatus_Skipped) Reset() { *x = SendStatus_Skipped{} - mi := &file_backuppb_Backup_proto_msgTypes[102] + mi := &file_backuppb_Backup_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9311,7 +9466,7 @@ func (x *SendStatus_Skipped) String() string { func (*SendStatus_Skipped) ProtoMessage() {} func (x *SendStatus_Skipped) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[102] + mi := &file_backuppb_Backup_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9336,7 +9491,7 @@ type SendStatus_Failed struct { func (x *SendStatus_Failed) Reset() { *x = SendStatus_Failed{} - mi := &file_backuppb_Backup_proto_msgTypes[103] + mi := &file_backuppb_Backup_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9348,7 +9503,7 @@ func (x *SendStatus_Failed) String() string { func (*SendStatus_Failed) ProtoMessage() {} func (x *SendStatus_Failed) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[103] + mi := &file_backuppb_Backup_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9381,7 +9536,7 @@ type DirectStoryReplyMessage_TextReply struct { func (x *DirectStoryReplyMessage_TextReply) Reset() { *x = DirectStoryReplyMessage_TextReply{} - mi := &file_backuppb_Backup_proto_msgTypes[104] + mi := &file_backuppb_Backup_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9393,7 +9548,7 @@ func (x *DirectStoryReplyMessage_TextReply) String() string { func (*DirectStoryReplyMessage_TextReply) ProtoMessage() {} func (x *DirectStoryReplyMessage_TextReply) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[104] + mi := &file_backuppb_Backup_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9438,7 +9593,7 @@ type PaymentNotification_TransactionDetails struct { func (x *PaymentNotification_TransactionDetails) Reset() { *x = PaymentNotification_TransactionDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[105] + mi := &file_backuppb_Backup_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9450,7 +9605,7 @@ func (x *PaymentNotification_TransactionDetails) String() string { func (*PaymentNotification_TransactionDetails) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[105] + mi := &file_backuppb_Backup_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9519,7 +9674,7 @@ type PaymentNotification_TransactionDetails_MobileCoinTxoIdentification struct { func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Reset() { *x = PaymentNotification_TransactionDetails_MobileCoinTxoIdentification{} - mi := &file_backuppb_Backup_proto_msgTypes[106] + mi := &file_backuppb_Backup_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9531,7 +9686,7 @@ func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Str func (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[106] + mi := &file_backuppb_Backup_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9570,7 +9725,7 @@ type PaymentNotification_TransactionDetails_FailedTransaction struct { func (x *PaymentNotification_TransactionDetails_FailedTransaction) Reset() { *x = PaymentNotification_TransactionDetails_FailedTransaction{} - mi := &file_backuppb_Backup_proto_msgTypes[107] + mi := &file_backuppb_Backup_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9582,7 +9737,7 @@ func (x *PaymentNotification_TransactionDetails_FailedTransaction) String() stri func (*PaymentNotification_TransactionDetails_FailedTransaction) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_FailedTransaction) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[107] + mi := &file_backuppb_Backup_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9623,7 +9778,7 @@ type PaymentNotification_TransactionDetails_Transaction struct { func (x *PaymentNotification_TransactionDetails_Transaction) Reset() { *x = PaymentNotification_TransactionDetails_Transaction{} - mi := &file_backuppb_Backup_proto_msgTypes[108] + mi := &file_backuppb_Backup_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9635,7 +9790,7 @@ func (x *PaymentNotification_TransactionDetails_Transaction) String() string { func (*PaymentNotification_TransactionDetails_Transaction) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_Transaction) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[108] + mi := &file_backuppb_Backup_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9714,7 +9869,7 @@ type ContactAttachment_Name struct { func (x *ContactAttachment_Name) Reset() { *x = ContactAttachment_Name{} - mi := &file_backuppb_Backup_proto_msgTypes[109] + mi := &file_backuppb_Backup_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9726,7 +9881,7 @@ func (x *ContactAttachment_Name) String() string { func (*ContactAttachment_Name) ProtoMessage() {} func (x *ContactAttachment_Name) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[109] + mi := &file_backuppb_Backup_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9795,7 +9950,7 @@ type ContactAttachment_Phone struct { func (x *ContactAttachment_Phone) Reset() { *x = ContactAttachment_Phone{} - mi := &file_backuppb_Backup_proto_msgTypes[110] + mi := &file_backuppb_Backup_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9807,7 +9962,7 @@ func (x *ContactAttachment_Phone) String() string { func (*ContactAttachment_Phone) ProtoMessage() {} func (x *ContactAttachment_Phone) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[110] + mi := &file_backuppb_Backup_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9855,7 +10010,7 @@ type ContactAttachment_Email struct { func (x *ContactAttachment_Email) Reset() { *x = ContactAttachment_Email{} - mi := &file_backuppb_Backup_proto_msgTypes[111] + mi := &file_backuppb_Backup_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9867,7 +10022,7 @@ func (x *ContactAttachment_Email) String() string { func (*ContactAttachment_Email) ProtoMessage() {} func (x *ContactAttachment_Email) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[111] + mi := &file_backuppb_Backup_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9921,7 +10076,7 @@ type ContactAttachment_PostalAddress struct { func (x *ContactAttachment_PostalAddress) Reset() { *x = ContactAttachment_PostalAddress{} - mi := &file_backuppb_Backup_proto_msgTypes[112] + mi := &file_backuppb_Backup_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9933,7 +10088,7 @@ func (x *ContactAttachment_PostalAddress) String() string { func (*ContactAttachment_PostalAddress) ProtoMessage() {} func (x *ContactAttachment_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[112] + mi := &file_backuppb_Backup_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10048,7 +10203,7 @@ type FilePointer_LocatorInfo struct { func (x *FilePointer_LocatorInfo) Reset() { *x = FilePointer_LocatorInfo{} - mi := &file_backuppb_Backup_proto_msgTypes[113] + mi := &file_backuppb_Backup_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10060,7 +10215,7 @@ func (x *FilePointer_LocatorInfo) String() string { func (*FilePointer_LocatorInfo) ProtoMessage() {} func (x *FilePointer_LocatorInfo) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[113] + mi := &file_backuppb_Backup_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10180,7 +10335,7 @@ type Quote_QuotedAttachment struct { func (x *Quote_QuotedAttachment) Reset() { *x = Quote_QuotedAttachment{} - mi := &file_backuppb_Backup_proto_msgTypes[114] + mi := &file_backuppb_Backup_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10192,7 +10347,7 @@ func (x *Quote_QuotedAttachment) String() string { func (*Quote_QuotedAttachment) ProtoMessage() {} func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[114] + mi := &file_backuppb_Backup_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10229,6 +10384,110 @@ func (x *Quote_QuotedAttachment) GetThumbnail() *MessageAttachment { return nil } +type Poll_PollOption struct { + state protoimpl.MessageState `protogen:"open.v1"` + Option string `protobuf:"bytes,1,opt,name=option,proto3" json:"option,omitempty"` // Between 1-100 characters + Votes []*Poll_PollOption_PollVote `protobuf:"bytes,2,rep,name=votes,proto3" json:"votes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Poll_PollOption) Reset() { + *x = Poll_PollOption{} + mi := &file_backuppb_Backup_proto_msgTypes[117] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Poll_PollOption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Poll_PollOption) ProtoMessage() {} + +func (x *Poll_PollOption) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[117] + 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 Poll_PollOption.ProtoReflect.Descriptor instead. +func (*Poll_PollOption) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{32, 0} +} + +func (x *Poll_PollOption) GetOption() string { + if x != nil { + return x.Option + } + return "" +} + +func (x *Poll_PollOption) GetVotes() []*Poll_PollOption_PollVote { + if x != nil { + return x.Votes + } + return nil +} + +type Poll_PollOption_PollVote struct { + state protoimpl.MessageState `protogen:"open.v1"` + VoterId uint64 `protobuf:"varint,1,opt,name=voterId,proto3" json:"voterId,omitempty"` // A direct reference to Recipient proto id. Must be self or contact. + VoteCount uint32 `protobuf:"varint,2,opt,name=voteCount,proto3" json:"voteCount,omitempty"` // Tracks how many times you voted. + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Poll_PollOption_PollVote) Reset() { + *x = Poll_PollOption_PollVote{} + mi := &file_backuppb_Backup_proto_msgTypes[118] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Poll_PollOption_PollVote) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Poll_PollOption_PollVote) ProtoMessage() {} + +func (x *Poll_PollOption_PollVote) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[118] + 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 Poll_PollOption_PollVote.ProtoReflect.Descriptor instead. +func (*Poll_PollOption_PollVote) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{32, 0, 0} +} + +func (x *Poll_PollOption_PollVote) GetVoterId() uint64 { + if x != nil { + return x.VoterId + } + return 0 +} + +func (x *Poll_PollOption_PollVote) GetVoteCount() uint32 { + if x != nil { + return x.VoteCount + } + return 0 +} + type GroupChangeChatUpdate_Update struct { state protoimpl.MessageState `protogen:"open.v1"` // If unset, importers should consider it to be a GenericGroupUpdate with unset updaterAci @@ -10276,7 +10535,7 @@ type GroupChangeChatUpdate_Update struct { func (x *GroupChangeChatUpdate_Update) Reset() { *x = GroupChangeChatUpdate_Update{} - mi := &file_backuppb_Backup_proto_msgTypes[115] + mi := &file_backuppb_Backup_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10288,7 +10547,7 @@ func (x *GroupChangeChatUpdate_Update) String() string { func (*GroupChangeChatUpdate_Update) ProtoMessage() {} func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[115] + mi := &file_backuppb_Backup_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10301,7 +10560,7 @@ func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChangeChatUpdate_Update.ProtoReflect.Descriptor instead. func (*GroupChangeChatUpdate_Update) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{41, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{42, 0} } func (x *GroupChangeChatUpdate_Update) GetUpdate() isGroupChangeChatUpdate_Update_Update { @@ -10862,7 +11121,7 @@ type GroupInvitationRevokedUpdate_Invitee struct { func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { *x = GroupInvitationRevokedUpdate_Invitee{} - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10874,7 +11133,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) String() string { func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10887,7 +11146,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Messa // Deprecated: Use GroupInvitationRevokedUpdate_Invitee.ProtoReflect.Descriptor instead. func (*GroupInvitationRevokedUpdate_Invitee) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{61, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{62, 0} } func (x *GroupInvitationRevokedUpdate_Invitee) GetInviterAci() []byte { @@ -10922,7 +11181,7 @@ type ChatStyle_Gradient struct { func (x *ChatStyle_Gradient) Reset() { *x = ChatStyle_Gradient{} - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10934,7 +11193,7 @@ func (x *ChatStyle_Gradient) String() string { func (*ChatStyle_Gradient) ProtoMessage() {} func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10947,7 +11206,7 @@ func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_Gradient.ProtoReflect.Descriptor instead. func (*ChatStyle_Gradient) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 0} } func (x *ChatStyle_Gradient) GetAngle() uint32 { @@ -10987,7 +11246,7 @@ type ChatStyle_CustomChatColor struct { func (x *ChatStyle_CustomChatColor) Reset() { *x = ChatStyle_CustomChatColor{} - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10999,7 +11258,7 @@ func (x *ChatStyle_CustomChatColor) String() string { func (*ChatStyle_CustomChatColor) ProtoMessage() {} func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11012,7 +11271,7 @@ func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_CustomChatColor.ProtoReflect.Descriptor instead. func (*ChatStyle_CustomChatColor) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 1} } func (x *ChatStyle_CustomChatColor) GetId() uint64 { @@ -11071,7 +11330,7 @@ type ChatStyle_AutomaticBubbleColor struct { func (x *ChatStyle_AutomaticBubbleColor) Reset() { *x = ChatStyle_AutomaticBubbleColor{} - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11083,7 +11342,7 @@ func (x *ChatStyle_AutomaticBubbleColor) String() string { func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11096,7 +11355,7 @@ func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_AutomaticBubbleColor.ProtoReflect.Descriptor instead. func (*ChatStyle_AutomaticBubbleColor) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77, 2} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 2} } var File_backuppb_Backup_proto protoreflect.FileDescriptor @@ -11385,7 +11644,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tONLY_WITH\x10\x01\x12\x0e\n" + "\n" + "ALL_EXCEPT\x10\x02\x12\a\n" + - "\x03ALL\x10\x03\"\xc8\f\n" + + "\x03ALL\x10\x03\"\xf3\f\n" + "\bChatItem\x12\x16\n" + "\x06chatId\x18\x01 \x01(\x04R\x06chatId\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12\x1a\n" + @@ -11406,7 +11665,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x13paymentNotification\x18\x10 \x01(\v2\".signal.backup.PaymentNotificationH\x01R\x13paymentNotification\x128\n" + "\tgiftBadge\x18\x11 \x01(\v2\x18.signal.backup.GiftBadgeH\x01R\tgiftBadge\x12J\n" + "\x0fviewOnceMessage\x18\x12 \x01(\v2\x1e.signal.backup.ViewOnceMessageH\x01R\x0fviewOnceMessage\x12b\n" + - "\x17directStoryReplyMessage\x18\x13 \x01(\v2&.signal.backup.DirectStoryReplyMessageH\x01R\x17directStoryReplyMessage\x1a\xb4\x01\n" + + "\x17directStoryReplyMessage\x18\x13 \x01(\v2&.signal.backup.DirectStoryReplyMessageH\x01R\x17directStoryReplyMessage\x12)\n" + + "\x04poll\x18\x14 \x01(\v2\x13.signal.backup.PollH\x01R\x04poll\x1a\xb4\x01\n" + "\x16IncomingMessageDetails\x12\"\n" + "\fdateReceived\x18\x01 \x01(\x04R\fdateReceived\x12+\n" + "\x0edateServerSent\x18\x02 \x01(\x04H\x00R\x0edateServerSent\x88\x01\x01\x12\x12\n" + @@ -11669,7 +11929,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\a_heightB\n" + "\n" + "\b_captionB\v\n" + - "\t_blurHashJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03J\x04\b\x03\x10\x04J\x04\b\f\x10\r\"\xae\x04\n" + + "\t_blurHashJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03J\x04\b\x03\x10\x04J\x04\b\f\x10\r\"\xb8\x04\n" + "\x05Quote\x125\n" + "\x13targetSentTimestamp\x18\x01 \x01(\x04H\x00R\x13targetSentTimestamp\x88\x01\x01\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12,\n" + @@ -11683,14 +11943,15 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\f_contentTypeB\v\n" + "\t_fileNameB\f\n" + "\n" + - "_thumbnail\">\n" + + "_thumbnail\"H\n" + "\x04Type\x12\v\n" + "\aUNKNOWN\x10\x00\x12\n" + "\n" + "\x06NORMAL\x10\x01\x12\x0e\n" + "\n" + "GIFT_BADGE\x10\x02\x12\r\n" + - "\tVIEW_ONCE\x10\x03B\x16\n" + + "\tVIEW_ONCE\x10\x03\x12\b\n" + + "\x04POLL\x10\x04B\x16\n" + "\x14_targetSentTimestampB\a\n" + "\x05_text\"\xfe\x01\n" + "\tBodyRange\x12\x14\n" + @@ -11713,7 +11974,19 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x05emoji\x18\x01 \x01(\tR\x05emoji\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12$\n" + "\rsentTimestamp\x18\x03 \x01(\x04R\rsentTimestamp\x12\x1c\n" + - "\tsortOrder\x18\x04 \x01(\x04R\tsortOrder\"\xe8\x05\n" + + "\tsortOrder\x18\x04 \x01(\x04R\tsortOrder\"\xc8\x02\n" + + "\x04Poll\x12\x1a\n" + + "\bquestion\x18\x01 \x01(\tR\bquestion\x12$\n" + + "\rallowMultiple\x18\x02 \x01(\bR\rallowMultiple\x128\n" + + "\aoptions\x18\x03 \x03(\v2\x1e.signal.backup.Poll.PollOptionR\aoptions\x12\x1a\n" + + "\bhasEnded\x18\x04 \x01(\bR\bhasEnded\x1a\xa7\x01\n" + + "\n" + + "PollOption\x12\x16\n" + + "\x06option\x18\x01 \x01(\tR\x06option\x12=\n" + + "\x05votes\x18\x02 \x03(\v2'.signal.backup.Poll.PollOption.PollVoteR\x05votes\x1aB\n" + + "\bPollVote\x12\x18\n" + + "\avoterId\x18\x01 \x01(\x04R\avoterId\x12\x1c\n" + + "\tvoteCount\x18\x02 \x01(\rR\tvoteCount\"\xb4\x06\n" + "\x11ChatUpdateMessage\x12E\n" + "\fsimpleUpdate\x18\x01 \x01(\v2\x1f.signal.backup.SimpleChatUpdateH\x00R\fsimpleUpdate\x12H\n" + "\vgroupChange\x18\x02 \x01(\v2$.signal.backup.GroupChangeChatUpdateH\x00R\vgroupChange\x12`\n" + @@ -11723,7 +11996,9 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x11sessionSwitchover\x18\x06 \x01(\v2*.signal.backup.SessionSwitchoverChatUpdateH\x00R\x11sessionSwitchover\x12G\n" + "\x0eindividualCall\x18\a \x01(\v2\x1d.signal.backup.IndividualCallH\x00R\x0eindividualCall\x128\n" + "\tgroupCall\x18\b \x01(\v2\x18.signal.backup.GroupCallH\x00R\tgroupCall\x12]\n" + - "\x14learnedProfileChange\x18\t \x01(\v2'.signal.backup.LearnedProfileChatUpdateH\x00R\x14learnedProfileChangeB\b\n" + + "\x14learnedProfileChange\x18\t \x01(\v2'.signal.backup.LearnedProfileChatUpdateH\x00R\x14learnedProfileChange\x12J\n" + + "\rpollTerminate\x18\n" + + " \x01(\v2\".signal.backup.PollTerminateUpdateH\x00R\rpollTerminateB\b\n" + "\x06update\"\x9d\x04\n" + "\x0eIndividualCall\x12\x1b\n" + "\x06callId\x18\x01 \x01(\x04H\x00R\x06callId\x88\x01\x01\x126\n" + @@ -12028,7 +12303,10 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "updaterAci\x18\x02 \x01(\fH\x00R\n" + "updaterAci\x88\x01\x01B\r\n" + - "\v_updaterAci\"?\n" + + "\v_updaterAci\"c\n" + + "\x13PollTerminateUpdate\x120\n" + + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x12\x1a\n" + + "\bquestion\x18\x02 \x01(\tR\bquestion\"?\n" + "\vStickerPack\x12\x16\n" + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + "\apackKey\x18\x02 \x01(\fR\apackKey\"\x80\r\n" + @@ -12188,7 +12466,7 @@ func file_backuppb_Backup_proto_rawDescGZIP() []byte { } var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 31) -var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 120) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 124) var file_backuppb_Backup_proto_goTypes = []any{ (AvatarColor)(0), // 0: signal.backup.AvatarColor (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel @@ -12253,108 +12531,112 @@ var file_backuppb_Backup_proto_goTypes = []any{ (*Quote)(nil), // 60: signal.backup.Quote (*BodyRange)(nil), // 61: signal.backup.BodyRange (*Reaction)(nil), // 62: signal.backup.Reaction - (*ChatUpdateMessage)(nil), // 63: signal.backup.ChatUpdateMessage - (*IndividualCall)(nil), // 64: signal.backup.IndividualCall - (*GroupCall)(nil), // 65: signal.backup.GroupCall - (*SimpleChatUpdate)(nil), // 66: signal.backup.SimpleChatUpdate - (*ExpirationTimerChatUpdate)(nil), // 67: signal.backup.ExpirationTimerChatUpdate - (*ProfileChangeChatUpdate)(nil), // 68: signal.backup.ProfileChangeChatUpdate - (*LearnedProfileChatUpdate)(nil), // 69: signal.backup.LearnedProfileChatUpdate - (*ThreadMergeChatUpdate)(nil), // 70: signal.backup.ThreadMergeChatUpdate - (*SessionSwitchoverChatUpdate)(nil), // 71: signal.backup.SessionSwitchoverChatUpdate - (*GroupChangeChatUpdate)(nil), // 72: signal.backup.GroupChangeChatUpdate - (*GenericGroupUpdate)(nil), // 73: signal.backup.GenericGroupUpdate - (*GroupCreationUpdate)(nil), // 74: signal.backup.GroupCreationUpdate - (*GroupNameUpdate)(nil), // 75: signal.backup.GroupNameUpdate - (*GroupAvatarUpdate)(nil), // 76: signal.backup.GroupAvatarUpdate - (*GroupDescriptionUpdate)(nil), // 77: signal.backup.GroupDescriptionUpdate - (*GroupMembershipAccessLevelChangeUpdate)(nil), // 78: signal.backup.GroupMembershipAccessLevelChangeUpdate - (*GroupAttributesAccessLevelChangeUpdate)(nil), // 79: signal.backup.GroupAttributesAccessLevelChangeUpdate - (*GroupAnnouncementOnlyChangeUpdate)(nil), // 80: signal.backup.GroupAnnouncementOnlyChangeUpdate - (*GroupAdminStatusUpdate)(nil), // 81: signal.backup.GroupAdminStatusUpdate - (*GroupMemberLeftUpdate)(nil), // 82: signal.backup.GroupMemberLeftUpdate - (*GroupMemberRemovedUpdate)(nil), // 83: signal.backup.GroupMemberRemovedUpdate - (*SelfInvitedToGroupUpdate)(nil), // 84: signal.backup.SelfInvitedToGroupUpdate - (*SelfInvitedOtherUserToGroupUpdate)(nil), // 85: signal.backup.SelfInvitedOtherUserToGroupUpdate - (*GroupUnknownInviteeUpdate)(nil), // 86: signal.backup.GroupUnknownInviteeUpdate - (*GroupInvitationAcceptedUpdate)(nil), // 87: signal.backup.GroupInvitationAcceptedUpdate - (*GroupInvitationDeclinedUpdate)(nil), // 88: signal.backup.GroupInvitationDeclinedUpdate - (*GroupMemberJoinedUpdate)(nil), // 89: signal.backup.GroupMemberJoinedUpdate - (*GroupMemberAddedUpdate)(nil), // 90: signal.backup.GroupMemberAddedUpdate - (*GroupSelfInvitationRevokedUpdate)(nil), // 91: signal.backup.GroupSelfInvitationRevokedUpdate - (*GroupInvitationRevokedUpdate)(nil), // 92: signal.backup.GroupInvitationRevokedUpdate - (*GroupJoinRequestUpdate)(nil), // 93: signal.backup.GroupJoinRequestUpdate - (*GroupJoinRequestApprovalUpdate)(nil), // 94: signal.backup.GroupJoinRequestApprovalUpdate - (*GroupJoinRequestCanceledUpdate)(nil), // 95: signal.backup.GroupJoinRequestCanceledUpdate - (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 96: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - (*GroupInviteLinkResetUpdate)(nil), // 97: signal.backup.GroupInviteLinkResetUpdate - (*GroupInviteLinkEnabledUpdate)(nil), // 98: signal.backup.GroupInviteLinkEnabledUpdate - (*GroupInviteLinkAdminApprovalUpdate)(nil), // 99: signal.backup.GroupInviteLinkAdminApprovalUpdate - (*GroupInviteLinkDisabledUpdate)(nil), // 100: signal.backup.GroupInviteLinkDisabledUpdate - (*GroupMemberJoinedByLinkUpdate)(nil), // 101: signal.backup.GroupMemberJoinedByLinkUpdate - (*GroupV2MigrationUpdate)(nil), // 102: signal.backup.GroupV2MigrationUpdate - (*GroupV2MigrationSelfInvitedUpdate)(nil), // 103: signal.backup.GroupV2MigrationSelfInvitedUpdate - (*GroupV2MigrationInvitedMembersUpdate)(nil), // 104: signal.backup.GroupV2MigrationInvitedMembersUpdate - (*GroupV2MigrationDroppedMembersUpdate)(nil), // 105: signal.backup.GroupV2MigrationDroppedMembersUpdate - (*GroupExpirationTimerUpdate)(nil), // 106: signal.backup.GroupExpirationTimerUpdate - (*StickerPack)(nil), // 107: signal.backup.StickerPack - (*ChatStyle)(nil), // 108: signal.backup.ChatStyle - (*NotificationProfile)(nil), // 109: signal.backup.NotificationProfile - (*ChatFolder)(nil), // 110: signal.backup.ChatFolder - (*AccountData_UsernameLink)(nil), // 111: signal.backup.AccountData.UsernameLink - (*AccountData_AccountSettings)(nil), // 112: signal.backup.AccountData.AccountSettings - (*AccountData_SubscriberData)(nil), // 113: signal.backup.AccountData.SubscriberData - (*AccountData_IAPSubscriberData)(nil), // 114: signal.backup.AccountData.IAPSubscriberData - (*Contact_Registered)(nil), // 115: signal.backup.Contact.Registered - (*Contact_NotRegistered)(nil), // 116: signal.backup.Contact.NotRegistered - (*Contact_Name)(nil), // 117: signal.backup.Contact.Name - (*Group_GroupSnapshot)(nil), // 118: signal.backup.Group.GroupSnapshot - (*Group_GroupAttributeBlob)(nil), // 119: signal.backup.Group.GroupAttributeBlob - (*Group_Member)(nil), // 120: signal.backup.Group.Member - (*Group_MemberPendingProfileKey)(nil), // 121: signal.backup.Group.MemberPendingProfileKey - (*Group_MemberPendingAdminApproval)(nil), // 122: signal.backup.Group.MemberPendingAdminApproval - (*Group_MemberBanned)(nil), // 123: signal.backup.Group.MemberBanned - (*Group_AccessControl)(nil), // 124: signal.backup.Group.AccessControl - (*ChatItem_IncomingMessageDetails)(nil), // 125: signal.backup.ChatItem.IncomingMessageDetails - (*ChatItem_OutgoingMessageDetails)(nil), // 126: signal.backup.ChatItem.OutgoingMessageDetails - (*ChatItem_DirectionlessMessageDetails)(nil), // 127: signal.backup.ChatItem.DirectionlessMessageDetails - (*SendStatus_Pending)(nil), // 128: signal.backup.SendStatus.Pending - (*SendStatus_Sent)(nil), // 129: signal.backup.SendStatus.Sent - (*SendStatus_Delivered)(nil), // 130: signal.backup.SendStatus.Delivered - (*SendStatus_Read)(nil), // 131: signal.backup.SendStatus.Read - (*SendStatus_Viewed)(nil), // 132: signal.backup.SendStatus.Viewed - (*SendStatus_Skipped)(nil), // 133: signal.backup.SendStatus.Skipped - (*SendStatus_Failed)(nil), // 134: signal.backup.SendStatus.Failed - (*DirectStoryReplyMessage_TextReply)(nil), // 135: signal.backup.DirectStoryReplyMessage.TextReply - (*PaymentNotification_TransactionDetails)(nil), // 136: signal.backup.PaymentNotification.TransactionDetails - (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 137: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 138: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - (*PaymentNotification_TransactionDetails_Transaction)(nil), // 139: signal.backup.PaymentNotification.TransactionDetails.Transaction - (*ContactAttachment_Name)(nil), // 140: signal.backup.ContactAttachment.Name - (*ContactAttachment_Phone)(nil), // 141: signal.backup.ContactAttachment.Phone - (*ContactAttachment_Email)(nil), // 142: signal.backup.ContactAttachment.Email - (*ContactAttachment_PostalAddress)(nil), // 143: signal.backup.ContactAttachment.PostalAddress - (*FilePointer_LocatorInfo)(nil), // 144: signal.backup.FilePointer.LocatorInfo - (*Quote_QuotedAttachment)(nil), // 145: signal.backup.Quote.QuotedAttachment - (*GroupChangeChatUpdate_Update)(nil), // 146: signal.backup.GroupChangeChatUpdate.Update - (*GroupInvitationRevokedUpdate_Invitee)(nil), // 147: signal.backup.GroupInvitationRevokedUpdate.Invitee - (*ChatStyle_Gradient)(nil), // 148: signal.backup.ChatStyle.Gradient - (*ChatStyle_CustomChatColor)(nil), // 149: signal.backup.ChatStyle.CustomChatColor - (*ChatStyle_AutomaticBubbleColor)(nil), // 150: signal.backup.ChatStyle.AutomaticBubbleColor + (*Poll)(nil), // 63: signal.backup.Poll + (*ChatUpdateMessage)(nil), // 64: signal.backup.ChatUpdateMessage + (*IndividualCall)(nil), // 65: signal.backup.IndividualCall + (*GroupCall)(nil), // 66: signal.backup.GroupCall + (*SimpleChatUpdate)(nil), // 67: signal.backup.SimpleChatUpdate + (*ExpirationTimerChatUpdate)(nil), // 68: signal.backup.ExpirationTimerChatUpdate + (*ProfileChangeChatUpdate)(nil), // 69: signal.backup.ProfileChangeChatUpdate + (*LearnedProfileChatUpdate)(nil), // 70: signal.backup.LearnedProfileChatUpdate + (*ThreadMergeChatUpdate)(nil), // 71: signal.backup.ThreadMergeChatUpdate + (*SessionSwitchoverChatUpdate)(nil), // 72: signal.backup.SessionSwitchoverChatUpdate + (*GroupChangeChatUpdate)(nil), // 73: signal.backup.GroupChangeChatUpdate + (*GenericGroupUpdate)(nil), // 74: signal.backup.GenericGroupUpdate + (*GroupCreationUpdate)(nil), // 75: signal.backup.GroupCreationUpdate + (*GroupNameUpdate)(nil), // 76: signal.backup.GroupNameUpdate + (*GroupAvatarUpdate)(nil), // 77: signal.backup.GroupAvatarUpdate + (*GroupDescriptionUpdate)(nil), // 78: signal.backup.GroupDescriptionUpdate + (*GroupMembershipAccessLevelChangeUpdate)(nil), // 79: signal.backup.GroupMembershipAccessLevelChangeUpdate + (*GroupAttributesAccessLevelChangeUpdate)(nil), // 80: signal.backup.GroupAttributesAccessLevelChangeUpdate + (*GroupAnnouncementOnlyChangeUpdate)(nil), // 81: signal.backup.GroupAnnouncementOnlyChangeUpdate + (*GroupAdminStatusUpdate)(nil), // 82: signal.backup.GroupAdminStatusUpdate + (*GroupMemberLeftUpdate)(nil), // 83: signal.backup.GroupMemberLeftUpdate + (*GroupMemberRemovedUpdate)(nil), // 84: signal.backup.GroupMemberRemovedUpdate + (*SelfInvitedToGroupUpdate)(nil), // 85: signal.backup.SelfInvitedToGroupUpdate + (*SelfInvitedOtherUserToGroupUpdate)(nil), // 86: signal.backup.SelfInvitedOtherUserToGroupUpdate + (*GroupUnknownInviteeUpdate)(nil), // 87: signal.backup.GroupUnknownInviteeUpdate + (*GroupInvitationAcceptedUpdate)(nil), // 88: signal.backup.GroupInvitationAcceptedUpdate + (*GroupInvitationDeclinedUpdate)(nil), // 89: signal.backup.GroupInvitationDeclinedUpdate + (*GroupMemberJoinedUpdate)(nil), // 90: signal.backup.GroupMemberJoinedUpdate + (*GroupMemberAddedUpdate)(nil), // 91: signal.backup.GroupMemberAddedUpdate + (*GroupSelfInvitationRevokedUpdate)(nil), // 92: signal.backup.GroupSelfInvitationRevokedUpdate + (*GroupInvitationRevokedUpdate)(nil), // 93: signal.backup.GroupInvitationRevokedUpdate + (*GroupJoinRequestUpdate)(nil), // 94: signal.backup.GroupJoinRequestUpdate + (*GroupJoinRequestApprovalUpdate)(nil), // 95: signal.backup.GroupJoinRequestApprovalUpdate + (*GroupJoinRequestCanceledUpdate)(nil), // 96: signal.backup.GroupJoinRequestCanceledUpdate + (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 97: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + (*GroupInviteLinkResetUpdate)(nil), // 98: signal.backup.GroupInviteLinkResetUpdate + (*GroupInviteLinkEnabledUpdate)(nil), // 99: signal.backup.GroupInviteLinkEnabledUpdate + (*GroupInviteLinkAdminApprovalUpdate)(nil), // 100: signal.backup.GroupInviteLinkAdminApprovalUpdate + (*GroupInviteLinkDisabledUpdate)(nil), // 101: signal.backup.GroupInviteLinkDisabledUpdate + (*GroupMemberJoinedByLinkUpdate)(nil), // 102: signal.backup.GroupMemberJoinedByLinkUpdate + (*GroupV2MigrationUpdate)(nil), // 103: signal.backup.GroupV2MigrationUpdate + (*GroupV2MigrationSelfInvitedUpdate)(nil), // 104: signal.backup.GroupV2MigrationSelfInvitedUpdate + (*GroupV2MigrationInvitedMembersUpdate)(nil), // 105: signal.backup.GroupV2MigrationInvitedMembersUpdate + (*GroupV2MigrationDroppedMembersUpdate)(nil), // 106: signal.backup.GroupV2MigrationDroppedMembersUpdate + (*GroupExpirationTimerUpdate)(nil), // 107: signal.backup.GroupExpirationTimerUpdate + (*PollTerminateUpdate)(nil), // 108: signal.backup.PollTerminateUpdate + (*StickerPack)(nil), // 109: signal.backup.StickerPack + (*ChatStyle)(nil), // 110: signal.backup.ChatStyle + (*NotificationProfile)(nil), // 111: signal.backup.NotificationProfile + (*ChatFolder)(nil), // 112: signal.backup.ChatFolder + (*AccountData_UsernameLink)(nil), // 113: signal.backup.AccountData.UsernameLink + (*AccountData_AccountSettings)(nil), // 114: signal.backup.AccountData.AccountSettings + (*AccountData_SubscriberData)(nil), // 115: signal.backup.AccountData.SubscriberData + (*AccountData_IAPSubscriberData)(nil), // 116: signal.backup.AccountData.IAPSubscriberData + (*Contact_Registered)(nil), // 117: signal.backup.Contact.Registered + (*Contact_NotRegistered)(nil), // 118: signal.backup.Contact.NotRegistered + (*Contact_Name)(nil), // 119: signal.backup.Contact.Name + (*Group_GroupSnapshot)(nil), // 120: signal.backup.Group.GroupSnapshot + (*Group_GroupAttributeBlob)(nil), // 121: signal.backup.Group.GroupAttributeBlob + (*Group_Member)(nil), // 122: signal.backup.Group.Member + (*Group_MemberPendingProfileKey)(nil), // 123: signal.backup.Group.MemberPendingProfileKey + (*Group_MemberPendingAdminApproval)(nil), // 124: signal.backup.Group.MemberPendingAdminApproval + (*Group_MemberBanned)(nil), // 125: signal.backup.Group.MemberBanned + (*Group_AccessControl)(nil), // 126: signal.backup.Group.AccessControl + (*ChatItem_IncomingMessageDetails)(nil), // 127: signal.backup.ChatItem.IncomingMessageDetails + (*ChatItem_OutgoingMessageDetails)(nil), // 128: signal.backup.ChatItem.OutgoingMessageDetails + (*ChatItem_DirectionlessMessageDetails)(nil), // 129: signal.backup.ChatItem.DirectionlessMessageDetails + (*SendStatus_Pending)(nil), // 130: signal.backup.SendStatus.Pending + (*SendStatus_Sent)(nil), // 131: signal.backup.SendStatus.Sent + (*SendStatus_Delivered)(nil), // 132: signal.backup.SendStatus.Delivered + (*SendStatus_Read)(nil), // 133: signal.backup.SendStatus.Read + (*SendStatus_Viewed)(nil), // 134: signal.backup.SendStatus.Viewed + (*SendStatus_Skipped)(nil), // 135: signal.backup.SendStatus.Skipped + (*SendStatus_Failed)(nil), // 136: signal.backup.SendStatus.Failed + (*DirectStoryReplyMessage_TextReply)(nil), // 137: signal.backup.DirectStoryReplyMessage.TextReply + (*PaymentNotification_TransactionDetails)(nil), // 138: signal.backup.PaymentNotification.TransactionDetails + (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 139: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 140: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + (*PaymentNotification_TransactionDetails_Transaction)(nil), // 141: signal.backup.PaymentNotification.TransactionDetails.Transaction + (*ContactAttachment_Name)(nil), // 142: signal.backup.ContactAttachment.Name + (*ContactAttachment_Phone)(nil), // 143: signal.backup.ContactAttachment.Phone + (*ContactAttachment_Email)(nil), // 144: signal.backup.ContactAttachment.Email + (*ContactAttachment_PostalAddress)(nil), // 145: signal.backup.ContactAttachment.PostalAddress + (*FilePointer_LocatorInfo)(nil), // 146: signal.backup.FilePointer.LocatorInfo + (*Quote_QuotedAttachment)(nil), // 147: signal.backup.Quote.QuotedAttachment + (*Poll_PollOption)(nil), // 148: signal.backup.Poll.PollOption + (*Poll_PollOption_PollVote)(nil), // 149: signal.backup.Poll.PollOption.PollVote + (*GroupChangeChatUpdate_Update)(nil), // 150: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 151: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 152: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 153: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 154: signal.backup.ChatStyle.AutomaticBubbleColor } var file_backuppb_Backup_proto_depIdxs = []int32{ 33, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData 34, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient 39, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat 44, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem - 107, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack + 109, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack 41, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall - 109, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile - 110, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder - 111, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink - 113, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData - 112, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings - 114, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData + 111, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile + 112, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder + 113, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink + 115, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData + 114, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings + 116, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData 35, // 12: signal.backup.Recipient.contact:type_name -> signal.backup.Contact 36, // 13: signal.backup.Recipient.group:type_name -> signal.backup.Group 42, // 14: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem @@ -12362,165 +12644,169 @@ var file_backuppb_Backup_proto_depIdxs = []int32{ 38, // 16: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes 40, // 17: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink 5, // 18: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility - 115, // 19: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered - 116, // 20: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered + 117, // 19: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered + 118, // 20: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered 4, // 21: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState - 117, // 22: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name + 119, // 22: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name 0, // 23: signal.backup.Contact.avatarColor:type_name -> signal.backup.AvatarColor 6, // 24: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode - 118, // 25: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot + 120, // 25: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot 0, // 26: signal.backup.Group.avatarColor:type_name -> signal.backup.AvatarColor 0, // 27: signal.backup.Self.avatarColor:type_name -> signal.backup.AvatarColor - 108, // 28: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle + 110, // 28: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle 9, // 29: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions 10, // 30: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State 43, // 31: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList 11, // 32: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode 44, // 33: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem - 125, // 34: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails - 126, // 35: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails - 127, // 36: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails + 127, // 34: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails + 128, // 35: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails + 129, // 36: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails 47, // 37: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage 48, // 38: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage 54, // 39: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage 55, // 40: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage - 63, // 41: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage + 64, // 41: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage 50, // 42: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification 51, // 43: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge 52, // 44: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage 49, // 45: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage - 128, // 46: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending - 129, // 47: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent - 130, // 48: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered - 131, // 49: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read - 132, // 50: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed - 133, // 51: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped - 134, // 52: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed - 61, // 53: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange - 60, // 54: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote - 46, // 55: signal.backup.StandardMessage.text:type_name -> signal.backup.Text - 58, // 56: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment - 57, // 57: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview - 59, // 58: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer - 62, // 59: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction - 53, // 60: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment - 62, // 61: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction - 135, // 62: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply - 62, // 63: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction - 136, // 64: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails - 15, // 65: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State - 58, // 66: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment - 62, // 67: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction - 140, // 68: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name - 141, // 69: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone - 142, // 70: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email - 143, // 71: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress - 59, // 72: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer - 56, // 73: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker - 62, // 74: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction - 59, // 75: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer - 59, // 76: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer - 59, // 77: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer - 19, // 78: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag - 144, // 79: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo - 46, // 80: signal.backup.Quote.text:type_name -> signal.backup.Text - 145, // 81: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 20, // 82: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 21, // 83: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 66, // 84: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 72, // 85: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 67, // 86: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 68, // 87: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 70, // 88: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 71, // 89: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 64, // 90: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 65, // 91: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 69, // 92: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 22, // 93: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 23, // 94: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 24, // 95: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 25, // 96: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 26, // 97: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 146, // 98: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 1, // 99: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 1, // 100: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 147, // 101: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 27, // 102: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 59, // 103: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 150, // 104: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 28, // 105: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 29, // 106: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 30, // 107: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 3, // 108: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 2, // 109: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 108, // 110: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 149, // 111: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 119, // 112: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 113: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 119, // 114: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 124, // 115: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 120, // 116: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 121, // 117: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 122, // 118: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 123, // 119: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 7, // 120: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 120, // 121: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 8, // 122: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 123: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 124: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 45, // 125: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 12, // 126: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 46, // 127: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 59, // 128: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 139, // 129: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 138, // 130: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 13, // 131: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 14, // 132: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 137, // 133: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 16, // 134: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 17, // 135: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 18, // 136: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 58, // 137: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 73, // 138: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 74, // 139: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 75, // 140: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 76, // 141: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 77, // 142: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 78, // 143: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 79, // 144: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 80, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 81, // 146: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 82, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 83, // 148: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 84, // 149: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 85, // 150: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 86, // 151: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 87, // 152: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 88, // 153: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 89, // 154: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 90, // 155: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 91, // 156: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 92, // 157: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 93, // 158: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 94, // 159: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 95, // 160: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 97, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 98, // 162: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 99, // 163: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 100, // 164: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 101, // 165: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 102, // 166: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 103, // 167: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 104, // 168: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 105, // 169: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 96, // 170: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 106, // 171: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 148, // 172: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 173, // [173:173] is the sub-list for method output_type - 173, // [173:173] is the sub-list for method input_type - 173, // [173:173] is the sub-list for extension type_name - 173, // [173:173] is the sub-list for extension extendee - 0, // [0:173] is the sub-list for field type_name + 63, // 46: signal.backup.ChatItem.poll:type_name -> signal.backup.Poll + 130, // 47: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending + 131, // 48: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent + 132, // 49: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered + 133, // 50: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read + 134, // 51: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed + 135, // 52: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped + 136, // 53: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed + 61, // 54: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange + 60, // 55: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote + 46, // 56: signal.backup.StandardMessage.text:type_name -> signal.backup.Text + 58, // 57: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment + 57, // 58: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview + 59, // 59: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer + 62, // 60: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction + 53, // 61: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment + 62, // 62: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction + 137, // 63: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply + 62, // 64: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction + 138, // 65: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails + 15, // 66: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State + 58, // 67: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment + 62, // 68: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction + 142, // 69: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name + 143, // 70: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone + 144, // 71: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email + 145, // 72: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress + 59, // 73: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer + 56, // 74: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker + 62, // 75: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction + 59, // 76: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer + 59, // 77: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer + 59, // 78: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer + 19, // 79: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag + 146, // 80: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo + 46, // 81: signal.backup.Quote.text:type_name -> signal.backup.Text + 147, // 82: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 20, // 83: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 21, // 84: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 148, // 85: signal.backup.Poll.options:type_name -> signal.backup.Poll.PollOption + 67, // 86: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 73, // 87: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 68, // 88: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 69, // 89: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 71, // 90: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 72, // 91: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 65, // 92: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 66, // 93: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 70, // 94: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 108, // 95: signal.backup.ChatUpdateMessage.pollTerminate:type_name -> signal.backup.PollTerminateUpdate + 22, // 96: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 23, // 97: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 24, // 98: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 25, // 99: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 26, // 100: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 150, // 101: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 102: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 103: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 151, // 104: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 27, // 105: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 59, // 106: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 154, // 107: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 28, // 108: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 29, // 109: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 30, // 110: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 3, // 111: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 2, // 112: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 110, // 113: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 153, // 114: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 121, // 115: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 121, // 116: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 121, // 117: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 126, // 118: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 122, // 119: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 123, // 120: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 124, // 121: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 125, // 122: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 7, // 123: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 122, // 124: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 8, // 125: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 126: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 8, // 127: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 45, // 128: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 12, // 129: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 46, // 130: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 59, // 131: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 141, // 132: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 140, // 133: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 13, // 134: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 14, // 135: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 139, // 136: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 16, // 137: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 17, // 138: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 18, // 139: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 58, // 140: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 149, // 141: signal.backup.Poll.PollOption.votes:type_name -> signal.backup.Poll.PollOption.PollVote + 74, // 142: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 75, // 143: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 76, // 144: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 77, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 78, // 146: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 79, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 80, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 81, // 149: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 82, // 150: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 83, // 151: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 84, // 152: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 85, // 153: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 86, // 154: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 87, // 155: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 88, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 89, // 157: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 90, // 158: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 91, // 159: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 92, // 160: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 93, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 94, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 95, // 163: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 96, // 164: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 98, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 99, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 100, // 167: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 101, // 168: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 102, // 169: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 103, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 104, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 105, // 172: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 106, // 173: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 97, // 174: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 107, // 175: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 152, // 176: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 177, // [177:177] is the sub-list for method output_type + 177, // [177:177] is the sub-list for method input_type + 177, // [177:177] is the sub-list for extension type_name + 177, // [177:177] is the sub-list for extension extendee + 0, // [0:177] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -12572,6 +12858,7 @@ func file_backuppb_Backup_proto_init() { (*ChatItem_GiftBadge)(nil), (*ChatItem_ViewOnceMessage)(nil), (*ChatItem_DirectStoryReplyMessage)(nil), + (*ChatItem_Poll)(nil), } file_backuppb_Backup_proto_msgTypes[14].OneofWrappers = []any{ (*SendStatus_Pending_)(nil), @@ -12598,7 +12885,7 @@ func file_backuppb_Backup_proto_init() { (*BodyRange_MentionAci)(nil), (*BodyRange_Style_)(nil), } - file_backuppb_Backup_proto_msgTypes[32].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[33].OneofWrappers = []any{ (*ChatUpdateMessage_SimpleUpdate)(nil), (*ChatUpdateMessage_GroupChange)(nil), (*ChatUpdateMessage_ExpirationTimerChange)(nil), @@ -12608,14 +12895,14 @@ func file_backuppb_Backup_proto_init() { (*ChatUpdateMessage_IndividualCall)(nil), (*ChatUpdateMessage_GroupCall)(nil), (*ChatUpdateMessage_LearnedProfileChange)(nil), + (*ChatUpdateMessage_PollTerminate)(nil), } - file_backuppb_Backup_proto_msgTypes[33].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[34].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[38].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[35].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[39].OneofWrappers = []any{ (*LearnedProfileChatUpdate_E164)(nil), (*LearnedProfileChatUpdate_Username)(nil), } - file_backuppb_Backup_proto_msgTypes[42].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[43].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[44].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[45].OneofWrappers = []any{} @@ -12624,51 +12911,52 @@ func file_backuppb_Backup_proto_init() { file_backuppb_Backup_proto_msgTypes[48].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[49].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[50].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[52].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[51].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[53].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[55].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[54].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[56].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[57].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[59].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[58].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[60].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[61].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[63].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[66].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[62].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[64].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[67].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[68].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[69].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[75].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[77].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[70].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[76].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[79].OneofWrappers = []any{ (*ChatStyle_WallpaperPreset_)(nil), (*ChatStyle_WallpaperPhoto)(nil), (*ChatStyle_AutoBubbleColor)(nil), (*ChatStyle_BubbleColorPreset_)(nil), (*ChatStyle_CustomColorId)(nil), } - file_backuppb_Backup_proto_msgTypes[78].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[81].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[83].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[80].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[83].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[85].OneofWrappers = []any{ (*AccountData_IAPSubscriberData_PurchaseToken)(nil), (*AccountData_IAPSubscriberData_OriginalTransactionId)(nil), } - file_backuppb_Backup_proto_msgTypes[88].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[90].OneofWrappers = []any{ (*Group_GroupAttributeBlob_Title)(nil), (*Group_GroupAttributeBlob_Avatar)(nil), (*Group_GroupAttributeBlob_DisappearingMessagesDuration)(nil), (*Group_GroupAttributeBlob_DescriptionText)(nil), } - file_backuppb_Backup_proto_msgTypes[94].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[105].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[96].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[107].OneofWrappers = []any{ (*PaymentNotification_TransactionDetails_Transaction_)(nil), (*PaymentNotification_TransactionDetails_FailedTransaction_)(nil), } - file_backuppb_Backup_proto_msgTypes[108].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[113].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[110].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[115].OneofWrappers = []any{ (*FilePointer_LocatorInfo_PlaintextHash)(nil), (*FilePointer_LocatorInfo_EncryptedDigest)(nil), } - file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[115].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{ (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), @@ -12704,8 +12992,8 @@ func file_backuppb_Backup_proto_init() { (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), } - file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[118].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[122].OneofWrappers = []any{ (*ChatStyle_CustomChatColor_Solid)(nil), (*ChatStyle_CustomChatColor_Gradient)(nil), } @@ -12715,7 +13003,7 @@ func file_backuppb_Backup_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), NumEnums: 31, - NumMessages: 120, + NumMessages: 124, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 464301d..66125fc 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -428,6 +428,7 @@ message ChatItem { GiftBadge giftBadge = 17; ViewOnceMessage viewOnceMessage = 18; DirectStoryReplyMessage directStoryReplyMessage = 19; // group story reply messages are not backed up + Poll poll = 20; } } @@ -759,6 +760,7 @@ message Quote { NORMAL = 1; GIFT_BADGE = 2; VIEW_ONCE = 3; + POLL = 4; } message QuotedAttachment { @@ -805,6 +807,25 @@ message Reaction { uint64 sortOrder = 4; } +message Poll { + + message PollOption { + + message PollVote { + uint64 voterId = 1; // A direct reference to Recipient proto id. Must be self or contact. + uint32 voteCount = 2; // Tracks how many times you voted. + } + + string option = 1; // Between 1-100 characters + repeated PollVote votes = 2; + } + + string question = 1; // Between 1-100 characters + bool allowMultiple = 2; + repeated PollOption options = 3; // At least two + bool hasEnded = 4; +} + message ChatUpdateMessage { // If unset, importers should ignore the update message without throwing an error. oneof update { @@ -817,6 +838,7 @@ message ChatUpdateMessage { IndividualCall individualCall = 7; GroupCall groupCall = 8; LearnedProfileChatUpdate learnedProfileChange = 9; + PollTerminateUpdate pollTerminate = 10; } } @@ -1182,6 +1204,11 @@ message GroupExpirationTimerUpdate { optional bytes updaterAci = 2; } +message PollTerminateUpdate { + uint64 targetSentTimestamp = 1; + string question = 2; // Between 1-100 characters +} + message StickerPack { bytes packId = 1; bytes packKey = 2; diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index bcdd71b..d8fea17 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-62fdf3d1aa9f637729ae67b55aadcc24f38f0117} -DESKTOP_GIT_REVISION=${1:-203a1cc5e3f9c1533a58caff72e13aa6eaeeddc7} +ANDROID_GIT_REVISION=${1:-d261f3ebf51864da067b968ee3366ed3e7369c78} +DESKTOP_GIT_REVISION=${1:-fb566c48e0fa146dfe0bea077ecdb3ff846ef80a} update_proto() { case "$1" in @@ -38,6 +38,7 @@ update_proto Signal-Android-App Backup.proto mv Backup.proto backuppb/Backup.proto update_proto Signal-Desktop DeviceName.proto -update_proto Signal-Desktop UnidentifiedDelivery.proto +# TODO this was moved to libsignal only +#update_proto Signal-Desktop UnidentifiedDelivery.proto # Android has CDSI.proto too, but the types have more generic names (since android uses a different package name) update_proto Signal-Desktop ContactDiscovery.proto From c9303dcd6dd89353d9b98fb31bf7a6491edc56c5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 29 Oct 2025 14:36:15 +0200 Subject: [PATCH 578/718] msgconv/from-signal: add support for polls --- ROADMAP.md | 6 +- pkg/connector/backfill.go | 2 +- pkg/connector/config.go | 2 + pkg/connector/connector.go | 1 + pkg/connector/example-config.yaml | 2 + pkg/connector/handlesignal.go | 4 +- pkg/msgconv/from-signal-backup.go | 10 +++ pkg/msgconv/from-signal.go | 139 +++++++++++++++++++++++++++++- pkg/msgconv/msgconv.go | 1 + pkg/signalid/dbmeta.go | 3 +- 10 files changed, 163 insertions(+), 7 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 1695ea0..7f6db0d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,6 +5,7 @@ * [x] Text * [x] Formatting * [x] Mentions + * [ ] Polls * [x] Media * [x] Images * [x] Audio files @@ -34,6 +35,7 @@ * [x] Text * [x] Formatting * [x] Mentions + * [x] Polls * [ ] Media * [x] Images * [x] Voice notes @@ -65,8 +67,8 @@ * [ ] Delivery receipts (there's no good way to bridge these) * [x] Disappearing messages * Misc - * [ ] Automatic portal creation - * [ ] After login + * [x] Automatic portal creation + * [x] After login * [x] When receiving message * [x] Linking as secondary device * [ ] Registering as primary device diff --git a/pkg/connector/backfill.go b/pkg/connector/backfill.go index 2dde03f..3f9a611 100644 --- a/pkg/connector/backfill.go +++ b/pkg/connector/backfill.go @@ -151,7 +151,7 @@ func (s *SignalClient) FetchMessages(ctx context.Context, params bridgev2.FetchM if dm == nil { continue } - cm := s.Main.MsgConv.ToMatrix(ctx, s.Client, params.Portal, s.Main.Bridge.Bot, dm, attMap) + cm := s.Main.MsgConv.ToMatrix(ctx, s.Client, params.Portal, senderACI, s.Main.Bridge.Bot, dm, attMap) convertedReactions := make([]*bridgev2.BackfillReaction, 0, len(reactions)) for _, reaction := range reactions { reactionSenderACI, err := getRecipientACI(reaction.AuthorId) diff --git a/pkg/connector/config.go b/pkg/connector/config.go index 4e42186..232571f 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -42,6 +42,7 @@ type SignalConfig struct { NoteToSelfAvatar id.ContentURIString `yaml:"note_to_self_avatar"` LocationFormat string `yaml:"location_format"` DisappearViewOnce bool `yaml:"disappear_view_once"` + ExtEvPolls bool `yaml:"extev_polls"` displaynameTemplate *template.Template `yaml:"-"` } @@ -103,6 +104,7 @@ func upgradeConfig(helper up.Helper) { helper.Copy(up.Str, "note_to_self_avatar") helper.Copy(up.Str, "location_format") helper.Copy(up.Bool, "disappear_view_once") + helper.Copy(up.Bool, "extev_polls") } func (s *SignalConnector) GetConfig() (string, any, up.Upgrader) { diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index e81ef7a..30be4a4 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -63,6 +63,7 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { s.MsgConv = msgconv.NewMessageConverter(bridge) s.MsgConv.LocationFormat = s.Config.LocationFormat s.MsgConv.DisappearViewOnce = s.Config.DisappearViewOnce + s.MsgConv.ExtEvPolls = s.Config.ExtEvPolls } func (s *SignalConnector) SetMaxFileSize(maxSize int64) { diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml index e9ff6b4..25fe035 100644 --- a/pkg/connector/example-config.yaml +++ b/pkg/connector/example-config.yaml @@ -24,3 +24,5 @@ note_to_self_avatar: mxc://maunium.net/REBIVrqjZwmaWpssCZpBlmlL location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s' # Should view-once messages disappear shortly after sending a read receipt on Matrix? disappear_view_once: false +# Should polls be sent using unstable MSC3381 event types? +extev_polls: false diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index d60acc0..6a2f3b5 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -327,7 +327,7 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po if !ok { return nil, fmt.Errorf("ConvertMessage() called for non-DataMessage event") } - converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, dataMsg, nil) + converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, evt.Info.Sender, intent, dataMsg, nil) if converted.Disappear.Type != "" { evtTS := evt.GetTimestamp() if !dataMsg.GetIsViewOnce() { @@ -352,7 +352,7 @@ func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Porta return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event") } // TODO tell converter about existing parts to avoid reupload? - converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, intent, editMsg.GetDataMessage(), nil) + 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]) editPart.Part.EditCount++ diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index 7e8d4e1..97f756c 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -81,6 +81,16 @@ func BackupToDataMessage(ci *backuppb.ChatItem, attMap AttachmentMap) (*signalpb Emoji: ti.StickerMessage.Sticker.Emoji, Data: backupToSignalAttachment(ti.StickerMessage.Sticker.Data, 0, uuid.New(), attMap), } + case *backuppb.ChatItem_Poll: + dm.PollCreate = &signalpb.DataMessage_PollCreate{ + Question: &ti.Poll.Question, + AllowMultiple: &ti.Poll.AllowMultiple, + Options: exslices.CastFunc(ti.Poll.Options, func(from *backuppb.Poll_PollOption) string { + return from.Option + }), + } + // TODO handle votes + // TODO handle hasEnded somehow? case *backuppb.ChatItem_RemoteDeletedMessage: // TODO handle some other way? (also disappeared view-once messages) return nil, nil diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index ac3fe65..9392616 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "net/http" + "strconv" "strings" "time" @@ -51,7 +52,7 @@ func calculateLength(dm *signalpb.DataMessage) int { if dm.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0 { return 1 } - if dm.Sticker != nil { + if dm.Sticker != nil || dm.PollVote != nil || dm.PollCreate != nil || dm.PollTerminate != nil { return 1 } length := len(dm.Attachments) + len(dm.Contact) @@ -80,6 +81,7 @@ func (mc *MessageConverter) ToMatrix( ctx context.Context, client *signalmeow.Client, portal *bridgev2.Portal, + sender uuid.UUID, intent bridgev2.MatrixAPI, dm *signalpb.DataMessage, attMap AttachmentMap, @@ -108,6 +110,18 @@ func (mc *MessageConverter) ToMatrix( // Don't allow any other parts in a sticker message return cm } + if dm.PollVote != nil { + cm.Parts = append(cm.Parts, mc.convertPollVoteToMatrix(ctx, dm.PollVote)) + return cm + } + if dm.PollCreate != nil { + cm.Parts = append(cm.Parts, mc.convertPollCreateToMatrix(dm.PollCreate)) + return cm + } + if dm.PollTerminate != nil { + cm.Parts = append(cm.Parts, mc.convertPollTerminateToMatrix(ctx, sender, dm.PollTerminate)) + return cm + } for i, att := range dm.GetAttachments() { if att.GetContentType() != "text/x-signal-plain" { cm.Parts = append(cm.Parts, mc.convertAttachmentToMatrix(ctx, i, att, attMap)) @@ -602,3 +616,126 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp Extra: extra, }, nil } + +func (mc *MessageConverter) convertPollCreateToMatrix(create *signalpb.DataMessage_PollCreate) *bridgev2.ConvertedMessagePart { + evtType := event.EventMessage + if mc.ExtEvPolls { + evtType = event.EventUnstablePollStart + } + maxChoices := 1 + if create.GetAllowMultiple() { + maxChoices = len(create.GetOptions()) + } + msc3381Answers := make([]map[string]any, len(create.GetOptions())) + optionsListText := make([]string, len(create.GetOptions())) + optionsListHTML := make([]string, len(create.GetOptions())) + for i, option := range create.GetOptions() { + msc3381Answers[i] = map[string]any{ + "id": strconv.Itoa(i), + "org.matrix.msc1767.text": option, + } + optionsListText[i] = fmt.Sprintf("%d. %s\n", i+1, option) + optionsListHTML[i] = fmt.Sprintf("
  • %s
  • ", event.TextToHTML(option)) + } + body := fmt.Sprintf("%s\n\n%s\n\n(This message is a poll. Please open Signal to vote.)", create.GetQuestion(), strings.Join(optionsListText, "\n")) + formattedBody := fmt.Sprintf("

    %s

      %s

    (This message is a poll. Please open Signal to vote.)

    ", event.TextToHTML(create.GetQuestion()), strings.Join(optionsListHTML, "")) + return &bridgev2.ConvertedMessagePart{ + Type: evtType, + Content: &event.MessageEventContent{ + MsgType: event.MsgText, + Body: body, + Format: event.FormatHTML, + FormattedBody: formattedBody, + }, + Extra: map[string]any{ + "fi.mau.signal.poll": map[string]any{ + "question": create.GetQuestion(), + "allow_multiple": create.GetAllowMultiple(), + "options": create.GetOptions(), + }, + "org.matrix.msc1767.message": []map[string]any{ + {"mimetype": "text/html", "body": formattedBody}, + {"mimetype": "text/plain", "body": body}, + }, + "org.matrix.msc3381.poll.start": map[string]any{ + "kind": "org.matrix.msc3381.poll.disclosed", + "max_selections": maxChoices, + "question": map[string]any{ + "org.matrix.msc1767.text": create.GetQuestion(), + }, + "answers": msc3381Answers, + }, + }, + DBMetadata: nil, + DontBridge: false, + } +} + +func (mc *MessageConverter) convertPollTerminateToMatrix(ctx context.Context, senderACI uuid.UUID, terminate *signalpb.DataMessage_PollTerminate) *bridgev2.ConvertedMessagePart { + pollMessageID := signalid.MakeMessageID(senderACI, terminate.GetTargetSentTimestamp()) + pollMessage, err := mc.Bridge.DB.Message.GetPartByID(ctx, getPortal(ctx).Receiver, pollMessageID, "") + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get poll terminate target message") + return &bridgev2.ConvertedMessagePart{ + Type: event.EventUnstablePollEnd, + Content: &event.MessageEventContent{}, + DontBridge: true, + } + } + return &bridgev2.ConvertedMessagePart{ + Type: event.EventUnstablePollEnd, + Content: &event.MessageEventContent{ + RelatesTo: &event.RelatesTo{ + Type: event.RelReference, + EventID: pollMessage.MXID, + }, + }, + Extra: map[string]any{ + "org.matrix.msc3381.poll.end": map[string]any{}, + }, + } +} + +var invalidPollVote = &bridgev2.ConvertedMessagePart{ + Type: event.EventUnstablePollResponse, + Content: &event.MessageEventContent{}, + DontBridge: true, +} + +func (mc *MessageConverter) convertPollVoteToMatrix(ctx context.Context, vote *signalpb.DataMessage_PollVote) *bridgev2.ConvertedMessagePart { + if len(vote.GetTargetAuthorAciBinary()) != 16 { + zerolog.Ctx(ctx).Debug(). + Str("author_aci_b64", base64.StdEncoding.EncodeToString(vote.GetTargetAuthorAciBinary())). + Msg("Invalid author ACI in poll vote") + return invalidPollVote + } + pollMessageID := signalid.MakeMessageID(uuid.UUID(vote.GetTargetAuthorAciBinary()), vote.GetTargetSentTimestamp()) + pollMessage, err := mc.Bridge.DB.Message.GetPartByID(ctx, getPortal(ctx).Receiver, pollMessageID, "") + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to get poll vote target message") + return invalidPollVote + } + mxOptionIDs := pollMessage.Metadata.(*signalid.MessageMetadata).MatrixPollOptionIDs + optionIDs := make([]string, len(vote.GetOptionIndexes())) + for i, optionIndex := range vote.GetOptionIndexes() { + if int(optionIndex) < len(mxOptionIDs) { + optionIDs[i] = mxOptionIDs[optionIndex] + } else { + optionIDs[i] = strconv.Itoa(int(optionIndex)) + } + } + return &bridgev2.ConvertedMessagePart{ + Type: event.EventUnstablePollResponse, + Content: &event.MessageEventContent{ + RelatesTo: &event.RelatesTo{ + Type: event.RelReference, + EventID: pollMessage.MXID, + }, + }, + Extra: map[string]any{ + "org.matrix.msc3381.poll.response": map[string]any{ + "answers": optionIDs, + }, + }, + } +} diff --git a/pkg/msgconv/msgconv.go b/pkg/msgconv/msgconv.go index 86e7e2d..1b8564a 100644 --- a/pkg/msgconv/msgconv.go +++ b/pkg/msgconv/msgconv.go @@ -48,6 +48,7 @@ type MessageConverter struct { LocationFormat string DisappearViewOnce bool DirectMedia bool + ExtEvPolls bool } func NewMessageConverter(br *bridgev2.Bridge) *MessageConverter { diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index 72112a8..bbbcc92 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -28,7 +28,8 @@ type PortalMetadata struct { } type MessageMetadata struct { - ContainsAttachments bool `json:"contains_attachments,omitempty"` + ContainsAttachments bool `json:"contains_attachments,omitempty"` + MatrixPollOptionIDs []string `json:"matrix_poll_option_ids,omitempty"` } type UserLoginMetadata struct { From 71e2e221f79e359bcffc48b6d90ba0f3e73cceb2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 29 Oct 2025 14:50:26 +0200 Subject: [PATCH 579/718] handlematrix: add support for polls --- ROADMAP.md | 2 +- pkg/connector/handlematrix.go | 74 +++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 7f6db0d..228b271 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,7 +5,7 @@ * [x] Text * [x] Formatting * [x] Mentions - * [ ] Polls + * [x] Polls * [x] Media * [x] Images * [x] Audio files diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 65e7b7c..3aa266b 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -21,6 +21,7 @@ import ( "crypto/sha256" "errors" "fmt" + "slices" "strconv" "time" @@ -52,6 +53,7 @@ var ( _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) _ bridgev2.DisappearTimerChangingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.PollHandlingNetworkAPI = (*SignalClient)(nil) ) func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { @@ -116,9 +118,27 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma if err != nil { return nil, err } + return s.doSendMessage(ctx, ts, msg, converted, &signalid.MessageMetadata{ + ContainsAttachments: len(converted.Attachments) > 0, + }) +} + +func (s *SignalClient) doSendMessage( + ctx context.Context, + ts uint64, + msg *bridgev2.MatrixMessage, + converted *signalpb.DataMessage, + meta *signalid.MessageMetadata, +) (*bridgev2.MatrixMessageResponse, error) { + if ts == 0 { + ts = getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) + } + if meta == nil { + meta = &signalid.MessageMetadata{} + } msgID := signalid.MakeMessageID(s.Client.Store.ACI, ts) msg.AddPendingToIgnore(networkid.TransactionID(msgID)) - err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) + err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) if err != nil { return nil, bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } @@ -126,9 +146,7 @@ func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Ma ID: msgID, SenderID: signalid.MakeUserID(s.Client.Store.ACI), Timestamp: time.UnixMilli(int64(ts)), - Metadata: &signalid.MessageMetadata{ - ContainsAttachments: len(converted.Attachments) > 0, - }, + Metadata: meta, } return &bridgev2.MatrixMessageResponse{ DB: dbMsg, @@ -679,3 +697,51 @@ func (s *SignalClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *b return true, nil } } + +func (s *SignalClient) HandleMatrixPollStart(ctx context.Context, msg *bridgev2.MatrixPollStart) (*bridgev2.MatrixMessageResponse, error) { + optionNames := make([]string, len(msg.Content.PollStart.Answers)) + optionIDs := make([]string, len(msg.Content.PollStart.Answers)) + for i, option := range msg.Content.PollStart.Answers { + optionNames[i] = option.Text + optionIDs[i] = option.ID + } + converted := &signalpb.DataMessage{ + PollCreate: &signalpb.DataMessage_PollCreate{ + Question: ptr.Ptr(msg.Content.PollStart.Question.Text), + AllowMultiple: ptr.Ptr(msg.Content.PollStart.MaxSelections != 1), + Options: optionNames, + }, + RequiredProtocolVersion: ptr.Ptr(uint32(signalpb.DataMessage_POLLS)), + } + return s.doSendMessage(ctx, 0, &msg.MatrixMessage, converted, &signalid.MessageMetadata{ + MatrixPollOptionIDs: optionIDs, + }) +} + +func (s *SignalClient) HandleMatrixPollVote(ctx context.Context, msg *bridgev2.MatrixPollVote) (*bridgev2.MatrixMessageResponse, error) { + senderACI, msgTS, err := signalid.ParseMessageID(msg.VoteTo.ID) + if err != nil { + return nil, err + } + mxOptions := msg.VoteTo.Metadata.(*signalid.MessageMetadata).MatrixPollOptionIDs + optionIndexes := make([]uint32, len(msg.Content.Response.Answers)) + for i, answer := range msg.Content.Response.Answers { + if idx := slices.Index(mxOptions, answer); idx >= 0 { + optionIndexes[i] = uint32(idx) + } else if idx, err = strconv.Atoi(answer); err == nil && idx >= 0 { + optionIndexes[i] = uint32(idx) + } else { + return nil, fmt.Errorf("unknown poll answer ID: %s", answer) + } + } + converted := &signalpb.DataMessage{ + PollVote: &signalpb.DataMessage_PollVote{ + TargetAuthorAciBinary: senderACI[:], + TargetSentTimestamp: &msgTS, + OptionIndexes: optionIndexes, + VoteCount: nil, // TODO + }, + RequiredProtocolVersion: ptr.Ptr(uint32(signalpb.DataMessage_POLLS)), + } + return s.doSendMessage(ctx, 0, &msg.MatrixMessage, converted, nil) +} From e3d058732adc0325674991dabf2fc65883a39024 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Oct 2025 22:35:49 +0200 Subject: [PATCH 580/718] libsignal: update to v0.85.2 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 88 +++++++++++++++++++++++++++++++++ pkg/libsignalgo/version.go | 2 +- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index c02859f..57f2254 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit c02859f57552477680fb7928c3c3426193040313 +Subproject commit 57f2254605086b0bf0c7d274ed8eaa6fafa84ee2 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index a516a23..157f642 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -255,6 +255,8 @@ typedef enum { SignalErrorCodeRegistrationLock = 201, SignalErrorCodeKeyTransparencyError = 210, SignalErrorCodeKeyTransparencyVerificationFailed = 211, + SignalErrorCodeRequestUnauthorized = 220, + SignalErrorCodeMismatchedDevices = 221, } SignalErrorCode; enum SignalSvr2CredentialsResult { @@ -897,6 +899,35 @@ typedef struct { uint32_t second; } SignalPairOfc_charu32; +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + uint32_t *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfu32; + +typedef struct { + SignalServiceIdFixedWidthBinaryBytes account; + SignalOwnedBufferOfu32 missing_devices; + SignalOwnedBufferOfu32 extra_devices; + SignalOwnedBufferOfu32 stale_devices; +} SignalFfiMismatchedDevicesError; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalFfiMismatchedDevicesError *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfFfiMismatchedDevicesError; + typedef struct { const char *first; SignalOwnedBuffer second; @@ -941,6 +972,17 @@ typedef struct { size_t length; } SignalOwnedBufferOfFfiRegisterResponseBadge; +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalServiceIdFixedWidthBinaryBytes *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfServiceIdFixedWidthBinaryBytes; + typedef struct { SignalSenderKeyRecord *raw; } SignalMutPointerSenderKeyRecord; @@ -1418,6 +1460,42 @@ typedef struct { SignalCancellationId cancellation_id; } SignalCPromiseOptionalUuid; +typedef struct { + bool present; + const char *first; + uint8_t second[32]; +} SignalOptionalPairOfc_charu832; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalOptionalPairOfc_charu832 *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseOptionalPairOfc_charu832; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalOwnedBufferOfServiceIdFixedWidthBinaryBytes *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseOwnedBufferOfServiceIdFixedWidthBinaryBytes; + typedef struct { SignalValidatingMac *raw; } SignalMutPointerValidatingMac; @@ -1704,6 +1782,8 @@ SignalFfiError *signal_error_get_invalid_protocol_address(SignalPairOfc_charu32 SignalFfiError *signal_error_get_message(const char **out, SignalUnwindSafeArgSignalFfiError err); +SignalFfiError *signal_error_get_mismatched_device_errors(SignalOwnedBufferOfFfiMismatchedDevicesError *out, SignalUnwindSafeArgSignalFfiError err); + SignalFfiError *signal_error_get_our_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_rate_limit_challenge(SignalPairOfc_charOwnedBufferOfc_uchar *out, SignalUnwindSafeArgSignalFfiError err); @@ -1746,8 +1826,12 @@ void signal_free_buffer(const unsigned char *buf, size_t buf_len); void signal_free_bytestring_array(SignalBytestringArray array); +void signal_free_list_of_mismatched_device_errors(SignalOwnedBufferOfFfiMismatchedDevicesError buffer); + void signal_free_list_of_register_response_badges(SignalOwnedBufferOfFfiRegisterResponseBadge buffer); +void signal_free_list_of_service_ids(SignalOwnedBufferOfServiceIdFixedWidthBinaryBytes buffer); + void signal_free_list_of_strings(SignalOwnedBufferOfCStringPtr buffer); void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); @@ -2516,8 +2600,12 @@ SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConst SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_hash(SignalCPromiseOptionalUuid *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer hash); +SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_link(SignalCPromiseOptionalPairOfc_charu832 *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const uint8_t (*uuid)[16], SignalBorrowedBuffer entropy); + SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); +SignalFfiError *signal_unauthenticated_chat_connection_send_multi_recipient_message(SignalCPromiseOwnedBufferOfServiceIdFixedWidthBinaryBytes *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer payload, uint64_t timestamp, SignalBorrowedBuffer auth, bool online_only, bool is_urgent); + SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); SignalFfiError *signal_unidentified_sender_message_content_destroy(SignalMutPointerUnidentifiedSenderMessageContent p); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index b859d49..b04d73b 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.84.0" +const Version = "v0.85.2" From f01415c61add68c6dca86ca04eb98118dc8f4c84 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 9 Nov 2025 11:41:52 +0200 Subject: [PATCH 581/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f61bdd1..464486c 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.46.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.3-0.20251028130646-bea28c1381cd + maunium.net/go/mautrix v0.25.3-0.20251109094010-14e16a3a8190 ) require ( diff --git a/go.sum b/go.sum index fa344cc..f89121c 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.25.3-0.20251028130646-bea28c1381cd h1:4OfgnwTd71vgHGc+kBwhWsb92ePZVvsDbyTLJiy+PKU= -maunium.net/go/mautrix v0.25.3-0.20251028130646-bea28c1381cd/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.25.3-0.20251109094010-14e16a3a8190 h1:5v25ZS99ilLXHjYX3uMiyHGBNhFPXgOgGfr9GkakRTg= +maunium.net/go/mautrix v0.25.3-0.20251109094010-14e16a3a8190/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= From 6987023492df81563d535ddc9ca73207a4059b9d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 11 Nov 2025 13:30:22 +0200 Subject: [PATCH 582/718] libsignal: update to v0.86.2 --- CHANGELOG.md | 4 ++++ pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 2 ++ pkg/libsignalgo/version.go | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e38aa4..858c3bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # v25.11 (unreleased) +* Updated libsignal to v0.86.2. * Added support for bridging invite state in groups for phone number invites. +* Added support for polls. * Fixed PNI signature not being sent when replying to message requests. * Fixed unnecessary repeating error notices when Signal is down. +* Fixed sticker size metadata on Matrix not matching how native Signal Desktop + renders them. # v25.10 diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 57f2254..2dcd1e0 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 57f2254605086b0bf0c7d274ed8eaa6fafa84ee2 +Subproject commit 2dcd1e0b793469013043d3a0d37dc55f95b0babd diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 157f642..26cbb6b 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -1510,6 +1510,8 @@ typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN]; typedef uint8_t SignalUnidentifiedAccessKey[SignalACCESS_KEY_LEN]; + + SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy); SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index b04d73b..b202516 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.85.2" +const Version = "v0.86.2" From f4aa0847651cff4fe7d28ca9ec975133f7715bfc Mon Sep 17 00:00:00 2001 From: Conan Date: Sat, 15 Nov 2025 04:21:29 +0800 Subject: [PATCH 583/718] handlematrix: implement DeleteChatHandlingNetworkAPI (#616) Co-authored-by: Tulir Asokan --- pkg/connector/capabilities.go | 4 +- pkg/connector/handlematrix.go | 87 +++++++++++++++++++++++++++++++++++ pkg/signalmeow/sending.go | 2 + 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index b9cb632..ca2975c 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_10_27" + base := "fi.mau.signal.capabilities.2025_10_28" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -169,6 +169,8 @@ var signalCaps = &event.RoomFeatures{ CustomEmojiReactions: false, ReadReceipts: true, TypingNotifications: true, + + DeleteChat: true, } var signalDisappearingCap = &event.DisappearingTimerCapability{ diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 3aa266b..deb52e3 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -53,6 +53,7 @@ var ( _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) _ bridgev2.DisappearTimerChangingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.DeleteChatHandlingNetworkAPI = (*SignalClient)(nil) _ bridgev2.PollHandlingNetworkAPI = (*SignalClient)(nil) ) @@ -698,6 +699,92 @@ func (s *SignalClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *b } } +func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2.MatrixDeleteChat) error { + userID, groupID, err := signalid.ParsePortalID(msg.Portal.ID) + if err != nil { + return fmt.Errorf("failed to parse portal ID: %w", err) + } + + // Build ConversationIdentifier based on portal type + var conversationID *signalpb.ConversationIdentifier + if groupID == "" { + conversationID = &signalpb.ConversationIdentifier{ + Identifier: &signalpb.ConversationIdentifier_ThreadServiceId{ + ThreadServiceId: userID.String(), + }, + } + } else { + gid, err := groupID.Bytes() + if err != nil { + return fmt.Errorf("failed to parse group ID: %w", err) + } + conversationID = &signalpb.ConversationIdentifier{ + Identifier: &signalpb.ConversationIdentifier_ThreadGroupId{ + ThreadGroupId: gid[:], + }, + } + } + + // Retrieve most recent messages from the portal + var mostRecentMessages []*signalpb.AddressableMessage + dbMessages, err := s.Main.Bridge.DB.Message.GetMessagesBetweenTimeQuery( + ctx, + msg.Portal.PortalKey, + time.Now().Add(-30*24*time.Hour), // Last 30 days + time.Now(), + ) + if err != nil { + zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get recent messages for conversation delete") + } else if len(dbMessages) > 0 { + // Limit to the 5 most recent messages overall + limit := 5 + startIdx := 0 + if len(dbMessages) > limit { + startIdx = len(dbMessages) - limit + } + + // Create AddressableMessage for most recent messages + for _, dbMsg := range dbMessages[startIdx:] { + senderACI, timestamp, err := signalid.ParseMessageID(dbMsg.ID) + if err != nil { + continue + } + + mostRecentMessages = append(mostRecentMessages, &signalpb.AddressableMessage{ + Author: &signalpb.AddressableMessage_AuthorServiceId{ + AuthorServiceId: senderACI.String(), + }, + SentTimestamp: proto.Uint64(timestamp), + }) + } + } + + recipientID := s.Client.Store.ACIServiceID() + // Send DeleteForMe sync message to self + result := s.Client.SendMessage(ctx, recipientID, &signalpb.Content{ + SyncMessage: &signalpb.SyncMessage{ + DeleteForMe: &signalpb.SyncMessage_DeleteForMe{ + ConversationDeletes: []*signalpb.SyncMessage_DeleteForMe_ConversationDelete{{ + Conversation: conversationID, + MostRecentMessages: mostRecentMessages, + IsFullDelete: proto.Bool(true), + }}, + }, + }, + }) + + zerolog.Ctx(ctx).Debug(). + Str("portal_id", string(msg.Portal.ID)). + Int("recent_messages_count", len(mostRecentMessages)). + Msg("Sent conversation deletion to Signal") + + if !result.WasSuccessful { + return fmt.Errorf("failed to send delete conversation sync message: %w %s %s", result.Error, userID, groupID) + } + + return nil +} + func (s *SignalClient) HandleMatrixPollStart(ctx context.Context, msg *bridgev2.MatrixPollStart) (*bridgev2.MatrixMessageResponse, error) { optionNames := make([]string, len(msg.Content.PollStart.Answers)) optionIDs := make([]string, len(msg.Content.PollStart.Answers)) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index c1b2016..8bfc5a5 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -660,6 +660,8 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) + } else if content.GetSyncMessage() != nil { + syncContent = content } if syncContent != nil { _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, false) From 12808bbe8a3ecb2d274436a8c198778162f71d4b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 15 Nov 2025 18:40:57 +0200 Subject: [PATCH 584/718] libsignal: update to v0.86.4 --- CHANGELOG.md | 2 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/version.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 858c3bc..a3a256c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # v25.11 (unreleased) -* Updated libsignal to v0.86.2. +* Updated libsignal to v0.86.4. * Added support for bridging invite state in groups for phone number invites. * Added support for polls. * Fixed PNI signature not being sent when replying to message requests. diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 2dcd1e0..5a64e17 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 2dcd1e0b793469013043d3a0d37dc55f95b0babd +Subproject commit 5a64e17ed4450eaf5fe29bfa611c9838736ac1a6 diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index b202516..dbb024d 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.86.2" +const Version = "v0.86.4" From 74d9ebb371d9d5b48458f967e7fade4589f8e905 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 15 Nov 2025 18:59:21 +0200 Subject: [PATCH 585/718] signalmeow/attachments: update group avatar upload url --- pkg/signalmeow/attachments.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index ea03c21..67a55c8 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -305,7 +305,7 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi } // Get upload form from Signal server - formPath := "/v1/groups/avatar/form" + formPath := "/v2/groups/avatar/form" opts := &web.HTTPReqOpt{Username: &groupAuth.Username, Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, Host: web.StorageHostname} resp, err := web.SendHTTPRequest(ctx, http.MethodGet, formPath, opts) if err != nil { From a3cab68309d741214c876eee0962ad2756a09604 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Nov 2025 13:43:08 +0200 Subject: [PATCH 586/718] Bump version to v25.11 --- CHANGELOG.md | 2 +- cmd/mautrix-signal/main.go | 2 +- go.mod | 18 +++++++++--------- go.sum | 32 ++++++++++++++++---------------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3a256c..4f147c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v25.11 (unreleased) +# v25.11 * Updated libsignal to v0.86.4. * Added support for bridging invite state in groups for phone number invites. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 73a2921..522834f 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -34,7 +34,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "25.10", + Version: "25.11", SemCalVer: true, Connector: &connector.SignalConnector{}, diff --git a/go.mod b/go.mod index 464486c..e2700a0 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.24.0 -toolchain go1.25.3 +toolchain go1.25.4 require ( github.com/coder/websocket v1.8.14 @@ -12,13 +12,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.2 - golang.org/x/crypto v0.43.0 - golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b - golang.org/x/net v0.46.0 + go.mau.fi/util v0.9.3 + golang.org/x/crypto v0.44.0 + golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 + golang.org/x/net v0.47.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.25.3-0.20251109094010-14e16a3a8190 + maunium.net/go/mautrix v0.26.0 ) require ( @@ -40,9 +40,9 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.13 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/text v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // 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 diff --git a/go.sum b/go.sum index f89121c..9b47a04 100644 --- a/go.sum +++ b/go.sum @@ -65,25 +65,25 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.2 h1:+S4Z03iCsGqU2WY8X2gySFsFjaLlUHFRDVCYvVwynKM= -go.mau.fi/util v0.9.2/go.mod h1:055elBBCJSdhRsmub7ci9hXZPgGr1U6dYg44cSgRgoU= +go.mau.fi/util v0.9.3 h1:aqNF8KDIN8bFpFbybSk+mEBil7IHeBwlujfyTnvP0uU= +go.mau.fi/util v0.9.3/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ= 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.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA= -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0= +golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -95,5 +95,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.25.3-0.20251109094010-14e16a3a8190 h1:5v25ZS99ilLXHjYX3uMiyHGBNhFPXgOgGfr9GkakRTg= -maunium.net/go/mautrix v0.25.3-0.20251109094010-14e16a3a8190/go.mod h1:EWgYyp2iFZP7pnSm+rufHlO8YVnA2KnoNBDpwekiAwI= +maunium.net/go/mautrix v0.26.0 h1:valc2VmZF+oIY4bMq4Cd5H9cEKMRe8eP4FM7iiaYLxI= +maunium.net/go/mautrix v0.26.0/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= From 8afd786108ef8b59303231ffb31408ecf20dd5a7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Nov 2025 15:40:36 +0200 Subject: [PATCH 587/718] signalmeow/provisioning: fix link capabilities --- pkg/signalmeow/provisioning.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 8e87738..d877276 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -299,7 +299,7 @@ func startProvisioning(ctx context.Context, ws *websocket.Conn, provisioningCiph return "", fmt.Errorf("failed to unmarshal provisioning UUID: %w", err) } - linkCapabilities := []string{"backup4", "backup5"} + linkCapabilities := []string{"backup4,backup5"} if !allowBackup { linkCapabilities = []string{} } From f9adb1641599b74228e5292842a9ce983f00d9f5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Nov 2025 15:07:15 +0200 Subject: [PATCH 588/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e2700a0..e25aa3b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.47.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.0 + maunium.net/go/mautrix v0.26.1-0.20251119111538-57657d54eeac ) require ( diff --git a/go.sum b/go.sum index 9b47a04..a96f394 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.26.0 h1:valc2VmZF+oIY4bMq4Cd5H9cEKMRe8eP4FM7iiaYLxI= -maunium.net/go/mautrix v0.26.0/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= +maunium.net/go/mautrix v0.26.1-0.20251119111538-57657d54eeac h1:zRQXrl+c9Isc1pJ7/MAdov8OKt+MVPGh5qjTzefxb+k= +maunium.net/go/mautrix v0.26.1-0.20251119111538-57657d54eeac/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= From 75653b339261db938e57ace37fd838bc9865d0d1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Nov 2025 23:15:02 +0200 Subject: [PATCH 589/718] dependencies: update mautrix-go again --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e25aa3b..1d83420 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.47.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251119111538-57657d54eeac + maunium.net/go/mautrix v0.26.1-0.20251119211341-fa56255a06be ) require ( diff --git a/go.sum b/go.sum index a96f394..dbd972c 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.26.1-0.20251119111538-57657d54eeac h1:zRQXrl+c9Isc1pJ7/MAdov8OKt+MVPGh5qjTzefxb+k= -maunium.net/go/mautrix v0.26.1-0.20251119111538-57657d54eeac/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= +maunium.net/go/mautrix v0.26.1-0.20251119211341-fa56255a06be h1:RoTQW/g3Upum3RSzdbOlpxhphDsA7+FtFzmF3Obe0o0= +maunium.net/go/mautrix v0.26.1-0.20251119211341-fa56255a06be/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= From bc47e22ae4a2f7138f96a9fb79873a8b3900075f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 19 Nov 2025 23:22:24 +0200 Subject: [PATCH 590/718] dependencies: update mautrix-go again --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1d83420..9cd9dbb 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( golang.org/x/net v0.47.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251119211341-fa56255a06be + maunium.net/go/mautrix v0.26.1-0.20251119212156-1fac8ceb6653 ) require ( diff --git a/go.sum b/go.sum index dbd972c..835ede2 100644 --- a/go.sum +++ b/go.sum @@ -95,5 +95,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.26.1-0.20251119211341-fa56255a06be h1:RoTQW/g3Upum3RSzdbOlpxhphDsA7+FtFzmF3Obe0o0= -maunium.net/go/mautrix v0.26.1-0.20251119211341-fa56255a06be/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= +maunium.net/go/mautrix v0.26.1-0.20251119212156-1fac8ceb6653 h1:z62cPre4V+NGIonN5qlvt1ZtZH5/93ix9DR7KR8yImU= +maunium.net/go/mautrix v0.26.1-0.20251119212156-1fac8ceb6653/go.mod h1:NWMv+243NX/gDrLofJ2nNXJPrG8vzoM+WUCWph85S6Q= From b9061c2aa01cd1625a527092e33acc30ffa45fb0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Nov 2025 13:16:20 +0200 Subject: [PATCH 591/718] signalmeow/receiving: split sync message handling to new function --- pkg/signalmeow/receiving.go | 271 +++++++++++++++++++----------------- 1 file changed, 140 insertions(+), 131 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index d630386..dc678e4 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -417,6 +417,22 @@ func (cli *Client) handleDecryptedResult( }() } + theirServiceID, err := result.SenderAddress.NameServiceID() + if err != nil { + log.Warn(). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Msg("Failed to get sender name as service ID") + return fmt.Errorf("failed to get sender name as service ID: %w", err) + } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { + log.Warn(). + Any("their_service_id", theirServiceID). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Msg("Dropping message from non-ACI sender") + return nil + } + handlerSuccess := true // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted @@ -430,12 +446,6 @@ func (cli *Client) handleDecryptedResult( logEvt.Msg("Decryption error with unknown sender") return nil } - theirServiceID, err := result.SenderAddress.NameServiceID() - if err != nil { - log.Err(err).Msg("Name error handling decryption error") - } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { - log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") - } if errors.Is(result.Err, EventAlreadyProcessed) { logEvt.Discard().Msg("") log.Debug().Err(result.Err). @@ -471,12 +481,11 @@ func (cli *Client) handleDecryptedResult( return nil } - name, _ := result.SenderAddress.Name() - deviceId, _ := result.SenderAddress.DeviceID() - log.Trace().Any("raw_data", content).Str("sender", name).Uint("sender_device", deviceId).Msg("Raw event data") + deviceID, _ := result.SenderAddress.DeviceID() + log.Trace().Any("raw_data", content).Stringer("sender", theirServiceID).Uint("sender_device", deviceID).Msg("Raw event data") newLog := log.With(). - Str("sender_name", name). - Uint("sender_device_id", deviceId). + Stringer("sender_name", theirServiceID). + Uint("sender_device_id", deviceID). Str("destination_service_id", destinationServiceID.String()). Logger() log = &newLog @@ -507,15 +516,6 @@ func (cli *Client) handleDecryptedResult( } } - theirServiceID, err := result.SenderAddress.NameServiceID() - if err != nil { - log.Err(err).Msg("Name error") - return err - } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { - log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") - return nil - } - if destinationServiceID == cli.Store.PNIServiceID() { _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { if !recipient.NeedsPNISignature { @@ -541,118 +541,11 @@ func (cli *Client) handleDecryptedResult( } } - // TODO: handle more sync messages - if content.SyncMessage != nil { - if content.SyncMessage.Keys != nil { - aep := libsignalgo.AccountEntropyPool(content.SyncMessage.Keys.GetAccountEntropyPool()) - cli.Store.MasterKey = content.SyncMessage.Keys.GetMaster() - if aep != "" { - aepMasterKey, err := aep.DeriveSVRKey() - if err != nil { - log.Err(err).Msg("Failed to derive master key from account entropy pool") - } else if cli.Store.MasterKey == nil { - cli.Store.MasterKey = aepMasterKey - log.Debug().Msg("Derived master key from account entropy pool (no master key in sync message)") - } else if !bytes.Equal(aepMasterKey, cli.Store.MasterKey) { - log.Warn().Msg("Derived master key doesn't match one in sync message") - } else { - log.Debug().Msg("Derived master key matches one in sync message") - } - } else { - log.Debug().Msg("No account entropy pool in sync message") - } - err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) - if err != nil { - log.Err(err).Msg("Failed to save device after receiving master key") - } else { - log.Info().Msg("Received master key") - go cli.SyncStorage(ctx) - } - } else if content.SyncMessage.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { - log.Debug().Msg("Received storage manifest fetch latest notice") - go cli.SyncStorage(ctx) + if content.SyncMessage != nil && theirServiceID == cli.Store.ACIServiceID() { + handlerSuccess, err = cli.handleSyncMessage(ctx, content.SyncMessage, envelope) + if err != nil { + return err } - syncSent := content.SyncMessage.GetSent() - if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { - destination := syncSent.DestinationServiceId - var syncDestinationServiceID libsignalgo.ServiceID - if destination != nil { - syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) - if err != nil { - log.Err(err).Msg("Sync message destination parse error") - return err - } - if syncSent.GetDestinationE164() != "" { - aci, pni := syncDestinationServiceID.ToACIAndPNI() - _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) - if err != nil { - log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") - } - } - } - if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { - log.Warn().Msg("sync message sent destination is nil") - } else if content.SyncMessage.Sent.Message != nil { - // TODO handle expiration start ts, and maybe the sync message ts? - cli.incomingDataMessage(ctx, content.SyncMessage.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) - } else if content.SyncMessage.Sent.EditMessage != nil { - cli.incomingEditMessage(ctx, content.SyncMessage.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) - } - } - if content.SyncMessage.Contacts != nil { - log.Debug().Msg("Recieved sync message contacts") - blob := content.SyncMessage.Contacts.Blob - if blob != nil { - contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil) - if err != nil { - log.Err(err).Msg("Contacts Sync DownloadAttachment error") - } - // unmarshall contacts - contacts, avatars, err := unmarshalContactDetailsMessages(contactsBytes) - if err != nil { - log.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") - } - log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") - convertedContacts := make([]*types.Recipient, 0, len(contacts)) - err = cli.Store.DoContactTxn(ctx, func(ctx context.Context) error { - for i, signalContact := range contacts { - if signalContact.Aci == nil || *signalContact.Aci == "" { - // TODO lookup PNI via CDSI and store that when ACI is missing? - log.Info(). - Any("contact", signalContact). - Msg("Signal Contact UUID is nil, skipping") - continue - } - contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) - if err != nil { - return err - } - convertedContacts = append(convertedContacts, contact) - } - return nil - }) - if err != nil { - log.Err(err).Msg("Error storing contacts") - } else { - handlerSuccess = cli.handleEvent(&events.ContactList{ - Contacts: convertedContacts, - }) - } - } - } - if content.SyncMessage.Read != nil { - handlerSuccess = cli.handleEvent(&events.ReadSelf{ - Timestamp: envelope.GetTimestamp(), - Messages: content.SyncMessage.GetRead(), - }) - } - if content.SyncMessage.DeleteForMe != nil { - handlerSuccess = cli.handleEvent(&events.DeleteForMe{ - Timestamp: envelope.GetTimestamp(), - SyncMessage_DeleteForMe: content.SyncMessage.DeleteForMe, - }) - } - } sendDeliveryReceipt := true @@ -725,6 +618,122 @@ func groupOrUserID(groupID types.GroupIdentifier, userID libsignalgo.ServiceID) return string(groupID) } +func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMessage, envelope *signalpb.Envelope) (handlerSuccess bool, err error) { + // TODO: handle more sync messages + handlerSuccess = true + log := zerolog.Ctx(ctx) + if msg.Keys != nil { + aep := libsignalgo.AccountEntropyPool(msg.Keys.GetAccountEntropyPool()) + cli.Store.MasterKey = msg.Keys.GetMaster() + if aep != "" { + aepMasterKey, err := aep.DeriveSVRKey() + if err != nil { + log.Err(err).Msg("Failed to derive master key from account entropy pool") + } else if cli.Store.MasterKey == nil { + cli.Store.MasterKey = aepMasterKey + log.Debug().Msg("Derived master key from account entropy pool (no master key in sync message)") + } else if !bytes.Equal(aepMasterKey, cli.Store.MasterKey) { + log.Warn().Msg("Derived master key doesn't match one in sync message") + } else { + log.Debug().Msg("Derived master key matches one in sync message") + } + } else { + log.Debug().Msg("No account entropy pool in sync message") + } + err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + if err != nil { + log.Err(err).Msg("Failed to save device after receiving master key") + } else { + log.Info().Msg("Received master key") + go cli.SyncStorage(ctx) + } + } else if msg.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { + log.Debug().Msg("Received storage manifest fetch latest notice") + go cli.SyncStorage(ctx) + } + syncSent := msg.GetSent() + if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { + destination := syncSent.DestinationServiceId + var syncDestinationServiceID libsignalgo.ServiceID + if destination != nil { + syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) + if err != nil { + log.Err(err).Msg("Sync message destination parse error") + return + } + if syncSent.GetDestinationE164() != "" { + aci, pni := syncDestinationServiceID.ToACIAndPNI() + _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) + if err != nil { + log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") + } + } + } + if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { + log.Warn().Msg("sync message sent destination is nil") + } else if msg.Sent.Message != nil { + // TODO handle expiration start ts, and maybe the sync message ts? + cli.incomingDataMessage(ctx, msg.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) + } else if msg.Sent.EditMessage != nil { + cli.incomingEditMessage(ctx, msg.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) + } + } + if msg.Contacts != nil { + log.Debug().Msg("Recieved sync message contacts") + blob := msg.Contacts.Blob + if blob != nil { + contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil) + if err != nil { + log.Err(err).Msg("Contacts Sync DownloadAttachment error") + } + // unmarshall contacts + contacts, avatars, err := unmarshalContactDetailsMessages(contactsBytes) + if err != nil { + log.Err(err).Msg("Contacts Sync unmarshalContactDetailsMessages error") + } + log.Debug().Int("contact_count", len(contacts)).Msg("Contacts Sync received contacts") + convertedContacts := make([]*types.Recipient, 0, len(contacts)) + err = cli.Store.DoContactTxn(ctx, func(ctx context.Context) error { + for i, signalContact := range contacts { + if signalContact.Aci == nil || *signalContact.Aci == "" { + // TODO lookup PNI via CDSI and store that when ACI is missing? + log.Info(). + Any("contact", signalContact). + Msg("Signal Contact UUID is nil, skipping") + continue + } + contact, err := cli.StoreContactDetailsAsContact(ctx, signalContact, &avatars[i]) + if err != nil { + return err + } + convertedContacts = append(convertedContacts, contact) + } + return nil + }) + if err != nil { + log.Err(err).Msg("Error storing contacts") + } else { + handlerSuccess = cli.handleEvent(&events.ContactList{ + Contacts: convertedContacts, + }) + } + } + } + if msg.Read != nil { + handlerSuccess = cli.handleEvent(&events.ReadSelf{ + Timestamp: envelope.GetTimestamp(), + Messages: msg.GetRead(), + }) + } + if msg.DeleteForMe != nil { + handlerSuccess = cli.handleEvent(&events.DeleteForMe{ + Timestamp: envelope.GetTimestamp(), + SyncMessage_DeleteForMe: msg.DeleteForMe, + }) + } + return +} + func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsignalgo.ServiceID, msg *signalpb.PniSignatureMessage) error { if sender.Type != libsignalgo.ServiceIDTypeACI { return fmt.Errorf("PNI signature message sender is not an ACI") From aab8af046c60c826d471fd17f88fde838b069cd6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Nov 2025 13:29:38 +0200 Subject: [PATCH 592/718] signalmeow: drop DMs from blocked contacts on signal --- pkg/signalmeow/receiving.go | 61 +++++++++++++------ pkg/signalmeow/storageservice.go | 4 ++ pkg/signalmeow/store/backup_store.go | 4 +- pkg/signalmeow/store/container.go | 2 +- pkg/signalmeow/store/device.go | 3 + pkg/signalmeow/store/recipient_store.go | 38 ++++++++++-- pkg/signalmeow/store/upgrades/00-latest.sql | 3 +- .../store/upgrades/23-recipient-blocked.sql | 2 + pkg/signalmeow/types/contact.go | 1 + 9 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/23-recipient-blocked.sql diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index dc678e4..9e035ce 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -548,13 +548,20 @@ func (cli *Client) handleDecryptedResult( } } - sendDeliveryReceipt := true + isBlocked, err := cli.Store.RecipientStore.IsBlocked(ctx, theirServiceID.UUID) + if err != nil { + log.Err(err).Stringer("sender", theirServiceID).Msg("Failed to check if sender is blocked") + } + + var sendDeliveryReceipt bool if content.DataMessage != nil { - handlerSuccess = cli.incomingDataMessage(ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) + handlerSuccess, sendDeliveryReceipt = cli.incomingDataMessage( + ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked, + ) } else if content.EditMessage != nil { - handlerSuccess = cli.incomingEditMessage(ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp()) - } else { - sendDeliveryReceipt = false + handlerSuccess, sendDeliveryReceipt = cli.incomingEditMessage( + ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked, + ) } if sendDeliveryReceipt && handlerSuccess { err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) @@ -563,7 +570,7 @@ func (cli *Client) handleDecryptedResult( } } - if content.TypingMessage != nil { + if content.TypingMessage != nil && (!isBlocked || content.TypingMessage.GetGroupId() != nil) { var groupID types.GroupIdentifier if content.TypingMessage.GetGroupId() != nil { gidBytes := content.TypingMessage.GetGroupId() @@ -581,7 +588,7 @@ func (cli *Client) handleDecryptedResult( } // DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) - if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { + if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) && !isBlocked { handlerSuccess = cli.handleEvent(&events.Call{ Info: events.MessageInfo{ Sender: theirServiceID.UUID, @@ -673,9 +680,9 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess log.Warn().Msg("sync message sent destination is nil") } else if msg.Sent.Message != nil { // TODO handle expiration start ts, and maybe the sync message ts? - cli.incomingDataMessage(ctx, msg.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) + cli.incomingDataMessage(ctx, msg.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) } else if msg.Sent.EditMessage != nil { - cli.incomingEditMessage(ctx, msg.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp()) + cli.incomingEditMessage(ctx, msg.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) } } if msg.Contacts != nil { @@ -784,7 +791,14 @@ func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsign return nil } -func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalpb.EditMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID, serverTimestamp uint64) bool { +func (cli *Client) incomingEditMessage( + ctx context.Context, + editMessage *signalpb.EditMessage, + messageSenderACI uuid.UUID, + chatRecipient libsignalgo.ServiceID, + serverTimestamp uint64, + isBlocked bool, +) (handlerSuccess, sendDeliveryReceipt bool) { // If it's a group message, get the ID and invalidate cache if necessary var groupID types.GroupIdentifier var groupRevision uint32 @@ -796,9 +810,12 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp groupID, err = cli.StoreMasterKey(ctx, masterKey) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("StoreMasterKey error") - return false + return } groupRevision = editMessage.GetDataMessage().GetGroupV2().GetRevision() + } else if isBlocked { + zerolog.Ctx(ctx).Debug().Msg("Dropping direct message from blocked user") + return true, false } return cli.handleEvent(&events.ChatEvent{ Info: events.MessageInfo{ @@ -808,17 +825,24 @@ func (cli *Client) incomingEditMessage(ctx context.Context, editMessage *signalp ServerTimestamp: serverTimestamp, }, Event: editMessage, - }) + }), true } -func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalpb.DataMessage, messageSenderACI uuid.UUID, chatRecipient libsignalgo.ServiceID, serverTimestamp uint64) bool { +func (cli *Client) incomingDataMessage( + ctx context.Context, + dataMessage *signalpb.DataMessage, + messageSenderACI uuid.UUID, + chatRecipient libsignalgo.ServiceID, + serverTimestamp uint64, + isBlocked bool, +) (handlerSuccess, sendDeliveryReceipt bool) { // If there's a profile key, save it if dataMessage.ProfileKey != nil { profileKey := libsignalgo.ProfileKey(dataMessage.ProfileKey) err := cli.Store.RecipientStore.StoreProfileKey(ctx, messageSenderACI, profileKey) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("StoreProfileKey error") - return false + return } } @@ -833,9 +857,12 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp groupID, err = cli.StoreMasterKey(ctx, masterKey) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("StoreMasterKey error") - return false + return } groupRevision = dataMessage.GetGroupV2().GetRevision() + } else if isBlocked { + zerolog.Ctx(ctx).Debug().Msg("Dropping direct message from blocked user") + return true, false } evtInfo := events.MessageInfo{ @@ -851,12 +878,12 @@ func (cli *Client) incomingDataMessage(ctx context.Context, dataMessage *signalp Info: evtInfo, Timestamp: dataMessage.GetTimestamp(), IsRinging: isRinging, - }) + }), true } else { return cli.handleEvent(&events.ChatEvent{ Info: evtInfo, Event: dataMessage, - }) + }), true } } diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 06b0283..7c35dec 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -99,6 +99,10 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat changed = changed || recipient.E164 != contact.E164 recipient.E164 = contact.E164 } + if contact.Blocked != recipient.Blocked { + changed = true + recipient.Blocked = contact.Blocked + } topLevelChanged = changed return }) diff --git a/pkg/signalmeow/store/backup_store.go b/pkg/signalmeow/store/backup_store.go index 4575b05..fb5d5ff 100644 --- a/pkg/signalmeow/store/backup_store.go +++ b/pkg/signalmeow/store/backup_store.go @@ -161,9 +161,11 @@ func (s *sqlStore) AddBackupRecipient(ctx context.Context, recipient *backuppb.R if dest.Contact.ProfileGivenName != nil || dest.Contact.ProfileFamilyName != nil { recipient.Profile.Name = strings.TrimSpace(fmt.Sprintf("%s %s", dest.Contact.GetProfileGivenName(), dest.Contact.GetProfileFamilyName())) } + recipient.Blocked = dest.Contact.Blocked changed = oldRecipient.E164 != recipient.E164 || oldRecipient.Profile.Key != recipient.Profile.Key || - oldRecipient.Profile.Name != recipient.Profile.Name + oldRecipient.Profile.Name != recipient.Profile.Name || + oldRecipient.Blocked != recipient.Blocked return }) if err != nil { diff --git a/pkg/signalmeow/store/container.go b/pkg/signalmeow/store/container.go index f6842ac..e6335e5 100644 --- a/pkg/signalmeow/store/container.go +++ b/pkg/signalmeow/store/container.go @@ -85,7 +85,7 @@ func (c *Container) scanDevice(row dbutil.Scannable) (*Device, error) { device.AccountEntropyPool = libsignalgo.AccountEntropyPool(accountEntropyPool.String) device.EphemeralBackupKey = libsignalgo.BytesToBackupKey(ephemeralBackupKey) device.MediaRootBackupKey = libsignalgo.BytesToBackupKey(mediaRootBackupKey) - baseStore := &sqlStore{Container: c, AccountID: device.ACI} + baseStore := &sqlStore{Container: c, AccountID: device.ACI, blockCache: make(map[uuid.UUID]bool)} aciStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.ACIServiceID()} pniStore := &scopedSQLStore{Container: c, AccountID: device.ACI, ServiceID: device.PNIServiceID()} device.ACIPreKeyStore = aciStore diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index aabee03..8843ddf 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -18,6 +18,9 @@ type sqlStore struct { AccountID uuid.UUID contactLock sync.Mutex + + blockCacheLock sync.RWMutex + blockCache map[uuid.UUID]bool } type scopedSQLStore struct { diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 9e2bb8e..00646df 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -38,6 +38,7 @@ type RecipientStore interface { MyProfileKey(ctx context.Context) (*libsignalgo.ProfileKey, error) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUID, updater RecipientUpdaterFunc) (*types.Recipient, error) + IsBlocked(ctx context.Context, aci uuid.UUID) (bool, error) LoadRecipientByE164(ctx context.Context, e164 string) (*types.Recipient, error) StoreRecipient(ctx context.Context, recipient *types.Recipient) error UpdateRecipientE164(ctx context.Context, aci, pni uuid.UUID, e164 string) (*types.Recipient, error) @@ -62,7 +63,8 @@ const ( profile_about_emoji, profile_avatar_path, profile_fetched_at, - needs_pni_signature + needs_pni_signature, + blocked FROM signalmeow_recipients WHERE account_id = $1 ` @@ -87,9 +89,10 @@ const ( profile_about_emoji, profile_avatar_path, profile_fetched_at, - needs_pni_signature + needs_pni_signature, + blocked ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) ON CONFLICT (account_id, aci_uuid) DO UPDATE SET pni_uuid = excluded.pni_uuid, e164_number = excluded.e164_number, @@ -102,7 +105,8 @@ const ( profile_about_emoji = excluded.profile_about_emoji, profile_avatar_path = excluded.profile_avatar_path, profile_fetched_at = excluded.profile_fetched_at, - needs_pni_signature = excluded.needs_pni_signature + needs_pni_signature = excluded.needs_pni_signature, + blocked = excluded.blocked ` upsertPNIRecipientQuery = ` INSERT INTO signalmeow_recipients ( @@ -139,6 +143,7 @@ func scanRecipient(row dbutil.Scannable) (*types.Recipient, error) { &recipient.Profile.AvatarPath, &profileFetchedAt, &recipient.NeedsPNISignature, + &recipient.Blocked, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -208,6 +213,13 @@ func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUI return false, nil } } + defer func() { + if outRecipient != nil && outRecipient.ACI != uuid.Nil && outErr == nil { + s.blockCacheLock.Lock() + s.blockCache[outRecipient.ACI] = outRecipient.Blocked + s.blockCacheLock.Unlock() + } + }() if ctx.Value(contextKeyContactLock) == nil { s.contactLock.Lock() defer s.contactLock.Unlock() @@ -295,6 +307,20 @@ func (s *sqlStore) LoadAndUpdateRecipient(ctx context.Context, aci, pni uuid.UUI return } +func (s *sqlStore) IsBlocked(ctx context.Context, aci uuid.UUID) (bool, error) { + s.blockCacheLock.RLock() + cachedVal, ok := s.blockCache[aci] + s.blockCacheLock.RUnlock() + if ok { + return cachedVal, nil + } + recipient, err := s.LoadAndUpdateRecipient(ctx, aci, uuid.Nil, nil) + if err != nil { + return false, err + } + return recipient.Blocked, nil +} + func (s *sqlStore) UpdateRecipientE164(ctx context.Context, aci, pni uuid.UUID, e164 string) (*types.Recipient, error) { return s.LoadAndUpdateRecipient(ctx, aci, pni, func(recipient *types.Recipient) (bool, error) { if recipient.E164 != e164 { @@ -341,7 +367,11 @@ func (s *sqlStore) StoreRecipient(ctx context.Context, recipient *types.Recipien recipient.Profile.AvatarPath, dbutil.UnixMilliPtr(recipient.Profile.FetchedAt), recipient.NeedsPNISignature, + recipient.Blocked, ) + s.blockCacheLock.Lock() + s.blockCache[recipient.ACI] = recipient.Blocked + s.blockCacheLock.Unlock() } else if recipient.PNI != uuid.Nil { _, err = s.db.Exec( ctx, diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 2c550c9..ddf871a 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v22 (compatible with v13+): Latest revision +-- v0 -> v23 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -117,6 +117,7 @@ CREATE TABLE signalmeow_recipients ( profile_avatar_path TEXT NOT NULL DEFAULT '', profile_fetched_at BIGINT, needs_pni_signature BOOLEAN NOT NULL DEFAULT false, + blocked BOOLEAN NOT NULL DEFAULT false, CONSTRAINT signalmeow_contacts_account_id_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE, diff --git a/pkg/signalmeow/store/upgrades/23-recipient-blocked.sql b/pkg/signalmeow/store/upgrades/23-recipient-blocked.sql new file mode 100644 index 0000000..3a9654a --- /dev/null +++ b/pkg/signalmeow/store/upgrades/23-recipient-blocked.sql @@ -0,0 +1,2 @@ +-- v23 (compatible with v13+): Store block status for recipients +ALTER TABLE signalmeow_recipients ADD COLUMN blocked BOOLEAN NOT NULL DEFAULT false; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index 53852aa..bed25ac 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -55,6 +55,7 @@ type Recipient struct { Profile Profile NeedsPNISignature bool + Blocked bool } type ContactAvatar struct { From 67f53eb68ff633f87b2f0df43271bb6c0aaa0278 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 20 Nov 2025 17:15:32 +0200 Subject: [PATCH 593/718] signalmeow/receiving: fix handling missing sender address --- pkg/signalmeow/receiving.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 9e035ce..12a360f 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -417,8 +417,17 @@ func (cli *Client) handleDecryptedResult( }() } - theirServiceID, err := result.SenderAddress.NameServiceID() - if err != nil { + var theirServiceID libsignalgo.ServiceID + var err error + if result.SenderAddress == nil { + log.Err(result.Err). + Bool("urgent", envelope.GetUrgent()). + Stringer("content_hint", result.ContentHint). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Msg("No sender address received") + return nil + } else if theirServiceID, err = result.SenderAddress.NameServiceID(); err != nil { log.Warn(). Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("client_ts", envelope.GetTimestamp()). @@ -437,17 +446,7 @@ func (cli *Client) handleDecryptedResult( // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted if result.Err != nil { - logEvt := log.Err(result.Err). - Bool("urgent", envelope.GetUrgent()). - Stringer("content_hint", result.ContentHint). - Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()) - if result.SenderAddress == nil { - logEvt.Msg("Decryption error with unknown sender") - return nil - } if errors.Is(result.Err, EventAlreadyProcessed) { - logEvt.Discard().Msg("") log.Debug().Err(result.Err). Bool("urgent", envelope.GetUrgent()). Stringer("content_hint", result.ContentHint). @@ -457,7 +456,13 @@ func (cli *Client) handleDecryptedResult( Msg("Ignoring already processed event") return nil } - logEvt.Stringer("sender", theirServiceID).Msg("Decryption error with known sender") + log.Err(result.Err). + Bool("urgent", envelope.GetUrgent()). + Stringer("content_hint", result.ContentHint). + Uint64("server_ts", envelope.GetServerTimestamp()). + Uint64("client_ts", envelope.GetTimestamp()). + Stringer("sender", theirServiceID). + Msg("Decryption error with known sender") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot if envelope.GetUrgent() && From 2d7eec319f09a0e9e150399250c3d29fb867ccde Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Mon, 24 Nov 2025 15:20:48 +0000 Subject: [PATCH 594/718] signalmeow/web: use exsync.Map for response channels (#621) Co-authored-by: Tulir Asokan --- go.mod | 2 +- go.sum | 4 ++-- pkg/signalmeow/web/signalwebsocket.go | 16 ++++++---------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 9cd9dbb..a1be9e8 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.3 + go.mau.fi/util v0.9.4-0.20251124151504-71e0e3476592 golang.org/x/crypto v0.44.0 golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 golang.org/x/net v0.47.0 diff --git a/go.sum b/go.sum index 835ede2..aeb8cf5 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.3 h1:aqNF8KDIN8bFpFbybSk+mEBil7IHeBwlujfyTnvP0uU= -go.mau.fi/util v0.9.3/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ= +go.mau.fi/util v0.9.4-0.20251124151504-71e0e3476592 h1:qSGoV3kSle4DJIFNTK7AdA3NP5MuA6tlTvQrCKsY9iU= +go.mau.fi/util v0.9.4-0.20251124151504-71e0e3476592/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ= 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.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index ca09208..e062c43 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -305,7 +305,7 @@ func (s *SignalWebsocket) connectLoop( retrying = false backoff = initialBackoff - responseChannels := make(map[uint64]chan *signalpb.WebSocketResponseMessage) + responseChannels := exsync.NewMap[uint64, chan *signalpb.WebSocketResponseMessage]() loopCtx, loopCancel := context.WithCancelCause(ctx) var wg sync.WaitGroup wg.Add(3) @@ -388,7 +388,7 @@ func (s *SignalWebsocket) connectLoop( // Clean up ws.Close(websocket.StatusGoingAway, "Going away") - for _, responseChannel := range responseChannels { + for _, responseChannel := range responseChannels.SwapData(nil) { close(responseChannel) } loopCancel(nil) @@ -407,7 +407,7 @@ func readLoop( ctx context.Context, ws *websocket.Conn, incomingRequestChan chan *signalpb.WebSocketRequestMessage, - responseChannels map[uint64]chan *signalpb.WebSocketResponseMessage, + responseChannels *exsync.Map[uint64, chan *signalpb.WebSocketResponseMessage], ) error { log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_read_loop"). @@ -447,7 +447,7 @@ func readLoop( if msg.Response.Id == nil { log.Fatal().Msg("Received response with no id") } - responseChannel, ok := responseChannels[*msg.Response.Id] + responseChannel, ok := responseChannels.Pop(*msg.Response.Id) if !ok { log.Warn(). Uint64("response_id", *msg.Response.Id). @@ -459,10 +459,6 @@ func readLoop( Uint32("response_status", *msg.Response.Status). Msg("Received WS response") responseChannel <- msg.Response - delete(responseChannels, *msg.Response.Id) - log.Debug(). - Uint64("response_id", *msg.Response.Id). - Msg("Deleted response channel for ID") close(responseChannel) } else if *msg.Type == signalpb.WebSocketMessage_UNKNOWN { return fmt.Errorf("received message with unknown type: %v", *msg.Type) @@ -486,7 +482,7 @@ func writeLoop( ctx context.Context, ws *websocket.Conn, sendChannel chan SignalWebsocketSendMessage, - responseChannels map[uint64]chan *signalpb.WebSocketResponseMessage, + responseChannels *exsync.Map[uint64, chan *signalpb.WebSocketResponseMessage], ) error { log := zerolog.Ctx(ctx).With(). Str("loop", "signal_websocket_write_loop"). @@ -509,7 +505,7 @@ func writeLoop( Request: request.RequestMessage, } request.RequestMessage.Id = &i - responseChannels[i] = request.ResponseChannel + responseChannels.Set(i, request.ResponseChannel) path := *request.RequestMessage.Path if len(path) > 30 { path = path[:40] From f8358f6eaf5fc27456bd1fa6ce1226f3e1a6af0e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 14:34:29 +0200 Subject: [PATCH 595/718] signalmeow/web: refactor SendRequest parameters --- pkg/signalmeow/groups.go | 3 +-- pkg/signalmeow/profile.go | 8 ++++---- pkg/signalmeow/sending.go | 9 ++++----- pkg/signalmeow/web/signalwebsocket.go | 19 ++++++++++++++++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index d938e10..7a3d64b 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -314,8 +314,7 @@ func (cli *Client) fetchNewGroupCreds(ctx context.Context, today time.Time) (*Gr Logger() sevenDaysOut := today.Add(7 * 24 * time.Hour) path := fmt.Sprintf("/v1/certificate/auth/group?redemptionStartSeconds=%d&redemptionEndSeconds=%d&pniAsServiceId=true", today.Unix(), sevenDaysOut.Unix()) - authRequest := web.CreateWSRequest(http.MethodGet, path, nil, nil, nil) - resp, err := cli.AuthedWS.SendRequest(ctx, authRequest) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { return nil, fmt.Errorf("SendRequest error: %w", err) } diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 81f1ed8..9510f37 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -218,12 +218,12 @@ func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID u path += "/" + string(credentialRequest) path += "?credentialType=expiringProfileKey" } - profileRequest := web.CreateWSRequest(http.MethodGet, path, nil, nil, nil) + headers := http.Header{} if useUnidentified { - profileRequest.Headers = append(profileRequest.Headers, "unidentified-access-key:"+base64AccessKey) - profileRequest.Headers = append(profileRequest.Headers, "accept-language:en-CA") + headers.Set("Unidentified-Access-Key", base64AccessKey) + headers.Set("Accept-Language", "en-US") } - resp, err := cli.UnauthedWS.SendRequest(ctx, profileRequest) + resp, err := cli.UnauthedWS.SendRequest(ctx, http.MethodGet, path, nil, headers) if err != nil { return nil, fmt.Errorf("error sending request: %w", err) } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 8bfc5a5..11ed08d 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -884,17 +884,16 @@ func (cli *Client) sendContent( return false, err } path := fmt.Sprintf("/v1/messages/%s", recipient) - request := web.CreateWSRequest(http.MethodPut, path, jsonBytes, nil, nil) var response *signalpb.WebSocketResponseMessage if useUnidentifiedSender { log.Trace().Msg("Sending message over unidentified WS") - base64AccessKey := base64.StdEncoding.EncodeToString(accessKey[:]) - request.Headers = append(request.Headers, "unidentified-access-key:"+base64AccessKey) - response, err = cli.UnauthedWS.SendRequest(ctx, request) + response, err = cli.UnauthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, http.Header{ + "Unidentified-Access-Key": []string{base64.StdEncoding.EncodeToString(accessKey[:])}, + }) } else { log.Trace().Msg("Sending message over authed WS") - response, err = cli.AuthedWS.SendRequest(ctx, request) + response, err = cli.AuthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, nil) } sentUnidentified = useUnidentifiedSender if err != nil { diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index e062c43..75e22e1 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -560,13 +560,26 @@ func writeLoop( func (s *SignalWebsocket) SendRequest( ctx context.Context, - request *signalpb.WebSocketRequestMessage, + method, + path string, + body []byte, + headers http.Header, ) (*signalpb.WebSocketResponseMessage, error) { if s == nil { return nil, errors.New("websocket is nil") } - startTime := time.Now() - return s.sendRequestInternal(ctx, request, startTime, 0) + headerArray := make([]string, len(headers)) + for key, values := range headers { + for _, value := range values { + headerArray = append(headerArray, fmt.Sprintf("%s:%s", strings.ToLower(key), value)) + } + } + return s.sendRequestInternal(ctx, &signalpb.WebSocketRequestMessage{ + Verb: &method, + Path: &path, + Body: body, + Headers: headerArray, + }, time.Now(), 0) } func (s *SignalWebsocket) sendRequestInternal( From bd9b96e3a04575ab5bbae58cc18f67dde49956db Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 15:03:02 +0200 Subject: [PATCH 596/718] signalmeow: move all normal authed requests to websocket --- pkg/connector/client.go | 6 --- pkg/signalmeow/attachments.go | 27 +++++------ pkg/signalmeow/backup.go | 19 +++----- pkg/signalmeow/client.go | 10 ++++ pkg/signalmeow/devicename.go | 13 ++--- pkg/signalmeow/groups.go | 15 ++---- pkg/signalmeow/keys.go | 44 +++++++---------- pkg/signalmeow/profile.go | 5 +- pkg/signalmeow/provisioning.go | 25 ++-------- pkg/signalmeow/pushreg.go | 23 +++------ pkg/signalmeow/receiving.go | 6 +++ pkg/signalmeow/sending.go | 15 +++--- pkg/signalmeow/serviceauth.go | 10 +--- pkg/signalmeow/storageservice.go | 6 +-- pkg/signalmeow/web/signalwebsocket.go | 7 +++ pkg/signalmeow/web/web.go | 69 +++++++++++++++------------ 16 files changed, 129 insertions(+), 171 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 0ff578f..c85ae35 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -298,12 +298,6 @@ func (s *SignalClient) postLoginConnect() { } func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bool) { - err := s.Client.RegisterCapabilities(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to register capabilities") - } else { - zerolog.Ctx(ctx).Debug().Msg("Successfully registered capabilities") - } ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 67a55c8..22884fe 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -70,8 +70,7 @@ func DownloadAttachmentWithPointer(ctx context.Context, a *signalpb.AttachmentPo } func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNumber uint32, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) { - path := getAttachmentPath(cdnID, cdnKey) - resp, err := web.GetAttachment(ctx, path, cdnNumber, nil) + resp, err := web.GetAttachment(ctx, getAttachmentPath(cdnID, cdnKey), cdnNumber) if err != nil { return nil, err } @@ -174,15 +173,13 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb // Get upload attributes from Signal server attributesPath := "/v4/attachments/form/upload" - username, password := cli.Store.BasicAuthCreds() - opts := &web.HTTPReqOpt{Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, attributesPath, opts) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, attributesPath, nil, nil) if err != nil { log.Err(err).Msg("Failed to request upload attributes") return nil, fmt.Errorf("failed to request upload attributes: %w", err) } var uploadAttributes attachmentV4UploadAttributes - err = web.DecodeHTTPResponseBody(ctx, &uploadAttributes, resp) + err = web.DecodeWSResponseBody(ctx, &uploadAttributes, resp) if err != nil { log.Err(err).Msg("Failed to decode upload attributes") return nil, fmt.Errorf("failed to decode upload attributes: %w", err) @@ -192,7 +189,7 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb err = cli.uploadAttachmentTUS(ctx, uploadAttributes, encryptedWithMAC) } else { log.Trace().Msg("Using legacy upload") - err = cli.uploadAttachmentLegacy(ctx, uploadAttributes, encryptedWithMAC, username, password) + err = cli.uploadAttachmentLegacy(ctx, uploadAttributes, encryptedWithMAC) } if err != nil { log.Err(err).Msg("Failed to upload attachment") @@ -218,11 +215,10 @@ func (cli *Client) uploadAttachmentLegacy( ctx context.Context, uploadAttributes attachmentV4UploadAttributes, encryptedWithMAC []byte, - username string, - password string, ) error { + username, password := cli.Store.BasicAuthCreds() // Allocate attachment on CDN - resp, err := web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ + resp, err := web.SendHTTPRequest(ctx, "", http.MethodPost, "", &web.HTTPReqOpt{ OverrideURL: uploadAttributes.SignedUploadLocation, ContentType: web.ContentTypeOctetStream, Headers: uploadAttributes.Headers, @@ -236,7 +232,7 @@ func (cli *Client) uploadAttachmentLegacy( } // Upload attachment to CDN - resp, err = web.SendHTTPRequest(ctx, http.MethodPut, "", &web.HTTPReqOpt{ + resp, err = web.SendHTTPRequest(ctx, "", http.MethodPut, "", &web.HTTPReqOpt{ OverrideURL: resp.Header.Get("Location"), Body: encryptedWithMAC, ContentType: web.ContentTypeOctetStream, @@ -260,7 +256,7 @@ func (cli *Client) uploadAttachmentTUS( uploadAttributes.Headers["Upload-Length"] = fmt.Sprintf("%d", len(encryptedWithMAC)) uploadAttributes.Headers["Upload-Metadata"] = "filename " + base64.StdEncoding.EncodeToString([]byte(uploadAttributes.Key)) - resp, err := web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ + resp, err := web.SendHTTPRequest(ctx, "", http.MethodPost, "", &web.HTTPReqOpt{ OverrideURL: uploadAttributes.SignedUploadLocation, Body: encryptedWithMAC, ContentType: web.ContentTypeOffsetOctetStream, @@ -306,8 +302,8 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi // Get upload form from Signal server formPath := "/v2/groups/avatar/form" - opts := &web.HTTPReqOpt{Username: &groupAuth.Username, Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, Host: web.StorageHostname} - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, formPath, opts) + opts := &web.HTTPReqOpt{Username: &groupAuth.Username, Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf} + resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodGet, formPath, opts) if err != nil { log.Err(err).Msg("Error sending request fetching avatar upload form") return "", err @@ -338,10 +334,9 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi w.Close() // Upload avatar to CDN - resp, err = web.SendHTTPRequest(ctx, http.MethodPost, "", &web.HTTPReqOpt{ + resp, err = web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodPost, "", &web.HTTPReqOpt{ Body: requestBody.Bytes(), ContentType: web.ContentType(w.FormDataContentType()), - Host: web.CDN1Hostname, }) if err != nil { log.Err(err).Msg("Error sending request uploading attachment") diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index 43c2f78..fcbfff0 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -239,7 +239,7 @@ func (cli *Client) deriveTransferKeys() (aesKey, hmacKey [32]byte, err error) { } func downloadTransferArchive(ctx context.Context, meta *TransferArchiveMetadata, writeTo io.Writer) error { - resp, err := web.GetAttachment(ctx, getAttachmentPath(0, meta.Key), meta.CDN, nil) + resp, err := web.GetAttachment(ctx, getAttachmentPath(0, meta.Key), meta.CDN) if err != nil { return fmt.Errorf("failed to download transfer archive: %w", err) } @@ -291,21 +291,14 @@ func (cli *Client) tryRequestTransferArchive(ctx context.Context, timeout time.D reqCtx, cancel := context.WithTimeout(ctx, timeout+15*time.Second) defer cancel() path := "/v1/devices/transfer_archive?timeout=" + strconv.Itoa(int(timeout.Seconds())) - username, password := cli.Store.BasicAuthCreds() - opts := &web.HTTPReqOpt{Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(reqCtx, http.MethodGet, path, opts) - defer func() { - if resp != nil && resp.Body != nil { - _ = resp.Body.Close() - } - }() + resp, err := cli.AuthedWS.SendRequest(reqCtx, http.MethodGet, path, nil, nil) if err != nil { return nil, err - } else if resp.StatusCode == http.StatusNoContent { + } else if resp.GetStatus() == http.StatusNoContent { return nil, nil - } else if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) - } else if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil { + } else if resp.GetStatus() != http.StatusOK { + return nil, fmt.Errorf("unexpected status code %d", resp.GetStatus()) + } else if err = json.Unmarshal(resp.Body, &respBody); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } else { return respBody, nil diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 42979c1..ea5eb17 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -18,7 +18,9 @@ package signalmeow import ( "context" + "encoding/json" "errors" + "net/http" "net/url" "sync" "time" @@ -110,3 +112,11 @@ func (cli *Client) connectUnauthedWS(ctx context.Context) (chan web.SignalWebsoc func (cli *Client) IsLoggedIn() bool { return cli.Store != nil && cli.Store.IsDeviceLoggedIn() } + +func (cli *Client) GetRemoteConfig(ctx context.Context) (json.RawMessage, error) { + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, "/v2/config", nil, nil) + if err != nil { + return nil, err + } + return resp.Body, web.DecodeWSResponseBody(ctx, nil, resp) +} diff --git a/pkg/signalmeow/devicename.go b/pkg/signalmeow/devicename.go index c22e94d..ceca1e4 100644 --- a/pkg/signalmeow/devicename.go +++ b/pkg/signalmeow/devicename.go @@ -30,7 +30,6 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" - "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) func hmacSHA256(key, input []byte) []byte { @@ -63,18 +62,12 @@ func (cli *Client) updateDeviceName(ctx context.Context, encryptedName []byte) e if err != nil { return fmt.Errorf("failed to marshal device name update request: %w", err) } - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodPut, "/v1/accounts/name", &web.HTTPReqOpt{ - Body: reqData, - Username: &username, - Password: &password, - }) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodPut, "/v1/accounts/name", reqData, nil) if err != nil { return fmt.Errorf("failed to send device name update request: %w", err) } - defer resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return fmt.Errorf("device name update request returned status %d", resp.StatusCode) + if resp.GetStatus() < 200 || resp.GetStatus() >= 300 { + return fmt.Errorf("device name update request returned status %d", resp.GetStatus()) } return nil } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 7a3d64b..39753bb 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -648,9 +648,8 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t Username: &groupAuth.Username, Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, - Host: web.StorageHostname, } - response, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v2/groups", opts) + response, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodGet, "/v2/groups", opts) if err != nil { return nil, err } @@ -695,11 +694,10 @@ func (cli *Client) parseGroupResponse(ctx context.Context, response *http.Respon func (cli *Client) DownloadGroupAvatar(ctx context.Context, avatarPath string, groupMasterKey types.SerializedGroupMasterKey) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ - Host: web.CDN1Hostname, Username: &username, Password: &password, } - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, avatarPath, opts) + resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodGet, avatarPath, opts) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } @@ -1503,9 +1501,8 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, Body: requestBody, - Host: web.StorageHostname, } - resp, err := web.SendHTTPRequest(ctx, http.MethodPatch, path, opts) + resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodPatch, path, opts) if err != nil { return nil, fmt.Errorf("SendRequest error: %w", err) } @@ -1738,9 +1735,8 @@ func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Grou Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, Body: requestBody, - Host: web.StorageHostname, } - resp, err := web.SendHTTPRequest(ctx, http.MethodPut, path, opts) + resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodPut, path, opts) if err != nil { return nil, fmt.Errorf("SendRequest error: %w", err) } @@ -1803,7 +1799,6 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent Username: &groupAuth.Username, Password: &groupAuth.Password, ContentType: web.ContentTypeProtobuf, - Host: web.StorageHostname, Headers: map[string]string{ // TODO actually cache the data and provide real expiry timestamp "Cached-Send-Endorsements": "0", @@ -1811,7 +1806,7 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent } // highest known epoch seems to always be 5, but that may change in the future. includeLastState is always false path := fmt.Sprintf("/v2/groups/logs/%d?maxSupportedChangeEpoch=%d&includeFirstState=%t&includeLastState=false", fromRevision, 5, includeFirstState) - response, err := web.SendHTTPRequest(ctx, http.MethodGet, path, opts) + response, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodGet, path, opts) if err != nil { return nil, err } diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index a3f2690..4756514 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -97,10 +97,9 @@ func (cli *Client) RegisterAllPreKeys(ctx context.Context, pks store.PreKeyStore KyberPreKeys: kyberPreKeys, IdentityKey: identityKey, } - preKeyUsername := fmt.Sprintf("%s.%d", cli.Store.ACI, cli.Store.DeviceID) log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() log.Debug().Int("num_prekeys", len(preKeys)).Int("num_kyber_prekeys", len(kyberPreKeys)).Msg("Registering prekeys") - err = RegisterPreKeys(ctx, &generatedPreKeys, pni, preKeyUsername, cli.Store.Password) + err = cli.RegisterPreKeys(ctx, &generatedPreKeys, pni) if err != nil { return fmt.Errorf("failed to register prekeys: %w", err) } @@ -346,11 +345,11 @@ func KyberPreKeyToJSON(kyberPreKey *libsignalgo.KyberPreKeyRecord) (map[string]i var errPrekeyUpload422 = errors.New("http 422 while registering prekeys") -func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pni bool, username string, password string) error { +func (cli *Client) RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pni bool) error { log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() // Convert generated prekeys to JSON - preKeysJson := []map[string]interface{}{} - kyberPreKeysJson := []map[string]interface{}{} + preKeysJson := []map[string]any{} + kyberPreKeysJson := []map[string]any{} for _, preKey := range generatedPreKeys.PreKeys { preKeyJson, err := PreKeyToJSON(preKey) if err != nil { @@ -367,32 +366,27 @@ func RegisterPreKeys(ctx context.Context, generatedPreKeys *GeneratedPreKeys, pn } identityKey := generatedPreKeys.IdentityKey - register_json := map[string]interface{}{ + registerJSON := map[string]any{ "preKeys": preKeysJson, "pqPreKeys": kyberPreKeysJson, "identityKey": base64.StdEncoding.EncodeToString(identityKey), } // Send request - jsonBytes, err := json.Marshal(register_json) + jsonBytes, err := json.Marshal(registerJSON) if err != nil { log.Err(err).Msg("Error marshalling register JSON") return err } - opts := &web.HTTPReqOpt{Body: jsonBytes, Username: &username, Password: &password} - resp, err := web.SendHTTPRequest(ctx, http.MethodPut, keysPath(pni), opts) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodPut, keysPath(pni), jsonBytes, nil) if err != nil { log.Err(err).Msg("Error sending request") return err } - defer resp.Body.Close() - // status code not 2xx - if resp.StatusCode == 422 { + if resp.GetStatus() == 422 { return errPrekeyUpload422 - } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return fmt.Errorf("error registering prekeys: %v", resp.Status) } - return err + return web.DecodeWSResponseBody(ctx, nil, resp) } type prekeyResponse struct { @@ -434,18 +428,17 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib deviceIDPath = "/" + fmt.Sprint(specificDeviceID) } path := "/v2/keys/" + theirServiceID.String() + deviceIDPath + "?pq=true" - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{Username: &username, Password: &password}) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { return fmt.Errorf("error sending request: %w", err) } - var prekeyResponse prekeyResponse - err = web.DecodeHTTPResponseBody(ctx, &prekeyResponse, resp) + var respData prekeyResponse + err = web.DecodeWSResponseBody(ctx, &respData, resp) if err != nil { return fmt.Errorf("error decoding response body: %w", err) } - rawIdentityKey, err := addBase64PaddingAndDecode(prekeyResponse.IdentityKey) + rawIdentityKey, err := addBase64PaddingAndDecode(respData.IdentityKey) if err != nil { return fmt.Errorf("error decoding identity key: %w", err) } @@ -458,7 +451,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib } // Process each prekey in response (should only be one at the moment) - for _, d := range prekeyResponse.Devices { + for _, d := range respData.Devices { var publicKey *libsignalgo.PublicKey var preKeyID uint32 if d.PreKey != nil { @@ -555,19 +548,18 @@ func keysPath(pni bool) string { func (cli *Client) GetMyKeyCounts(ctx context.Context, pni bool) (int, int, error) { log := zerolog.Ctx(ctx).With().Str("action", "get my key counts").Logger() - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, keysPath(pni), &web.HTTPReqOpt{Username: &username, Password: &password}) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, keysPath(pni), nil, nil) if err != nil { log.Err(err).Msg("Error sending request") return 0, 0, err } - var preKeyCountResponse preKeyCountResponse - err = web.DecodeHTTPResponseBody(ctx, &preKeyCountResponse, resp) + var respData preKeyCountResponse + err = web.DecodeWSResponseBody(ctx, &respData, resp) if err != nil { log.Err(err).Msg("Fetching prekey counts, error with response body") return 0, 0, err } - return preKeyCountResponse.Count, preKeyCountResponse.PQCount, err + return respData.Count, respData.PQCount, err } func (cli *Client) CheckAndUploadNewPreKeys(ctx context.Context, pks store.PreKeyStore) error { diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 9510f37..4284a8b 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -229,7 +229,7 @@ func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID u } var profile types.Profile profile.FetchedAt = time.Now() - logEvt := log.Trace().Uint32("status_code", resp.GetStatus()) + logEvt := log.Trace().Uint32("status_code", resp.GetStatus()).Str("resp_message", resp.GetMessage()) if logEvt.Enabled() { if json.Valid(resp.Body) { logEvt.RawJSON("response_data", resp.Body) @@ -288,11 +288,10 @@ func (cli *Client) fetchProfileWithRequestAndKey(ctx context.Context, signalID u func (cli *Client) DownloadUserAvatar(ctx context.Context, avatarPath string, profileKey libsignalgo.ProfileKey) ([]byte, error) { username, password := cli.Store.BasicAuthCreds() opts := &web.HTTPReqOpt{ - Host: web.CDN1Hostname, Username: &username, Password: &password, } - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, avatarPath, opts) + resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodGet, avatarPath, opts) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index d877276..2343e32 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -366,36 +366,19 @@ var signalCapabilities = map[string]any{ var signalCapabilitiesBody = exerrors.Must(json.Marshal(signalCapabilities)) func (cli *Client) RegisterCapabilities(ctx context.Context) error { - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodPut, "/v1/devices/capabilities", &web.HTTPReqOpt{ - Body: signalCapabilitiesBody, - Username: &username, - Password: &password, - ContentType: web.ContentTypeJSON, - }) - if resp != nil { - _ = resp.Body.Close() - } + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodPut, "/v1/devices/capabilities", signalCapabilitiesBody, nil) if err != nil { return err - } else if resp.StatusCode >= 400 { - return fmt.Errorf("unexpected status code %d", resp.StatusCode) } - return nil + return web.DecodeWSResponseBody(ctx, nil, resp) } func (cli *Client) Unlink(ctx context.Context) error { - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodDelete, fmt.Sprintf("/v1/devices/%d", cli.Store.DeviceID), &web.HTTPReqOpt{ - Username: &username, - Password: &password, - }) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodDelete, fmt.Sprintf("/v1/devices/%d", cli.Store.DeviceID), nil, nil) if err != nil { return err - } else if resp.StatusCode >= 400 { - return fmt.Errorf("unexpected status code %d", resp.StatusCode) } - return nil + return web.DecodeWSResponseBody(ctx, nil, resp) } func confirmDevice( diff --git a/pkg/signalmeow/pushreg.go b/pkg/signalmeow/pushreg.go index fe45785..79d0318 100644 --- a/pkg/signalmeow/pushreg.go +++ b/pkg/signalmeow/pushreg.go @@ -19,9 +19,9 @@ package signalmeow import ( "context" "encoding/json" - "fmt" "net/http" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -36,30 +36,21 @@ type ReqRegisterAPNs struct { } func (cli *Client) registerPush(ctx context.Context, pushType string, data any) error { - username, password := cli.Store.BasicAuthCreds() - req := &web.HTTPReqOpt{ - Username: &username, - Password: &password, - } - var method string + var resp *signalpb.WebSocketResponseMessage + var err error if data != nil { - method = http.MethodPut - req.ContentType = web.ContentTypeJSON - var err error - req.Body, err = json.Marshal(data) + body, err := json.Marshal(data) if err != nil { return err } + resp, err = cli.AuthedWS.SendRequest(ctx, http.MethodPut, "/v1/accounts/"+pushType, body, nil) } else { - method = http.MethodDelete + resp, err = cli.AuthedWS.SendRequest(ctx, http.MethodDelete, "/v1/accounts/"+pushType, nil, nil) } - resp, err := web.SendHTTPRequest(ctx, method, "/v1/accounts/"+pushType, req) if err != nil { return err - } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { - return fmt.Errorf("unexpected status code %d", resp.StatusCode) } - return nil + return web.DecodeWSResponseBody(ctx, nil, resp) } func (cli *Client) RegisterFCM(ctx context.Context, token string) error { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 12a360f..622f18c 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -255,6 +255,12 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection return case <-initialConnectChan: log.Info().Msg("Both websockets connected, sending contacts sync request") + err = cli.RegisterCapabilities(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to register capabilities") + } else { + zerolog.Ctx(ctx).Debug().Msg("Successfully registered capabilities") + } // TODO hacky if cli.SyncContactsOnConnect { cli.SendContactSyncRequest(loopCtx) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 11ed08d..ee35cd4 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -70,17 +70,15 @@ func (cli *Client) senderCertificate(ctx context.Context, e164 bool) (*libsignal } var r response - username, password := cli.Store.BasicAuthCreds() - opts := &web.HTTPReqOpt{Username: &username, Password: &password} var query string if !e164 { query = "?includeE164=false" } - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, "/v1/certificate/delivery"+query, opts) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, "/v1/certificate/delivery"+query, nil, nil) if err != nil { return nil, err } - err = web.DecodeHTTPResponseBody(ctx, &r, resp) + err = web.DecodeWSResponseBody(ctx, &r, resp) if err != nil { return nil, err } @@ -886,14 +884,15 @@ func (cli *Client) sendContent( path := fmt.Sprintf("/v1/messages/%s", recipient) var response *signalpb.WebSocketResponseMessage + header := http.Header{} + header.Set("Content-Type", string(web.ContentTypeJSON)) if useUnidentifiedSender { log.Trace().Msg("Sending message over unidentified WS") - response, err = cli.UnauthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, http.Header{ - "Unidentified-Access-Key": []string{base64.StdEncoding.EncodeToString(accessKey[:])}, - }) + header.Set("Unidentified-Access-Key", base64.StdEncoding.EncodeToString(accessKey[:])) + response, err = cli.UnauthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, header) } else { log.Trace().Msg("Sending message over authed WS") - response, err = cli.AuthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, nil) + response, err = cli.AuthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, header) } sentUnidentified = useUnidentifiedSender if err != nil { diff --git a/pkg/signalmeow/serviceauth.go b/pkg/signalmeow/serviceauth.go index b945f30..5365ded 100644 --- a/pkg/signalmeow/serviceauth.go +++ b/pkg/signalmeow/serviceauth.go @@ -58,20 +58,14 @@ func (cli *Client) getCredentialsWithCache(ctx context.Context, cache **basicExp } func (cli *Client) getCredentialsFromServer(ctx context.Context, path string) (*basicExpiringCredentials, error) { - username, password := cli.Store.BasicAuthCreds() - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{ - Username: &username, - Password: &password, - }) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { return nil, err - } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { - return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } var auth basicExpiringCredentials auth.CreatedAt = time.Now() - err = web.DecodeHTTPResponseBody(ctx, &auth, resp) + err = web.DecodeWSResponseBody(ctx, &auth, resp) if err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 7c35dec..45a008e 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -243,11 +243,10 @@ func (cli *Client) fetchStorageManifest(ctx context.Context, storageKey []byte, } var encryptedManifest signalpb.StorageManifest var manifestRecord signalpb.ManifestRecord - resp, err := web.SendHTTPRequest(ctx, http.MethodGet, path, &web.HTTPReqOpt{ + resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodGet, path, &web.HTTPReqOpt{ Username: &storageCreds.Username, Password: &storageCreds.Password, ContentType: web.ContentTypeProtobuf, - Host: web.StorageHostname, }) if err != nil { return nil, fmt.Errorf("failed to fetch storage manifest: %w", err) @@ -349,12 +348,11 @@ func (cli *Client) fetchStorageItemsChunk(ctx context.Context, recordKeys [][]by return nil, fmt.Errorf("failed to marshal read operation: %w", err) } var storageItems signalpb.StorageItems - resp, err := web.SendHTTPRequest(ctx, http.MethodPut, "/v1/storage/read", &web.HTTPReqOpt{ + resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodPut, "/v1/storage/read", &web.HTTPReqOpt{ Username: &storageCreds.Username, Password: &storageCreds.Password, Body: body, ContentType: web.ContentTypeProtobuf, - Host: web.StorageHostname, }) if err != nil { return nil, fmt.Errorf("failed to fetch storage records: %w", err) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 75e22e1..4c2ac7a 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -569,11 +569,18 @@ func (s *SignalWebsocket) SendRequest( return nil, errors.New("websocket is nil") } headerArray := make([]string, len(headers)) + var hasContentType bool for key, values := range headers { + if strings.ToLower(key) == "content-type" { + hasContentType = true + } for _, value := range values { headerArray = append(headerArray, fmt.Sprintf("%s:%s", strings.ToLower(key), value)) } } + if !hasContentType && body != nil { + headerArray = append(headerArray, "content-type:application/json") + } return s.sendRequestInternal(ctx, &signalpb.WebSocketRequestMessage{ Verb: &method, Path: &path, diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index 3644451..ed3558c 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -34,6 +34,7 @@ import ( "github.com/rs/zerolog" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) const proxyUrlStr = "" // Set this to proxy requests @@ -106,25 +107,21 @@ type HTTPReqOpt struct { Username *string Password *string ContentType ContentType - Host string Headers map[string]string OverrideURL string // Override the full URL, if set ignores path and Host } var httpReqCounter = 0 -func SendHTTPRequest(ctx context.Context, method string, path string, opt *HTTPReqOpt) (*http.Response, error) { +func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPReqOpt) (*http.Response, error) { // Set defaults if opt == nil { opt = &HTTPReqOpt{} } - if opt.Host == "" { - opt.Host = APIHostname - } if len(path) > 0 && path[0] != '/' { path = "/" + path } - urlStr := "https://" + opt.Host + path + urlStr := "https://" + host + path if opt.OverrideURL != "" { urlStr = opt.OverrideURL } @@ -169,6 +166,22 @@ func SendHTTPRequest(ctx context.Context, method string, path string, opt *HTTPR return resp, nil } +func DecodeWSResponseBody(ctx context.Context, out any, resp *signalpb.WebSocketResponseMessage) error { + if resp.GetStatus() < 200 || resp.GetStatus() >= 300 { + zerolog.Ctx(ctx).Debug(). + Bytes("body", resp.Body). + Str("resp_message", resp.GetMessage()). + Strs("headers", resp.Headers). + Uint32("status_code", resp.GetStatus()). + Msg("Unexpected status code") + return fmt.Errorf("unexpected response status %d", resp.GetStatus()) + } + if out == nil { + return nil + } + return json.Unmarshal(resp.Body, &out) +} + // DecodeHTTPResponseBody checks status code, reads an http.Response's Body and decodes it into the provided interface. func DecodeHTTPResponseBody(ctx context.Context, out any, resp *http.Response) error { defer resp.Body.Close() @@ -192,37 +205,33 @@ func DecodeHTTPResponseBody(ctx context.Context, out any, resp *http.Response) e return nil } -func GetAttachment(ctx context.Context, path string, cdnNumber uint32, opt *HTTPReqOpt) (*http.Response, error) { +func GetAttachment(ctx context.Context, path string, cdnNumber uint32) (*http.Response, error) { log := zerolog.Ctx(ctx).With(). Str("action", "get_attachment"). Str("path", path). Uint32("cdn_number", cdnNumber). Logger() - if opt == nil { - opt = &HTTPReqOpt{} + var host string + if int(cdnNumber) > len(CDNHosts) { + log.Warn().Msg("Invalid CDN index") + host = CDN1Hostname + } else { + host = CDNHosts[cdnNumber] } - if opt.Host == "" { - if int(cdnNumber) > len(CDNHosts) { - log.Warn().Msg("Invalid CDN index") - opt.Host = CDN1Hostname - } else { - opt.Host = CDNHosts[cdnNumber] - } - if cdnNumber == 0 { - // This is basically a fallback if cdnNumber is not set - // but it also seems to be the right host if cdnNumber == 0 - opt.Host = CDNHosts[0] - } else if cdnNumber > 0 && int(cdnNumber) <= len(CDNHosts) { - // Pull CDN hosts from array (cdnNumber is 1-indexed, but we have a placeholder host at index 0) - // (the 1-indexed is just an assumption, other clients seem to only explicitly handle cdnNumber == 0 and 2) - opt.Host = CDNHosts[cdnNumber] - } else { - opt.Host = CDNHosts[0] - log.Warn().Msg("Invalid CDN index") - } + if cdnNumber == 0 { + // This is basically a fallback if cdnNumber is not set, + // but it also seems to be the right host if cdnNumber == 0 + host = CDNHosts[0] + } else if cdnNumber > 0 && int(cdnNumber) <= len(CDNHosts) { + // Pull CDN hosts from array (cdnNumber is 1-indexed, but we have a placeholder host at index 0) + // (the 1-indexed is just an assumption, other clients seem to only explicitly handle cdnNumber == 0 and 2) + host = CDNHosts[cdnNumber] + } else { + host = CDNHosts[0] + log.Warn().Msg("Invalid CDN index") } - log.Debug().Str("host", opt.Host).Msg("getting attachment") - urlStr := "https://" + opt.Host + path + log.Debug().Str("host", host).Msg("getting attachment") + urlStr := "https://" + host + path req, err := http.NewRequest(http.MethodGet, urlStr, nil) if err != nil { return nil, err From b06ca0eefe590ec05e72636dc9b258c90c21b72e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 16:53:26 +0200 Subject: [PATCH 597/718] handle*: fix bugs with polls --- pkg/connector/handlematrix.go | 24 +++++++++++------------- pkg/connector/handlesignal.go | 2 +- pkg/msgconv/from-matrix.go | 4 +--- pkg/signalmeow/sending.go | 3 ++- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index deb52e3..1dbd48a 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -112,28 +112,25 @@ func getTimestampForEvent(txnID networkid.RawTransactionID, evt *event.Event, or } func (s *SignalClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) { - ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) converted, err := s.Main.MsgConv.ToSignal( - ctx, s.Client, msg.Portal, msg.Event, msg.Content, ts, msg.OrigSender != nil, msg.ReplyTo, + ctx, s.Client, msg.Portal, msg.Event, msg.Content, msg.OrigSender != nil, msg.ReplyTo, ) if err != nil { return nil, err } - return s.doSendMessage(ctx, ts, msg, converted, &signalid.MessageMetadata{ + return s.doSendMessage(ctx, msg, converted, &signalid.MessageMetadata{ ContainsAttachments: len(converted.Attachments) > 0, }) } func (s *SignalClient) doSendMessage( ctx context.Context, - ts uint64, msg *bridgev2.MatrixMessage, converted *signalpb.DataMessage, meta *signalid.MessageMetadata, ) (*bridgev2.MatrixMessageResponse, error) { - if ts == 0 { - ts = getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) - } + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) + converted.Timestamp = &ts if meta == nil { meta = &signalid.MessageMetadata{} } @@ -169,11 +166,12 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri return fmt.Errorf("failed to get message reply target: %w", err) } } - ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) - converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, ts, msg.OrigSender != nil, replyTo) + converted, err := s.Main.MsgConv.ToSignal(ctx, s.Client, msg.Portal, msg.Event, msg.Content, msg.OrigSender != nil, replyTo) if err != nil { return err } + ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) + converted.Timestamp = &ts err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ TargetSentTimestamp: proto.Uint64(targetSentTimestamp), DataMessage: converted, @@ -800,7 +798,7 @@ func (s *SignalClient) HandleMatrixPollStart(ctx context.Context, msg *bridgev2. }, RequiredProtocolVersion: ptr.Ptr(uint32(signalpb.DataMessage_POLLS)), } - return s.doSendMessage(ctx, 0, &msg.MatrixMessage, converted, &signalid.MessageMetadata{ + return s.doSendMessage(ctx, &msg.MatrixMessage, converted, &signalid.MessageMetadata{ MatrixPollOptionIDs: optionIDs, }) } @@ -826,9 +824,9 @@ func (s *SignalClient) HandleMatrixPollVote(ctx context.Context, msg *bridgev2.M TargetAuthorAciBinary: senderACI[:], TargetSentTimestamp: &msgTS, OptionIndexes: optionIndexes, - VoteCount: nil, // TODO + VoteCount: proto.Uint32(1), // TODO }, - RequiredProtocolVersion: ptr.Ptr(uint32(signalpb.DataMessage_POLLS)), + RequiredProtocolVersion: proto.Uint32(0), } - return s.doSendMessage(ctx, 0, &msg.MatrixMessage, converted, nil) + return s.doSendMessage(ctx, &msg.MatrixMessage, converted, nil) } diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 6a2f3b5..0293a53 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -167,7 +167,7 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { case *signalpb.DataMessage: switch { case innerEvt.Body != nil, innerEvt.Attachments != nil, innerEvt.Contact != nil, innerEvt.Sticker != nil, - innerEvt.Payment != nil, innerEvt.GiftBadge != nil, + innerEvt.Payment != nil, innerEvt.GiftBadge != nil, innerEvt.PollCreate != nil, innerEvt.PollVote != nil, innerEvt.GetRequiredProtocolVersion() > uint32(signalpb.DataMessage_CURRENT), innerEvt.GetFlags()&uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE) != 0: return bridgev2.RemoteEventMessage diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 9af4dc5..67352f1 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -44,7 +44,6 @@ func (mc *MessageConverter) ToSignal( portal *bridgev2.Portal, evt *event.Event, content *event.MessageEventContent, - timestamp uint64, relaybotFormatted bool, replyTo *database.Message, ) (*signalpb.DataMessage, error) { @@ -55,8 +54,7 @@ func (mc *MessageConverter) ToSignal( } dm := &signalpb.DataMessage{ - Timestamp: ×tamp, - Preview: mc.convertURLPreviewToSignal(ctx, content), + Preview: mc.convertURLPreviewToSignal(ctx, content), } if replyTo != nil { authorACI, messageID, err := signalid.ParseMessageID(replyTo.ID) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index ee35cd4..c1c0232 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -824,7 +824,6 @@ func (cli *Client) sendContent( Uint64("timestamp", messageTimestamp). Logger() ctx = log.WithContext(ctx) - log.Trace().Any("raw_content", content).Stringer("recipient", recipient).Msg("Raw data of outgoing message") // If it's a data message, add our profile key if content.DataMessage != nil { @@ -836,6 +835,8 @@ func (cli *Client) sendContent( } } + log.Trace().Any("raw_content", content).Stringer("recipient", recipient).Msg("Raw data of outgoing message") + if retryCount > 3 { log.Error().Int("retry_count", retryCount).Msg("sendContent too many retries") return false, fmt.Errorf("too many retries") From 974259ee3fafd3c2bb2869deeae39ed4a12cd2a2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 17:38:01 +0200 Subject: [PATCH 598/718] signalmeow/provisioning: remove prekey upload on login They need to be uploaded via the websocket, so easier to let the normal upload flow do it. --- pkg/connector/login.go | 43 ++++--------------------- pkg/signalmeow/keys.go | 57 ++++++++++++++-------------------- pkg/signalmeow/provisioning.go | 31 ++---------------- pkg/signalmeow/receiving.go | 13 ++++---- 4 files changed, 38 insertions(+), 106 deletions(-) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 12d548d..5cfdae1 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -52,8 +52,6 @@ type QRLogin struct { cancelChan context.CancelFunc ProvChan chan signalmeow.ProvisioningResponse newQRCount int - - ProvData *store.DeviceData } var _ bridgev2.LoginProcessDisplayAndWait = (*QRLogin)(nil) @@ -112,14 +110,6 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) { return nil, fmt.Errorf("login not started") } - if qr.ProvData == nil { - return qr.qrWait(ctx) - } else { - return qr.processingWait(ctx) - } -} - -func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { select { case resp := <-qr.ProvChan: if resp.Err != nil { @@ -132,15 +122,7 @@ func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { qr.cancelChan() return nil, fmt.Errorf("no signal account ID received") } - qr.ProvData = resp.ProvisioningData - return &bridgev2.LoginStep{ - Type: bridgev2.LoginStepTypeDisplayAndWait, - StepID: LoginStepProcess, - Instructions: fmt.Sprintf("Processing login as %s...", resp.ProvisioningData.Number), - DisplayAndWaitParams: &bridgev2.LoginDisplayAndWaitParams{ - Type: bridgev2.LoginDisplayTypeNothing, - }, - }, nil + return qr.loginComplete(ctx, resp.ProvisioningData) // 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. @@ -158,26 +140,13 @@ func (qr *QRLogin) qrWait(ctx context.Context) (*bridgev2.LoginStep, error) { } } -func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, error) { +func (qr *QRLogin) loginComplete(ctx context.Context, provData *store.DeviceData) (*bridgev2.LoginStep, error) { defer qr.cancelChan() - newLoginID := signalid.MakeUserLoginID(qr.ProvData.ACI) - - select { - case resp := <-qr.ProvChan: - if resp.Err != nil { - return nil, resp.Err - } else if resp.State != signalmeow.StateProvisioningPreKeysRegistered { - return nil, fmt.Errorf("unexpected state %v", resp.State) - } - case <-ctx.Done(): - return nil, ctx.Err() - } - ul, err := qr.User.NewLogin(ctx, &database.UserLogin{ - ID: newLoginID, - RemoteName: qr.ProvData.Number, + ID: signalid.MakeUserLoginID(provData.ACI), + RemoteName: provData.Number, RemoteProfile: status.RemoteProfile{ - Phone: qr.ProvData.Number, + Phone: provData.Number, }, Metadata: &signalid.UserLoginMetadata{}, }, &bridgev2.NewLoginParams{ @@ -190,7 +159,7 @@ func (qr *QRLogin) processingWait(ctx context.Context) (*bridgev2.LoginStep, err return &bridgev2.LoginStep{ Type: bridgev2.LoginStepTypeComplete, StepID: LoginStepComplete, - Instructions: fmt.Sprintf("Successfully logged in as %s / %s", qr.ProvData.Number, qr.ProvData.ACI), + Instructions: fmt.Sprintf("Successfully logged in as %s / %s", provData.Number, provData.ACI), CompleteParams: &bridgev2.LoginCompleteParams{ UserLoginID: ul.ID, UserLogin: ul, diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 4756514..19ad1f6 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -22,7 +22,7 @@ import ( "encoding/json" "errors" "fmt" - "math/rand" + "math/rand/v2" "net/http" "strings" "time" @@ -43,25 +43,6 @@ type GeneratedPreKeys struct { IdentityKey []uint8 } -func (cli *Client) GenerateAndRegisterPreKeys(ctx context.Context, pks store.PreKeyStore) error { - _, err := cli.GenerateAndSaveNextPreKeyBatch(ctx, pks, 0) - if err != nil { - return fmt.Errorf("failed to generate and save next prekey batch: %w", err) - } - _, err = cli.GenerateAndSaveNextKyberPreKeyBatch(ctx, pks, 0) - if err != nil { - return fmt.Errorf("failed to generate and save next kyber prekey batch: %w", err) - } - - // We need to upload all currently valid prekeys, not just the ones we just generated - err = cli.RegisterAllPreKeys(ctx, pks) - if err != nil { - return fmt.Errorf("failed to register prekey batches: %w", err) - } - - return err -} - func (cli *Client) RegisterAllPreKeys(ctx context.Context, pks store.PreKeyStore) error { var identityKeyPair *libsignalgo.IdentityKeyPair var pni bool @@ -97,8 +78,10 @@ func (cli *Client) RegisterAllPreKeys(ctx context.Context, pks store.PreKeyStore KyberPreKeys: kyberPreKeys, IdentityKey: identityKey, } - log := zerolog.Ctx(ctx).With().Str("action", "register prekeys").Logger() - log.Debug().Int("num_prekeys", len(preKeys)).Int("num_kyber_prekeys", len(kyberPreKeys)).Msg("Registering prekeys") + zerolog.Ctx(ctx).Debug(). + Int("num_prekeys", len(preKeys)). + Int("num_kyber_prekeys", len(kyberPreKeys)). + Msg("Registering all prekeys") err = cli.RegisterPreKeys(ctx, &generatedPreKeys, pni) if err != nil { return fmt.Errorf("failed to register prekeys: %w", err) @@ -596,23 +579,29 @@ func (cli *Client) keyCheckLoop(ctx context.Context) { log := zerolog.Ctx(ctx).With().Str("action", "start key check loop").Logger() // Do the initial check in 5-10 minutes after starting the loop - window_start := 0 - window_size := 1 + windowStart := 0 + windowSize := 1 + firstRun := true for { - random_minutes_in_window := rand.Intn(window_size) + window_start - check_time := time.Duration(random_minutes_in_window) * time.Minute - log.Debug().Dur("check_time", check_time).Msg("Waiting to check for new prekeys") + randomMinutesInWindow := rand.IntN(windowSize) + windowStart + checkTime := time.Duration(randomMinutesInWindow) * time.Minute + if firstRun { + checkTime = 0 + firstRun = false + } else { + log.Debug().Dur("check_time", checkTime).Msg("Waiting to check for new prekeys") + } select { case <-ctx.Done(): return - case <-time.After(check_time): + case <-time.After(checkTime): err := cli.CheckAndUploadNewPreKeys(ctx, cli.Store.ACIPreKeyStore) if err != nil { log.Err(err).Msg("Error checking and uploading new prekeys for ACI identity") // Retry within half an hour - window_start = 5 - window_size = 25 + windowStart = 5 + windowSize = 25 continue } err = cli.CheckAndUploadNewPreKeys(ctx, cli.Store.PNIPreKeyStore) @@ -628,13 +617,13 @@ func (cli *Client) keyCheckLoop(ctx context.Context) { } log.Err(err).Msg("Error checking and uploading new prekeys for PNI identity") // Retry within half an hour - window_start = 5 - window_size = 25 + windowStart = 5 + windowSize = 25 continue } // After a successful check, check again in 36 to 60 hours - window_start = 36 * 60 - window_size = 24 * 60 + windowStart = 36 * 60 + windowSize = 24 * 60 } } } diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 2343e32..48a8042 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -22,7 +22,7 @@ import ( "encoding/base64" "encoding/json" "fmt" - mrand "math/rand" + mrand "math/rand/v2" "net/http" "net/url" "time" @@ -54,7 +54,6 @@ const ( StateProvisioningError ProvisioningState = iota StateProvisioningURLReceived StateProvisioningDataReceived - StateProvisioningPreKeysRegistered ) func (s ProvisioningState) String() string { @@ -65,8 +64,6 @@ func (s ProvisioningState) String() string { return "StateProvisioningURLReceived" case StateProvisioningDataReceived: return "StateProvisioningDataReceived" - case StateProvisioningPreKeysRegistered: - return "StateProvisioningPreKeysRegistered" default: return fmt.Sprintf("ProvisioningState(%d)", s) } @@ -128,8 +125,8 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev username := *provisioningMessage.Number password := random.String(22) code := provisioningMessage.ProvisioningCode - aciRegistrationID := mrand.Intn(16383) + 1 - pniRegistrationID := mrand.Intn(16383) + 1 + aciRegistrationID := mrand.IntN(16383) + 1 + pniRegistrationID := mrand.IntN(16383) + 1 aciSignedPreKey := GenerateSignedPreKey(1, aciIdentityKeyPair) pniSignedPreKey := GenerateSignedPreKey(1, pniIdentityKeyPair) aciPQLastResortPreKey := GenerateKyberPreKeys(1, 1, aciIdentityKeyPair)[0] @@ -250,28 +247,6 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev // Return the provisioning data c <- ProvisioningResponse{State: StateProvisioningDataReceived, ProvisioningData: data} - - // Generate, store, and register prekeys - // TODO hacky client construction - cli := &Client{Store: device} - err = cli.GenerateAndRegisterPreKeys(ctx, device.ACIPreKeyStore) - if err != nil { - c <- ProvisioningResponse{ - State: StateProvisioningError, - Err: fmt.Errorf("error generating and registering ACI prekeys: %w", err), - } - return - } - err = cli.GenerateAndRegisterPreKeys(ctx, device.PNIPreKeyStore) - if err != nil { - c <- ProvisioningResponse{ - State: StateProvisioningError, - Err: fmt.Errorf("error generating and registering PNI prekeys: %w", err), - } - return - } - - c <- ProvisioningResponse{State: StateProvisioningPreKeysRegistered} }() return c } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 622f18c..7267d0b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -261,6 +261,12 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection } else { zerolog.Ctx(ctx).Debug().Msg("Successfully registered capabilities") } + // Start loop to check for and upload more prekeys + cli.loopWg.Add(1) + go func() { + defer cli.loopWg.Done() + cli.keyCheckLoop(loopCtx) + }() // TODO hacky if cli.SyncContactsOnConnect { cli.SendContactSyncRequest(loopCtx) @@ -273,13 +279,6 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection } }() - // Start loop to check for and upload more prekeys - cli.loopWg.Add(1) - go func() { - defer cli.loopWg.Done() - cli.keyCheckLoop(loopCtx) - }() - return statusChan, nil } From 7a72795f5d1b2038d30c50d735785371393e84c7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 17:43:32 +0200 Subject: [PATCH 599/718] signalmeow/receiving: remove redundant loop waiting for websocket connect --- pkg/signalmeow/receiving.go | 49 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 7267d0b..2a023ca 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -249,32 +249,29 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection cli.loopWg.Add(1) go func() { defer cli.loopWg.Done() - for { - select { - case <-loopCtx.Done(): - return - case <-initialConnectChan: - log.Info().Msg("Both websockets connected, sending contacts sync request") - err = cli.RegisterCapabilities(ctx) - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to register capabilities") - } else { - zerolog.Ctx(ctx).Debug().Msg("Successfully registered capabilities") - } - // Start loop to check for and upload more prekeys - cli.loopWg.Add(1) - go func() { - defer cli.loopWg.Done() - cli.keyCheckLoop(loopCtx) - }() - // TODO hacky - if cli.SyncContactsOnConnect { - cli.SendContactSyncRequest(loopCtx) - } - if cli.Store.MasterKey == nil { - cli.SendStorageMasterKeyRequest(loopCtx) - } - return + select { + case <-loopCtx.Done(): + return + case <-initialConnectChan: + log.Info().Msg("Both websockets connected, sending contacts sync request") + err = cli.RegisterCapabilities(ctx) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to register capabilities") + } else { + zerolog.Ctx(ctx).Debug().Msg("Successfully registered capabilities") + } + // Start loop to check for and upload more prekeys + cli.loopWg.Add(1) + go func() { + defer cli.loopWg.Done() + cli.keyCheckLoop(loopCtx) + }() + // TODO hacky + if cli.SyncContactsOnConnect { + cli.SendContactSyncRequest(loopCtx) + } + if cli.Store.MasterKey == nil { + cli.SendStorageMasterKeyRequest(loopCtx) } } }() From cd598b872197522bdea96c5b6a28af66364232a2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 17:57:18 +0200 Subject: [PATCH 600/718] signalmeow/web: include server response content in logs --- pkg/signalmeow/web/signalwebsocket.go | 18 ++++++++++++++---- pkg/signalmeow/web/web.go | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 4c2ac7a..c4172aa 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -19,6 +19,7 @@ package web import ( "context" "encoding/base64" + "encoding/json" "errors" "fmt" "net/http" @@ -454,10 +455,19 @@ func readLoop( Msg("Received response with unknown id") continue } - log.Debug(). - Uint64("response_id", *msg.Response.Id). - Uint32("response_status", *msg.Response.Status). - Msg("Received WS response") + logEvt := log.Debug(). + Uint64("response_id", msg.Response.GetId()). + Uint32("response_status", msg.Response.GetStatus()). + Str("response_message", msg.Response.GetMessage()) + if log.GetLevel() == zerolog.TraceLevel { + logEvt.Strs("response_headers", msg.Response.Headers) + if json.Valid(msg.Response.Body) { + logEvt.RawJSON("response_body", msg.Response.Body) + } else { + logEvt.Str("response_body", base64.StdEncoding.EncodeToString(msg.Response.Body)) + } + } + logEvt.Msg("Received WS response") responseChannel <- msg.Response close(responseChannel) } else if *msg.Type == signalpb.WebSocketMessage_UNKNOWN { diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index ed3558c..cb1efa7 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -168,7 +168,7 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe func DecodeWSResponseBody(ctx context.Context, out any, resp *signalpb.WebSocketResponseMessage) error { if resp.GetStatus() < 200 || resp.GetStatus() >= 300 { - zerolog.Ctx(ctx).Debug(). + zerolog.Ctx(ctx).Warn(). Bytes("body", resp.Body). Str("resp_message", resp.GetMessage()). Strs("headers", resp.Headers). From c54b104b2ec67615f1f6a080646ac9879a26f86b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 18:16:46 +0200 Subject: [PATCH 601/718] signalmeow/sending: remove incorrect check for sync messages --- pkg/signalmeow/sending.go | 50 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index c1c0232..d919546 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -623,14 +623,13 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.Se } } - // No need to send to ourselves if we don't have any other devices - if cli.howManyOtherDevicesDoWeHave(ctx) > 0 { - var syncContent *signalpb.Content - if content.GetDataMessage() != nil { - syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo) - } else if content.GetEditMessage() != nil { - syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) - } + var syncContent *signalpb.Content + if content.GetDataMessage() != nil { + syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo) + } else if content.GetEditMessage() != nil { + syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) + } + if syncContent != nil { _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true, true) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") @@ -649,25 +648,22 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.Se } func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool { - // If we have other devices, send Sync messages to them too - if cli.howManyOtherDevicesDoWeHave(ctx) > 0 { - var syncContent *signalpb.Content - if content.GetDataMessage() != nil { - syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result) - } else if content.GetEditMessage() != nil { - syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) - } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { - syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) - } else if content.GetSyncMessage() != nil { - syncContent = content - } - if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, false) - if selfSendErr != nil { - zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") - } else { - return true - } + var syncContent *signalpb.Content + if content.GetDataMessage() != nil { + syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result) + } else if content.GetEditMessage() != nil { + syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) + } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { + syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) + } else if content.GetSyncMessage() != nil { + syncContent = content + } + if syncContent != nil { + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, false) + if selfSendErr != nil { + zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") + } else { + return true } } return false From edacab163c9031d427d6d8a0d4ed4d1c073b7652 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 24 Nov 2025 18:18:50 +0200 Subject: [PATCH 602/718] client: unlink before disconnecting websocket --- pkg/connector/client.go | 10 +++++----- pkg/signalmeow/web/signalwebsocket.go | 3 ++- pkg/signalmeow/web/web.go | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index c85ae35..233ad91 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -78,14 +78,14 @@ func (s *SignalClient) LogoutRemote(ctx context.Context) { if s.Client == nil { return } - err := s.Client.StopReceiveLoops() - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") - } - err = s.Client.Unlink(ctx) + err := s.Client.Unlink(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to unlink device") } + err = s.Client.StopReceiveLoops() + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to stop receive loops for logout") + } err = s.Main.Store.DeleteDevice(context.TODO(), &s.Client.Store.DeviceData) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to delete device from store") diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index c4172aa..38dcc4d 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -619,7 +619,8 @@ func (s *SignalWebsocket) sendRequestInternal( } response := <-responseChannel - if response == nil { + isSelfDelete := request.GetVerb() == http.MethodDelete && strings.HasPrefix(request.GetPath(), "/v1/devices/") + if response == nil && !isSelfDelete { // If out of retries, return error no matter what if retryCount >= 3 { // TODO: I think error isn't getting passed in this context (as it's not the one in writeLoop) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index cb1efa7..e16d7c7 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -167,6 +167,9 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe } func DecodeWSResponseBody(ctx context.Context, out any, resp *signalpb.WebSocketResponseMessage) error { + if resp == nil { + return nil + } if resp.GetStatus() < 200 || resp.GetStatus() >= 300 { zerolog.Ctx(ctx).Warn(). Bytes("body", resp.Body). From c7b7ea71f81c3c23ae266700b712d9edef01e182 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Nov 2025 15:55:32 +0200 Subject: [PATCH 603/718] main: adjust signalmeow user agent --- cmd/mautrix-signal/main.go | 4 ++++ pkg/signalmeow/web/web.go | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 522834f..d224f32 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -17,9 +17,12 @@ package main import ( + "fmt" + "maunium.net/go/mautrix/bridgev2/matrix/mxmain" "go.mau.fi/mautrix-signal/pkg/connector" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) // Information to find out exactly which commit the bridge was built from. @@ -41,6 +44,7 @@ var m = mxmain.BridgeMain{ } func main() { + web.UserAgent = fmt.Sprintf("mautrix-signal/%s %s", m.Version, web.BaseUserAgent) m.PostStart = func() { if m.Matrix.Provisioning != nil { m.Matrix.Provisioning.Router.HandleFunc("GET /v2/resolve_identifier/{phonenum}", legacyProvResolveIdentifier) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index e16d7c7..84a04b9 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -40,7 +40,8 @@ import ( const proxyUrlStr = "" // Set this to proxy requests const caCertPath = "" // Set this to trust a self-signed cert (ie. for mitmproxy) -var UserAgent = "signalmeow/0.1.0 libsignal/" + libsignalgo.Version + " go/" + strings.TrimPrefix(runtime.Version(), "go") +var BaseUserAgent = "libsignal/" + libsignalgo.Version + " go/" + strings.TrimPrefix(runtime.Version(), "go") +var UserAgent = "signalmeow/0.1.0 " + BaseUserAgent var SignalAgent = "MAU" const ( From 60c42c68fc556615ee31003cea0c997f426f1f38 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 25 Nov 2025 20:15:52 +0200 Subject: [PATCH 604/718] signalmeow/groups: fix group cache --- pkg/connector/connector.go | 13 +- pkg/signalmeow/client.go | 31 +++- pkg/signalmeow/groupcache.go | 281 +++++++++++++++++++++++++++++++++++ pkg/signalmeow/groups.go | 120 ++++----------- pkg/signalmeow/profile.go | 8 - pkg/signalmeow/receiving.go | 2 +- pkg/signalmeow/sending.go | 10 +- 7 files changed, 349 insertions(+), 116 deletions(-) create mode 100644 pkg/signalmeow/groupcache.go diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 30be4a4..59f8640 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -94,13 +94,12 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use queueEmptyWaiter: exsync.NewEvent(), } if device != nil { - sc.Client = &signalmeow.Client{ - Store: device, - Log: sc.UserLogin.Log.With().Str("component", "signalmeow").Logger(), - EventHandler: sc.handleSignalEvent, - - SyncContactsOnConnect: s.Config.SyncContactsOnStartup, - } + sc.Client = signalmeow.NewClient( + device, + sc.UserLogin.Log.With().Str("component", "signalmeow").Logger(), + sc.handleSignalEvent, + ) + sc.Client.SyncContactsOnConnect = s.Config.SyncContactsOnStartup } login.Client = sc return nil diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index ea5eb17..2a7f470 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -30,6 +30,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/signalmeow/events" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) @@ -37,14 +38,14 @@ type Client struct { Store *store.Device Log zerolog.Logger - SenderCertificateWithE164 *libsignalgo.SenderCertificate - SenderCertificateNoE164 *libsignalgo.SenderCertificate - GroupCredentials *GroupCredentials - GroupCache *GroupCache - ProfileCache *ProfileCache - GroupCallCache *map[string]bool - LastContactRequestTime time.Time - SyncContactsOnConnect bool + senderCertificateWithE164 *libsignalgo.SenderCertificate + senderCertificateNoE164 *libsignalgo.SenderCertificate + senderCertificateCache sync.Mutex + + GroupCache *GroupCache + ProfileCache *ProfileCache + LastContactRequestTime time.Time + SyncContactsOnConnect bool encryptionLock sync.Mutex @@ -66,6 +67,20 @@ type Client struct { writeCallbackCounter chan time.Time } +func NewClient(device *store.Device, log zerolog.Logger, evtHandler func(events.SignalEvent) bool) *Client { + return &Client{ + Store: device, + Log: log, + EventHandler: evtHandler, + GroupCache: NewGroupCache(), + ProfileCache: &ProfileCache{ + profiles: make(map[string]*types.Profile), + errors: make(map[string]*error), + lastFetched: make(map[string]time.Time), + }, + } +} + func (cli *Client) handleEvent(evt events.SignalEvent) bool { return cli.EventHandler(evt) } diff --git a/pkg/signalmeow/groupcache.go b/pkg/signalmeow/groupcache.go new file mode 100644 index 0000000..557203a --- /dev/null +++ b/pkg/signalmeow/groupcache.go @@ -0,0 +1,281 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "fmt" + "slices" + "sync" + "time" + + "github.com/google/uuid" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +type cachedGroup struct { + *Group + SendEndorsement []byte + FetchedAt time.Time + UpdatedAt time.Time +} + +type GroupCache struct { + credentials *GroupCredentials + credentialsLock sync.RWMutex + + data map[types.GroupIdentifier]*cachedGroup + lock sync.RWMutex + + activeCalls map[types.GroupIdentifier]string + callsLock sync.RWMutex +} + +func NewGroupCache() *GroupCache { + return &GroupCache{ + data: make(map[types.GroupIdentifier]*cachedGroup), + activeCalls: make(map[types.GroupIdentifier]string), + } +} + +func (gc *GroupCache) GetCredentials( + ctx context.Context, + fetch func(context.Context, time.Time) (*GroupCredentials, error), +) (*GroupCredential, error) { + today := time.Now().Truncate(24 * time.Hour) + gc.credentialsLock.RLock() + cred := gc.getCachedCredentials(today.Unix()) + gc.credentialsLock.RUnlock() + if cred != nil { + return cred, nil + } + + gc.credentialsLock.Lock() + defer gc.credentialsLock.Unlock() + cred = gc.getCachedCredentials(today.Unix()) + if cred != nil { + return cred, nil + } + creds, err := fetch(ctx, today) + if err != nil { + return nil, err + } + gc.credentials = creds + cred = gc.getCachedCredentials(today.Unix()) + if cred == nil { + return nil, fmt.Errorf("no credentials for today after fetch") + } + return cred, nil +} + +func (gc *GroupCache) getCachedCredentials(today int64) *GroupCredential { + if gc.credentials == nil { + return nil + } + for _, cred := range gc.credentials.Credentials { + if cred.RedemptionTime == today { + return &cred + } + } + return nil +} + +func (gc *GroupCache) UpdateActiveCall(id types.GroupIdentifier, callID string) bool { + gc.callsLock.Lock() + defer gc.callsLock.Unlock() + currentCallID, ok := gc.activeCalls[id] + if ok { + // If we do, then this must be ending the call + if currentCallID == callID { + delete(gc.activeCalls, id) + return false + } + } + gc.activeCalls[id] = callID + return true +} + +func (gc *GroupCache) Get(id types.GroupIdentifier) (*Group, bool) { + gc.lock.RLock() + defer gc.lock.RUnlock() + c, ok := gc.data[id] + if !ok { + return nil, false + } + return c.Group, true +} + +func (gc *GroupCache) Delete(id types.GroupIdentifier) { + gc.lock.Lock() + defer gc.lock.Unlock() + delete(gc.data, id) +} + +func (gc *GroupCache) Put(data *Group, endorsementResponse []byte) { + gc.lock.Lock() + defer gc.lock.Unlock() + cached, exists := gc.data[data.GroupIdentifier] + if exists && cached.Revision > data.Revision { + return + } + gc.data[data.GroupIdentifier] = &cachedGroup{ + Group: data, + FetchedAt: time.Now(), + UpdatedAt: time.Now(), + + //SendEndorsement: endorsementResponse, + } +} + +func (gc *GroupCache) ApplyUpdate(change *GroupChange, endorsementResponse []byte) { + rawGroupID, err := masterKeyToBytes(change.GroupMasterKey).GroupIdentifier() + if err != nil { + return + } + id := types.GroupIdentifier(rawGroupID.String()) + + gc.lock.Lock() + defer gc.lock.Unlock() + + cached, exists := gc.data[id] + if !exists || cached.Revision >= change.Revision { + return + } else if cached.Revision < change.Revision-1 { + // We missed an update, evict + delete(gc.data, id) + return + } + + // Pending member adds, promotes and removes + cached.PendingMembers = append(cached.PendingMembers, change.AddPendingMembers...) + for _, promo := range change.PromotePendingMembers { + cached.PendingMembers = slices.DeleteFunc(cached.PendingMembers, func(p *PendingMember) bool { + return p.ServiceID.Type == libsignalgo.ServiceIDTypeACI && p.ServiceID.UUID == promo.ACI + }) + cached.Members = append(cached.Members, &GroupMember{ + ACI: promo.ACI, + ProfileKey: promo.ProfileKey, + Role: GroupMember_DEFAULT, + JoinedAtRevision: change.Revision, + }) + } + for _, promo := range change.PromotePendingPniAciMembers { + cached.PendingMembers = slices.DeleteFunc(cached.PendingMembers, func(p *PendingMember) bool { + return (p.ServiceID.Type == libsignalgo.ServiceIDTypePNI && p.ServiceID.UUID == promo.PNI) || + (p.ServiceID.Type == libsignalgo.ServiceIDTypeACI && p.ServiceID.UUID == promo.ACI) + }) + cached.Members = append(cached.Members, &GroupMember{ + ACI: promo.ACI, + ProfileKey: promo.ProfileKey, + Role: GroupMember_DEFAULT, + JoinedAtRevision: change.Revision, + }) + } + cached.PendingMembers = slices.DeleteFunc(cached.PendingMembers, func(p *PendingMember) bool { + return slices.ContainsFunc(change.DeletePendingMembers, func(s *libsignalgo.ServiceID) bool { + return s != nil && p.ServiceID == *s + }) + }) + + // Requesting member adds, promotes and removes + cached.RequestingMembers = append(cached.RequestingMembers, change.AddRequestingMembers...) + for _, promo := range change.PromoteRequestingMembers { + var profileKey libsignalgo.ProfileKey + cached.RequestingMembers = slices.DeleteFunc(cached.RequestingMembers, func(r *RequestingMember) bool { + if r.ACI == promo.ACI { + profileKey = r.ProfileKey + return true + } + return false + }) + cached.Members = append(cached.Members, &GroupMember{ + ACI: promo.ACI, + ProfileKey: profileKey, + Role: promo.Role, + JoinedAtRevision: change.Revision, + }) + } + cached.RequestingMembers = slices.DeleteFunc(cached.RequestingMembers, func(r *RequestingMember) bool { + return slices.ContainsFunc(change.DeleteRequestingMembers, func(u *uuid.UUID) bool { + return u != nil && r.ACI == *u + }) + }) + + // Direct member adds, removes and modifications + for _, member := range change.AddMembers { + cached.Members = append(cached.Members, &GroupMember{ + ACI: member.ACI, + Role: member.Role, + ProfileKey: member.ProfileKey, + JoinedAtRevision: member.JoinedAtRevision, + }) + } + for _, rm := range change.ModifyMemberRoles { + cached.findMemberOrEmpty(rm.ACI).Role = rm.Role + } + for _, pk := range change.ModifyMemberProfileKeys { + cached.findMemberOrEmpty(pk.ACI).ProfileKey = pk.ProfileKey + } + cached.Members = slices.DeleteFunc(cached.Members, func(member *GroupMember) bool { + return slices.ContainsFunc(change.DeleteMembers, func(u *uuid.UUID) bool { + return u != nil && *u == member.ACI + }) + }) + + // Banned members + cached.BannedMembers = append(cached.BannedMembers, change.AddBannedMembers...) + cached.BannedMembers = slices.DeleteFunc(cached.BannedMembers, func(b *BannedMember) bool { + return slices.ContainsFunc(change.DeleteBannedMembers, func(s *libsignalgo.ServiceID) bool { + return s != nil && b.ServiceID == *s + }) + }) + + // Non-member modifications + if change.ModifyInviteLinkPassword != nil { + cached.InviteLinkPassword = change.ModifyInviteLinkPassword + } + if change.ModifyTitle != nil { + cached.Title = *change.ModifyTitle + } + if change.ModifyDescription != nil { + cached.Description = *change.ModifyDescription + } + if change.ModifyAvatar != nil { + cached.AvatarPath = *change.ModifyAvatar + } + if change.ModifyAnnouncementsOnly != nil { + cached.AnnouncementsOnly = *change.ModifyAnnouncementsOnly + } + if change.ModifyDisappearingMessagesDuration != nil { + cached.DisappearingMessagesDuration = *change.ModifyDisappearingMessagesDuration + } + if change.ModifyAttributesAccess != nil { + cached.AccessControl.Attributes = *change.ModifyAttributesAccess + } + if change.ModifyMemberAccess != nil { + cached.AccessControl.Members = *change.ModifyMemberAccess + } + if change.ModifyAddFromInviteLinkAccess != nil { + cached.AccessControl.AddFromInviteLink = *change.ModifyAddFromInviteLinkAccess + } + + // TODO handle endorsement responses + cached.UpdatedAt = time.Now() + cached.Revision = change.Revision +} diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 39753bb..f25f835 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -114,6 +114,15 @@ func (group *Group) GetInviteLink() (string, error) { return "https://signal.group/#" + inviteLinkPath, nil } +func (group *Group) findMemberOrEmpty(aci uuid.UUID) *GroupMember { + for _, member := range group.Members { + if member.ACI == aci { + return member + } + } + return &GroupMember{} +} + type GroupAccessControl struct { Members AccessControl AddFromInviteLink AccessControl @@ -328,51 +337,22 @@ func (cli *Client) fetchNewGroupCreds(ctx context.Context, today time.Time) (*Gr log.Err(err).Msg("json.Unmarshal error") return nil, err } - // make sure pni matches device pni if creds.PNI != cli.Store.PNI { - err := fmt.Errorf("creds.PNI != d.PNI") - log.Err(err).Msg("creds.PNI != d.PNI") - return nil, err + return nil, fmt.Errorf("mismatching PNI in group credentials: %s != %s", creds.PNI, cli.Store.PNI) } return &creds, nil } -func (cli *Client) getCachedAuthorizationForToday(today time.Time) *GroupCredential { - if cli.GroupCredentials == nil { - // No cached credentials - return nil - } - allCreds := cli.GroupCredentials - // Get the credential for today - for _, cred := range allCreds.Credentials { - if cred.RedemptionTime == today.Unix() { - return &cred - } - } - return nil -} - func (cli *Client) GetAuthorizationForToday(ctx context.Context, masterKey libsignalgo.GroupMasterKey) (*GroupAuth, error) { log := zerolog.Ctx(ctx).With(). Str("action", "get authorization for today"). Logger() - // Timestamps for the start of today, and 7 days later - today := time.Now().Truncate(24 * time.Hour) - todayCred := cli.getCachedAuthorizationForToday(today) - if todayCred == nil { - creds, err := cli.fetchNewGroupCreds(ctx, today) - if err != nil { - return nil, fmt.Errorf("fetchNewGroupCreds error: %w", err) - } - cli.GroupCredentials = creds - todayCred = cli.getCachedAuthorizationForToday(today) - } - if todayCred == nil { - return nil, fmt.Errorf("couldn't get credential for today") + todayCred, err := cli.GroupCache.GetCredentials(ctx, cli.fetchNewGroupCreds) + if err != nil { + return nil, fmt.Errorf("failed to get group credentials: %w", err) } - //TODO: cache cred after unmarshalling redemptionTime := uint64(todayCred.RedemptionTime) credential := todayCred.Credential authCredentialResponse, err := libsignalgo.NewAuthCredentialWithPniResponse(credential) @@ -674,6 +654,7 @@ func (cli *Client) parseGroupResponse(ctx context.Context, response *http.Respon if err != nil { return nil, fmt.Errorf("failed to decrypt group: %w", err) } + cli.GroupCache.Put(group, groupResponse.GroupSendEndorsementsResponse) // Store the profile keys in case they're new for _, member := range group.Members { @@ -717,22 +698,11 @@ func (cli *Client) DownloadGroupAvatar(ctx context.Context, avatarPath string, g } func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentifier, revision uint32) (*Group, error) { - cli.initGroupCache() - - lastFetched, ok := cli.GroupCache.lastFetched[gid] - if ok && time.Since(lastFetched) < 1*time.Hour { - group, ok := cli.GroupCache.groups[gid] - if ok && group.Revision >= revision { - return group, nil - } + cached, ok := cli.GroupCache.Get(gid) + if ok && cached.Revision >= revision { + return cached, nil } - group, err := cli.fetchGroupByID(ctx, gid) - if err != nil { - return nil, err - } - cli.GroupCache.groups[gid] = group - cli.GroupCache.lastFetched[gid] = time.Now() - return group, nil + return cli.fetchGroupByID(ctx, gid) } // We should store the group master key in the group store as soon as we see it, @@ -750,40 +720,6 @@ func (cli *Client) StoreMasterKey(ctx context.Context, groupMasterKey types.Seri return groupIdentifier, nil } -// We need to track active calls so we don't send too many IncomingSignalMessageCalls -// Of course for group calls Signal doesn't tell us *anything* so we're mostly just inferring -// So we just jam a new call ID in, and return true if we *think* this is a new incoming call -func (cli *Client) UpdateActiveCalls(gid types.GroupIdentifier, callID string) (isActive bool) { - cli.initGroupCache() - // Check to see if we currently have an active call for this group - currentCallID, ok := cli.GroupCache.activeCalls[gid] - if ok { - // If we do, then this must be ending the call - if currentCallID == callID { - delete(cli.GroupCache.activeCalls, gid) - return false - } - } - cli.GroupCache.activeCalls[gid] = callID - return true -} - -func (cli *Client) initGroupCache() { - if cli.GroupCache == nil { - cli.GroupCache = &GroupCache{ - groups: make(map[types.GroupIdentifier]*Group), - lastFetched: make(map[types.GroupIdentifier]time.Time), - activeCalls: make(map[types.GroupIdentifier]string), - } - } -} - -type GroupCache struct { - groups map[types.GroupIdentifier]*Group - lastFetched map[types.GroupIdentifier]time.Time - activeCalls map[types.GroupIdentifier]string -} - func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalpb.GroupContextV2) (*GroupChange, error) { masterKeyBytes := libsignalgo.GroupMasterKey(groupContext.MasterKey) groupMasterKey := masterKeyFromBytes(masterKeyBytes) @@ -801,6 +737,15 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange log := zerolog.Ctx(ctx).With().Str("action", "decrypt group change").Logger() serverSignature := encryptedGroupChange.ServerSignature encryptedActionsBytes := encryptedGroupChange.Actions + var success bool + defer func() { + if !success { + rawGroupID, _ := masterKeyToBytes(groupMasterKey).GroupIdentifier() + if rawGroupID != nil { + cli.GroupCache.Delete(types.GroupIdentifier(rawGroupID.String())) + } + } + }() var err error if verifySignature { @@ -1103,6 +1048,9 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange decryptedGroupChange.ModifyInviteLinkPassword = &inviteLinkPassword } + success = true + cli.GroupCache.ApplyUpdate(decryptedGroupChange, nil) + return decryptedGroupChange, nil } @@ -1574,9 +1522,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi return 0, fmt.Errorf("failed to update group: %w", err) } } else if errors.Is(err, ConflictError) { - delete(cli.GroupCache.groups, gid) - delete(cli.GroupCache.lastFetched, gid) - delete(cli.GroupCache.activeCalls, gid) + cli.GroupCache.Delete(gid) group, err = cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { return 0, fmt.Errorf("failed to fetch group after conflict: %w", err) @@ -1590,12 +1536,10 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi return 0, fmt.Errorf("unknown error encrypting and signing group change: %w", err) } } - delete(cli.GroupCache.groups, gid) - delete(cli.GroupCache.lastFetched, gid) - delete(cli.GroupCache.activeCalls, gid) if signedGroupChange == nil { return 0, fmt.Errorf("no signed group change returned: %w", err) } + cli.GroupCache.ApplyUpdate(groupChange, signedGroupChange.GroupSendEndorsementsResponse) groupChangeBytes, err := proto.Marshal(signedGroupChange.GroupChange) if err != nil { return 0, fmt.Errorf("failed to marshal signed group change: %w", err) diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index 4284a8b..f40d6ce 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -134,14 +134,6 @@ func (cli *Client) getCachedProfileByID(signalID uuid.UUID, refreshAfter time.Du } func (cli *Client) RetrieveProfileByID(ctx context.Context, signalID uuid.UUID, refreshAfter time.Duration) (*types.Profile, error) { - if cli.ProfileCache == nil { - cli.ProfileCache = &ProfileCache{ - profiles: make(map[string]*types.Profile), - errors: make(map[string]*error), - lastFetched: make(map[string]time.Time), - } - } - // Check if we have a cached profile that is less than an hour old // or if we have a cached error that is less than an hour old profile, err := cli.getCachedProfileByID(signalID, refreshAfter) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 2a023ca..0feee6b 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -880,7 +880,7 @@ func (cli *Client) incomingDataMessage( } // Hacky special case for group calls to cache the state if dataMessage.GroupCallUpdate != nil { - isRinging := cli.UpdateActiveCalls(groupID, dataMessage.GroupCallUpdate.GetEraId()) + isRinging := cli.GroupCache.UpdateActiveCall(groupID, dataMessage.GroupCallUpdate.GetEraId()) return cli.handleEvent(&events.Call{ Info: evtInfo, Timestamp: dataMessage.GetTimestamp(), diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index d919546..e8dc71f 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -42,15 +42,17 @@ import ( // Sending func (cli *Client) senderCertificate(ctx context.Context, e164 bool) (*libsignalgo.SenderCertificate, error) { - cached := cli.SenderCertificateNoE164 + cli.senderCertificateCache.Lock() + defer cli.senderCertificateCache.Unlock() + cached := cli.senderCertificateNoE164 if e164 { - cached = cli.SenderCertificateWithE164 + cached = cli.senderCertificateWithE164 } setCache := func(val *libsignalgo.SenderCertificate) { if e164 { - cli.SenderCertificateWithE164 = val + cli.senderCertificateWithE164 = val } else { - cli.SenderCertificateNoE164 = val + cli.senderCertificateNoE164 = val } } if cached != nil { From 659222b31bc77729b5b09e3274ee7756547a3ca1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Nov 2025 16:53:59 +0200 Subject: [PATCH 605/718] signalmeow: implement sending with sender keys --- go.mod | 2 +- go.sum | 4 +- pkg/libsignalgo/profilekey.go | 22 +- pkg/libsignalgo/sealedsender.go | 47 ++- pkg/libsignalgo/serviceid.go | 13 + pkg/signalmeow/keys.go | 8 + pkg/signalmeow/senderkey.go | 374 ++++++++++++++++++ pkg/signalmeow/sending.go | 328 +++++++-------- pkg/signalmeow/store/device.go | 2 +- pkg/signalmeow/store/sender_key_store.go | 67 +++- pkg/signalmeow/store/session_store.go | 65 ++- pkg/signalmeow/store/upgrades/00-latest.sql | 9 + .../upgrades/24-outbound-sender-keys.sql | 9 + pkg/signalmeow/web/web.go | 9 +- 14 files changed, 755 insertions(+), 204 deletions(-) create mode 100644 pkg/signalmeow/senderkey.go create mode 100644 pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql diff --git a/go.mod b/go.mod index a1be9e8..0b128b6 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.4-0.20251124151504-71e0e3476592 + go.mau.fi/util v0.9.4-0.20251126134359-7710832c1450 golang.org/x/crypto v0.44.0 golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 golang.org/x/net v0.47.0 diff --git a/go.sum b/go.sum index aeb8cf5..f2d3989 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.4-0.20251124151504-71e0e3476592 h1:qSGoV3kSle4DJIFNTK7AdA3NP5MuA6tlTvQrCKsY9iU= -go.mau.fi/util v0.9.4-0.20251124151504-71e0e3476592/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ= +go.mau.fi/util v0.9.4-0.20251126134359-7710832c1450 h1:sYj7slS8b3sav+hYnC2VXEqRpRS6bVvyuQIUGF85k04= +go.mau.fi/util v0.9.4-0.20251126134359-7710832c1450/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ= 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.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= diff --git a/pkg/libsignalgo/profilekey.go b/pkg/libsignalgo/profilekey.go index 8d2ae04..e49801a 100644 --- a/pkg/libsignalgo/profilekey.go +++ b/pkg/libsignalgo/profilekey.go @@ -23,6 +23,7 @@ package libsignalgo */ import "C" import ( + "encoding/base64" "errors" "runtime" "unsafe" @@ -54,10 +55,6 @@ func (pk *ProfileKey) IsEmpty() bool { return pk == nil || *pk == blankProfileKey } -func (ak *AccessKey) String() string { - return string(ak[:]) -} - func (pv *ProfileKeyVersion) String() string { return string(pv[:]) } @@ -69,6 +66,23 @@ func (pk *ProfileKey) Slice() []byte { return pk[:] } +func (ak *AccessKey) Xor(other *AccessKey) *AccessKey { + if ak == nil { + return other + } else if other == nil { + return ak + } + var result AccessKey + for i := 0; i < C.SignalACCESS_KEY_LEN; i++ { + result[i] = ak[i] ^ other[i] + } + return &result +} + +func (ak *AccessKey) String() string { + return base64.StdEncoding.EncodeToString(ak[:]) +} + 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)) diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 1530183..5a55a2c 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -24,6 +24,7 @@ import "C" import ( "context" "runtime" + "unsafe" "github.com/google/uuid" ) @@ -78,8 +79,50 @@ func SealedSenderEncrypt(ctx context.Context, usmc *UnidentifiedSenderMessageCon return CopySignalOwnedBufferToBytes(encrypted), nil } -func SealedSenderMultiRecipientEncrypt(messageContent *UnidentifiedSenderMessageContent, forRecipients []*Address, identityStore IdentityKeyStore, sessionStore SessionStore, ctx *CallbackContext) ([]byte, error) { - panic("not implemented") +type SessionAddressTuple struct { + ServiceID ServiceID + DeviceID int + Address *Address + Record *SessionRecord +} + +func SealedSenderMultiRecipientEncrypt( + ctx context.Context, + usmc *UnidentifiedSenderMessageContent, + recipients []SessionAddressTuple, + identityStore IdentityKeyStore, +) ([]byte, error) { + var encrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + callbackCtx := NewCallbackContext(ctx) + defer callbackCtx.Unref() + recipientAddresses := make([]C.SignalConstPointerProtocolAddress, len(recipients)) + recipientSessions := make([]C.SignalConstPointerSessionRecord, len(recipients)) + for i, recipient := range recipients { + recipientAddresses[i] = recipient.Address.constPtr() + recipientSessions[i] = recipient.Record.constPtr() + } + signalFfiError := C.signal_sealed_sender_multi_recipient_encrypt( + &encrypted, + C.SignalBorrowedSliceOfConstPointerProtocolAddress{ + base: unsafe.SliceData(recipientAddresses), + length: C.size_t(len(recipientAddresses)), + }, + C.SignalBorrowedSliceOfConstPointerSessionRecord{ + base: unsafe.SliceData(recipientSessions), + length: C.size_t(len(recipientSessions)), + }, + BytesToBuffer(nil), + usmc.constPtr(), + callbackCtx.wrapIdentityKeyStore(identityStore), + ) + runtime.KeepAlive(usmc) + runtime.KeepAlive(recipients) + runtime.KeepAlive(recipientAddresses) + runtime.KeepAlive(recipientSessions) + if signalFfiError != nil { + return nil, callbackCtx.wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(encrypted), nil } type SealedSenderResult struct { diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index 19513de..6b0c864 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -118,6 +118,19 @@ func (s ServiceID) GoString() string { return fmt.Sprintf(`libsignalgo.ServiceID{Type: %#v, UUID: uuid.MustParse("%s")}`, s.Type, s.UUID) } +func (s ServiceID) MarshalText() ([]byte, error) { + return []byte(s.String()), nil +} + +func (s *ServiceID) UnmarshalText(text []byte) error { + parsed, err := ServiceIDFromString(string(text)) + if err != nil { + return err + } + *s = parsed + return nil +} + func (s ServiceID) MarshalZerologObject(e *zerolog.Event) { e.Stringer("type", s.Type) e.Stringer("uuid", s.UUID) diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 19ad1f6..724565a 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -404,16 +404,24 @@ func addBase64PaddingAndDecode(data string) ([]byte, error) { return base64.StdEncoding.DecodeString(data) } +var ( + ErrUnregisteredUser = errors.New("got 404 when fetching prekey, user is unregistered") + ErrDevicesChanged = errors.New("device list changed while sending skdm") +) + func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, specificDeviceID int) error { // Fetch prekey deviceIDPath := "/*" if specificDeviceID >= 0 { deviceIDPath = "/" + fmt.Sprint(specificDeviceID) } + // TODO this should be done via the unauthed websocket if possible path := "/v2/keys/" + theirServiceID.String() + deviceIDPath + "?pq=true" resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, path, nil, nil) if err != nil { return fmt.Errorf("error sending request: %w", err) + } else if resp.GetStatus() == 404 { + return ErrUnregisteredUser } var respData prekeyResponse err = web.DecodeWSResponseBody(ctx, &respData, resp) diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go new file mode 100644 index 0000000..133ef80 --- /dev/null +++ b/pkg/signalmeow/senderkey.go @@ -0,0 +1,374 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "maps" + "net/http" + "slices" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/exslices" + "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/store" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +const SenderKeyMaxAge = 14 * 24 * time.Hour + +type contextKey int + +const ( + contextKeyEncryptionLock contextKey = iota +) + +func (cli *Client) sendToGroupWithSenderKey( + ctx context.Context, + groupID types.GroupIdentifier, + allRecipients []libsignalgo.ServiceID, + content *signalpb.Content, + messageTimestamp uint64, + retries int, +) (*GroupMessageSendResult, error) { + if retries >= 3 { + return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, nil) + } + myAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)) + if err != nil { + return nil, fmt.Errorf("failed to get own address: %w", err) + } + log := zerolog.Ctx(ctx) + + cli.encryptionLock.Lock() + unlocked := false + doUnlock := func() { + if !unlocked { + unlocked = true + cli.encryptionLock.Unlock() + } + } + defer doUnlock() + ctx = context.WithValue(ctx, contextKeyEncryptionLock, true) + result := &GroupMessageSendResult{ + SuccessfullySentTo: make([]SuccessfulSendResult, 0), + FailedToSendTo: make([]FailedSendResult, 0), + } + + deviceIDs, senderKeyRecipients, fallbackRecipients := cli.getDevicesIDs(ctx, allRecipients, result) + ski, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupID) + if err != nil { + return nil, fmt.Errorf("failed to get sender key info: %w", err) + } else if ski == nil || time.Since(ski.CreatedAt) > SenderKeyMaxAge { + if ski != nil && time.Since(ski.CreatedAt) > SenderKeyMaxAge { + log.Debug().Any("old_sender_key_info", ski).Msg("Sender key expired, creating new one") + err = cli.Store.SenderKeyStore.DeleteSenderKey(ctx, myAddress, ski.DistributionID) + if err != nil { + return nil, fmt.Errorf("failed to delete old sender key: %w", err) + } + } else { + log.Debug().Msg("No existing sender key, creating new one") + } + ski = &store.SenderKeyInfo{ + DistributionID: uuid.New(), + CreatedAt: time.Now(), + SharedWith: make(map[libsignalgo.ServiceID][]int), + } + } else { + log.Debug().Any("sender_key_info", ski).Msg("Reusing existing sender key") + } + xak, devicesAddedTo, reset := diffRecipients(ski.SharedWith, deviceIDs) + if reset { + log.Debug().Msg("Resetting sender key due to recipient device changes") + devicesAddedTo = slices.Collect(maps.Keys(deviceIDs)) + err = cli.Store.SenderKeyStore.DeleteSenderKey(ctx, myAddress, ski.DistributionID) + if err != nil { + return nil, fmt.Errorf("failed to delete old sender key: %w", err) + } + } + if len(devicesAddedTo) > 0 { + log.Debug(). + Any("devices_added_to", devicesAddedTo). + Msg("Sending sender key distribution message to users with new devices") + skdm, err := libsignalgo.NewSenderKeyDistributionMessage(ctx, myAddress, ski.DistributionID, cli.Store.SenderKeyStore) + if err != nil { + return nil, fmt.Errorf("failed to create sender key distribution message: %w", err) + } + skdmBytes, err := skdm.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to serialize sender key distribution message: %w", err) + } + var needsRetry bool + for _, recipient := range devicesAddedTo { + log := log.With().Str("subaction", "skdm").Stringer("recipient_id", recipient).Logger() + _, err = cli.sendContent(log.WithContext(ctx), recipient, messageTimestamp, &signalpb.Content{ + SenderKeyDistributionMessage: skdmBytes, + }, 0, true, true) + if errors.Is(err, ErrDevicesChanged) || errors.Is(err, ErrUnregisteredUser) { + log.Warn().Err(err).Msg("Failed to send sender key distribution message due to device changes, will retry") + needsRetry = true + } else if err != nil { + log.Err(err).Msg("Failed to send sender key distribution message") + fallbackRecipients = append(fallbackRecipients, recipient) + delete(deviceIDs, recipient) + senderKeyRecipients = slices.DeleteFunc(senderKeyRecipients, func(tuple store.SessionAddressTuple) bool { + return tuple.ServiceID == recipient + }) + } else { + log.Debug().Msg("Successfully sent sender key distribution message") + ski.SharedWith[recipient] = deviceIDs[recipient].DeviceIDs + } + } + err = cli.Store.SenderKeyStore.PutSenderKeyInfo(ctx, groupID, ski) + if err != nil { + return nil, fmt.Errorf("failed to store updated sender key info: %w", err) + } + if needsRetry { + doUnlock() + return cli.sendToGroupWithSenderKey(ctx, groupID, allRecipients, content, messageTimestamp, retries+1) + } + } + ssCiphertext, err := cli.encryptWithSenderKey(ctx, groupID, ski.DistributionID, myAddress, senderKeyRecipients, content) + if err != nil { + return nil, err + } + header := http.Header{} + header.Set("Content-Type", string(web.ContentTypeMultiRecipientMessage)) + //if groupSendToken != nil { + // header.Set("Group-Send-Token", groupSendToken.String()) + //} else { + header.Set("Unidentified-Access-Key", xak.String()) + //} + path := fmt.Sprintf( + "/v1/messages/multi_recipient?ts=%d&urgent=%t&online=false", + messageTimestamp, isUrgent(content), + ) + log.Debug(). + Any("recipients", ski.SharedWith). + Any("fallback_recipients", fallbackRecipients). + Msg("Sending multi-recipient message with sender key") + resp, err := cli.UnauthedWS.SendRequest(ctx, http.MethodPut, path, ssCiphertext, header) + switch resp.GetStatus() { + case 200: + var respData MultiRecipient200Response + err = json.Unmarshal(resp.Body, &respData) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal 200 response: %w", err) + } + log.Debug(). + Any("response_data", respData). + Msg("Got successful multi-recipient send response") + for serviceID := range deviceIDs { + if slices.Contains(respData.UUIDs404, serviceID) { + // TODO flag recipient as unregistered + err = cli.Store.ACISessionStore.RemoveAllSessionsForServiceID(ctx, serviceID) + if err != nil { + log.Err(err).Stringer("recipient_id", serviceID). + Msg("Failed to remove sessions after 404") + } + result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ + Recipient: serviceID, + Error: fmt.Errorf("multi-recipient send 404"), + }) + } else { + result.SuccessfullySentTo = append(result.SuccessfullySentTo, SuccessfulSendResult{ + Recipient: serviceID, + Unidentified: true, + }) + } + } + doUnlock() + // Send with fallback for any recipients that couldn't do sender key, plus our own sync copy + return cli.sendToGroup(ctx, fallbackRecipients, content, messageTimestamp, result) + case 401, 404: + log.Warn().Uint32("status_code", resp.GetStatus()). + Msg("Multi-recipient send failed, falling back to normal send") + doUnlock() + // Fall back to normal send for all recipients + return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, nil) + case 409, 410: + log.Warn().Uint32("status_code", resp.GetStatus()). + Msg("Multi-recipient send failed due to outdated device list, refreshing and retrying") + err = cli.handleMultiRecipient409410Response(ctx, resp) + if err != nil { + return nil, err + } + doUnlock() + // Retry recursively after fixing device lists + return cli.sendToGroupWithSenderKey(ctx, groupID, allRecipients, content, messageTimestamp, retries+1) + default: + return nil, fmt.Errorf("unexpected status code %d in multi-recipient send", resp.GetStatus()) + } +} + +func (cli *Client) encryptWithSenderKey( + ctx context.Context, + groupID types.GroupIdentifier, + distributionID uuid.UUID, + myAddress *libsignalgo.Address, + senderKeyRecipients []store.SessionAddressTuple, + content *signalpb.Content, +) ([]byte, error) { + plaintext, err := proto.Marshal(content) + if err != nil { + return nil, fmt.Errorf("failed to marshal content: %w", err) + } + plaintext, err = addPadding(3, plaintext) + if err != nil { + return nil, fmt.Errorf("failed to add padding: %w", err) + } + ciphertext, err := libsignalgo.GroupEncrypt(ctx, plaintext, myAddress, distributionID, cli.Store.SenderKeyStore) + if err != nil { + return nil, fmt.Errorf("failed to encrypt group message: %w", err) + } + cert, err := cli.senderCertificate(ctx, false) + if err != nil { + return nil, fmt.Errorf("failed to get sender certificate: %w", err) + } + groupIDBytes, err := groupID.Bytes() + if err != nil { + return nil, fmt.Errorf("failed to deserialize group ID: %w", err) + } + usmc, err := libsignalgo.NewUnidentifiedSenderMessageContent(ciphertext, cert, getContentHint(content), groupIDBytes[:]) + if err != nil { + return nil, fmt.Errorf("failed to create unidentified sender message content: %w", err) + } + ssCiphertext, err := libsignalgo.SealedSenderMultiRecipientEncrypt(ctx, usmc, senderKeyRecipients, cli.Store.ACIIdentityStore) + if err != nil { + return nil, fmt.Errorf("failed to create sealed sender multi-recipient message: %w", err) + } + return ssCiphertext, nil +} + +func diffRecipients( + prevDevices map[libsignalgo.ServiceID][]int, newDevices map[libsignalgo.ServiceID]senderKeySendMeta, +) ( + xak *libsignalgo.AccessKey, devicesAddedTo []libsignalgo.ServiceID, reset bool, +) { + collector := make(map[libsignalgo.ServiceID]uint8, max(len(prevDevices), len(newDevices))) + for key := range prevDevices { + collector[key] |= 0b01 + } + for key := range newDevices { + collector[key] |= 0b10 + } + for serviceID, mask := range collector { + if mask != 0b01 { + xak = xak.Xor(newDevices[serviceID].AccessKey) + } + switch mask { + case 0b01: + // Someone left the group + reset = true + case 0b10: + // Someone was added to the group + devicesAddedTo = append(devicesAddedTo, serviceID) + case 0b11: + removedDevices, addedDevices := exslices.Diff(prevDevices[serviceID], newDevices[serviceID].DeviceIDs) + if len(removedDevices) > 0 { + // Device was removed + reset = true + } else if len(addedDevices) > 0 { + // User got new devices + devicesAddedTo = append(devicesAddedTo, serviceID) + } + } + } + return +} + +type senderKeySendMeta struct { + DeviceIDs []int + AccessKey *libsignalgo.AccessKey +} + +func (cli *Client) getDevicesIDs(ctx context.Context, recipients []libsignalgo.ServiceID, result *GroupMessageSendResult) ( + map[libsignalgo.ServiceID]senderKeySendMeta, []store.SessionAddressTuple, []libsignalgo.ServiceID, +) { + log := zerolog.Ctx(ctx) + out := make(map[libsignalgo.ServiceID]senderKeySendMeta) + fallbackRecipients := recipients[:0] + senderKeyRecipients := make([]store.SessionAddressTuple, 0, len(recipients)) + for _, recipient := range recipients { + if recipient == cli.Store.ACIServiceID() { + // We'll send a sync copy to ourselves, not sender key and no need to include in fallback recipients either + continue + } + fallbackRecipients = append(fallbackRecipients, recipient) + if recipient.Type != libsignalgo.ServiceIDTypeACI { + continue + } + profileKey, err := cli.Store.RecipientStore.LoadProfileKey(ctx, recipient.UUID) + if err != nil { + log.Err(err).Stringer("recipient_id", recipient.UUID).Msg("Failed to get profile key") + continue + } else if profileKey == nil { + log.Debug().Stringer("recipient_id", recipient.UUID).Msg("No profile key for recipient") + continue + } + accessKey, err := profileKey.DeriveAccessKey() + if err != nil { + log.Err(err).Stringer("recipient_id", recipient.UUID).Msg("Failed to derive access key") + continue + } + sessions, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) + if err == nil && len(sessions) == 0 { + // No sessions, make one with prekey + err = cli.FetchAndProcessPreKey(ctx, recipient, -1) + if errors.Is(err, ErrUnregisteredUser) { + fallbackRecipients = fallbackRecipients[:len(fallbackRecipients)-1] + result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ + Recipient: recipient, + Error: err, + }) + log.Debug(). + Stringer("recipient_id", recipient). + Msg("Recipient is not registered, won't try to send") + continue + } else if err != nil { + log.Warn().Err(err).Stringer("recipient_id", recipient.UUID).Msg("Failed to fetch keys for recipient") + continue + } + sessions, err = cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) + } + if err != nil { + log.Err(err).Stringer("recipient_id", recipient.UUID).Msg("Failed to get sessions for recipient") + continue + } else if len(sessions) == 0 { + log.Debug().Stringer("recipient_id", recipient.UUID).Msg("No sessions for recipient after fetching keys") + continue + } + fallbackRecipients = fallbackRecipients[:len(fallbackRecipients)-1] + out[recipient] = senderKeySendMeta{ + DeviceIDs: exslices.CastFunc(sessions, func(from store.SessionAddressTuple) int { + return from.DeviceID + }), + AccessKey: accessKey, + } + senderKeyRecipients = append(senderKeyRecipients, sessions...) + } + return out, senderKeyRecipients, fallbackRecipients +} diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index e8dc71f..d9fd831 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -143,72 +143,39 @@ func addPadding(version uint32, contents []byte) ([]byte, error) { } } -func checkForErrorWithSessions(err error, addresses []*libsignalgo.Address, sessionRecords []*libsignalgo.SessionRecord) error { - if err != nil { - return err +func (cli *Client) buildMessagesToSend( + ctx context.Context, + recipient libsignalgo.ServiceID, + content *signalpb.Content, + unauthenticated, isGroup bool, +) ([]MyMessage, error) { + if ctx.Value(contextKeyEncryptionLock) != true { + cli.encryptionLock.Lock() + defer cli.encryptionLock.Unlock() } - if addresses == nil || sessionRecords == nil { - return fmt.Errorf("addresses or session records are nil") - } - if len(addresses) != len(sessionRecords) { - return fmt.Errorf("mismatched number of addresses (%d) and session records (%d)", len(addresses), len(sessionRecords)) - } - if len(addresses) == 0 || len(sessionRecords) == 0 { - return fmt.Errorf("no addresses or session records") - } - return nil -} -func (cli *Client) howManyOtherDevicesDoWeHave(ctx context.Context) int { - addresses, _, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, cli.Store.ACIServiceID()) - if err != nil { - return 0 - } - // Filter out our deviceID - otherDevices := 0 - for _, address := range addresses { - deviceID, err := address.DeviceID() - if err != nil { - zerolog.Ctx(ctx).Err(err).Msg("Error getting deviceID from address") - continue - } - if deviceID != uint(cli.Store.DeviceID) { - otherDevices++ - } - } - return otherDevices -} - -func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalgo.ServiceID, content *signalpb.Content, unauthenticated, isGroup bool) ([]MyMessage, error) { - // We need to prevent multiple encryption operations from happening at once, or else ratchets can race - cli.encryptionLock.Lock() - defer cli.encryptionLock.Unlock() - - addresses, sessionRecords, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) - if err == nil && (len(addresses) == 0 || len(sessionRecords) == 0) { + sessions, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) + if err == nil && len(sessions) == 0 { // No sessions, make one with prekey err = cli.FetchAndProcessPreKey(ctx, recipient, -1) if err != nil { + // TODO flag 404s as unregistered return nil, err } - addresses, sessionRecords, err = cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) + sessions, err = cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) } - err = checkForErrorWithSessions(err, addresses, sessionRecords) if err != nil { return nil, err + } else if len(sessions) == 0 { + return nil, fmt.Errorf("no sessions found for recipient %s", recipient.String()) } - messages := make([]MyMessage, 0, len(addresses)) - for i, recipientAddress := range addresses { - recipientDeviceID, err := recipientAddress.DeviceID() - if err != nil { - return nil, err - } - + messages := make([]MyMessage, 0, len(sessions)) + for _, tuple := range sessions { // Don't send to this device that we are sending from - if recipient == cli.Store.ACIServiceID() && recipientDeviceID == uint(cli.Store.DeviceID) { + if recipient == cli.Store.ACIServiceID() && tuple.DeviceID == cli.Store.DeviceID { zerolog.Ctx(ctx).Debug(). - Uint("recipient_device_id", recipientDeviceID). + Int("recipient_device_id", tuple.DeviceID). Msg("Not sending to the device I'm sending from") continue } @@ -222,29 +189,28 @@ func (cli *Client) buildMessagesToSend(ctx context.Context, recipient libsignalg if err != nil { return nil, err } - sessionRecord := sessionRecords[i] var envelopeType int var encryptedPayload []byte if unauthenticated { includeE164 := !isGroup && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY envelopeType, encryptedPayload, err = cli.buildSSMessageToSend( - ctx, recipientAddress, paddedMessage, getContentHint(content), includeE164, + ctx, tuple.Address, paddedMessage, getContentHint(content), includeE164, ) } else { - envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, recipientAddress, paddedMessage) + envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, tuple.Address, paddedMessage) } if err != nil { return nil, err } - destinationRegistrationID, err := sessionRecord.GetRemoteRegistrationID() + destinationRegistrationID, err := tuple.Record.GetRemoteRegistrationID() if err != nil { return nil, err } outgoingMessage := MyMessage{ Type: envelopeType, - DestinationDeviceID: int(recipientDeviceID), + DestinationDeviceID: tuple.DeviceID, DestinationRegistrationID: int(destinationRegistrationID), Content: base64.StdEncoding.EncodeToString(encryptedPayload), } @@ -549,26 +515,28 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte GroupV2: groupContext, } content := wrapDataMessageInContent(dm) - var recipients []*libsignalgo.ServiceID + var recipients []libsignalgo.ServiceID for _, member := range group.Members { serviceID := member.UserServiceID() - recipients = append(recipients, &serviceID) + recipients = append(recipients, serviceID) } for _, member := range group.PendingMembers { - recipients = append(recipients, &member.ServiceID) + recipients = append(recipients, member.ServiceID) } if groupChange != nil { for _, member := range groupChange.AddPendingMembers { - recipients = append(recipients, &member.ServiceID) + recipients = append(recipients, member.ServiceID) } for _, member := range groupChange.AddMembers { serviceID := member.UserServiceID() - recipients = append(recipients, &serviceID) + recipients = append(recipients, serviceID) } } - return cli.sendToGroup(ctx, recipients, content, timestamp) + return cli.sendToGroup(ctx, recipients, content, timestamp, nil) } +const enableSenderKeySend = false + func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { log := zerolog.Ctx(ctx).With(). Str("action", "send group message"). @@ -587,44 +555,83 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi } else if content.GetEditMessage().GetDataMessage() != nil { messageTimestamp = content.EditMessage.DataMessage.GetTimestamp() content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) + } else if content.GetTypingMessage() != nil { + messageTimestamp = content.TypingMessage.GetTimestamp() + groupIDBytes, err := group.GroupIdentifier.Bytes() + if err != nil { + return nil, err + } + content.TypingMessage.GroupId = groupIDBytes[:] } - var recipients []*libsignalgo.ServiceID + var recipients []libsignalgo.ServiceID for _, member := range group.Members { - serviceID := member.UserServiceID() - recipients = append(recipients, &serviceID) + recipients = append(recipients, member.UserServiceID()) } - return cli.sendToGroup(ctx, recipients, content, messageTimestamp) + if enableSenderKeySend { + return cli.sendToGroupWithSenderKey(ctx, gid, recipients, content, messageTimestamp, 0) + } + return cli.sendToGroup(ctx, recipients, content, messageTimestamp, nil) } -func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.ServiceID, content *signalpb.Content, messageTimestamp uint64) (*GroupMessageSendResult, error) { - // Send to each member of the group - result := &GroupMessageSendResult{ - SuccessfullySentTo: []SuccessfulSendResult{}, - FailedToSendTo: []FailedSendResult{}, +func (cli *Client) sendToGroup( + ctx context.Context, + recipients []libsignalgo.ServiceID, + content *signalpb.Content, + messageTimestamp uint64, + result *GroupMessageSendResult, +) (*GroupMessageSendResult, error) { + if result == nil { + result = &GroupMessageSendResult{ + SuccessfullySentTo: []SuccessfulSendResult{}, + FailedToSendTo: []FailedSendResult{}, + } + } + if content.TypingMessage != nil { + // Never send typing messages via fallback path + return result, nil } for _, recipient := range recipients { if recipient.Type == libsignalgo.ServiceIDTypeACI && recipient.UUID == cli.Store.ACI { // Don't send normal DataMessages to ourselves continue } - log := zerolog.Ctx(ctx).With().Stringer("member", *recipient).Logger() + log := zerolog.Ctx(ctx).With().Stringer("member", recipient).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, *recipient, messageTimestamp, content, 0, true, true) + sentUnidentified, err := cli.sendContent(ctx, recipient, messageTimestamp, content, 0, true, true) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ - Recipient: *recipient, + Recipient: recipient, Error: err, }) log.Err(err).Msg("Failed to send to user") } else { result.SuccessfullySentTo = append(result.SuccessfullySentTo, SuccessfulSendResult{ - Recipient: *recipient, + Recipient: recipient, Unidentified: sentUnidentified, }) log.Trace().Msg("Successfully sent to user") } } + cli.sendGroupSyncCopy(ctx, content, messageTimestamp, result) + + if len(result.FailedToSendTo) == 0 && len(result.SuccessfullySentTo) == 0 { + return result, nil // I only sent to myself + } + if len(result.SuccessfullySentTo) == 0 { + lastError := result.FailedToSendTo[len(result.FailedToSendTo)-1].Error + return nil, fmt.Errorf("failed to send to any group members: %w", lastError) + } + + return result, nil +} + +func (cli *Client) sendGroupSyncCopy( + ctx context.Context, + content *signalpb.Content, + messageTimestamp uint64, + result *GroupMessageSendResult, +) { var syncContent *signalpb.Content if content.GetDataMessage() != nil { syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo) @@ -637,16 +644,6 @@ func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.Se zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } } - - if len(result.FailedToSendTo) == 0 && len(result.SuccessfullySentTo) == 0 { - return result, nil // I only sent to myself - } - if len(result.SuccessfullySentTo) == 0 { - lastError := result.FailedToSendTo[len(result.FailedToSendTo)-1].Error - return nil, fmt.Errorf("failed to send to any group members: %w", lastError) - } - - return result, nil } func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool { @@ -862,6 +859,9 @@ func (cli *Client) sendContent( useUnidentifiedSender = false } } + if !useUnidentifiedSender && content.SenderKeyDistributionMessage != nil { + return false, fmt.Errorf("won't send sender key distribution message without sealed sender") + } var messages []MyMessage messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, isGroup) @@ -887,7 +887,7 @@ func (cli *Client) sendContent( header.Set("Content-Type", string(web.ContentTypeJSON)) if useUnidentifiedSender { log.Trace().Msg("Sending message over unidentified WS") - header.Set("Unidentified-Access-Key", base64.StdEncoding.EncodeToString(accessKey[:])) + header.Set("Unidentified-Access-Key", accessKey.String()) response, err = cli.UnauthedWS.SendRequest(ctx, http.MethodPut, path, jsonBytes, header) } else { log.Trace().Msg("Sending message over authed WS") @@ -921,11 +921,14 @@ func (cli *Client) sendContent( } if needToRetry { - var err error - if *response.Status == 409 { - err = cli.handle409(ctx, recipient, response) - } else if *response.Status == 410 { - err = cli.handle410(ctx, recipient, response) + if *response.Status == 409 || *response.Status == 410 { + err = cli.handleSingleRecipient409410Response(ctx, recipient, response) + if content.SenderKeyDistributionMessage != nil { + if err == nil { + err = ErrDevicesChanged + } + return false, err + } } else if *response.Status == 428 { err = cli.handle428(ctx, recipient, response) } @@ -939,6 +942,9 @@ func (cli *Client) sendContent( return sentUnidentified, err } } else if *response.Status == 401 && useUnidentifiedSender { + if content.SenderKeyDistributionMessage != nil { + return sentUnidentified, fmt.Errorf("unauthorized to send sender key distribution message via sealed sender") + } log.Debug().Msg("Retrying send without sealed sender") // Try to send again (**RECURSIVELY**) sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, false, isGroup) @@ -946,6 +952,13 @@ func (cli *Client) sendContent( log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err } + } else if *response.Status == 404 { + // TODO flag recipient as unregistered + err = cli.Store.ACISessionStore.RemoveAllSessionsForServiceID(ctx, recipient) + if err != nil { + log.Err(err).Msg("Failed to remove sessions after 404") + } + return sentUnidentified, ErrUnregisteredUser } else if *response.Status != 200 { return sentUnidentified, fmt.Errorf("unexpected status code while sending: %d", *response.Status) } @@ -953,81 +966,88 @@ func (cli *Client) sendContent( return sentUnidentified, nil } -// A 409 means our device list was out of date, so we will fix it up -func (cli *Client) handle409(ctx context.Context, recipient libsignalgo.ServiceID, response *signalpb.WebSocketResponseMessage) error { - log := zerolog.Ctx(ctx) - // Decode json body - // TODO use an actual struct for this - var body map[string]interface{} - err := json.Unmarshal(response.Body, &body) - if err != nil { - log.Err(err).Msg("Unmarshal error") - return err - } - // check for missingDevices and extraDevices - if body["missingDevices"] != nil { - missingDevices := body["missingDevices"].([]any) - log.Debug().Any("missing_devices", missingDevices).Msg("missing devices found in 409 response") - // TODO: establish session with missing devices - for _, missingDevice := range missingDevices { - err = cli.FetchAndProcessPreKey(ctx, recipient, int(missingDevice.(float64))) - if err != nil { - return nil - } - } - } - if body["extraDevices"] != nil { - extraDevices := body["extraDevices"].([]any) - log.Debug().Any("extra_devices", extraDevices).Msg("extra devices found in 409 response") - for _, extraDevice := range extraDevices { - recipientAddr, err := recipient.Address(uint(extraDevice.(float64))) - if err != nil { - log.Err(err).Msg("NewAddress error") - return err - } - err = cli.Store.ACISessionStore.RemoveSession(ctx, recipientAddr) - if err != nil { - log.Err(err).Msg("RemoveSession error") - return err - } - } - } - return err +type SingleRecipient409410Response struct { + MissingDevices []uint `json:"missingDevices"` + ExtraDevices []uint `json:"extraDevices"` + StaleDevices []uint `json:"staleDevices"` } -// A 410 means we have a stale device, so get rid of it -func (cli *Client) handle410(ctx context.Context, recipient libsignalgo.ServiceID, response *signalpb.WebSocketResponseMessage) error { - log := zerolog.Ctx(ctx) - // Decode json body - // TODO use an actual struct - var body map[string]interface{} +type MultiRecipient409410Response struct { + UUID libsignalgo.ServiceID `json:"uuid"` + Devices SingleRecipient409410Response `json:"devices"` +} + +type MultiRecipient200Response struct { + UUIDs404 []libsignalgo.ServiceID `json:"uuids404"` + NeedsSync bool `json:"needsSync"` +} + +func (cli *Client) handleSingleRecipient409410Response(ctx context.Context, recipient libsignalgo.ServiceID, response *signalpb.WebSocketResponseMessage) error { + var body SingleRecipient409410Response err := json.Unmarshal(response.Body, &body) if err != nil { - log.Err(err).Msg("Unmarshal error") - return err + return fmt.Errorf("failed to unmarshal error response body: %w", err) } - // check for staleDevices and make new sessions with them - if body["staleDevices"] != nil { - staleDevices := body["staleDevices"].([]any) - log.Debug().Any("stale_devices", staleDevices).Msg("stale devices found in 410 response") - for _, staleDevice := range staleDevices { - recipientAddr, err := recipient.Address(uint(staleDevice.(float64))) + return cli.handle409410(ctx, recipient, body) +} + +func (cli *Client) handleMultiRecipient409410Response(ctx context.Context, response *signalpb.WebSocketResponseMessage) error { + var body []MultiRecipient409410Response + err := json.Unmarshal(response.Body, &body) + if err != nil { + return fmt.Errorf("failed to unmarshal error response body: %w", err) + } + for _, recipientBody := range body { + err = cli.handle409410(ctx, recipientBody.UUID, recipientBody.Devices) + if err != nil { + return err + } + } + return nil +} + +func (cli *Client) handle409410(ctx context.Context, recipient libsignalgo.ServiceID, body SingleRecipient409410Response) error { + log := zerolog.Ctx(ctx) + if body.StaleDevices != nil { + log.Debug().Uints("stale_devices", body.StaleDevices).Msg("stale devices found in 410 response") + for _, staleDevice := range body.StaleDevices { + recipientAddr, err := recipient.Address(staleDevice) if err != nil { - log.Err(err).Msg("error creating new UUID Address") - return err + return fmt.Errorf("failed to get address for stale device %s:%d: %w", recipient, staleDevice, err) } err = cli.Store.ACISessionStore.RemoveSession(ctx, recipientAddr) if err != nil { - log.Err(err).Msg("RemoveSession error") - return err + return fmt.Errorf("failed to remove session for stale device %s:%d: %w", recipient, staleDevice, err) } - err = cli.FetchAndProcessPreKey(ctx, recipient, int(staleDevice.(float64))) + err = cli.FetchAndProcessPreKey(ctx, recipient, int(staleDevice)) if err != nil { - return err + return fmt.Errorf("failed to fetch and process prekey for stale device %s:%d: %w", recipient, staleDevice, err) } } } - return err + if body.MissingDevices != nil { + log.Debug().Uints("missing_devices", body.MissingDevices).Msg("missing devices found in 409 response") + for _, missingDevice := range body.MissingDevices { + err := cli.FetchAndProcessPreKey(ctx, recipient, int(missingDevice)) + if err != nil { + return fmt.Errorf("failed to fetch and process prekey for missing device %s:%d: %w", recipient, missingDevice, err) + } + } + } + if body.ExtraDevices != nil { + log.Debug().Any("extra_devices", body.ExtraDevices).Msg("extra devices found in 409 response") + for _, extraDevice := range body.ExtraDevices { + recipientAddr, err := recipient.Address(extraDevice) + if err != nil { + return fmt.Errorf("failed to get address for extra device %s:%d: %w", recipient, extraDevice, err) + } + err = cli.Store.ACISessionStore.RemoveSession(ctx, recipientAddr) + if err != nil { + return fmt.Errorf("failed to remove session for extra device %s:%d: %w", recipient, extraDevice, err) + } + } + } + return nil } // We got rate limited. @@ -1091,5 +1111,5 @@ func (cli *Client) handle428(ctx context.Context, recipient libsignalgo.ServiceI // } // } //} - return nil + return fmt.Errorf("got 428 error") } diff --git a/pkg/signalmeow/store/device.go b/pkg/signalmeow/store/device.go index 8843ddf..e72c04f 100644 --- a/pkg/signalmeow/store/device.go +++ b/pkg/signalmeow/store/device.go @@ -76,7 +76,7 @@ type Device struct { ACIIdentityStore libsignalgo.IdentityKeyStore PNIIdentityStore libsignalgo.IdentityKeyStore IdentityKeyStore IdentityKeyStore - SenderKeyStore libsignalgo.SenderKeyStore + SenderKeyStore SenderKeyStore GroupStore GroupStore RecipientStore RecipientStore diff --git a/pkg/signalmeow/store/sender_key_store.go b/pkg/signalmeow/store/sender_key_store.go index 092bcdd..a38e389 100644 --- a/pkg/signalmeow/store/sender_key_store.go +++ b/pkg/signalmeow/store/sender_key_store.go @@ -21,18 +21,40 @@ import ( "database/sql" "errors" "fmt" + "time" "github.com/google/uuid" "go.mau.fi/util/dbutil" "go.mau.fi/mautrix-signal/pkg/libsignalgo" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -var _ libsignalgo.SenderKeyStore = (*sqlStore)(nil) +type SenderKeyStore interface { + libsignalgo.SenderKeyStore + DeleteSenderKey(ctx context.Context, address *libsignalgo.Address, distributionID uuid.UUID) error + GetSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier) (*SenderKeyInfo, error) + PutSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier, info *SenderKeyInfo) error +} + +var _ SenderKeyStore = (*sqlStore)(nil) const ( - loadSenderKeyQuery = `SELECT key_record FROM signalmeow_sender_keys WHERE account_id=$1 AND sender_uuid=$2 AND sender_device_id=$3 AND distribution_id=$4` - storeSenderKeyQuery = `INSERT INTO signalmeow_sender_keys (account_id, sender_uuid, sender_device_id, distribution_id, key_record) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (account_id, sender_uuid, sender_device_id, distribution_id) DO UPDATE SET key_record=excluded.key_record` + loadSenderKeyQuery = `SELECT key_record FROM signalmeow_sender_keys WHERE account_id=$1 AND sender_uuid=$2 AND sender_device_id=$3 AND distribution_id=$4` + storeSenderKeyQuery = `INSERT INTO signalmeow_sender_keys (account_id, sender_uuid, sender_device_id, distribution_id, key_record) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (account_id, sender_uuid, sender_device_id, distribution_id) DO UPDATE SET key_record=excluded.key_record` + deleteSenderKeyQuery = `DELETE FROM signalmeow_sender_keys WHERE account_id=$1 AND sender_uuid=$2 AND sender_device_id=$3 AND distribution_id=$4` + + getSenderKeyInfoQuery = ` + SELECT distribution_id, shared_with + FROM signalmeow_outbound_sender_key_info + WHERE account_id=$1 AND group_id=$2 + ` + putSenderKeyInfoQuery = ` + INSERT INTO signalmeow_outbound_sender_key_info (account_id, group_id, distribution_id, shared_with) + VALUES ($1, $2, $3, $4) + ON CONFLICT (account_id, group_id) DO UPDATE + SET distribution_id=excluded.distribution_id, shared_with=excluded.shared_with + ` ) func scanSenderKey(row dbutil.Scannable) (*libsignalgo.SenderKeyRecord, error) { @@ -74,3 +96,42 @@ func (s *sqlStore) StoreSenderKey(ctx context.Context, sender *libsignalgo.Addre _, err = s.db.Exec(ctx, storeSenderKeyQuery, s.AccountID, senderUUID, deviceID, distributionID, serialized) return err } + +func (s *sqlStore) DeleteSenderKey(ctx context.Context, sender *libsignalgo.Address, distributionID uuid.UUID) error { + senderUUID, err := sender.Name() + if err != nil { + return fmt.Errorf("failed to get sender UUID: %w", err) + } + deviceID, err := sender.DeviceID() + if err != nil { + return fmt.Errorf("failed to get sender device ID: %w", err) + } + _, err = s.db.Exec(ctx, deleteSenderKeyQuery, s.AccountID, senderUUID, deviceID, distributionID) + return err +} + +type SenderKeyInfo struct { + DistributionID uuid.UUID `json:"distribution_id"` + SharedWith map[libsignalgo.ServiceID][]int `json:"shared_with"` + CreatedAt time.Time `json:"created_at"` +} + +func scanSenderKeyInfo(row dbutil.Scannable) (*SenderKeyInfo, error) { + var ski SenderKeyInfo + err := row.Scan(&ski.DistributionID, dbutil.JSON{Data: &ski}) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } else if err != nil { + return nil, err + } + return &ski, nil +} + +func (s *sqlStore) GetSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier) (*SenderKeyInfo, error) { + return scanSenderKeyInfo(s.db.QueryRow(ctx, getSenderKeyInfoQuery, s.AccountID, groupID)) +} + +func (s *sqlStore) PutSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier, info *SenderKeyInfo) error { + _, err := s.db.Exec(ctx, putSenderKeyInfoQuery, s.AccountID, groupID, info.DistributionID, dbutil.JSON{Data: info}) + return err +} diff --git a/pkg/signalmeow/store/session_store.go b/pkg/signalmeow/store/session_store.go index 5fe6cba..3956714 100644 --- a/pkg/signalmeow/store/session_store.go +++ b/pkg/signalmeow/store/session_store.go @@ -30,40 +30,49 @@ import ( var _ SessionStore = (*scopedSQLStore)(nil) const ( - loadSessionQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3 AND their_device_id=$4` + loadSessionQuery = `SELECT their_service_id, their_device_id, record FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3 AND their_device_id=$4` storeSessionQuery = ` INSERT INTO signalmeow_sessions (account_id, service_id, their_service_id, their_device_id, record) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (account_id, service_id, their_service_id, their_device_id) DO UPDATE SET record=excluded.record ` - allSessionsQuery = `SELECT their_device_id, record FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3` - removeSessionQuery = `DELETE FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3 AND their_device_id=$4` - deleteAllSessionsQuery = "DELETE FROM signalmeow_sessions WHERE account_id=$1" + allSessionsQuery = `SELECT their_service_id, their_device_id, record FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3` + removeSessionQuery = `DELETE FROM signalmeow_sessions WHERE account_id=$1 AND service_id=$2 AND their_service_id=$3 AND their_device_id=$4` + removeSessionsForRecipientQuery = "DELETE FROM signalmeow_sessions WHERE account_id=$1 AND their_service_id=$2" + deleteAllSessionsQuery = "DELETE FROM signalmeow_sessions WHERE account_id=$1" ) +type SessionAddressTuple = libsignalgo.SessionAddressTuple + type SessionStore interface { libsignalgo.SessionStore ServiceScopedStore // AllSessionsForServiceID returns all sessions for the given service ID. - AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) + AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]SessionAddressTuple, error) // RemoveSession removes the session for the given address. RemoveSession(ctx context.Context, address *libsignalgo.Address) error + RemoveAllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) error // RemoveAllSessions removes all sessions for our ACI UUID RemoveAllSessions(ctx context.Context) error } -func scanSessionRecord(row dbutil.Scannable) (int, *libsignalgo.SessionRecord, error) { - var record []byte - var deviceID int - err := row.Scan(&deviceID, &record) +func scanSessionRecord(row dbutil.Scannable) (tuple SessionAddressTuple, err error) { + var rawServiceID string + var rawRecord []byte + err = row.Scan(&rawServiceID, &tuple.DeviceID, &rawRecord) if errors.Is(err, sql.ErrNoRows) { - return 0, nil, nil + err = nil } else if err != nil { - return 0, nil, err + // return error as-is + } else if tuple.Record, err = libsignalgo.DeserializeSessionRecord(rawRecord); err != nil { + err = fmt.Errorf("failed to deserialize session record: %w", err) + } else if tuple.ServiceID, err = libsignalgo.ServiceIDFromString(rawServiceID); err != nil { + err = fmt.Errorf("failed to parse service ID: %w", err) + } else if tuple.Address, err = tuple.ServiceID.Address(uint(tuple.DeviceID)); err != nil { + err = fmt.Errorf("failed to construct address: %w", err) } - sessionRecord, err := libsignalgo.DeserializeSessionRecord(record) - return deviceID, sessionRecord, err + return } func (s *scopedSQLStore) RemoveSession(ctx context.Context, address *libsignalgo.Address) error { @@ -79,27 +88,17 @@ func (s *scopedSQLStore) RemoveSession(ctx context.Context, address *libsignalgo return err } -func (s *scopedSQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]*libsignalgo.Address, []*libsignalgo.SessionRecord, error) { +func (s *scopedSQLStore) AllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) ([]SessionAddressTuple, error) { rows, err := s.db.Query(ctx, allSessionsQuery, s.AccountID, s.ServiceID, theirID) if err != nil { - return nil, nil, err + return nil, err } - defer rows.Close() - var records []*libsignalgo.SessionRecord - var addresses []*libsignalgo.Address - for rows.Next() { - deviceID, record, err := scanSessionRecord(rows) - if err != nil { - return nil, nil, err - } - records = append(records, record) - address, err := theirID.Address(uint(deviceID)) - if err != nil { - return nil, nil, err - } - addresses = append(addresses, address) - } - return addresses, records, rows.Err() + return dbutil.NewRowIterWithError(rows, scanSessionRecord, err).AsList() +} + +func (s *scopedSQLStore) RemoveAllSessionsForServiceID(ctx context.Context, theirID libsignalgo.ServiceID) error { + _, err := s.db.Exec(ctx, removeSessionsForRecipientQuery, s.AccountID, theirID) + return err } func (s *scopedSQLStore) LoadSession(ctx context.Context, address *libsignalgo.Address) (*libsignalgo.SessionRecord, error) { @@ -111,8 +110,8 @@ func (s *scopedSQLStore) LoadSession(ctx context.Context, address *libsignalgo.A if err != nil { return nil, fmt.Errorf("failed to get their device ID: %w", err) } - _, record, err := scanSessionRecord(s.db.QueryRow(ctx, loadSessionQuery, s.AccountID, s.ServiceID, theirServiceID, deviceID)) - return record, err + tuple, err := scanSessionRecord(s.db.QueryRow(ctx, loadSessionQuery, s.AccountID, s.ServiceID, theirServiceID, deviceID)) + return tuple.Record, err } func (s *scopedSQLStore) StoreSession(ctx context.Context, address *libsignalgo.Address, record *libsignalgo.SessionRecord) error { diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index ddf871a..7fe18a8 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -94,6 +94,15 @@ CREATE TABLE signalmeow_sender_keys ( FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); +CREATE TABLE signalmeow_outbound_sender_key_info ( + account_id TEXT NOT NULL, + group_id TEXT NOT NULL, + distribution_id TEXT NOT NULL, + shared_with jsonb NOT NULL, + + PRIMARY KEY (account_id, group_id) +); + CREATE TABLE signalmeow_groups ( account_id TEXT NOT NULL, group_identifier TEXT NOT NULL, diff --git a/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql b/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql new file mode 100644 index 0000000..bcc3d34 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql @@ -0,0 +1,9 @@ +-- v24 (compatible with v13+): Store outbound sender keys for groups +CREATE TABLE signalmeow_outbound_sender_key_info ( + account_id TEXT NOT NULL, + group_id TEXT NOT NULL, + distribution_id TEXT NOT NULL, + shared_with jsonb NOT NULL, + + PRIMARY KEY (account_id, group_id) +); diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index 84a04b9..f6c6743 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -97,10 +97,11 @@ func init() { type ContentType string const ( - ContentTypeJSON ContentType = "application/json" - ContentTypeProtobuf ContentType = "application/x-protobuf" - ContentTypeOctetStream ContentType = "application/octet-stream" - ContentTypeOffsetOctetStream ContentType = "application/offset+octet-stream" + ContentTypeJSON ContentType = "application/json" + ContentTypeProtobuf ContentType = "application/x-protobuf" + ContentTypeOctetStream ContentType = "application/octet-stream" + ContentTypeOffsetOctetStream ContentType = "application/offset+octet-stream" + ContentTypeMultiRecipientMessage ContentType = "application/vnd.signal-messenger.mrm" ) type HTTPReqOpt struct { From e4f9c344cbb9879c7d625c30c87430fc40eff7aa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Nov 2025 16:54:12 +0200 Subject: [PATCH 606/718] signalmeow/web: don't truncate paths in logs --- pkg/signalmeow/web/signalwebsocket.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 38dcc4d..f2631fe 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -516,10 +516,6 @@ func writeLoop( } request.RequestMessage.Id = &i responseChannels.Set(i, request.ResponseChannel) - path := *request.RequestMessage.Path - if len(path) > 30 { - path = path[:40] - } if !request.RequestTime.IsZero() { elapsed := time.Since(request.RequestTime) if elapsed > 1*time.Minute { @@ -528,14 +524,14 @@ func writeLoop( log.Warn(). Uint64("request_id", i). Str("request_verb", *request.RequestMessage.Verb). - Str("request_path", path). + Str("request_path", *request.RequestMessage.Path). Dur("elapsed", elapsed). Msg("Sending WS request") } else { log.Debug(). Uint64("request_id", i). Str("request_verb", *request.RequestMessage.Verb). - Str("request_path", path). + Str("request_path", *request.RequestMessage.Path). Dur("elapsed", elapsed). Msg("Sending WS request") } From 73e8668bc58db8032db2531c524e8ca05239d2bd Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Nov 2025 16:54:23 +0200 Subject: [PATCH 607/718] handlematrix: enable typing notifications in groups --- pkg/connector/handlematrix.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 1dbd48a..968d55c 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -319,18 +319,21 @@ func (s *SignalClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bri } func (s *SignalClient) HandleMatrixTyping(ctx context.Context, typing *bridgev2.MatrixTyping) error { - userID, _, err := signalid.ParsePortalID(typing.Portal.ID) + userID, groupID, err := signalid.ParsePortalID(typing.Portal.ID) if err != nil { return err } - // Only send typing notifications in DMs for now - // Sending efficiently to groups requires implementing the proper SenderKey stuff first + typingMessage := signalmeow.TypingMessage(typing.IsTyping) if !userID.IsEmpty() && userID.Type == libsignalgo.ServiceIDTypeACI { - typingMessage := signalmeow.TypingMessage(typing.IsTyping) result := s.Client.SendMessage(ctx, userID, typingMessage) if !result.WasSuccessful { return result.Error } + } else if groupID != "" { + _, err = s.Client.SendGroupMessage(ctx, groupID, typingMessage) + if err != nil { + return err + } } return nil } From daba2d098cd57171abd66bb1644ca25d6b26c13d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Nov 2025 17:15:13 +0200 Subject: [PATCH 608/718] handlematrix: remove duplicate error log --- pkg/connector/handlematrix.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 968d55c..e2472a2 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -73,17 +73,17 @@ func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.Porta Int("failed_to_send_to_count", len(result.FailedToSendTo)). Int("successfully_sent_to_count", len(result.SuccessfullySentTo)). Logger() - if len(result.FailedToSendTo) > 0 { - log.Error().Msg("Failed to send event to some members of Signal group") - } if len(result.SuccessfullySentTo) == 0 && len(result.FailedToSendTo) == 0 { log.Debug().Msg("No successes or failures - Probably sent to myself") } else if len(result.SuccessfullySentTo) == 0 { log.Error().Msg("Failed to send event to all members of Signal group") return errors.New("failed to send to any members of Signal group") - } else if len(result.SuccessfullySentTo) < totalRecipients { - log.Warn().Msg("Only sent event to some members of Signal group") + if len(result.FailedToSendTo) > 0 { + log.Warn().Msg("Failed to send event to some members of Signal group") + } else { + log.Warn().Msg("Only sent event to some members of Signal group") + } } else { log.Debug().Msg("Sent event to all members of Signal group") } From 48cc6ac0aa06f3e44d7cc17e970a8918b3a5cda9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Nov 2025 17:15:26 +0200 Subject: [PATCH 609/718] signalmeow/web: always log short response bodies --- pkg/signalmeow/web/signalwebsocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index f2631fe..8a0c845 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -459,7 +459,7 @@ func readLoop( Uint64("response_id", msg.Response.GetId()). Uint32("response_status", msg.Response.GetStatus()). Str("response_message", msg.Response.GetMessage()) - if log.GetLevel() == zerolog.TraceLevel { + if log.GetLevel() == zerolog.TraceLevel || len(msg.Response.Body) < 256 { logEvt.Strs("response_headers", msg.Response.Headers) if json.Valid(msg.Response.Body) { logEvt.RawJSON("response_body", msg.Response.Body) From 33e0830088c84f756e13fd4cd7c552662423180b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 27 Nov 2025 17:15:38 +0200 Subject: [PATCH 610/718] handlematrix: add support for encrypted room avatars --- pkg/connector/handlematrix.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index e2472a2..cdd3c0a 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -380,8 +380,8 @@ func (s *SignalClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2 } var avatarPath string var avatarHash [32]byte - if msg.Content.URL != "" { - data, err := s.Main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, nil) + if msg.Content.URL != "" || msg.Content.MSC3414File != nil { + data, err := s.Main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, msg.Content.MSC3414File) if err != nil { return false, fmt.Errorf("failed to download avatar: %w", err) } From 079223eed63b39f10978972ca689b5641813ee33 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Nov 2025 16:18:45 +0200 Subject: [PATCH 611/718] signalmeow/store: fix latest version number --- pkg/signalmeow/store/upgrades/00-latest.sql | 2 +- pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 7fe18a8..4d42cde 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v23 (compatible with v13+): Latest revision +-- v0 -> v24 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, diff --git a/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql b/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql index bcc3d34..4f02389 100644 --- a/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql +++ b/pkg/signalmeow/store/upgrades/24-outbound-sender-keys.sql @@ -1,5 +1,5 @@ -- v24 (compatible with v13+): Store outbound sender keys for groups -CREATE TABLE signalmeow_outbound_sender_key_info ( +CREATE TABLE IF NOT EXISTS signalmeow_outbound_sender_key_info ( account_id TEXT NOT NULL, group_id TEXT NOT NULL, distribution_id TEXT NOT NULL, From 6abb263407707b7ee0245c3f2aab7c544b96d2bf Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Nov 2025 16:17:38 +0200 Subject: [PATCH 612/718] signalmeow,libsignalgo: add support for group send endorsements --- pkg/connector/groupinfo.go | 2 +- pkg/libsignalgo/buffer.go | 18 ++ pkg/libsignalgo/conversions.go | 14 ++ pkg/libsignalgo/groupsecretparams.go | 4 + pkg/libsignalgo/groupsendendorsement.go | 215 ++++++++++++++++++++++++ pkg/signalmeow/client.go | 2 +- pkg/signalmeow/groupcache.go | 99 +++++++++-- pkg/signalmeow/groups.go | 43 ++++- pkg/signalmeow/senderkey.go | 48 ++++-- pkg/signalmeow/sending.go | 5 +- 10 files changed, 409 insertions(+), 41 deletions(-) create mode 100644 pkg/libsignalgo/groupsendendorsement.go diff --git a/pkg/connector/groupinfo.go b/pkg/connector/groupinfo.go index a025fa4..d958463 100644 --- a/pkg/connector/groupinfo.go +++ b/pkg/connector/groupinfo.go @@ -98,7 +98,7 @@ func inviteLinkToJoinRule(inviteLinkAccess signalmeow.AccessControl) event.JoinR } func (s *SignalClient) getGroupInfo(ctx context.Context, groupID types.GroupIdentifier, minRevision uint32, backupChat *store.BackupChat) (*bridgev2.ChatInfo, error) { - groupInfo, err := s.Client.RetrieveGroupByID(ctx, groupID, minRevision) + groupInfo, _, err := s.Client.RetrieveGroupByID(ctx, groupID, minRevision) if err != nil { return nil, fmt.Errorf("failed to retrieve group by id: %w", err) } diff --git a/pkg/libsignalgo/buffer.go b/pkg/libsignalgo/buffer.go index e6aafdd..5518656 100644 --- a/pkg/libsignalgo/buffer.go +++ b/pkg/libsignalgo/buffer.go @@ -21,6 +21,8 @@ package libsignalgo */ import "C" import ( + "fmt" + "runtime" "unsafe" ) @@ -42,6 +44,22 @@ func BytesToBuffer(data []byte) C.SignalBorrowedBuffer { return buf } +func ManyBytesToBuffer[T ~[]byte](datas []T) (C.SignalBorrowedSliceOfBuffers, func()) { + 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)) + } + pinner.Pin(&data[0]) + buffers[i] = BytesToBuffer(data) + } + return C.SignalBorrowedSliceOfBuffers{ + base: unsafe.SliceData(buffers), + length: C.size_t(len(buffers)), + }, pinner.Unpin +} + func EmptyBorrowedBuffer() C.SignalBorrowedBuffer { return C.SignalBorrowedBuffer{} } diff --git a/pkg/libsignalgo/conversions.go b/pkg/libsignalgo/conversions.go index d17fa28..1963687 100644 --- a/pkg/libsignalgo/conversions.go +++ b/pkg/libsignalgo/conversions.go @@ -39,3 +39,17 @@ func CopySignalOwnedBufferToBytes(buffer C.SignalOwnedBuffer) (b []byte) { C.signal_free_buffer(buffer.base, buffer.length) return } + +func CopySignalBytestringArray[T ~[]byte](buffer C.SignalBytestringArray) (b []T) { + concatted := C.GoBytes(unsafe.Pointer(buffer.bytes.base), C.int(buffer.bytes.length)) + b = make([]T, int(buffer.lengths.length)) + sizeTSize := unsafe.Sizeof(C.size_t(0)) + offset := 0 + for i := 0; i < int(buffer.lengths.length); i++ { + length := int(*(*C.size_t)(unsafe.Add(unsafe.Pointer(buffer.lengths.base), uintptr(i)*sizeTSize))) + b[i] = concatted[offset : offset+length] + offset += length + } + C.signal_free_bytestring_array(buffer) + return +} diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index 5ad11fd..a6b370c 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -76,6 +76,10 @@ func (gmk GroupMasterKey) GroupIdentifier() (*GroupIdentifier, error) { } } +func (gmk GroupMasterKey) SecretParams() (GroupSecretParams, error) { + return DeriveGroupSecretParamsFromMasterKey(gmk) +} + 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))) diff --git a/pkg/libsignalgo/groupsendendorsement.go b/pkg/libsignalgo/groupsendendorsement.go new file mode 100644 index 0000000..73f175e --- /dev/null +++ b/pkg/libsignalgo/groupsendendorsement.go @@ -0,0 +1,215 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package libsignalgo + +/* +#include "./libsignal-ffi.h" +*/ +import "C" +import ( + "encoding/base64" + "runtime" + "time" + "unsafe" +) + +type GroupSendFullToken []byte + +func (gsft GroupSendFullToken) String() string { + return base64.StdEncoding.EncodeToString(gsft) +} + +func (gsft GroupSendFullToken) CheckValidContents() error { + signalFfiError := C.signal_group_send_full_token_check_valid_contents( + BytesToBuffer(gsft), + ) + runtime.KeepAlive(gsft) + if signalFfiError != nil { + return wrapError(signalFfiError) + } + return nil +} + +func (gsft GroupSendFullToken) GetExpiration() (time.Time, error) { + var expiration C.uint64_t + signalFfiError := C.signal_group_send_full_token_get_expiration( + &expiration, + BytesToBuffer(gsft), + ) + runtime.KeepAlive(gsft) + if signalFfiError != nil { + return time.Time{}, wrapError(signalFfiError) + } + return time.Unix(int64(expiration), 0), nil +} + +type GroupSendToken []byte + +func (gst GroupSendToken) CheckValidContents() error { + signalFfiError := C.signal_group_send_token_check_valid_contents( + BytesToBuffer(gst), + ) + runtime.KeepAlive(gst) + if signalFfiError != nil { + return wrapError(signalFfiError) + } + return nil +} + +func (gst GroupSendToken) ToFullToken(expiration time.Time) (GroupSendFullToken, error) { + var fullToken C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + signalFfiError := C.signal_group_send_token_to_full_token( + &fullToken, + BytesToBuffer(gst), + C.uint64_t(expiration.Unix()), + ) + runtime.KeepAlive(gst) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(fullToken), nil +} + +type GroupSendEndorsement []byte + +func (gse GroupSendEndorsement) ToToken(groupSecretParams *GroupSecretParams) (GroupSendToken, error) { + var token C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + signalFfiError := C.signal_group_send_endorsement_to_token( + &token, + BytesToBuffer(gse), + (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(groupSecretParams)), + ) + runtime.KeepAlive(gse) + runtime.KeepAlive(groupSecretParams) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(token), nil +} + +func (gse GroupSendEndorsement) ToFullToken(params *GroupSecretParams, expiration time.Time) (GroupSendFullToken, error) { + token, err := gse.ToToken(params) + if err != nil { + return nil, err + } + return token.ToFullToken(expiration) +} + +func (gse GroupSendEndorsement) CheckValidContents() error { + signalFfiError := C.signal_group_send_endorsement_check_valid_contents( + BytesToBuffer(gse), + ) + runtime.KeepAlive(gse) + if signalFfiError != nil { + return wrapError(signalFfiError) + } + return nil +} + +func (gse GroupSendEndorsement) Remove(other GroupSendEndorsement) (GroupSendEndorsement, error) { + var result C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + signalFfiError := C.signal_group_send_endorsement_remove( + &result, + BytesToBuffer(gse), + BytesToBuffer(other), + ) + runtime.KeepAlive(gse) + runtime.KeepAlive(other) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(result), nil +} + +func GroupSendEndorsementCombine(endorsements ...GroupSendEndorsement) (GroupSendEndorsement, error) { + var result C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + cEndorsements, unpin := ManyBytesToBuffer(endorsements) + defer unpin() + signalFfiError := C.signal_group_send_endorsement_combine( + &result, + cEndorsements, + ) + runtime.KeepAlive(endorsements) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + return CopySignalOwnedBufferToBytes(result), nil +} + +type GroupSendEndorsementsResponse []byte + +func (gser GroupSendEndorsementsResponse) GetExpiration() (time.Time, error) { + var expiration C.uint64_t + signalFfiError := C.signal_group_send_endorsements_response_get_expiration( + &expiration, + BytesToBuffer(gser), + ) + runtime.KeepAlive(gser) + if signalFfiError != nil { + return time.Time{}, wrapError(signalFfiError) + } + return time.Unix(int64(expiration), 0), nil +} + +func (gser GroupSendEndorsementsResponse) CheckValidContents() error { + signalFfiError := C.signal_group_send_endorsements_response_check_valid_contents( + BytesToBuffer(gser), + ) + runtime.KeepAlive(gser) + if signalFfiError != nil { + return wrapError(signalFfiError) + } + return nil +} + +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) + for i, member := range groupMembers { + copy(concatenatedMembers[i*17:(i+1)*17], member.FixedBytes()[:]) + } + signalFfiError := C.signal_group_send_endorsements_response_receive_and_combine_with_service_ids( + &out, + BytesToBuffer(gser), + BytesToBuffer(concatenatedMembers), + localUser.CFixedBytes(), + C.uint64_t(time.Now().Unix()), + (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(params)), + C.SignalConstPointerServerPublicParams{spp}, + ) + runtime.KeepAlive(gser) + runtime.KeepAlive(concatenatedMembers) + runtime.KeepAlive(params) + runtime.KeepAlive(spp) + if signalFfiError != nil { + return nil, nil, wrapError(signalFfiError) + } + endorsements := CopySignalBytestringArray[GroupSendEndorsement](out) + memberEndorsements := make(map[ServiceID]GroupSendEndorsement, len(groupMembers)) + for i, member := range groupMembers { + if len(endorsements) > i && len(endorsements[i]) > 0 { + memberEndorsements[member] = endorsements[i] + } + } + combined, err := GroupSendEndorsementCombine(endorsements...) + if err != nil { + return nil, memberEndorsements, err + } + return combined, memberEndorsements, nil +} diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 2a7f470..52fa12d 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -72,7 +72,7 @@ func NewClient(device *store.Device, log zerolog.Logger, evtHandler func(events. Store: device, Log: log, EventHandler: evtHandler, - GroupCache: NewGroupCache(), + GroupCache: NewGroupCache(device.ACIServiceID()), ProfileCache: &ProfileCache{ profiles: make(map[string]*types.Profile), errors: make(map[string]*error), diff --git a/pkg/signalmeow/groupcache.go b/pkg/signalmeow/groupcache.go index 557203a..ee8259f 100644 --- a/pkg/signalmeow/groupcache.go +++ b/pkg/signalmeow/groupcache.go @@ -29,14 +29,31 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) +type SendEndorsementCache struct { + SendEndorsement libsignalgo.GroupSendEndorsement + MemberEndorsements map[libsignalgo.ServiceID]libsignalgo.GroupSendEndorsement + Expiration time.Time + SecretParams *libsignalgo.GroupSecretParams +} + +func (sec *SendEndorsementCache) GetToken() (libsignalgo.GroupSendFullToken, error) { + return sec.GetTokenWith(sec.SendEndorsement) +} + +func (sec *SendEndorsementCache) GetTokenWith(altToken libsignalgo.GroupSendEndorsement) (libsignalgo.GroupSendFullToken, error) { + return altToken.ToFullToken(sec.SecretParams, sec.Expiration) +} + type cachedGroup struct { *Group - SendEndorsement []byte - FetchedAt time.Time - UpdatedAt time.Time + *SendEndorsementCache + FetchedAt time.Time + UpdatedAt time.Time } type GroupCache struct { + serviceID libsignalgo.ServiceID + credentials *GroupCredentials credentialsLock sync.RWMutex @@ -47,8 +64,9 @@ type GroupCache struct { callsLock sync.RWMutex } -func NewGroupCache() *GroupCache { +func NewGroupCache(serviceID libsignalgo.ServiceID) *GroupCache { return &GroupCache{ + serviceID: serviceID, data: make(map[types.GroupIdentifier]*cachedGroup), activeCalls: make(map[types.GroupIdentifier]string), } @@ -111,14 +129,14 @@ func (gc *GroupCache) UpdateActiveCall(id types.GroupIdentifier, callID string) return true } -func (gc *GroupCache) Get(id types.GroupIdentifier) (*Group, bool) { +func (gc *GroupCache) Get(id types.GroupIdentifier) (*Group, *SendEndorsementCache, bool) { gc.lock.RLock() defer gc.lock.RUnlock() c, ok := gc.data[id] - if !ok { - return nil, false + if !ok || time.Until(c.Expiration) < 5*time.Minute { + return nil, nil, false } - return c.Group, true + return c.Group, c.SendEndorsementCache, true } func (gc *GroupCache) Delete(id types.GroupIdentifier) { @@ -127,26 +145,50 @@ func (gc *GroupCache) Delete(id types.GroupIdentifier) { delete(gc.data, id) } -func (gc *GroupCache) Put(data *Group, endorsementResponse []byte) { +func (gc *GroupCache) Put(data *Group, endorsementResponse libsignalgo.GroupSendEndorsementsResponse) error { + gsp, err := masterKeyToBytes(data.GroupMasterKey).SecretParams() + if err != nil { + return fmt.Errorf("failed to get secret params: %w", err) + } + expiration, err := endorsementResponse.GetExpiration() + if err != nil { + return fmt.Errorf("failed to get endorsement expiration: %w", err) + } + endorsement, memberEndorsements, err := endorsementResponse.ReceiveWithServiceIDs(data.getMemberServiceIDs(), gc.serviceID, &gsp, prodServerPublicParams) + if err != nil { + return fmt.Errorf("failed to receive endorsements: %w", err) + } + gc.lock.Lock() defer gc.lock.Unlock() cached, exists := gc.data[data.GroupIdentifier] if exists && cached.Revision > data.Revision { - return + return nil } gc.data[data.GroupIdentifier] = &cachedGroup{ Group: data, FetchedAt: time.Now(), UpdatedAt: time.Now(), - //SendEndorsement: endorsementResponse, + SendEndorsementCache: &SendEndorsementCache{ + Expiration: expiration, + SendEndorsement: endorsement, + MemberEndorsements: memberEndorsements, + SecretParams: &gsp, + }, } + return nil } -func (gc *GroupCache) ApplyUpdate(change *GroupChange, endorsementResponse []byte) { - rawGroupID, err := masterKeyToBytes(change.GroupMasterKey).GroupIdentifier() +func (gc *GroupCache) ApplyUpdate(change *GroupChange, endorsementResponse libsignalgo.GroupSendEndorsementsResponse) error { + mkBytes := masterKeyToBytes(change.GroupMasterKey) + rawGroupID, err := mkBytes.GroupIdentifier() if err != nil { - return + return fmt.Errorf("failed to get group identifier: %w", err) + } + gsp, err := mkBytes.SecretParams() + if err != nil { + return fmt.Errorf("failed to get secret params: %w", err) } id := types.GroupIdentifier(rawGroupID.String()) @@ -155,11 +197,11 @@ func (gc *GroupCache) ApplyUpdate(change *GroupChange, endorsementResponse []byt cached, exists := gc.data[id] if !exists || cached.Revision >= change.Revision { - return + return nil } else if cached.Revision < change.Revision-1 { // We missed an update, evict delete(gc.data, id) - return + return nil } // Pending member adds, promotes and removes @@ -275,7 +317,30 @@ func (gc *GroupCache) ApplyUpdate(change *GroupChange, endorsementResponse []byt cached.AccessControl.AddFromInviteLink = *change.ModifyAddFromInviteLinkAccess } - // TODO handle endorsement responses cached.UpdatedAt = time.Now() cached.Revision = change.Revision + endorsement, memberEndorsements, err := endorsementResponse.ReceiveWithServiceIDs( + cached.getMemberServiceIDs(), + gc.serviceID, + &gsp, + prodServerPublicParams, + ) + if err != nil { + delete(gc.data, id) + return fmt.Errorf("failed to receive endorsements: %w", err) + } + expiration, err := endorsementResponse.GetExpiration() + if err != nil { + delete(gc.data, id) + return fmt.Errorf("failed to get endorsement expiration: %w", err) + } + // TODO do these responses overwrite the entire thing? + cached.SendEndorsementCache = &SendEndorsementCache{ + SendEndorsement: endorsement, + MemberEndorsements: memberEndorsements, + Expiration: expiration, + SecretParams: &gsp, + } + + return nil } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index f25f835..d8ba4b3 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -31,6 +31,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/exslices" "go.mau.fi/util/ptr" "go.mau.fi/util/random" "google.golang.org/protobuf/proto" @@ -90,6 +91,12 @@ type Group struct { //PublicKey *libsignalgo.PublicKey } +func (group *Group) getMemberServiceIDs() []libsignalgo.ServiceID { + return exslices.CastFunc(group.Members, func(from *GroupMember) libsignalgo.ServiceID { + return libsignalgo.NewACIServiceID(from.ACI) + }) +} + func (group *Group) GetInviteLink() (string, error) { if group.InviteLinkPassword == nil { return "", fmt.Errorf("no invite link password set") @@ -654,7 +661,10 @@ func (cli *Client) parseGroupResponse(ctx context.Context, response *http.Respon if err != nil { return nil, fmt.Errorf("failed to decrypt group: %w", err) } - cli.GroupCache.Put(group, groupResponse.GroupSendEndorsementsResponse) + err = cli.GroupCache.Put(group, groupResponse.GroupSendEndorsementsResponse) + if err != nil { + zerolog.Ctx(ctx).Err(err).Msg("Failed to cache group response") + } // Store the profile keys in case they're new for _, member := range group.Members { @@ -697,12 +707,21 @@ func (cli *Client) DownloadGroupAvatar(ctx context.Context, avatarPath string, g return decrypted, nil } -func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentifier, revision uint32) (*Group, error) { - cached, ok := cli.GroupCache.Get(gid) +func (cli *Client) RetrieveGroupByID(ctx context.Context, gid types.GroupIdentifier, revision uint32) (*Group, *SendEndorsementCache, error) { + cached, endorsement, ok := cli.GroupCache.Get(gid) if ok && cached.Revision >= revision { - return cached, nil + return cached, endorsement, nil } - return cli.fetchGroupByID(ctx, gid) + group, err := cli.fetchGroupByID(ctx, gid) + if err != nil { + return nil, nil, err + } + cached, endorsement, ok = cli.GroupCache.Get(gid) + if !ok { + zerolog.Ctx(ctx).Warn().Msg("Group not found in cache after fetching") + return group, nil, nil + } + return cached, endorsement, nil } // We should store the group master key in the group store as soon as we see it, @@ -1049,7 +1068,10 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange } success = true - cli.GroupCache.ApplyUpdate(decryptedGroupChange, nil) + err = cli.GroupCache.ApplyUpdate(decryptedGroupChange, nil) + if err != nil { + log.Err(err).Msg("Failed to apply group change to cache") + } return decryptedGroupChange, nil } @@ -1499,7 +1521,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi masterKeyBytes := masterKeyToBytes(groupMasterKey) var refetchedAddMemberCredentials bool var signedGroupChange *signalpb.GroupChangeResponse - group, err := cli.RetrieveGroupByID(ctx, gid, 0) + group, _, err := cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { return 0, fmt.Errorf("failed to fetch group info to update: %w", err) } @@ -1523,7 +1545,7 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi } } else if errors.Is(err, ConflictError) { cli.GroupCache.Delete(gid) - group, err = cli.RetrieveGroupByID(ctx, gid, 0) + group, _, err = cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { return 0, fmt.Errorf("failed to fetch group after conflict: %w", err) } @@ -1539,7 +1561,10 @@ func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gi if signedGroupChange == nil { return 0, fmt.Errorf("no signed group change returned: %w", err) } - cli.GroupCache.ApplyUpdate(groupChange, signedGroupChange.GroupSendEndorsementsResponse) + err = cli.GroupCache.ApplyUpdate(groupChange, signedGroupChange.GroupSendEndorsementsResponse) + if err != nil { + log.Err(err).Msg("Failed to apply group change to cache") + } groupChangeBytes, err := proto.Marshal(signedGroupChange.GroupChange) if err != nil { return 0, fmt.Errorf("failed to marshal signed group change: %w", err) diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index 133ef80..9dbe96f 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -50,6 +50,7 @@ func (cli *Client) sendToGroupWithSenderKey( ctx context.Context, groupID types.GroupIdentifier, allRecipients []libsignalgo.ServiceID, + sec SendEndorsementCache, content *signalpb.Content, messageTimestamp uint64, retries int, @@ -78,7 +79,7 @@ func (cli *Client) sendToGroupWithSenderKey( FailedToSendTo: make([]FailedSendResult, 0), } - deviceIDs, senderKeyRecipients, fallbackRecipients := cli.getDevicesIDs(ctx, allRecipients, result) + deviceIDs, senderKeyRecipients, fallbackRecipients := cli.getDevicesIDs(ctx, allRecipients, sec, result) ski, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupID) if err != nil { return nil, fmt.Errorf("failed to get sender key info: %w", err) @@ -148,7 +149,7 @@ func (cli *Client) sendToGroupWithSenderKey( } if needsRetry { doUnlock() - return cli.sendToGroupWithSenderKey(ctx, groupID, allRecipients, content, messageTimestamp, retries+1) + return cli.sendToGroupWithSenderKey(ctx, groupID, allRecipients, sec, content, messageTimestamp, retries+1) } } ssCiphertext, err := cli.encryptWithSenderKey(ctx, groupID, ski.DistributionID, myAddress, senderKeyRecipients, content) @@ -157,11 +158,27 @@ func (cli *Client) sendToGroupWithSenderKey( } header := http.Header{} header.Set("Content-Type", string(web.ContentTypeMultiRecipientMessage)) - //if groupSendToken != nil { - // header.Set("Group-Send-Token", groupSendToken.String()) - //} else { - header.Set("Unidentified-Access-Key", xak.String()) - //} + if sec.SendEndorsement != nil { + wantedEndorsements := make([]libsignalgo.GroupSendEndorsement, 0, len(deviceIDs)) + for serviceID := range deviceIDs { + endorsement, ok := sec.MemberEndorsements[serviceID] + if !ok { + return nil, fmt.Errorf("missing group send endorsement for service ID %s", serviceID.String()) + } + wantedEndorsements = append(wantedEndorsements, endorsement) + } + combinedEndorsement, err := libsignalgo.GroupSendEndorsementCombine(wantedEndorsements...) + if err != nil { + return nil, fmt.Errorf("failed to combine group send endorsements: %w", err) + } + groupSendToken, err := sec.GetTokenWith(combinedEndorsement) + if err != nil { + return nil, fmt.Errorf("failed to create group send full token: %w", err) + } + header.Set("Group-Send-Token", groupSendToken.String()) + } else { + header.Set("Unidentified-Access-Key", xak.String()) + } path := fmt.Sprintf( "/v1/messages/multi_recipient?ts=%d&urgent=%t&online=false", messageTimestamp, isUrgent(content), @@ -218,7 +235,7 @@ func (cli *Client) sendToGroupWithSenderKey( } doUnlock() // Retry recursively after fixing device lists - return cli.sendToGroupWithSenderKey(ctx, groupID, allRecipients, content, messageTimestamp, retries+1) + return cli.sendToGroupWithSenderKey(ctx, groupID, allRecipients, sec, content, messageTimestamp, retries+1) default: return nil, fmt.Errorf("unexpected status code %d in multi-recipient send", resp.GetStatus()) } @@ -305,8 +322,15 @@ type senderKeySendMeta struct { AccessKey *libsignalgo.AccessKey } -func (cli *Client) getDevicesIDs(ctx context.Context, recipients []libsignalgo.ServiceID, result *GroupMessageSendResult) ( - map[libsignalgo.ServiceID]senderKeySendMeta, []store.SessionAddressTuple, []libsignalgo.ServiceID, +func (cli *Client) getDevicesIDs( + ctx context.Context, + recipients []libsignalgo.ServiceID, + sendEndorsement SendEndorsementCache, + result *GroupMessageSendResult, +) ( + map[libsignalgo.ServiceID]senderKeySendMeta, + []store.SessionAddressTuple, + []libsignalgo.ServiceID, ) { log := zerolog.Ctx(ctx) out := make(map[libsignalgo.ServiceID]senderKeySendMeta) @@ -321,6 +345,10 @@ func (cli *Client) getDevicesIDs(ctx context.Context, recipients []libsignalgo.S if recipient.Type != libsignalgo.ServiceIDTypeACI { continue } + _, hasEndorsement := sendEndorsement.MemberEndorsements[recipient] + if !hasEndorsement { + continue + } profileKey, err := cli.Store.RecipientStore.LoadProfileKey(ctx, recipient.UUID) if err != nil { log.Err(err).Stringer("recipient_id", recipient.UUID).Msg("Failed to get profile key") diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index d9fd831..e37fdf0 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -543,11 +543,10 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi Stringer("group_id", gid). Logger() ctx = log.WithContext(ctx) - group, err := cli.RetrieveGroupByID(ctx, gid, 0) + group, endorsement, err := cli.RetrieveGroupByID(ctx, gid, 0) if err != nil { return nil, err } - var messageTimestamp uint64 if content.GetDataMessage() != nil { messageTimestamp = content.DataMessage.GetTimestamp() @@ -568,7 +567,7 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi recipients = append(recipients, member.UserServiceID()) } if enableSenderKeySend { - return cli.sendToGroupWithSenderKey(ctx, gid, recipients, content, messageTimestamp, 0) + return cli.sendToGroupWithSenderKey(ctx, gid, recipients, ptr.Val(endorsement), content, messageTimestamp, 0) } return cli.sendToGroup(ctx, recipients, content, messageTimestamp, nil) } From 207fc6a996d117df87dce6cad3f2c314fcf05743 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Nov 2025 16:51:51 +0200 Subject: [PATCH 613/718] signalmeow: add cache for unregistered ACIs --- pkg/signalmeow/keys.go | 8 +++-- pkg/signalmeow/receiving.go | 1 + pkg/signalmeow/senderkey.go | 2 +- pkg/signalmeow/sending.go | 5 ++- pkg/signalmeow/store/recipient_store.go | 35 +++++++++++++++++++ pkg/signalmeow/store/upgrades/00-latest.sql | 6 +++- .../upgrades/25-unregistered-user-cache.sql | 4 +++ 7 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/25-unregistered-user-cache.sql diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 724565a..f1801e5 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -405,11 +405,14 @@ func addBase64PaddingAndDecode(data string) ([]byte, error) { } var ( - ErrUnregisteredUser = errors.New("got 404 when fetching prekey, user is unregistered") + ErrUnregisteredUser = errors.New("user is unregistered") ErrDevicesChanged = errors.New("device list changed while sending skdm") ) func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID libsignalgo.ServiceID, specificDeviceID int) error { + if cli.Store.RecipientStore.IsUnregistered(ctx, theirServiceID) { + return fmt.Errorf("%w (cached)", ErrUnregisteredUser) + } // Fetch prekey deviceIDPath := "/*" if specificDeviceID >= 0 { @@ -421,7 +424,8 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib if err != nil { return fmt.Errorf("error sending request: %w", err) } else if resp.GetStatus() == 404 { - return ErrUnregisteredUser + cli.Store.RecipientStore.MarkUnregistered(ctx, theirServiceID, true) + return fmt.Errorf("%w (404 while querying keys)", ErrUnregisteredUser) } var respData prekeyResponse err = web.DecodeWSResponseBody(ctx, &respData, resp) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 0feee6b..a699fbc 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -443,6 +443,7 @@ func (cli *Client) handleDecryptedResult( Msg("Dropping message from non-ACI sender") return nil } + cli.Store.RecipientStore.MarkUnregistered(ctx, theirServiceID, false) handlerSuccess := true // result.Err is set if there was an error during decryption and we diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index 9dbe96f..4f54c81 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -200,12 +200,12 @@ func (cli *Client) sendToGroupWithSenderKey( Msg("Got successful multi-recipient send response") for serviceID := range deviceIDs { if slices.Contains(respData.UUIDs404, serviceID) { - // TODO flag recipient as unregistered err = cli.Store.ACISessionStore.RemoveAllSessionsForServiceID(ctx, serviceID) if err != nil { log.Err(err).Stringer("recipient_id", serviceID). Msg("Failed to remove sessions after 404") } + cli.Store.RecipientStore.MarkUnregistered(ctx, serviceID, true) result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ Recipient: serviceID, Error: fmt.Errorf("multi-recipient send 404"), diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index e37fdf0..47695d9 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -159,7 +159,6 @@ func (cli *Client) buildMessagesToSend( // No sessions, make one with prekey err = cli.FetchAndProcessPreKey(ctx, recipient, -1) if err != nil { - // TODO flag 404s as unregistered return nil, err } sessions, err = cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) @@ -952,12 +951,12 @@ func (cli *Client) sendContent( return sentUnidentified, err } } else if *response.Status == 404 { - // TODO flag recipient as unregistered err = cli.Store.ACISessionStore.RemoveAllSessionsForServiceID(ctx, recipient) if err != nil { log.Err(err).Msg("Failed to remove sessions after 404") } - return sentUnidentified, ErrUnregisteredUser + cli.Store.RecipientStore.MarkUnregistered(ctx, recipient, true) + return sentUnidentified, fmt.Errorf("%w (send returned 404)", ErrUnregisteredUser) } else if *response.Status != 200 { return sentUnidentified, fmt.Errorf("unexpected status code while sending: %d", *response.Status) } diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 00646df..98c7315 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -43,6 +43,9 @@ type RecipientStore interface { StoreRecipient(ctx context.Context, recipient *types.Recipient) error UpdateRecipientE164(ctx context.Context, aci, pni uuid.UUID, e164 string) (*types.Recipient, error) + IsUnregistered(ctx context.Context, serviceID libsignalgo.ServiceID) bool + MarkUnregistered(ctx context.Context, serviceID libsignalgo.ServiceID, unregistered bool) + LoadAllContacts(ctx context.Context) ([]*types.Recipient, error) } @@ -387,3 +390,35 @@ func (s *sqlStore) StoreRecipient(ctx context.Context, recipient *types.Recipien } return } + +const ( + isUnregisteredQuery = `SELECT 1 FROM signalmeow_unregistered_users WHERE aci_uuid=$1` + markUnregisteredQuery = `INSERT INTO signalmeow_unregistered_users (aci_uuid) VALUES ($1) ON CONFLICT (aci_uuid) DO NOTHING` + markRegisteredQuery = `DELETE FROM signalmeow_unregistered_users WHERE aci_uuid=$1` +) + +func (s *sqlStore) IsUnregistered(ctx context.Context, serviceID libsignalgo.ServiceID) (unregistered bool) { + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return + } + _ = s.db.QueryRow(ctx, isUnregisteredQuery, serviceID.UUID).Scan(&unregistered) + return +} + +func (s *sqlStore) MarkUnregistered(ctx context.Context, serviceID libsignalgo.ServiceID, unregistered bool) { + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return + } + var err error + if unregistered { + _, err = s.db.Exec(ctx, markUnregisteredQuery, serviceID.UUID) + } else { + _, err = s.db.Exec(ctx, markRegisteredQuery, serviceID.UUID) + } + if err != nil { + zerolog.Ctx(ctx).Err(err). + Stringer("service_id", serviceID). + Bool("unregistered", unregistered). + Msg("Failed to mark recipient as unregistered") + } +} diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 4d42cde..dee3509 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v24 (compatible with v13+): Latest revision +-- v0 -> v25 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -134,6 +134,10 @@ CREATE TABLE signalmeow_recipients ( CONSTRAINT signalmeow_contacts_pni_unique UNIQUE (account_id, pni_uuid) ); +CREATE TABLE signalmeow_unregistered_users ( + aci_uuid uuid PRIMARY KEY +); + CREATE TABLE signalmeow_backup_recipient ( account_id TEXT NOT NULL, recipient_id BIGINT NOT NULL, diff --git a/pkg/signalmeow/store/upgrades/25-unregistered-user-cache.sql b/pkg/signalmeow/store/upgrades/25-unregistered-user-cache.sql new file mode 100644 index 0000000..04a5233 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/25-unregistered-user-cache.sql @@ -0,0 +1,4 @@ +-- v25 (compatible with v13+): Cache unregistered users +CREATE TABLE signalmeow_unregistered_users ( + aci_uuid uuid PRIMARY KEY +); From 30e80bb18bb210c58736e4d34692867a3e44be08 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Nov 2025 16:59:12 +0200 Subject: [PATCH 614/718] signalmeow/sending: enable sender key sending --- pkg/signalmeow/sending.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 47695d9..97fdcdf 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -534,7 +534,7 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte return cli.sendToGroup(ctx, recipients, content, timestamp, nil) } -const enableSenderKeySend = false +const enableSenderKeySend = true func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifier, content *signalpb.Content) (*GroupMessageSendResult, error) { log := zerolog.Ctx(ctx).With(). From d8ccce0e477258759c5395a2112797f2c4de5393 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 28 Nov 2025 22:02:16 +0200 Subject: [PATCH 615/718] build: replace build-go with go tool and remove debug mode --- Dockerfile | 16 ++-------------- build-go.sh | 9 +-------- build-rust.sh | 9 +-------- go.mod | 13 ++++++++----- go.sum | 22 ++++++++++++---------- 5 files changed, 24 insertions(+), 45 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9c5e495..162ac86 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # -- Build libsignal (with Rust) -- -FROM rust:1-alpine as rust-builder +FROM rust:1-alpine AS rust-builder RUN apk add --no-cache git make cmake protoc musl-dev g++ clang-dev WORKDIR /build @@ -7,12 +7,11 @@ WORKDIR /build COPY pkg/libsignalgo/libsignal/. pkg/libsignalgo/libsignal/. COPY build-rust.sh . -ARG DBG=0 RUN ./build-rust.sh # -- Build mautrix-signal (with Go) -- FROM golang:1-alpine3.22 AS go-builder -RUN apk add --no-cache git ca-certificates build-base olm-dev +RUN apk add --no-cache git ca-certificates build-base olm-dev zlib-dev WORKDIR /build # Copy all files needed for Go build, and no Rust files @@ -26,15 +25,9 @@ COPY pkg/connector/. pkg/connector/. COPY cmd/. cmd/. COPY .git .git -ARG DBG=0 ENV LIBRARY_PATH=. COPY --from=rust-builder /build/pkg/libsignalgo/libsignal/target/*/libsignal_ffi.a ./ RUN < Date: Tue, 2 Dec 2025 15:26:16 +0200 Subject: [PATCH 616/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/handlematrix.go | 35 +++++++++++++++++------------------ 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 29e277e..35a4fb2 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.47.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251128114054-1d1ecb228668 + maunium.net/go/mautrix v0.26.1-0.20251202132204-2eeece694254 ) require ( diff --git a/go.sum b/go.sum index 64f1f5c..cc4b594 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.26.1-0.20251128114054-1d1ecb228668 h1:Y6B67gtYwMpePlI9Spz1EKVsLiAvKJ+rxRBZRWbGjmI= -maunium.net/go/mautrix v0.26.1-0.20251128114054-1d1ecb228668/go.mod h1:NaesYcOQWFDbixVYywCVS+Twlzab9hOUpFNlCBlvciE= +maunium.net/go/mautrix v0.26.1-0.20251202132204-2eeece694254 h1:rsc4H0sZVban6xQeIS6err1YangUiK5WzVfTS6s03ms= +maunium.net/go/mautrix v0.26.1-0.20251202132204-2eeece694254/go.mod h1:NaesYcOQWFDbixVYywCVS+Twlzab9hOUpFNlCBlvciE= diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index cdd3c0a..25d3f53 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -405,22 +405,21 @@ func (s *SignalClient) HandleMatrixRoomTopic(ctx context.Context, msg *bridgev2. }, nil) } -func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2.MatrixMembershipChange) (bool, error) { +func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2.MatrixMembershipChange) (*bridgev2.MatrixMembershipResult, error) { var targetIntent bridgev2.MatrixAPI var targetSignalID libsignalgo.ServiceID var err error if msg.Portal.RoomType == database.RoomTypeDM { - //TODO: this probably needs to revert some changes and clean up the portal on leaves switch msg.Type { case bridgev2.Invite: - return false, fmt.Errorf("cannot invite additional user to dm") + return nil, fmt.Errorf("cannot invite additional user to dm") default: - return false, nil + return nil, nil } } targetSignalID, err = signalid.ParseGhostOrUserLoginID(msg.Target) if err != nil { - return false, fmt.Errorf("failed to parse target signal id: %w", err) + return nil, fmt.Errorf("failed to parse target signal id: %w", err) } switch target := msg.Target.(type) { case *bridgev2.Ghost: @@ -430,12 +429,12 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 if targetIntent == nil { ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(target.ID)) if err != nil { - return false, fmt.Errorf("failed to get ghost for user: %w", err) + return nil, fmt.Errorf("failed to get ghost for user: %w", err) } targetIntent = ghost.Intent } default: - return false, fmt.Errorf("cannot get target intent: unknown type: %T", target) + return nil, fmt.Errorf("cannot get target intent: unknown type: %T", target) } log := zerolog.Ctx(ctx).With(). Str("From Membership", string(msg.Type.From)). @@ -455,7 +454,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 switch msg.Type { case bridgev2.AcceptInvite: if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { - return false, fmt.Errorf("can't accept invite for non-ACI service ID") + return nil, fmt.Errorf("can't accept invite for non-ACI service ID") } gc.PromotePendingMembers = []*signalmeow.PromotePendingMember{{ ACI: targetSignalID.UUID, @@ -464,7 +463,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 gc.DeletePendingMembers = []*libsignalgo.ServiceID{&targetSignalID} case bridgev2.Leave, bridgev2.Kick: if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { - return false, fmt.Errorf("can't kick non-ACI service ID") + return nil, fmt.Errorf("can't kick non-ACI service ID") } gc.DeleteMembers = []*uuid.UUID{&targetSignalID.UUID} case bridgev2.Invite: @@ -500,7 +499,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 // }} case bridgev2.AcceptKnock: if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { - return false, fmt.Errorf("can't accept knock from non-ACI service ID") + return nil, fmt.Errorf("can't accept knock from non-ACI service ID") } gc.PromoteRequestingMembers = []*signalmeow.RoleMember{{ ACI: targetSignalID.UUID, @@ -508,7 +507,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 }} case bridgev2.RetractKnock, bridgev2.RejectKnock: if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { - return false, fmt.Errorf("can't reject knock from non-ACI service ID") + return nil, fmt.Errorf("can't reject knock from non-ACI service ID") } gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID.UUID} case bridgev2.BanKnocked, bridgev2.BanInvited, bridgev2.BanJoined, bridgev2.BanLeft: @@ -519,39 +518,39 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 switch msg.Type { case bridgev2.BanJoined: if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { - return false, fmt.Errorf("can't ban joined non-ACI service ID") + return nil, fmt.Errorf("can't ban joined non-ACI service ID") } gc.DeleteMembers = []*uuid.UUID{&targetSignalID.UUID} case bridgev2.BanInvited: gc.DeletePendingMembers = []*libsignalgo.ServiceID{&targetSignalID} case bridgev2.BanKnocked: if targetSignalID.Type != libsignalgo.ServiceIDTypeACI { - return false, fmt.Errorf("can't ban knocked non-ACI service ID") + return nil, fmt.Errorf("can't ban knocked non-ACI service ID") } gc.DeleteRequestingMembers = []*uuid.UUID{&targetSignalID.UUID} } case bridgev2.Unban: gc.DeleteBannedMembers = []*libsignalgo.ServiceID{&targetSignalID} default: - return false, fmt.Errorf("unsupported membership change: %s -> %s", msg.Type.From, msg.Type.To) + return nil, fmt.Errorf("unsupported membership change: %s -> %s", msg.Type.From, msg.Type.To) } _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) if err != nil || groupID == "" { - return false, err + return nil, err } gc.Revision = msg.Portal.Metadata.(*signalid.PortalMetadata).Revision + 1 revision, err := s.Client.UpdateGroup(ctx, gc, groupID) if err != nil { - return false, err + return nil, err } if msg.Type == bridgev2.Invite && targetSignalID.Type != libsignalgo.ServiceIDTypePNI { err = targetIntent.EnsureJoined(ctx, msg.Portal.MXID) if err != nil { - return false, err + return nil, err } } msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision - return true, nil + return nil, nil } func plToRole(pl int) signalmeow.GroupMemberRole { From f286c41844dcc60c32951010a68a21236fe121e5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 5 Dec 2025 16:02:23 +0200 Subject: [PATCH 617/718] chatinfo: re-query recipient if ACI is marked as unregistered --- pkg/connector/chatinfo.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 88cf3e2..c8d6c2b 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -212,7 +212,7 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, _ b e164String := fmt.Sprintf("+%d", e164Number) if recipient, err = s.Client.ContactByE164(ctx, e164String); err != nil { return nil, fmt.Errorf("error looking up number in local contact list: %w", err) - } else if recipient != nil { + } else if recipient != nil && (recipient.ACI == uuid.Nil || !s.Client.Store.RecipientStore.IsUnregistered(ctx, libsignalgo.NewACIServiceID(recipient.ACI))) { aci = recipient.ACI pni = recipient.PNI } else if resp, err := s.Client.LookupPhone(ctx, e164Number); err != nil { @@ -228,6 +228,9 @@ func (s *SignalClient) ResolveIdentifier(ctx context.Context, number string, _ b zerolog.Ctx(ctx).Err(err).Msg("Failed to save recipient entry after looking up phone") } aci, pni = recipient.ACI, recipient.PNI + if aci != uuid.Nil { + s.Client.Store.RecipientStore.MarkUnregistered(ctx, libsignalgo.NewACIServiceID(aci), false) + } } } else { aci, pni = serviceID.ToACIAndPNI() From b2a6d23eed957d202501ef5a70323fdca5695fb1 Mon Sep 17 00:00:00 2001 From: Conan Date: Mon, 8 Dec 2025 21:32:08 +0800 Subject: [PATCH 618/718] capabilities: bump bridge info version (#625) --- pkg/connector/capabilities.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index ca2975c..97affb9 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -231,5 +231,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 6 + return 1, 7 } From b4048bf1e3baec7f5c5730e86489f91040618435 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 8 Dec 2025 16:45:42 +0200 Subject: [PATCH 619/718] signalmeow/receiving: read group ID from USMC --- pkg/libsignalgo/sealedsender.go | 28 ++++++++++++++++------------ pkg/signalmeow/receiving_decrypt.go | 7 +++++++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 5a55a2c..fd05031 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -23,6 +23,7 @@ package libsignalgo import "C" import ( "context" + "fmt" "runtime" "unsafe" @@ -252,18 +253,21 @@ func (usmc *UnidentifiedSenderMessageContent) GetContents() ([]byte, error) { return CopySignalOwnedBufferToBytes(contents), nil } -//func (usmc *UnidentifiedSenderMessageContent) GetGroupID() ([]byte, error) { -// var groupID *C.uchar -// var length C.ulong -// signalFfiError := C.signal_unidentified_sender_message_content_get_group_id(&groupID, &length, usmc.ptr) -// if signalFfiError != nil { -// return nil, wrapError(signalFfiError) -// } -// if groupID == nil { -// return nil, nil -// } -// return CopyBufferToBytes(groupID, length), nil -//} +func (usmc *UnidentifiedSenderMessageContent) GetGroupID() (*GroupIdentifier, error) { + var contents C.SignalOwnedBuffer = C.SignalOwnedBuffer{} + signalFfiError := C.signal_unidentified_sender_message_content_get_group_id_or_empty(&contents, usmc.constPtr()) + runtime.KeepAlive(usmc) + if signalFfiError != nil { + return nil, wrapError(signalFfiError) + } + bytes := CopySignalOwnedBufferToBytes(contents) + if len(bytes) == 0 { + return nil, nil + } else if len(bytes) != GroupIdentifierLength { + return nil, fmt.Errorf("unexpected group ID length: %d", len(bytes)) + } + return (*GroupIdentifier)(bytes), nil +} func (usmc *UnidentifiedSenderMessageContent) GetSenderCertificate() (*SenderCertificate, error) { var senderCertificate C.SignalMutPointerSenderCertificate diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 1ffceb0..e5c1b7a 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -39,6 +39,7 @@ type DecryptionResult struct { Content *signalpb.Content ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint Err error + GroupID *libsignalgo.GroupIdentifier } func (cli *Client) decryptEnvelope( @@ -315,6 +316,10 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin if err != nil { return result, fmt.Errorf("failed to get content hint: %w", err) } + result.GroupID, err = usmc.GetGroupID() + if err != nil { + return result, fmt.Errorf("failed to get group ID: %w", err) + } result.ContentHint = signalpb.UnidentifiedSenderMessage_Message_ContentHint(contentHint) senderUUID, err := senderCertificate.GetSenderUUID() if err != nil { @@ -339,6 +344,7 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin } newLog := log.With(). Stringer("sender_uuid", senderUUID). + Stringer("group_id", result.GroupID). Uint32("sender_device_id", senderDeviceID). Str("sender_e164", senderE164). Uint8("sealed_sender_type", uint8(messageType)). @@ -372,6 +378,7 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin if err != nil { return result, err } + resultPtr.GroupID = result.GroupID return *resultPtr, nil } From 36e9f02dce312d8407acf7ac3f6da08a387f942e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 8 Dec 2025 23:11:45 +0200 Subject: [PATCH 620/718] signalmeow: add support for retry receipts --- pkg/libsignalgo/decryptionerrormessage.go | 9 +- pkg/libsignalgo/publickey.go | 3 + pkg/libsignalgo/sealedsender.go | 14 +- pkg/libsignalgo/session_test.go | 2 +- pkg/libsignalgo/sessionrecord.go | 3 + pkg/signalmeow/client.go | 10 ++ pkg/signalmeow/receiving.go | 62 +++++-- pkg/signalmeow/receiving_decrypt.go | 42 ++++- pkg/signalmeow/retry.go | 206 ++++++++++++++++++++++ pkg/signalmeow/senderkey.go | 26 +-- pkg/signalmeow/sending.go | 161 +++++++++-------- 11 files changed, 425 insertions(+), 113 deletions(-) create mode 100644 pkg/signalmeow/retry.go diff --git a/pkg/libsignalgo/decryptionerrormessage.go b/pkg/libsignalgo/decryptionerrormessage.go index 105fffc..434d40f 100644 --- a/pkg/libsignalgo/decryptionerrormessage.go +++ b/pkg/libsignalgo/decryptionerrormessage.go @@ -23,7 +23,6 @@ package libsignalgo import "C" import ( "runtime" - "time" ) type DecryptionErrorMessage struct { @@ -49,7 +48,7 @@ func DeserializeDecryptionErrorMessage(messageBytes []byte) (*DecryptionErrorMes return wrapDecryptionErrorMessage(dem.raw), nil } -func DecryptionErrorMessageForOriginalMessage(originalBytes []byte, originalType uint8, originalTs uint64, originalSenderDeviceID uint) (*DecryptionErrorMessage, error) { +func DecryptionErrorMessageForOriginalMessage(originalBytes []byte, originalType CiphertextMessageType, originalTs uint64, originalSenderDeviceID uint) (*DecryptionErrorMessage, error) { var dem C.SignalMutPointerDecryptionErrorMessage signalFfiError := C.signal_decryption_error_message_for_original_message( &dem, @@ -112,14 +111,14 @@ func (dem *DecryptionErrorMessage) Serialize() ([]byte, error) { return CopySignalOwnedBufferToBytes(serialized), nil } -func (dem *DecryptionErrorMessage) GetTimestamp() (time.Time, error) { +func (dem *DecryptionErrorMessage) GetTimestamp() (uint64, error) { var ts C.uint64_t signalFfiError := C.signal_decryption_error_message_get_timestamp(&ts, dem.constPtr()) runtime.KeepAlive(dem) if signalFfiError != nil { - return time.Time{}, wrapError(signalFfiError) + return 0, wrapError(signalFfiError) } - return time.UnixMilli(int64(ts)), nil + return uint64(ts), nil } func (dem *DecryptionErrorMessage) GetDeviceID() (uint32, error) { diff --git a/pkg/libsignalgo/publickey.go b/pkg/libsignalgo/publickey.go index dcf9647..bd7452e 100644 --- a/pkg/libsignalgo/publickey.go +++ b/pkg/libsignalgo/publickey.go @@ -29,6 +29,9 @@ type PublicKey struct { } func wrapPublicKey(ptr *C.SignalPublicKey) *PublicKey { + if ptr == nil { + return nil + } publicKey := &PublicKey{ptr: ptr} runtime.SetFinalizer(publicKey, (*PublicKey).Destroy) return publicKey diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index fd05031..5327f1c 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -44,7 +44,7 @@ func NewSealedSenderAddress(e164 string, uuid uuid.UUID, deviceID uint32) *Seale } } -func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHint UnidentifiedSenderMessageContentHint, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { +func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHint UnidentifiedSenderMessageContentHint, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore, groupID *GroupIdentifier) ([]byte, error) { ciphertextMessage, err := Encrypt(ctx, message, forAddress, sessionStore, identityStore) if err != nil { return nil, err @@ -54,7 +54,7 @@ func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHi ciphertextMessage, fromSenderCert, contentHint, - nil, + groupID, ) if err != nil { return nil, err @@ -170,18 +170,22 @@ func wrapUnidentifiedSenderMessageContent(ptr *C.SignalUnidentifiedSenderMessage return messageContent } -func NewUnidentifiedSenderMessageContent(message *CiphertextMessage, senderCertificate *SenderCertificate, contentHint UnidentifiedSenderMessageContentHint, groupID []byte) (*UnidentifiedSenderMessageContent, error) { +func NewUnidentifiedSenderMessageContent(message *CiphertextMessage, senderCertificate *SenderCertificate, contentHint UnidentifiedSenderMessageContentHint, groupID *GroupIdentifier) (*UnidentifiedSenderMessageContent, error) { var usmc C.SignalMutPointerUnidentifiedSenderMessageContent + var groupIDBytes []byte + if groupID != nil { + groupIDBytes = groupID[:] + } signalFfiError := C.signal_unidentified_sender_message_content_new( &usmc, message.constPtr(), senderCertificate.constPtr(), C.uint32_t(contentHint), - BytesToBuffer(groupID), + BytesToBuffer(groupIDBytes), ) runtime.KeepAlive(message) runtime.KeepAlive(senderCertificate) - runtime.KeepAlive(groupID) + runtime.KeepAlive(groupIDBytes) if signalFfiError != nil { return nil, wrapError(signalFfiError) } diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index 30af762..6d0b720 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -241,7 +241,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) { }() for i := 0; i < 100; i++ { message := []byte(fmt.Sprintf("%04d vision", i)) - ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore) + ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore, nil) require.NoError(t, err) assert.NotNil(t, ciphertext) } diff --git a/pkg/libsignalgo/sessionrecord.go b/pkg/libsignalgo/sessionrecord.go index a2ee9dd..b4f2afb 100644 --- a/pkg/libsignalgo/sessionrecord.go +++ b/pkg/libsignalgo/sessionrecord.go @@ -83,6 +83,9 @@ func (sr *SessionRecord) ArchiveCurrentState() error { } func (sr *SessionRecord) CurrentRatchetKeyMatches(key *PublicKey) (bool, error) { + if sr == nil || key == nil { + return false, nil + } var result C.bool signalFfiError := C.signal_session_record_current_ratchet_key_matches( &result, diff --git a/pkg/signalmeow/client.go b/pkg/signalmeow/client.go index 52fa12d..57598cd 100644 --- a/pkg/signalmeow/client.go +++ b/pkg/signalmeow/client.go @@ -26,9 +26,11 @@ import ( "time" "github.com/rs/zerolog" + "go.mau.fi/util/exsync" "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/store" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" "go.mau.fi/mautrix-signal/pkg/signalmeow/web" @@ -42,6 +44,8 @@ type Client struct { senderCertificateNoE164 *libsignalgo.SenderCertificate senderCertificateCache sync.Mutex + sendCache *exsync.RingBuffer[sendCacheKey, *signalpb.Content] + GroupCache *GroupCache ProfileCache *ProfileCache LastContactRequestTime time.Time @@ -67,6 +71,11 @@ type Client struct { writeCallbackCounter chan time.Time } +// InMemorySendCacheSize specifies how large the cache for sent messages is, which is used to respond to retry receipts. +// The cache is large because every group member will be listed separately. +// 2k entries should hold at least 2 messages in max size groups. +var InMemorySendCacheSize = 2048 + func NewClient(device *store.Device, log zerolog.Logger, evtHandler func(events.SignalEvent) bool) *Client { return &Client{ Store: device, @@ -78,6 +87,7 @@ func NewClient(device *store.Device, log zerolog.Logger, evtHandler func(events. errors: make(map[string]*error), lastFetched: make(map[string]time.Time), }, + sendCache: exsync.NewRingBuffer[sendCacheKey, *signalpb.Content](InMemorySendCacheSize), } } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index a699fbc..b5ed96d 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -397,7 +397,7 @@ func (cli *Client) handleDecryptedResult( result DecryptionResult, envelope *signalpb.Envelope, destinationServiceID libsignalgo.ServiceID, -) error { +) (retErr error) { if errors.Is(result.Err, context.Canceled) { return result.Err } else if ctx.Err() != nil { @@ -446,6 +446,11 @@ func (cli *Client) handleDecryptedResult( cli.Store.RecipientStore.MarkUnregistered(ctx, theirServiceID, false) handlerSuccess := true + defer func() { + if retErr == nil && !handlerSuccess { + retErr = ErrHandlerFailed + } + }() // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted if result.Err != nil { @@ -477,6 +482,14 @@ func (cli *Client) handleDecryptedResult( Timestamp: envelope.GetTimestamp(), }) } + if result.Retriable { + go func() { + err := cli.sendRetryRequest(ctx, result, envelope.GetTimestamp()) + if err != nil { + log.Err(err).Msg("Failed to send retry request in background") + } + }() + } if !handlerSuccess { return ErrHandlerFailed } @@ -490,7 +503,11 @@ func (cli *Client) handleDecryptedResult( } deviceID, _ := result.SenderAddress.DeviceID() - log.Trace().Any("raw_data", content).Stringer("sender", theirServiceID).Uint("sender_device", deviceID).Msg("Raw event data") + log.Trace(). + Any("raw_data", content). + Stringer("sender", theirServiceID). + Uint("sender_device", deviceID). + Msg("Raw event data") newLog := log.With(). Stringer("sender_name", theirServiceID). Uint("sender_device_id", deviceID). @@ -502,7 +519,26 @@ func (cli *Client) handleDecryptedResult( if result.CiphertextHash != nil { logEvt = logEvt.Hex("ciphertext_hash", result.CiphertextHash[:]) } - logEvt.Msg("Decrypted message") + logEvt.Bool("unencrypted", result.Unencrypted).Msg("Decrypted message") + + if content.DecryptionErrorMessage != nil { + handlerSuccess = true + dem, err := libsignalgo.DeserializeDecryptionErrorMessage(content.DecryptionErrorMessage) + if err != nil { + log.Warn().Err(err).Msg("Failed to unmarshal decryption error message") + } else { + go func() { + err := cli.handleRetryRequest(ctx, result, dem) + if err != nil { + log.Err(err).Msg("Failed to handle decryption error message in background") + } + }() + } + return + } else if result.Unencrypted { + log.Warn().Msg("Unexpected non-decryption-error content in unencrypted message") + return nil + } // If there's a sender key distribution message, process it if content.GetSenderKeyDistributionMessage() != nil { @@ -538,22 +574,20 @@ func (cli *Client) handleDecryptedResult( } } - if content.GetPniSignatureMessage() != nil { + if content.PniSignatureMessage != nil { log.Debug().Msg("Content includes PNI signature message") - err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.GetPniSignatureMessage()) + err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.PniSignatureMessage) if err != nil { log.Err(err). - Hex("pni_raw", content.GetPniSignatureMessage().GetPni()). + Hex("pni_raw", content.PniSignatureMessage.GetPni()). Stringer("aci", theirServiceID.UUID). Msg("Failed to verify ACI-PNI mapping") } } if content.SyncMessage != nil && theirServiceID == cli.Store.ACIServiceID() { - handlerSuccess, err = cli.handleSyncMessage(ctx, content.SyncMessage, envelope) - if err != nil { - return err - } + handlerSuccess = cli.handleSyncMessage(ctx, content.SyncMessage, envelope) + return nil } isBlocked, err := cli.Store.RecipientStore.IsBlocked(ctx, theirServiceID.UUID) @@ -620,9 +654,6 @@ func (cli *Client) handleDecryptedResult( Content: content.ReceiptMessage, }) && handlerSuccess } - if !handlerSuccess { - return ErrHandlerFailed - } return nil } @@ -633,7 +664,7 @@ func groupOrUserID(groupID types.GroupIdentifier, userID libsignalgo.ServiceID) return string(groupID) } -func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMessage, envelope *signalpb.Envelope) (handlerSuccess bool, err error) { +func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMessage, envelope *signalpb.Envelope) (handlerSuccess bool) { // TODO: handle more sync messages handlerSuccess = true log := zerolog.Ctx(ctx) @@ -655,7 +686,7 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess } else { log.Debug().Msg("No account entropy pool in sync message") } - err = cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) + err := cli.Store.DeviceStore.PutDevice(ctx, &cli.Store.DeviceData) if err != nil { log.Err(err).Msg("Failed to save device after receiving master key") } else { @@ -671,6 +702,7 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess destination := syncSent.DestinationServiceId var syncDestinationServiceID libsignalgo.ServiceID if destination != nil { + var err error syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) if err != nil { log.Err(err).Msg("Sync message destination parse error") diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index e5c1b7a..5c8da08 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -40,6 +40,11 @@ type DecryptionResult struct { ContentHint signalpb.UnidentifiedSenderMessage_Message_ContentHint Err error GroupID *libsignalgo.GroupIdentifier + Unencrypted bool + + Retriable bool + Ciphertext []byte + CiphertextType libsignalgo.CiphertextMessageType } func (cli *Client) decryptEnvelope( @@ -80,12 +85,30 @@ func (cli *Client) decryptEnvelope( bundleType = "ciphertext" } if err != nil { - return DecryptionResult{Err: fmt.Errorf("failed to decrypt %s envelope: %w", bundleType, err), SenderAddress: sender} + return DecryptionResult{ + SenderAddress: sender, + Err: fmt.Errorf("failed to decrypt %s envelope: %w", bundleType, err), + Retriable: true, // TODO should these ever be not retriable? + Ciphertext: envelope.Content, + CiphertextType: libsignalgo.CiphertextMessageType(envelope.GetType()), + } } return *result case signalpb.Envelope_PLAINTEXT_CONTENT: - return DecryptionResult{Err: fmt.Errorf("plaintext messages are not supported")} + addr, err := libsignalgo.NewUUIDAddressFromString(envelope.GetSourceServiceId(), uint(envelope.GetSourceDevice())) + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} + } + content, err := stripPadding(envelope.GetContent()) + if err != nil { + return DecryptionResult{Err: fmt.Errorf("failed to strip padding: %w", err)} + } + return DecryptionResult{ + SenderAddress: addr, + Content: &signalpb.Content{DecryptionErrorMessage: content}, + Unencrypted: true, + } case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} @@ -342,6 +365,8 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin if err != nil { return result, fmt.Errorf("failed to get USMC contents: %w", err) } + result.Ciphertext = usmcContents + result.CiphertextType = messageType newLog := log.With(). Stringer("sender_uuid", senderUUID). Stringer("group_id", result.GroupID). @@ -369,13 +394,20 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin case libsignalgo.CiphertextMessageTypeWhisper: resultPtr, err = cli.decryptCiphertextEnvelope(ctx, destinationServiceID, senderAddress, usmcContents, envelope.GetServerTimestamp()) case libsignalgo.CiphertextMessageTypePlaintext: - // TODO: handle plaintext (usually DecryptionErrorMessage) and retries - // when implementing SenderKey groups - return result, fmt.Errorf("unsupported plaintext sealed sender message") + usmcContents, err = stripPadding(usmcContents) + if err != nil { + err = fmt.Errorf("failed to strip padding: %w", err) + } + result.Unencrypted = true + result.Content = &signalpb.Content{ + DecryptionErrorMessage: usmcContents, + } + return result, err default: return result, fmt.Errorf("unsupported sealed sender message type %d", messageType) } if err != nil { + result.Retriable = result.ContentHint == signalpb.UnidentifiedSenderMessage_Message_RESENDABLE return result, err } resultPtr.GroupID = result.GroupID diff --git a/pkg/signalmeow/retry.go b/pkg/signalmeow/retry.go new file mode 100644 index 0000000..2c89ecc --- /dev/null +++ b/pkg/signalmeow/retry.go @@ -0,0 +1,206 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "fmt" + "slices" + "time" + + "github.com/rs/zerolog" + + "go.mau.fi/mautrix-signal/pkg/libsignalgo" + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/types" +) + +type sendCacheKey struct { + recipient libsignalgo.ServiceID + groupID types.GroupIdentifier + timestamp uint64 +} + +const RetryRespondMaxAge = 30 * 24 * time.Hour + +func (cli *Client) sendRetryRequest(ctx context.Context, result DecryptionResult, originalTS uint64) error { + serviceID, err := result.SenderAddress.NameServiceID() + if err != nil { + return fmt.Errorf("failed to get sender name as service ID: %w", err) + } + deviceID, err := result.SenderAddress.DeviceID() + if err != nil { + return fmt.Errorf("failed to get sender device ID: %w", err) + } + dem, err := libsignalgo.DecryptionErrorMessageForOriginalMessage(result.Ciphertext, result.CiphertextType, originalTS, deviceID) + if err != nil { + return fmt.Errorf("failed to create decryption error message: %w", err) + } + demBytes, err := dem.Serialize() + if err != nil { + return fmt.Errorf("failed to serialize decryption error message: %w", err) + } + ptc, err := libsignalgo.PlaintextContentFromDecryptionErrorMessage(dem) + if err != nil { + return fmt.Errorf("failed to create plaintext content from decryption error message: %w", err) + } + ctm, err := libsignalgo.NewCiphertextMessage(ptc) + if err != nil { + return fmt.Errorf("failed to create ciphertext message from plaintext content: %w", err) + } + _, err = cli.sendContent(ctx, serviceID, uint64(time.Now().UnixMilli()), &signalpb.Content{ + DecryptionErrorMessage: demBytes, + }, 0, true, result.GroupID, ctm) + if err != nil { + return fmt.Errorf("failed to send decryption error message: %w", err) + } + zerolog.Ctx(ctx).Debug(). + Stringer("sender_service_id", serviceID). + Uint("sender_device_id", deviceID). + Stringer("group_id", result.GroupID). + Msg("Sent retry receipt") + return nil +} + +func (cli *Client) handleRetryRequest( + ctx context.Context, + result DecryptionResult, + dem *libsignalgo.DecryptionErrorMessage, +) error { + destDeviceID, err := dem.GetDeviceID() + if err != nil { + return fmt.Errorf("failed to get device ID from decryption error message: %w", err) + } else if int(destDeviceID) != cli.Store.DeviceID { + zerolog.Ctx(ctx).Debug(). + Uint32("dest_device_id", destDeviceID). + Msg("Ignoring decryption error message for another device") + return nil + } + serviceID, err := result.SenderAddress.NameServiceID() + if err != nil { + return fmt.Errorf("failed to get sender name as service ID: %w", err) + } + deviceID, err := result.SenderAddress.DeviceID() + if err != nil { + return fmt.Errorf("failed to get sender device ID: %w", err) + } + ts, err := dem.GetTimestamp() + if err != nil { + return fmt.Errorf("failed to get timestamp: %w", err) + } + + cli.encryptionLock.Lock() + defer cli.encryptionLock.Unlock() + ctx = context.WithValue(ctx, contextKeyEncryptionLock, true) + var didArchiveSession bool + if ratchetKey, err := dem.GetRatchetKey(); err != nil { + return fmt.Errorf("failed to get ratchet key: %w", err) + } else if ratchetKey == nil { + // No need to archive session if no ratchet key is provided, it was probably a sender key decryption error + } else if session, err := cli.Store.ACISessionStore.LoadSession(ctx, result.SenderAddress); err != nil { + return fmt.Errorf("failed to load session for sender: %w", err) + } else if match, err := session.CurrentRatchetKeyMatches(ratchetKey); err != nil { + return fmt.Errorf("failed to check ratchet key match: %w", err) + } else if match { + err = session.ArchiveCurrentState() + if err != nil { + return fmt.Errorf("failed to archive current session state: %w", err) + } + err = cli.Store.ACISessionStore.StoreSession(ctx, result.SenderAddress, session) + if err != nil { + return fmt.Errorf("failed to store archived session: %w", err) + } + didArchiveSession = true + } + var skdmBytes []byte + groupID := types.BytesToGroupIdentifier(result.GroupID) + if groupID != "" { + ski, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupID) + if err != nil { + return fmt.Errorf("failed to get sender key info for group %s: %w", groupID, err) + } + myAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)) + if err != nil { + return fmt.Errorf("failed to get own address: %w", err) + } + if slices.Contains(ski.SharedWith[serviceID], int(deviceID)) { + skdm, err := libsignalgo.NewSenderKeyDistributionMessage(ctx, myAddress, ski.DistributionID, cli.Store.SenderKeyStore) + if err != nil { + return fmt.Errorf("failed to create sender key distribution message: %w", err) + } + skdmBytes, err = skdm.Serialize() + if err != nil { + return fmt.Errorf("failed to serialize sender key distribution message: %w", err) + } + } else { + zerolog.Ctx(ctx).Warn(). + Stringer("group_id", result.GroupID). + Stringer("sender_service_id", serviceID). + Stringer("distribution_id", ski.DistributionID). + Uint("sender_device_id", deviceID). + Ints("shared_with", ski.SharedWith[serviceID]). + Msg("Sender key distribution list doesn't contain retry receipt sender") + } + } + var retryContent *signalpb.Content + var cacheHit bool + if time.Since(time.UnixMilli(int64(ts))) < RetryRespondMaxAge { + retryContent, cacheHit = cli.sendCache.Get(sendCacheKey{ + groupID: groupID, + recipient: serviceID, + timestamp: ts, + }) + if !cacheHit { + // TODO add support for external caches + } + } + if retryContent == nil { + retryContent = &signalpb.Content{} + } + retryContent.SenderKeyDistributionMessage = skdmBytes + if !cacheHit && skdmBytes == nil { + if !didArchiveSession { + zerolog.Ctx(ctx).Debug(). + Uint64("msg_timestamp", ts). + Stringer("sender_service_id", serviceID). + Uint("sender_device_id", deviceID). + Stringer("group_id", result.GroupID). + Msg("Not responding to decryption error message") + return nil + } + retryContent.NullMessage = &signalpb.NullMessage{} + } + responseTimestamp := uint64(time.Now().UnixMilli()) + if cacheHit { + responseTimestamp = ts + } + zerolog.Ctx(ctx).Debug(). + Uint32("dest_device_id", destDeviceID). + Uint64("requested_msg_timestamp", ts). + Stringer("sender_service_id", serviceID). + Uint("sender_device_id", deviceID). + Stringer("group_id", result.GroupID). + Bool("did_archive_session", didArchiveSession). + Bool("found_message_in_cache", cacheHit). + Bool("including_skdm", skdmBytes != nil). + Msg("Responding to decryption error message") + _, err = cli.sendContent(ctx, serviceID, responseTimestamp, retryContent, 0, true, result.GroupID, nil) + if err != nil { + return fmt.Errorf("failed to send response: %w", err) + } + return nil +} diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index 4f54c81..b676d6c 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -48,7 +48,7 @@ const ( func (cli *Client) sendToGroupWithSenderKey( ctx context.Context, - groupID types.GroupIdentifier, + groupID *libsignalgo.GroupIdentifier, allRecipients []libsignalgo.ServiceID, sec SendEndorsementCache, content *signalpb.Content, @@ -56,7 +56,7 @@ func (cli *Client) sendToGroupWithSenderKey( retries int, ) (*GroupMessageSendResult, error) { if retries >= 3 { - return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, nil) + return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, nil, groupID) } myAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)) if err != nil { @@ -79,8 +79,9 @@ func (cli *Client) sendToGroupWithSenderKey( FailedToSendTo: make([]FailedSendResult, 0), } + groupIDStr := types.GroupIdentifier(groupID.String()) deviceIDs, senderKeyRecipients, fallbackRecipients := cli.getDevicesIDs(ctx, allRecipients, sec, result) - ski, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupID) + ski, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupIDStr) if err != nil { return nil, fmt.Errorf("failed to get sender key info: %w", err) } else if ski == nil || time.Since(ski.CreatedAt) > SenderKeyMaxAge { @@ -127,7 +128,7 @@ func (cli *Client) sendToGroupWithSenderKey( log := log.With().Str("subaction", "skdm").Stringer("recipient_id", recipient).Logger() _, err = cli.sendContent(log.WithContext(ctx), recipient, messageTimestamp, &signalpb.Content{ SenderKeyDistributionMessage: skdmBytes, - }, 0, true, true) + }, 0, true, groupID, nil) if errors.Is(err, ErrDevicesChanged) || errors.Is(err, ErrUnregisteredUser) { log.Warn().Err(err).Msg("Failed to send sender key distribution message due to device changes, will retry") needsRetry = true @@ -143,7 +144,7 @@ func (cli *Client) sendToGroupWithSenderKey( ski.SharedWith[recipient] = deviceIDs[recipient].DeviceIDs } } - err = cli.Store.SenderKeyStore.PutSenderKeyInfo(ctx, groupID, ski) + err = cli.Store.SenderKeyStore.PutSenderKeyInfo(ctx, groupIDStr, ski) if err != nil { return nil, fmt.Errorf("failed to store updated sender key info: %w", err) } @@ -156,6 +157,9 @@ func (cli *Client) sendToGroupWithSenderKey( if err != nil { return nil, err } + for recipientID := range ski.SharedWith { + cli.addSendCache(recipientID, groupIDStr, messageTimestamp, content) + } header := http.Header{} header.Set("Content-Type", string(web.ContentTypeMultiRecipientMessage)) if sec.SendEndorsement != nil { @@ -219,13 +223,13 @@ func (cli *Client) sendToGroupWithSenderKey( } doUnlock() // Send with fallback for any recipients that couldn't do sender key, plus our own sync copy - return cli.sendToGroup(ctx, fallbackRecipients, content, messageTimestamp, result) + return cli.sendToGroup(ctx, fallbackRecipients, content, messageTimestamp, result, groupID) case 401, 404: log.Warn().Uint32("status_code", resp.GetStatus()). Msg("Multi-recipient send failed, falling back to normal send") doUnlock() // Fall back to normal send for all recipients - return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, nil) + return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, nil, groupID) case 409, 410: log.Warn().Uint32("status_code", resp.GetStatus()). Msg("Multi-recipient send failed due to outdated device list, refreshing and retrying") @@ -243,7 +247,7 @@ func (cli *Client) sendToGroupWithSenderKey( func (cli *Client) encryptWithSenderKey( ctx context.Context, - groupID types.GroupIdentifier, + groupID *libsignalgo.GroupIdentifier, distributionID uuid.UUID, myAddress *libsignalgo.Address, senderKeyRecipients []store.SessionAddressTuple, @@ -265,11 +269,7 @@ func (cli *Client) encryptWithSenderKey( if err != nil { return nil, fmt.Errorf("failed to get sender certificate: %w", err) } - groupIDBytes, err := groupID.Bytes() - if err != nil { - return nil, fmt.Errorf("failed to deserialize group ID: %w", err) - } - usmc, err := libsignalgo.NewUnidentifiedSenderMessageContent(ciphertext, cert, getContentHint(content), groupIDBytes[:]) + usmc, err := libsignalgo.NewUnidentifiedSenderMessageContent(ciphertext, cert, getContentHint(content), groupID) if err != nil { return nil, fmt.Errorf("failed to create unidentified sender message content: %w", err) } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 97fdcdf..0ea55f9 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -147,7 +147,9 @@ func (cli *Client) buildMessagesToSend( ctx context.Context, recipient libsignalgo.ServiceID, content *signalpb.Content, - unauthenticated, isGroup bool, + unauthenticated bool, + groupID *libsignalgo.GroupIdentifier, + ctmOverride *libsignalgo.CiphertextMessage, ) ([]MyMessage, error) { if ctx.Value(contextKeyEncryptionLock) != true { cli.encryptionLock.Lock() @@ -179,26 +181,19 @@ func (cli *Client) buildMessagesToSend( continue } - // Build message payload serializedMessage, err := proto.Marshal(content) if err != nil { return nil, err } - paddedMessage, err := addPadding(3, serializedMessage) // TODO: figure out how to get actual version + paddedMessage, err := addPadding(3, serializedMessage) if err != nil { return nil, err } - var envelopeType int - var encryptedPayload []byte - if unauthenticated { - includeE164 := !isGroup && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY - envelopeType, encryptedPayload, err = cli.buildSSMessageToSend( - ctx, tuple.Address, paddedMessage, getContentHint(content), includeE164, - ) - } else { - envelopeType, encryptedPayload, err = cli.buildAuthedMessageToSend(ctx, tuple.Address, paddedMessage) - } + includeE164 := groupID == nil && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY + envelopeType, encryptedPayload, err := cli.buildMessageToSend( + ctx, tuple.Address, paddedMessage, getContentHint(content), ctmOverride, groupID, includeE164, unauthenticated, + ) if err != nil { return nil, err } @@ -208,7 +203,7 @@ func (cli *Client) buildMessagesToSend( return nil, err } outgoingMessage := MyMessage{ - Type: envelopeType, + Type: int(envelopeType), DestinationDeviceID: tuple.DeviceID, DestinationRegistrationID: int(destinationRegistrationID), Content: base64.StdEncoding.EncodeToString(encryptedPayload), @@ -219,54 +214,59 @@ func (cli *Client) buildMessagesToSend( return messages, nil } -func (cli *Client) buildAuthedMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte) (envelopeType int, encryptedPayload []byte, err error) { - cipherTextMessage, err := libsignalgo.Encrypt( - ctx, - paddedMessage, - recipientAddress, - cli.Store.ACISessionStore, - cli.Store.ACIIdentityStore, - ) - if err != nil { - return 0, nil, err +func ctmTypeToEnvelopeType(ctmType libsignalgo.CiphertextMessageType) signalpb.Envelope_Type { + switch ctmType { + case libsignalgo.CiphertextMessageTypeWhisper: + return signalpb.Envelope_CIPHERTEXT // 2 -> 1 + case libsignalgo.CiphertextMessageTypePreKey: + return signalpb.Envelope_PREKEY_BUNDLE // 3 -> 3 + case libsignalgo.CiphertextMessageTypeSenderKey: + return signalpb.Envelope_SENDERKEY_MESSAGE // 7 -> 7 + case libsignalgo.CiphertextMessageTypePlaintext: + return signalpb.Envelope_PLAINTEXT_CONTENT // 8 -> 8 + default: + return signalpb.Envelope_UNKNOWN } - encryptedPayload, err = cipherTextMessage.Serialize() - if err != nil { - return 0, nil, err - } - - // OMG Signal are you serious why can't your magic numbers just align - cipherMessageType, _ := cipherTextMessage.MessageType() - if cipherMessageType == libsignalgo.CiphertextMessageTypePreKey { // 3 -> 3 - envelopeType = int(signalpb.Envelope_PREKEY_BUNDLE) - } else if cipherMessageType == libsignalgo.CiphertextMessageTypeWhisper { // 2 -> 1 - envelopeType = int(signalpb.Envelope_CIPHERTEXT) - } else { - return 0, nil, fmt.Errorf("unknown message type: %v", cipherMessageType) - } - return envelopeType, encryptedPayload, nil } -func (cli *Client) buildSSMessageToSend(ctx context.Context, recipientAddress *libsignalgo.Address, paddedMessage []byte, contentHint libsignalgo.UnidentifiedSenderMessageContentHint, includeE164 bool) (envelopeType int, encryptedPayload []byte, err error) { +func (cli *Client) buildMessageToSend( + ctx context.Context, + recipientAddress *libsignalgo.Address, + paddedMessage []byte, + contentHint libsignalgo.UnidentifiedSenderMessageContentHint, + ciphertextMessage *libsignalgo.CiphertextMessage, + groupID *libsignalgo.GroupIdentifier, + includeE164, sealedSender bool, +) (envelopeType signalpb.Envelope_Type, encryptedPayload []byte, err error) { + if ciphertextMessage == nil { + ciphertextMessage, err = libsignalgo.Encrypt( + ctx, + paddedMessage, + recipientAddress, + cli.Store.ACISessionStore, + cli.Store.ACIIdentityStore, + ) + if err != nil { + return 0, nil, err + } + } + cipherMessageType, _ := ciphertextMessage.MessageType() + envelopeType = ctmTypeToEnvelopeType(cipherMessageType) + if !sealedSender { + encryptedPayload, err = ciphertextMessage.Serialize() + return + } cert, err := cli.senderCertificate(ctx, includeE164) if err != nil { return 0, nil, err } - encryptedPayload, err = libsignalgo.SealedSenderEncryptPlaintext( - ctx, - paddedMessage, - contentHint, - recipientAddress, - cert, - cli.Store.ACISessionStore, - cli.Store.ACIIdentityStore, - ) + usmc, err := libsignalgo.NewUnidentifiedSenderMessageContent(ciphertextMessage, cert, contentHint, groupID) if err != nil { return 0, nil, err } - envelopeType = int(signalpb.Envelope_UNIDENTIFIED_SENDER) - - return envelopeType, encryptedPayload, nil + encryptedPayload, err = libsignalgo.SealedSenderEncrypt(ctx, usmc, recipientAddress, cli.Store.ACIIdentityStore) + envelopeType = signalpb.Envelope_UNIDENTIFIED_SENDER + return } type SuccessfulSendResult struct { @@ -427,7 +427,7 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), }, }, - }, 0, false, false) + }, 0, false, nil, nil) if err != nil { log.Err(err).Msg("Failed to send contact sync request message to myself") return err @@ -447,7 +447,7 @@ func (cli *Client) SendStorageMasterKeyRequest(ctx context.Context) error { Type: signalpb.SyncMessage_Request_KEYS.Enum(), }, }, - }, 0, false, false) + }, 0, false, nil, nil) if err != nil { log.Err(err).Msg("Failed to send key sync request message to myself") return err @@ -502,11 +502,23 @@ func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { } } +func (cli *Client) addSendCache(recipient libsignalgo.ServiceID, groupID types.GroupIdentifier, ts uint64, content *signalpb.Content) { + cli.sendCache.Push(sendCacheKey{ + recipient: recipient, + groupID: groupID, + timestamp: ts, + }, content) +} + func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupContext *signalpb.GroupContextV2, groupChange *GroupChange) (*GroupMessageSendResult, error) { log := zerolog.Ctx(ctx).With(). Str("action", "send group change message"). Stringer("group_id", group.GroupIdentifier). Logger() + gidBytes, err := group.GroupIdentifier.Bytes() + if err != nil { + return nil, err + } ctx = log.WithContext(ctx) timestamp := currentMessageTimestamp() dm := &signalpb.DataMessage{ @@ -518,20 +530,24 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte for _, member := range group.Members { serviceID := member.UserServiceID() recipients = append(recipients, serviceID) + cli.addSendCache(serviceID, group.GroupIdentifier, timestamp, content) } for _, member := range group.PendingMembers { recipients = append(recipients, member.ServiceID) + cli.addSendCache(member.ServiceID, group.GroupIdentifier, timestamp, content) } if groupChange != nil { for _, member := range groupChange.AddPendingMembers { recipients = append(recipients, member.ServiceID) + cli.addSendCache(member.ServiceID, group.GroupIdentifier, timestamp, content) } for _, member := range groupChange.AddMembers { serviceID := member.UserServiceID() recipients = append(recipients, serviceID) + cli.addSendCache(serviceID, group.GroupIdentifier, timestamp, content) } } - return cli.sendToGroup(ctx, recipients, content, timestamp, nil) + return cli.sendToGroup(ctx, recipients, content, timestamp, nil, &gidBytes) } const enableSenderKeySend = true @@ -565,10 +581,14 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi for _, member := range group.Members { recipients = append(recipients, member.UserServiceID()) } - if enableSenderKeySend { - return cli.sendToGroupWithSenderKey(ctx, gid, recipients, ptr.Val(endorsement), content, messageTimestamp, 0) + gidBytes, err := gid.Bytes() + if err != nil { + return nil, err } - return cli.sendToGroup(ctx, recipients, content, messageTimestamp, nil) + if enableSenderKeySend { + return cli.sendToGroupWithSenderKey(ctx, &gidBytes, recipients, ptr.Val(endorsement), content, messageTimestamp, 0) + } + return cli.sendToGroup(ctx, recipients, content, messageTimestamp, nil, &gidBytes) } func (cli *Client) sendToGroup( @@ -577,6 +597,7 @@ func (cli *Client) sendToGroup( content *signalpb.Content, messageTimestamp uint64, result *GroupMessageSendResult, + groupID *libsignalgo.GroupIdentifier, ) (*GroupMessageSendResult, error) { if result == nil { result = &GroupMessageSendResult{ @@ -595,7 +616,7 @@ func (cli *Client) sendToGroup( } log := zerolog.Ctx(ctx).With().Stringer("member", recipient).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, recipient, messageTimestamp, content, 0, true, true) + sentUnidentified, err := cli.sendContent(ctx, recipient, messageTimestamp, content, 0, true, groupID, nil) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ Recipient: recipient, @@ -611,7 +632,7 @@ func (cli *Client) sendToGroup( } } - cli.sendGroupSyncCopy(ctx, content, messageTimestamp, result) + cli.sendGroupSyncCopy(ctx, content, messageTimestamp, result, groupID) if len(result.FailedToSendTo) == 0 && len(result.SuccessfullySentTo) == 0 { return result, nil // I only sent to myself @@ -629,6 +650,7 @@ func (cli *Client) sendGroupSyncCopy( content *signalpb.Content, messageTimestamp uint64, result *GroupMessageSendResult, + groupID *libsignalgo.GroupIdentifier, ) { var syncContent *signalpb.Content if content.GetDataMessage() != nil { @@ -637,7 +659,7 @@ func (cli *Client) sendGroupSyncCopy( syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) } if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true, true) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTimestamp, syncContent, 0, true, groupID, nil) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } @@ -656,7 +678,7 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, syncContent = content } if syncContent != nil { - _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, false) + _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, nil, nil) if selfSendErr != nil { zerolog.Ctx(ctx).Err(selfSendErr).Msg("Failed to send sync message to myself") } else { @@ -740,8 +762,9 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } } + cli.addSendCache(recipientID, "", messageTimestamp, content) // Send to the recipient - sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0, true, false) + sentUnidentified, err := cli.sendContent(ctx, recipientID, messageTimestamp, content, 0, true, nil, nil) if err != nil { return SendMessageResult{ WasSuccessful: false, @@ -793,8 +816,7 @@ func isUrgent(content *signalpb.Content) bool { func getContentHint(content *signalpb.Content) libsignalgo.UnidentifiedSenderMessageContentHint { if content.DataMessage != nil || content.EditMessage != nil { - // TODO add support for resending before setting this - //return libsignalgo.UnidentifiedSenderMessageContentHintResendable + return libsignalgo.UnidentifiedSenderMessageContentHintResendable } if content.TypingMessage != nil || content.ReceiptMessage != nil { return libsignalgo.UnidentifiedSenderMessageContentHintImplicit @@ -809,7 +831,8 @@ func (cli *Client) sendContent( content *signalpb.Content, retryCount int, useUnidentifiedSender bool, - isGroup bool, + groupID *libsignalgo.GroupIdentifier, + ctmOverride *libsignalgo.CiphertextMessage, ) (sentUnidentified bool, err error) { log := zerolog.Ctx(ctx).With(). Str("action", "send content"). @@ -862,7 +885,7 @@ func (cli *Client) sendContent( } var messages []MyMessage - messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, isGroup) + messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, groupID, ctmOverride) if err != nil { log.Err(err).Msg("Error building messages to send") return false, err @@ -934,7 +957,7 @@ func (cli *Client) sendContent( return false, err } // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, sentUnidentified, isGroup) + sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, sentUnidentified, groupID, ctmOverride) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err @@ -945,7 +968,7 @@ func (cli *Client) sendContent( } log.Debug().Msg("Retrying send without sealed sender") // Try to send again (**RECURSIVELY**) - sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, false, isGroup) + sentUnidentified, err = cli.sendContent(ctx, recipient, messageTimestamp, content, retryCount+1, false, groupID, ctmOverride) if err != nil { log.Err(err).Msg("2nd try sendMessage error") return sentUnidentified, err From bcc5917067dc8a1ed542d434200b517559fe7582 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 8 Dec 2025 23:34:32 +0200 Subject: [PATCH 621/718] libsignalgo: add debug for duplicate destinations in multi-recipient send --- pkg/libsignalgo/sealedsender.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 5327f1c..eb6f655 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -24,10 +24,14 @@ import "C" import ( "context" "fmt" + "maps" "runtime" + "slices" "unsafe" "github.com/google/uuid" + "github.com/rs/zerolog" + "go.mau.fi/util/exerrors" ) type SealedSenderAddress struct { @@ -98,10 +102,31 @@ func SealedSenderMultiRecipientEncrypt( defer callbackCtx.Unref() recipientAddresses := make([]C.SignalConstPointerProtocolAddress, len(recipients)) recipientSessions := make([]C.SignalConstPointerSessionRecord, len(recipients)) + + type dedupTuple struct { + Name string + DeviceID uint + } + deviceDedup := make(map[dedupTuple]struct{}) + var duplicateFound *dedupTuple + for i, recipient := range recipients { + name := exerrors.Must(recipient.Address.Name()) + deviceID := exerrors.Must(recipient.Address.DeviceID()) + dedupKey := dedupTuple{name, deviceID} + if _, exists := deviceDedup[dedupKey]; exists { + duplicateFound = &dedupKey + } recipientAddresses[i] = recipient.Address.constPtr() recipientSessions[i] = recipient.Record.constPtr() } + if duplicateFound != nil { + zerolog.Ctx(ctx).Debug(). + Any("full_list", slices.Collect(maps.Keys(deviceDedup))). + Any("last_duplicate", *duplicateFound). + Msg("Duplicate debug data") + return nil, fmt.Errorf("duplicate recipient addresses found in SealedSenderMultiRecipientEncrypt") + } signalFfiError := C.signal_sealed_sender_multi_recipient_encrypt( &encrypted, C.SignalBorrowedSliceOfConstPointerProtocolAddress{ From b661b30b851d6892915a94acf71d1522a43cbcfa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Dec 2025 00:14:50 +0200 Subject: [PATCH 622/718] commands: add command to reset sender key --- pkg/connector/commands.go | 73 ++++++++++++++++++++++++ pkg/connector/connector.go | 2 + pkg/signalmeow/senderkey.go | 18 ++++++ pkg/signalmeow/store/sender_key_store.go | 10 ++++ 4 files changed, 103 insertions(+) create mode 100644 pkg/connector/commands.go diff --git a/pkg/connector/commands.go b/pkg/connector/commands.go new file mode 100644 index 0000000..0be2370 --- /dev/null +++ b/pkg/connector/commands.go @@ -0,0 +1,73 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2025 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "errors" + + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/commands" + "maunium.net/go/mautrix/bridgev2/networkid" + + "go.mau.fi/mautrix-signal/pkg/signalid" +) + +var CmdDiscardSenderKey = &commands.FullHandler{ + Func: fnDiscardSenderKey, + Name: "discard-sender-key", + Help: commands.HelpMeta{ + Section: commands.HelpSectionChats, + Description: "Discard the Signal-side sender key in the current group", + Args: "[_login ID_]", + }, + RequiresPortal: true, + RequiresLogin: true, +} + +func fnDiscardSenderKey(ce *commands.Event) { + _, groupID, _ := signalid.ParsePortalID(ce.Portal.ID) + if groupID == "" { + ce.Reply("This command can only be used in group chat portals") + return + } + var login *bridgev2.UserLogin + if len(ce.Args) > 0 { + login = ce.Bridge.GetCachedUserLoginByID(networkid.UserLoginID(ce.Args[0])) + if login == nil || login.UserMXID != ce.User.MXID { + ce.Reply("Login not found") + return + } + } else { + var err error + login, _, err = ce.Portal.FindPreferredLogin(ce.Ctx, ce.User, false) + if errors.Is(err, bridgev2.ErrNotLoggedIn) { + ce.Reply("You're not logged in in this portal") + return + } else if err != nil { + ce.Log.Err(err).Msg("Failed to find preferred login for portal") + ce.Reply("Failed to find preferred login for portal") + return + } + } + distributionID, err := login.Client.(*SignalClient).Client.ResetSenderKey(ce.Ctx, groupID) + if err != nil { + ce.Log.Err(err).Msg("Failed to reset sender key") + ce.Reply("Failed to reset sender key") + } else { + ce.Reply("Reset sender key with distribution ID %s", distributionID) + } +} diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 59f8640..0debb30 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -26,6 +26,7 @@ import ( "go.mau.fi/util/dbutil" "go.mau.fi/util/exsync" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/commands" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -64,6 +65,7 @@ func (s *SignalConnector) Init(bridge *bridgev2.Bridge) { s.MsgConv.LocationFormat = s.Config.LocationFormat s.MsgConv.DisappearViewOnce = s.Config.DisappearViewOnce s.MsgConv.ExtEvPolls = s.Config.ExtEvPolls + bridge.Commands.(*commands.Processor).AddHandlers(CmdDiscardSenderKey) } func (s *SignalConnector) SetMaxFileSize(maxSize int64) { diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index b676d6c..1c0da8a 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -46,6 +46,24 @@ const ( contextKeyEncryptionLock contextKey = iota ) +func (cli *Client) ResetSenderKey(ctx context.Context, groupID types.GroupIdentifier) (uuid.UUID, error) { + cli.encryptionLock.Lock() + defer cli.encryptionLock.Unlock() + info, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupID) + if err != nil { + return uuid.Nil, fmt.Errorf("failed to get sender key info: %w", err) + } else if info == nil { + return uuid.Nil, nil + } else if myAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)); err != nil { + return uuid.Nil, fmt.Errorf("failed to get own address: %w", err) + } else if err = cli.Store.SenderKeyStore.DeleteSenderKey(ctx, myAddress, info.DistributionID); err != nil { + return info.DistributionID, fmt.Errorf("failed to delete sender key: %w", err) + } else if err = cli.Store.SenderKeyStore.DeleteSenderKeyInfo(ctx, groupID); err != nil { + return info.DistributionID, fmt.Errorf("failed to delete sender key info: %w", err) + } + return info.DistributionID, nil +} + func (cli *Client) sendToGroupWithSenderKey( ctx context.Context, groupID *libsignalgo.GroupIdentifier, diff --git a/pkg/signalmeow/store/sender_key_store.go b/pkg/signalmeow/store/sender_key_store.go index a38e389..1334066 100644 --- a/pkg/signalmeow/store/sender_key_store.go +++ b/pkg/signalmeow/store/sender_key_store.go @@ -34,6 +34,7 @@ type SenderKeyStore interface { libsignalgo.SenderKeyStore DeleteSenderKey(ctx context.Context, address *libsignalgo.Address, distributionID uuid.UUID) error GetSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier) (*SenderKeyInfo, error) + DeleteSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier) error PutSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier, info *SenderKeyInfo) error } @@ -55,6 +56,10 @@ const ( ON CONFLICT (account_id, group_id) DO UPDATE SET distribution_id=excluded.distribution_id, shared_with=excluded.shared_with ` + deleteSenderKeyInfoQuery = ` + DELETE FROM signalmeow_outbound_sender_key_info + WHERE account_id=$1 AND group_id=$2 + ` ) func scanSenderKey(row dbutil.Scannable) (*libsignalgo.SenderKeyRecord, error) { @@ -135,3 +140,8 @@ func (s *sqlStore) PutSenderKeyInfo(ctx context.Context, groupID types.GroupIden _, err := s.db.Exec(ctx, putSenderKeyInfoQuery, s.AccountID, groupID, info.DistributionID, dbutil.JSON{Data: info}) return err } + +func (s *sqlStore) DeleteSenderKeyInfo(ctx context.Context, groupID types.GroupIdentifier) error { + _, err := s.db.Exec(ctx, deleteSenderKeyInfoQuery, s.AccountID, groupID) + return err +} From 1d43ea8c003775ee9816c53b3cb89fc62dff22d9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Dec 2025 12:41:39 +0200 Subject: [PATCH 623/718] client: add connecting bridge state --- pkg/connector/client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 233ad91..c1ad75c 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -298,6 +298,9 @@ func (s *SignalClient) postLoginConnect() { } func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bool) { + if retryCount == 0 { + s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) + } ch, err := s.Client.StartReceiveLoops(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to start receive loops") From cb678dd2f0b7cc3929671830bf9f2606713a7d64 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 9 Dec 2025 16:42:57 +0200 Subject: [PATCH 624/718] handle*,chatinfo: implement new interface for message requests --- go.mod | 4 +- go.sum | 8 +-- pkg/connector/capabilities.go | 6 +- pkg/connector/chatinfo.go | 6 +- pkg/connector/handlematrix.go | 110 +++++++++++++++++++++++++++---- pkg/connector/handlesignal.go | 32 +++++++++ pkg/signalmeow/events/message.go | 29 +++++--- pkg/signalmeow/receiving.go | 26 ++++++++ pkg/signalmeow/sending.go | 7 +- 9 files changed, 194 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 35a4fb2..03c6635 100644 --- a/go.mod +++ b/go.mod @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.4-0.20251128195053-c7fab4d88a04 + go.mau.fi/util v0.9.4-0.20251206205611-85e6fd6551e0 golang.org/x/crypto v0.45.0 golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 golang.org/x/net v0.47.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251202132204-2eeece694254 + maunium.net/go/mautrix v0.26.1-0.20251209144156-31579be20ad8 ) require ( diff --git a/go.sum b/go.sum index cc4b594..e085181 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.4-0.20251128195053-c7fab4d88a04 h1:1xsqu1gqwLUBEolvrsURhj/A3e9GACg95i8gITI0Be0= -go.mau.fi/util v0.9.4-0.20251128195053-c7fab4d88a04/go.mod h1:viDmhBOAFfcqDdKSk53EPJV3N4Mi8Jst5/ahGJ/vwsA= +go.mau.fi/util v0.9.4-0.20251206205611-85e6fd6551e0 h1:ESebxPGULuuxxcZigjcBFyyU62tiyY6ivtX17P4BkvY= +go.mau.fi/util v0.9.4-0.20251206205611-85e6fd6551e0/go.mod h1:viDmhBOAFfcqDdKSk53EPJV3N4Mi8Jst5/ahGJ/vwsA= 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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= @@ -97,5 +97,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.26.1-0.20251202132204-2eeece694254 h1:rsc4H0sZVban6xQeIS6err1YangUiK5WzVfTS6s03ms= -maunium.net/go/mautrix v0.26.1-0.20251202132204-2eeece694254/go.mod h1:NaesYcOQWFDbixVYywCVS+Twlzab9hOUpFNlCBlvciE= +maunium.net/go/mautrix v0.26.1-0.20251209144156-31579be20ad8 h1:dbv3iOml42fzC9l1/M2nWPmUPhsesvMJJjgw9ArdnmQ= +maunium.net/go/mautrix v0.26.1-0.20251209144156-31579be20ad8/go.mod h1:pzwIT42s+BhBjEYovmcOt69VlNW2RkJ6pCyZjYQHKIc= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 97affb9..e791324 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_10_28" + base := "fi.mau.signal.capabilities.2025_12_09" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -171,6 +171,10 @@ var signalCaps = &event.RoomFeatures{ TypingNotifications: true, DeleteChat: true, + MessageRequest: &event.MessageRequestFeatures{ + AcceptWithMessage: event.CapLevelPartialSupport, + AcceptWithButton: event.CapLevelFullySupported, + }, } var signalDisappearingCap = &event.DisappearingTimerCapability{ diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index c8d6c2b..7e5a983 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -480,9 +480,9 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type Members: members, Type: ptr.Ptr(database.RoomTypeDM), - CanBackfill: backupChat != nil, - - ExtraUpdates: updatePortalSyncMeta, + MessageRequest: ptr.Ptr(recipient.ACI != uuid.Nil && recipient.NeedsPNISignature), + CanBackfill: backupChat != nil, + ExtraUpdates: updatePortalSyncMeta, }, } } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 25d3f53..0c47a08 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -43,18 +43,19 @@ import ( ) var ( - _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.DisappearTimerChangingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.DeleteChatHandlingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.PollHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.EditHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RedactionHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ReadReceiptHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.TypingHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomNameHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomAvatarHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.RoomTopicHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.ChatViewingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.DisappearTimerChangingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.DeleteChatHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.PollHandlingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.MessageRequestAcceptingNetworkAPI = (*SignalClient)(nil) ) func (s *SignalClient) sendMessage(ctx context.Context, portalID networkid.PortalID, content *signalpb.Content) error { @@ -705,6 +706,14 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2 return fmt.Errorf("failed to parse portal ID: %w", err) } + if msg.Content.FromMessageRequest { + // TODO block and delete support? + err = s.syncMessageRequestResponse(ctx, msg.Portal, signalpb.SyncMessage_MessageRequestResponse_DELETE) + if err != nil { + return fmt.Errorf("failed to send message request delete sync: %w", err) + } + } + // Build ConversationIdentifier based on portal type var conversationID *signalpb.ConversationIdentifier if groupID == "" { @@ -832,3 +841,80 @@ func (s *SignalClient) HandleMatrixPollVote(ctx context.Context, msg *bridgev2.M } return s.doSendMessage(ctx, &msg.MatrixMessage, converted, nil) } + +func (s *SignalClient) syncMessageRequestResponse( + ctx context.Context, + portal *bridgev2.Portal, + respType signalpb.SyncMessage_MessageRequestResponse_Type, +) error { + userID, groupID, err := signalid.ParsePortalID(portal.ID) + if err != nil { + return err + } + accept := &signalpb.SyncMessage_MessageRequestResponse{ + Type: respType.Enum(), + } + if groupID != "" { + gidBytes, err := groupID.Bytes() + if err != nil { + return fmt.Errorf("failed to parse group ID: %w", err) + } + accept.GroupId = gidBytes[:] + } else if userID.Type == libsignalgo.ServiceIDTypeACI { + accept.ThreadAci = ptr.Ptr(userID.UUID.String()) + } else { + return fmt.Errorf("invalid portal ID for message request response: %s", portal.ID) + } + res := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(s.Client.Store.ACI), &signalpb.Content{ + SyncMessage: &signalpb.SyncMessage{ + MessageRequestResponse: accept, + }, + }) + if !res.WasSuccessful { + return res.Error + } + return nil +} + +func (s *SignalClient) HandleMatrixAcceptMessageRequest(ctx context.Context, msg *bridgev2.MatrixAcceptMessageRequest) error { + userID, _, err := signalid.ParsePortalID(msg.Portal.ID) + if err != nil { + return err + } + err = s.syncMessageRequestResponse(ctx, msg.Portal, signalpb.SyncMessage_MessageRequestResponse_ACCEPT) + if err != nil { + return fmt.Errorf("failed to sync message request acceptance: %w", err) + } + if userID.Type == libsignalgo.ServiceIDTypeACI { + profileKey, err := s.Client.ProfileKeyForSignalID(ctx, s.Client.Store.ACI) + if err != nil { + return fmt.Errorf("failed to get own profile key: %w", err) + } + var pniSig *signalpb.PniSignatureMessage + if s.Client.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY { + sig, err := s.Client.Store.PNIIdentityKeyPair.SignAlternateIdentity(s.Client.Store.ACIIdentityKeyPair.GetIdentityKey()) + if err != nil { + return fmt.Errorf("failed to generate PNI signature: %w", err) + } + pniSig = &signalpb.PniSignatureMessage{ + Pni: s.Client.Store.PNI[:], + Signature: sig, + } + } + res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ + DataMessage: &signalpb.DataMessage{ + Flags: proto.Uint32(uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE)), + ProfileKey: profileKey.Slice(), + Timestamp: proto.Uint64(getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)), + + RequiredProtocolVersion: proto.Uint32(0), + }, + PniSignatureMessage: pniSig, + }) + if !res.WasSuccessful { + return fmt.Errorf("failed to share profile key to accept message request: %w", res.Error) + } + // TODO send read receipts too? + } + return nil +} diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 0293a53..6e0e302 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -26,6 +26,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exzerolog" + "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" @@ -52,6 +53,8 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) bool { return s.handleSignalReadSelf(evt) case *events.DeleteForMe: return s.handleSignalDeleteForMe(evt) + case *events.MessageRequestResponse: + return s.handleSignalMessageRequestResponse(evt) case *events.Call: return s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapCallEvent(evt)).Success case *events.ContactList: @@ -620,6 +623,35 @@ func (s *SignalClient) handleSignalDeleteForMe(evt *events.DeleteForMe) bool { return true } +func (s *SignalClient) handleSignalMessageRequestResponse(evt *events.MessageRequestResponse) bool { + if evt.Type != signalpb.SyncMessage_MessageRequestResponse_ACCEPT { + // TODO do we need to do anything with blocks/deletes here or are they sent as normal delete events? + return true + } + var portalKey networkid.PortalKey + if evt.GroupID != nil { + portalKey = s.makePortalKey(evt.GroupID.String()) + } else if evt.ThreadACI != uuid.Nil { + portalKey = s.makeDMPortalKey(libsignalgo.NewACIServiceID(evt.ThreadACI)) + } else { + return true + } + res := s.UserLogin.QueueRemoteEvent(&simplevent.ChatInfoChange{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatInfoChange, + PortalKey: portalKey, + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + StreamOrder: int64(evt.Timestamp), + }, + ChatInfoChange: &bridgev2.ChatInfoChange{ + ChatInfo: &bridgev2.ChatInfo{ + MessageRequest: ptr.Ptr(false), + }, + }, + }) + return res.Success +} + func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { log := s.UserLogin.Log.With(). Str("action", "handle aci found"). diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 0642c33..7d3732a 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -28,16 +28,17 @@ type SignalEvent interface { isSignalEvent() } -func (*ChatEvent) isSignalEvent() {} -func (*DecryptionError) isSignalEvent() {} -func (*Receipt) isSignalEvent() {} -func (*ReadSelf) isSignalEvent() {} -func (*Call) isSignalEvent() {} -func (*ContactList) isSignalEvent() {} -func (*ACIFound) isSignalEvent() {} -func (*DeleteForMe) isSignalEvent() {} -func (*QueueEmpty) isSignalEvent() {} -func (*LoggedOut) isSignalEvent() {} +func (*ChatEvent) isSignalEvent() {} +func (*DecryptionError) isSignalEvent() {} +func (*Receipt) isSignalEvent() {} +func (*ReadSelf) isSignalEvent() {} +func (*Call) isSignalEvent() {} +func (*ContactList) isSignalEvent() {} +func (*ACIFound) isSignalEvent() {} +func (*DeleteForMe) isSignalEvent() {} +func (*MessageRequestResponse) isSignalEvent() {} +func (*QueueEmpty) isSignalEvent() {} +func (*LoggedOut) isSignalEvent() {} type MessageInfo struct { Sender uuid.UUID @@ -89,6 +90,14 @@ type DeleteForMe struct { *signalpb.SyncMessage_DeleteForMe } +type MessageRequestResponse struct { + Timestamp uint64 + ThreadACI uuid.UUID + GroupID *libsignalgo.GroupIdentifier + Type signalpb.SyncMessage_MessageRequestResponse_Type + Raw *signalpb.SyncMessage_MessageRequestResponse +} + type QueueEmpty struct{} type LoggedOut struct{ Error error } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index b5ed96d..8cc0be7 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -778,6 +778,32 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess SyncMessage_DeleteForMe: msg.DeleteForMe, }) } + if msg.MessageRequestResponse != nil { + aciUUID, _ := uuid.Parse(msg.MessageRequestResponse.GetThreadAci()) + if aciUUID != uuid.Nil && msg.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT { + _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aciUUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { + if recipient.NeedsPNISignature { + recipient.NeedsPNISignature = false + return true, nil + } + return false, nil + }) + if err != nil { + log.Err(err).Msg("Failed to clear needs_pni_signature flag after message request accept") + } + } + var groupID *libsignalgo.GroupIdentifier + if len(msg.MessageRequestResponse.GroupId) == libsignalgo.GroupIdentifierLength { + groupID = (*libsignalgo.GroupIdentifier)(msg.MessageRequestResponse.GroupId) + } + handlerSuccess = cli.handleEvent(&events.MessageRequestResponse{ + Timestamp: envelope.GetTimestamp(), + ThreadACI: aciUUID, + GroupID: groupID, + Type: msg.MessageRequestResponse.GetType(), + Raw: msg.MessageRequestResponse, + }) + } return } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 0ea55f9..fa0818a 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -708,7 +708,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv isTypingOrReceipt := content.TypingMessage != nil || content.ReceiptMessage != nil recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { needsPNISignature = recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature - if needsPNISignature && !isTypingOrReceipt { + if needsPNISignature && !isTypingOrReceipt && content.PniSignatureMessage == nil { zerolog.Ctx(ctx).Debug(). Stringer("recipient", recipientID). Msg("Including PNI identity in message") @@ -722,6 +722,9 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv Signature: sig, } return true, nil + } else if needsPNISignature && content.PniSignatureMessage != nil { + recipientData.NeedsPNISignature = false + return true, nil } return false, nil }) @@ -842,7 +845,7 @@ func (cli *Client) sendContent( ctx = log.WithContext(ctx) // If it's a data message, add our profile key - if content.DataMessage != nil { + if content.DataMessage != nil && content.DataMessage.ProfileKey == nil { profileKey, err := cli.ProfileKeyForSignalID(ctx, cli.Store.ACI) if err != nil { log.Err(err).Msg("Error getting profile key, not adding to outgoing message") From 3b4b6cf753dffca4bf2f6015d16b8e312924985b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Dec 2025 18:30:00 +0200 Subject: [PATCH 625/718] msgconv/from-signal: fix panic if poll vote target isn't found --- pkg/msgconv/from-signal.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 9392616..c8ac40e 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -714,6 +714,9 @@ func (mc *MessageConverter) convertPollVoteToMatrix(ctx context.Context, vote *s if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get poll vote target message") return invalidPollVote + } else if pollMessage == nil { + zerolog.Ctx(ctx).Warn().Msg("Poll vote target message not found") + return invalidPollVote } mxOptionIDs := pollMessage.Metadata.(*signalid.MessageMetadata).MatrixPollOptionIDs optionIDs := make([]string, len(vote.GetOptionIndexes())) From c79057718a98a1c18089a8d3dc8daef6a7f120c1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 11 Dec 2025 14:18:00 +0200 Subject: [PATCH 626/718] libsignal: update to v0.86.8 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 5a64e17..ace4048 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 5a64e17ed4450eaf5fe29bfa611c9838736ac1a6 +Subproject commit ace404879f5dc146a512d88f696115715095a841 diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index dbb024d..f690184 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.86.4" +const Version = "v0.86.8" From 2c78df26384716d7c338a59d5f928395f8607089 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 11 Dec 2025 15:31:47 +0200 Subject: [PATCH 627/718] changelog: update --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f147c6..6785804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# v25.12 (unreleased) + +* Updated libsignal to v0.86.8. +* Added support for dropping incoming DMs from blocked contacts on Signal. +* Added support for sender key encryption when sending to groups, which makes + sending much faster and enables sending typing notifications. +* Added support for encryption retry receipts. +* Fixed bugs with handling poll votes. +* Fixed history transfer option not showing up when pairing with Signal Android. + # v25.11 * Updated libsignal to v0.86.4. From 7f8b0b7596566af3b973eaa9c7128e41861f7ed8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 11 Dec 2025 16:27:19 +0200 Subject: [PATCH 628/718] signalmeow/store: handle message request and unregistered status from backup --- pkg/signalmeow/store/backup_store.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/store/backup_store.go b/pkg/signalmeow/store/backup_store.go index fb5d5ff..2b1adf7 100644 --- a/pkg/signalmeow/store/backup_store.go +++ b/pkg/signalmeow/store/backup_store.go @@ -161,11 +161,13 @@ func (s *sqlStore) AddBackupRecipient(ctx context.Context, recipient *backuppb.R if dest.Contact.ProfileGivenName != nil || dest.Contact.ProfileFamilyName != nil { recipient.Profile.Name = strings.TrimSpace(fmt.Sprintf("%s %s", dest.Contact.GetProfileGivenName(), dest.Contact.GetProfileFamilyName())) } + recipient.NeedsPNISignature = dest.Contact.GetVisibility() == backuppb.Contact_HIDDEN_MESSAGE_REQUEST recipient.Blocked = dest.Contact.Blocked changed = oldRecipient.E164 != recipient.E164 || oldRecipient.Profile.Key != recipient.Profile.Key || oldRecipient.Profile.Name != recipient.Profile.Name || - oldRecipient.Blocked != recipient.Blocked + oldRecipient.Blocked != recipient.Blocked || + oldRecipient.NeedsPNISignature != recipient.NeedsPNISignature return }) if err != nil { @@ -177,6 +179,9 @@ func (s *sqlStore) AddBackupRecipient(ctx context.Context, recipient *backuppb.R Any("entry", dest.Contact). Msg("Both ACI and PNI are invalid for registered contact recipient") } + if aci != uuid.Nil { + s.MarkUnregistered(ctx, libsignalgo.NewACIServiceID(aci), dest.Contact.GetNotRegistered() != nil) + } case *backuppb.Recipient_Group: groupMasterKey = types.SerializedGroupMasterKey(base64.StdEncoding.EncodeToString(dest.Group.MasterKey)) if len(dest.Group.MasterKey) == libsignalgo.GroupMasterKeyLength { From e4ad808ad0b1f984a352affd401d634bd079f60c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 11 Dec 2025 16:28:39 +0200 Subject: [PATCH 629/718] dependencies: update --- go.mod | 20 ++++++++++---------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 03c6635..33f2f4d 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.24.0 -toolchain go1.25.4 +toolchain go1.25.5 tool go.mau.fi/util/cmd/maubuild @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.4-0.20251206205611-85e6fd6551e0 - golang.org/x/crypto v0.45.0 - golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 - golang.org/x/net v0.47.0 + go.mau.fi/util v0.9.4-0.20251211121531-f6527b4882ae + golang.org/x/crypto v0.46.0 + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 + golang.org/x/net v0.48.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251209144156-31579be20ad8 + maunium.net/go/mautrix v0.26.1-0.20251211121745-efd4136c7a93 ) require ( @@ -42,10 +42,10 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.13 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // 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 diff --git a/go.sum b/go.sum index e085181..090940f 100644 --- a/go.sum +++ b/go.sum @@ -65,27 +65,27 @@ 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.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.4-0.20251206205611-85e6fd6551e0 h1:ESebxPGULuuxxcZigjcBFyyU62tiyY6ivtX17P4BkvY= -go.mau.fi/util v0.9.4-0.20251206205611-85e6fd6551e0/go.mod h1:viDmhBOAFfcqDdKSk53EPJV3N4Mi8Jst5/ahGJ/vwsA= +go.mau.fi/util v0.9.4-0.20251211121531-f6527b4882ae h1:tocQOutgT+Z/V6w668Jpk3D5942K5p25XmRAvXg8s2E= +go.mau.fi/util v0.9.4-0.20251211121531-f6527b4882ae/go.mod h1:OwI76F1QINxtH/TOydGAAj5/VvtPG0RnZzB41rtnKcA= 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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -97,5 +97,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.26.1-0.20251209144156-31579be20ad8 h1:dbv3iOml42fzC9l1/M2nWPmUPhsesvMJJjgw9ArdnmQ= -maunium.net/go/mautrix v0.26.1-0.20251209144156-31579be20ad8/go.mod h1:pzwIT42s+BhBjEYovmcOt69VlNW2RkJ6pCyZjYQHKIc= +maunium.net/go/mautrix v0.26.1-0.20251211121745-efd4136c7a93 h1:IG8VJk3YT7N4yGVW5VnJiEt9rA3nKZNatXngxFbwhPs= +maunium.net/go/mautrix v0.26.1-0.20251211121745-efd4136c7a93/go.mod h1:tMXkJiGf+2dEPvfrmhQVD6jReL5E8jI1o2dPSsy/39Y= From b2dbdb684c162a8bc4e3f1c3443dea50571b2355 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 11 Dec 2025 17:53:48 +0200 Subject: [PATCH 630/718] signalmeow: store whitelisted flag and use it for message requests --- pkg/connector/chatinfo.go | 2 +- pkg/connector/client.go | 4 ++- pkg/connector/handlesignal.go | 25 +++++++++++++++++++ pkg/signalmeow/receiving.go | 19 ++++++++------ pkg/signalmeow/sending.go | 8 +++--- pkg/signalmeow/storageservice.go | 5 ++++ pkg/signalmeow/store/backup_store.go | 11 +++++--- pkg/signalmeow/store/recipient_store.go | 13 +++++++--- pkg/signalmeow/store/upgrades/00-latest.sql | 3 ++- .../upgrades/26-recipient-whitelisted.sql | 2 ++ pkg/signalmeow/types/contact.go | 5 ++++ 11 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/26-recipient-whitelisted.sql diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 7e5a983..081c6d3 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -480,7 +480,7 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type Members: members, Type: ptr.Ptr(database.RoomTypeDM), - MessageRequest: ptr.Ptr(recipient.ACI != uuid.Nil && recipient.NeedsPNISignature), + MessageRequest: ptr.Ptr(recipient.ACI != uuid.Nil && recipient.ProbablyMessageRequest()), CanBackfill: backupChat != nil, ExtraUpdates: updatePortalSyncMeta, }, diff --git a/pkg/connector/client.go b/pkg/connector/client.go index c1ad75c..fb77bb0 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -287,10 +287,12 @@ func (s *SignalClient) postLoginConnect() { s.tryConnect(ctx, 0, false) if s.Client.Store.EphemeralBackupKey != nil { go func() { - s.syncChats(ctx) if s.Client.Store.MasterKey != nil { s.Client.SyncStorage(ctx) + } else { + s.UserLogin.Log.Warn().Msg("No master key for storage sync before backup sync") } + s.syncChats(ctx) }() } else if s.Client.Store.MasterKey != nil { go s.Client.SyncStorage(ctx) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 6e0e302..0ad8555 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -642,6 +642,9 @@ func (s *SignalClient) handleSignalMessageRequestResponse(evt *events.MessageReq PortalKey: portalKey, Timestamp: time.UnixMilli(int64(evt.Timestamp)), StreamOrder: int64(evt.Timestamp), + LogContext: func(c zerolog.Context) zerolog.Context { + return c.Str("action", "unmark message request").Str("source", "sync message") + }, }, ChatInfoChange: &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ @@ -706,6 +709,28 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { if contact.ACI == s.Client.Store.ACI { s.updateRemoteProfile(ctx, true) } + if ptr.Val(contact.Whitelisted) { + portal, err := s.Main.Bridge.GetExistingPortalByKey(ctx, s.makeDMPortalKey(libsignalgo.NewACIServiceID(contact.ACI))) + if err != nil { + log.Err(err).Msg("Failed to get existing portal to update contact info") + continue + } else if portal != nil && portal.MessageRequest { + s.UserLogin.QueueRemoteEvent(&simplevent.ChatInfoChange{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatInfoChange, + LogContext: func(c zerolog.Context) zerolog.Context { + return c.Str("action", "unmark message request").Str("source", "contact list") + }, + PortalKey: portal.PortalKey, + }, + ChatInfoChange: &bridgev2.ChatInfoChange{ + ChatInfo: &bridgev2.ChatInfo{ + MessageRequest: ptr.Ptr(false), + }, + }, + }) + } + } } } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 8cc0be7..a836893 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -29,6 +29,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" + "go.mau.fi/util/ptr" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -562,12 +563,17 @@ func (cli *Client) handleDecryptedResult( if destinationServiceID == cli.Store.PNIServiceID() { _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { + if recipient.Whitelisted == nil { + log.Debug().Msg("Marking recipient as not whitelisted") + recipient.Whitelisted = ptr.Ptr(false) + changed = true + } if !recipient.NeedsPNISignature { log.Debug().Msg("Marking recipient as needing PNI signature") recipient.NeedsPNISignature = true - return true, nil + changed = true } - return false, nil + return }) if err != nil { log.Err(err).Msg("Failed to set needs_pni_signature flag after receiving message to PNI service ID") @@ -782,11 +788,10 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess aciUUID, _ := uuid.Parse(msg.MessageRequestResponse.GetThreadAci()) if aciUUID != uuid.Nil && msg.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT { _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aciUUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { - if recipient.NeedsPNISignature { - recipient.NeedsPNISignature = false - return true, nil - } - return false, nil + changed = !ptr.Val(recipient.Whitelisted) || recipient.NeedsPNISignature + recipient.Whitelisted = ptr.Ptr(true) + recipient.NeedsPNISignature = false + return }) if err != nil { log.Err(err).Msg("Failed to clear needs_pni_signature flag after message request accept") diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index fa0818a..9a523bd 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -698,7 +698,6 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } else { messageTimestamp = currentMessageTimestamp() } - needsPNISignature := false var aci, pni uuid.UUID if recipientID.Type == libsignalgo.ServiceIDTypeACI { aci = recipientID.UUID @@ -707,7 +706,10 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } isTypingOrReceipt := content.TypingMessage != nil || content.ReceiptMessage != nil recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { - needsPNISignature = recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature + if content.GetDataMessage().GetFlags() == uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE) { + recipientData.Whitelisted = ptr.Ptr(true) + } + needsPNISignature := recipientID.Type == libsignalgo.ServiceIDTypeACI && recipientData.NeedsPNISignature if needsPNISignature && !isTypingOrReceipt && content.PniSignatureMessage == nil { zerolog.Ctx(ctx).Debug(). Stringer("recipient", recipientID). @@ -732,7 +734,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv zerolog.Ctx(ctx).Err(err).Msg("Failed to get message recipient data") } // Treat needs PNI signature as "this is a message request" and don't send receipts/typing - if needsPNISignature && isTypingOrReceipt { + if recipientData.ProbablyMessageRequest() && isTypingOrReceipt { zerolog.Ctx(ctx).Debug().Msg("Not sending typing/receipt message to recipient as needs PNI signature flag is set") res := SuccessfulSendResult{Recipient: recipientID} if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 45a008e..97c3d26 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -30,6 +30,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exerrors" + "go.mau.fi/util/ptr" "golang.org/x/crypto/hkdf" "golang.org/x/exp/maps" "google.golang.org/protobuf/proto" @@ -103,6 +104,10 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat changed = true recipient.Blocked = contact.Blocked } + if !ptr.Val(recipient.Whitelisted) { + changed = true + recipient.Whitelisted = &contact.Whitelisted + } topLevelChanged = changed return }) diff --git a/pkg/signalmeow/store/backup_store.go b/pkg/signalmeow/store/backup_store.go index 2b1adf7..e99b110 100644 --- a/pkg/signalmeow/store/backup_store.go +++ b/pkg/signalmeow/store/backup_store.go @@ -161,13 +161,16 @@ func (s *sqlStore) AddBackupRecipient(ctx context.Context, recipient *backuppb.R if dest.Contact.ProfileGivenName != nil || dest.Contact.ProfileFamilyName != nil { recipient.Profile.Name = strings.TrimSpace(fmt.Sprintf("%s %s", dest.Contact.GetProfileGivenName(), dest.Contact.GetProfileFamilyName())) } - recipient.NeedsPNISignature = dest.Contact.GetVisibility() == backuppb.Contact_HIDDEN_MESSAGE_REQUEST + if dest.Contact.ProfileSharing && !ptr.Val(recipient.Whitelisted) { + recipient.Whitelisted = ptr.Ptr(true) + changed = true + } recipient.Blocked = dest.Contact.Blocked - changed = oldRecipient.E164 != recipient.E164 || + changed = changed || + oldRecipient.E164 != recipient.E164 || oldRecipient.Profile.Key != recipient.Profile.Key || oldRecipient.Profile.Name != recipient.Profile.Name || - oldRecipient.Blocked != recipient.Blocked || - oldRecipient.NeedsPNISignature != recipient.NeedsPNISignature + oldRecipient.Blocked != recipient.Blocked return }) if err != nil { diff --git a/pkg/signalmeow/store/recipient_store.go b/pkg/signalmeow/store/recipient_store.go index 98c7315..5f328be 100644 --- a/pkg/signalmeow/store/recipient_store.go +++ b/pkg/signalmeow/store/recipient_store.go @@ -67,7 +67,8 @@ const ( profile_avatar_path, profile_fetched_at, needs_pni_signature, - blocked + blocked, + whitelisted FROM signalmeow_recipients WHERE account_id = $1 ` @@ -93,9 +94,10 @@ const ( profile_avatar_path, profile_fetched_at, needs_pni_signature, - blocked + blocked, + whitelisted ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) ON CONFLICT (account_id, aci_uuid) DO UPDATE SET pni_uuid = excluded.pni_uuid, e164_number = excluded.e164_number, @@ -109,7 +111,8 @@ const ( profile_avatar_path = excluded.profile_avatar_path, profile_fetched_at = excluded.profile_fetched_at, needs_pni_signature = excluded.needs_pni_signature, - blocked = excluded.blocked + blocked = excluded.blocked, + whitelisted = excluded.whitelisted ` upsertPNIRecipientQuery = ` INSERT INTO signalmeow_recipients ( @@ -147,6 +150,7 @@ func scanRecipient(row dbutil.Scannable) (*types.Recipient, error) { &profileFetchedAt, &recipient.NeedsPNISignature, &recipient.Blocked, + &recipient.Whitelisted, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -371,6 +375,7 @@ func (s *sqlStore) StoreRecipient(ctx context.Context, recipient *types.Recipien dbutil.UnixMilliPtr(recipient.Profile.FetchedAt), recipient.NeedsPNISignature, recipient.Blocked, + recipient.Whitelisted, ) s.blockCacheLock.Lock() s.blockCache[recipient.ACI] = recipient.Blocked diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index dee3509..8f54eac 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v25 (compatible with v13+): Latest revision +-- v0 -> v26 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -127,6 +127,7 @@ CREATE TABLE signalmeow_recipients ( profile_fetched_at BIGINT, needs_pni_signature BOOLEAN NOT NULL DEFAULT false, blocked BOOLEAN NOT NULL DEFAULT false, + whitelisted BOOLEAN, CONSTRAINT signalmeow_contacts_account_id_fkey FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE, diff --git a/pkg/signalmeow/store/upgrades/26-recipient-whitelisted.sql b/pkg/signalmeow/store/upgrades/26-recipient-whitelisted.sql new file mode 100644 index 0000000..c61bf33 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/26-recipient-whitelisted.sql @@ -0,0 +1,2 @@ +-- v26 (compatible with v13+): Store whitelisted status for recipients +ALTER TABLE signalmeow_recipients ADD COLUMN whitelisted BOOLEAN; diff --git a/pkg/signalmeow/types/contact.go b/pkg/signalmeow/types/contact.go index bed25ac..889dd3e 100644 --- a/pkg/signalmeow/types/contact.go +++ b/pkg/signalmeow/types/contact.go @@ -56,6 +56,11 @@ type Recipient struct { NeedsPNISignature bool Blocked bool + Whitelisted *bool +} + +func (r *Recipient) ProbablyMessageRequest() bool { + return r != nil && (r.NeedsPNISignature || (r.Whitelisted != nil && !*r.Whitelisted)) } type ContactAvatar struct { From fe3c072cd1f71fe90739574cc446e3ae2a552bd6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Dec 2025 14:08:06 +0200 Subject: [PATCH 631/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 33f2f4d..2d6984d 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.48.0 google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251211121745-efd4136c7a93 + maunium.net/go/mautrix v0.26.1-0.20251213090909-cb6f673e7a70 ) require ( diff --git a/go.sum b/go.sum index 090940f..3bcf2a9 100644 --- a/go.sum +++ b/go.sum @@ -97,5 +97,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.26.1-0.20251211121745-efd4136c7a93 h1:IG8VJk3YT7N4yGVW5VnJiEt9rA3nKZNatXngxFbwhPs= -maunium.net/go/mautrix v0.26.1-0.20251211121745-efd4136c7a93/go.mod h1:tMXkJiGf+2dEPvfrmhQVD6jReL5E8jI1o2dPSsy/39Y= +maunium.net/go/mautrix v0.26.1-0.20251213090909-cb6f673e7a70 h1:qLTFD+r20eh81SaFUpgBhIsQkDSzUNJWcCQPx+WNnm0= +maunium.net/go/mautrix v0.26.1-0.20251213090909-cb6f673e7a70/go.mod h1:tMXkJiGf+2dEPvfrmhQVD6jReL5E8jI1o2dPSsy/39Y= From df733a3c77670cd6f8e5eb2a43f30863d088eb52 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Mon, 15 Dec 2025 19:46:57 +0100 Subject: [PATCH 632/718] signalmeow/storageservice: fix nickname clearing not being bridged (#623) --- pkg/signalmeow/storageservice.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 97c3d26..676fc7f 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -92,9 +92,13 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat changed = true recipient.ContactName = strings.TrimSpace(fmt.Sprintf("%s %s", contact.SystemGivenName, contact.SystemFamilyName)) } + newNickname := "" if contact.Nickname != nil { + newNickname = strings.TrimSpace(fmt.Sprintf("%s %s", contact.Nickname.Given, contact.Nickname.Family)) + } + if recipient.Nickname != newNickname { changed = true - recipient.Nickname = strings.TrimSpace(fmt.Sprintf("%s %s", contact.Nickname.Given, contact.Nickname.Family)) + recipient.Nickname = newNickname } if contact.E164 != "" { changed = changed || recipient.E164 != contact.E164 From 57865d0cf4cf10ece07a0a8b69394927e382de38 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 14 Dec 2025 14:38:49 +0200 Subject: [PATCH 633/718] docker: update to Alpine 3.23 --- Dockerfile | 4 ++-- Dockerfile.ci | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 162ac86..63e7542 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ COPY build-rust.sh . RUN ./build-rust.sh # -- Build mautrix-signal (with Go) -- -FROM golang:1-alpine3.22 AS go-builder +FROM golang:1-alpine3.23 AS go-builder RUN apk add --no-cache git ca-certificates build-base olm-dev zlib-dev WORKDIR /build @@ -32,7 +32,7 @@ EOF RUN ./build-go.sh # -- Run mautrix-signal -- -FROM alpine:3.22 +FROM alpine:3.23 ENV UID=1337 \ GID=1337 diff --git a/Dockerfile.ci b/Dockerfile.ci index 7d34502..ea2699f 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,6 +1,6 @@ ARG DOCKER_HUB="docker.io" -FROM ${DOCKER_HUB}/alpine:3.22 +FROM ${DOCKER_HUB}/alpine:3.23 ENV UID=1337 \ GID=1337 From 464b0601c173dd207e25c9218f11f39727193bfe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 16 Dec 2025 12:39:04 +0200 Subject: [PATCH 634/718] ci: update actions and pre-commit hooks --- .github/workflows/go.yml | 8 ++++---- .github/workflows/stale.yml | 2 +- .pre-commit-config.yaml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3913002..767c119 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -15,10 +15,10 @@ jobs: name: Lint ${{ matrix.go-version == '1.25' && '(latest)' || '(old)' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version: ${{ matrix.go-version }} cache: true @@ -44,10 +44,10 @@ jobs: name: Test ${{ matrix.go-version == '1.25' && '(latest)' || '(old)' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version: ${{ matrix.go-version }} cache: true diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c2003f3..c15f2fa 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -17,7 +17,7 @@ jobs: lock-stale: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v5 + - uses: dessant/lock-threads@v6 id: lock with: issue-inactive-days: 90 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6b3302..c9cc6a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: check-added-large-files - repo: https://github.com/tekwizely/pre-commit-golang - rev: v1.0.0-rc.2 + rev: v1.0.0-rc.4 hooks: - id: go-imports exclude: "pb\\.go$" From 1e4b47375c3707bbb36b6361560b3f0766a14875 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 16 Dec 2025 12:41:32 +0200 Subject: [PATCH 635/718] Bump version to v25.12 --- CHANGELOG.md | 8 +++++++- cmd/mautrix-signal/main.go | 2 +- go.mod | 8 ++++---- go.sum | 15 ++++++++------- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6785804..1a5d207 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,18 @@ -# v25.12 (unreleased) +# v25.12 * Updated libsignal to v0.86.8. +* Updated Docker image to Alpine 3.23. * Added support for dropping incoming DMs from blocked contacts on Signal. * Added support for sender key encryption when sending to groups, which makes sending much faster and enables sending typing notifications. * Added support for encryption retry receipts. * Fixed bugs with handling poll votes. * Fixed history transfer option not showing up when pairing with Signal Android. +* Fixed nicknames being cleared not being bridged + (thanks to [@Enzime] in [#623]). + +[#623]: https://github.com/mautrix/signal/pull/623 +[@Enzime]: https://github.com/Enzime # v25.11 diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index d224f32..130e307 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -37,7 +37,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "25.11", + Version: "25.12", SemCalVer: true, Connector: &connector.SignalConnector{}, diff --git a/go.mod b/go.mod index 2d6984d..f898ff1 100644 --- a/go.mod +++ b/go.mod @@ -14,18 +14,18 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.4-0.20251211121531-f6527b4882ae + go.mau.fi/util v0.9.4 golang.org/x/crypto v0.46.0 golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 golang.org/x/net v0.48.0 - google.golang.org/protobuf v1.36.10 + google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1-0.20251213090909-cb6f673e7a70 + maunium.net/go/mautrix v0.26.1 ) require ( filippo.io/edwards25519 v1.1.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/lib/pq v1.10.9 // indirect diff --git a/go.sum b/go.sum index 3bcf2a9..62da235 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,9 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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= @@ -65,8 +66,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.4-0.20251211121531-f6527b4882ae h1:tocQOutgT+Z/V6w668Jpk3D5942K5p25XmRAvXg8s2E= -go.mau.fi/util v0.9.4-0.20251211121531-f6527b4882ae/go.mod h1:OwI76F1QINxtH/TOydGAAj5/VvtPG0RnZzB41rtnKcA= +go.mau.fi/util v0.9.4 h1:gWdUff+K2rCynRPysXalqqQyr2ahkSWaestH6YhSpso= +go.mau.fi/util v0.9.4/go.mod h1:647nVfwUvuhlZFOnro3aRNPmRd2y3iDha9USb8aKSmM= 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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= @@ -86,8 +87,8 @@ golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -97,5 +98,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.26.1-0.20251213090909-cb6f673e7a70 h1:qLTFD+r20eh81SaFUpgBhIsQkDSzUNJWcCQPx+WNnm0= -maunium.net/go/mautrix v0.26.1-0.20251213090909-cb6f673e7a70/go.mod h1:tMXkJiGf+2dEPvfrmhQVD6jReL5E8jI1o2dPSsy/39Y= +maunium.net/go/mautrix v0.26.1 h1:FWCC1xY5vwJ5ou3duEBjB6w9IIlwfc9el3q3Mju3Dlg= +maunium.net/go/mautrix v0.26.1/go.mod h1:UySSpb8OqXG1sMJ6dDqyzmfcqr2ayZK+KzwqOTAkAOM= From 7fc0b062ee41673f25d849175a6086c2730ab585 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Wed, 17 Dec 2025 10:16:32 +0000 Subject: [PATCH 636/718] client: exit sleep during connect retry if context canceled --- pkg/connector/client.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index fb77bb0..e224c17 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -312,7 +312,12 @@ func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bo retryInSeconds = 150 } zerolog.Ctx(ctx).Debug().Int("retry_in_seconds", retryInSeconds).Msg("Sleeping and retrying connection") - time.Sleep(time.Duration(retryInSeconds) * time.Second) + select { + case <-time.After(time.Duration(retryInSeconds) * time.Second): + case <-ctx.Done(): + zerolog.Ctx(ctx).Info().Msg("Context canceled, exit tryConnect") + return + } s.tryConnect(ctx, retryCount+1, doSync) } else { go s.bridgeStateLoop(ch) From 28c03d8e0e69566d6339578a706441841d7e0ec1 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 21 Dec 2025 23:34:31 +0200 Subject: [PATCH 637/718] libsignalgo/sealedsender: remove unnecessary debug code --- pkg/libsignalgo/sealedsender.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index eb6f655..56ffe8b 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -24,14 +24,10 @@ import "C" import ( "context" "fmt" - "maps" "runtime" - "slices" "unsafe" "github.com/google/uuid" - "github.com/rs/zerolog" - "go.mau.fi/util/exerrors" ) type SealedSenderAddress struct { @@ -103,30 +99,10 @@ func SealedSenderMultiRecipientEncrypt( recipientAddresses := make([]C.SignalConstPointerProtocolAddress, len(recipients)) recipientSessions := make([]C.SignalConstPointerSessionRecord, len(recipients)) - type dedupTuple struct { - Name string - DeviceID uint - } - deviceDedup := make(map[dedupTuple]struct{}) - var duplicateFound *dedupTuple - for i, recipient := range recipients { - name := exerrors.Must(recipient.Address.Name()) - deviceID := exerrors.Must(recipient.Address.DeviceID()) - dedupKey := dedupTuple{name, deviceID} - if _, exists := deviceDedup[dedupKey]; exists { - duplicateFound = &dedupKey - } recipientAddresses[i] = recipient.Address.constPtr() recipientSessions[i] = recipient.Record.constPtr() } - if duplicateFound != nil { - zerolog.Ctx(ctx).Debug(). - Any("full_list", slices.Collect(maps.Keys(deviceDedup))). - Any("last_duplicate", *duplicateFound). - Msg("Duplicate debug data") - return nil, fmt.Errorf("duplicate recipient addresses found in SealedSenderMultiRecipientEncrypt") - } signalFfiError := C.signal_sealed_sender_multi_recipient_encrypt( &encrypted, C.SignalBorrowedSliceOfConstPointerProtocolAddress{ From e04ff8b0f6a72a6e202d554a61dc2cbf85718986 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 21 Dec 2025 23:34:49 +0200 Subject: [PATCH 638/718] signalmeow/senderkey: don't mutate recipient list when finding target devices --- pkg/signalmeow/senderkey.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index 1c0da8a..e8a0714 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -352,8 +352,8 @@ func (cli *Client) getDevicesIDs( ) { log := zerolog.Ctx(ctx) out := make(map[libsignalgo.ServiceID]senderKeySendMeta) - fallbackRecipients := recipients[:0] senderKeyRecipients := make([]store.SessionAddressTuple, 0, len(recipients)) + fallbackRecipients := make([]libsignalgo.ServiceID, 0) for _, recipient := range recipients { if recipient == cli.Store.ACIServiceID() { // We'll send a sync copy to ourselves, not sender key and no need to include in fallback recipients either From 189fb181cc33605d0c96629639093bd76f14636d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 24 Dec 2025 20:07:53 +0200 Subject: [PATCH 639/718] signalmeow/senderkey: fall back to normal send if there are no sender key recipients --- pkg/signalmeow/senderkey.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index e8a0714..096d524 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -99,6 +99,11 @@ func (cli *Client) sendToGroupWithSenderKey( groupIDStr := types.GroupIdentifier(groupID.String()) deviceIDs, senderKeyRecipients, fallbackRecipients := cli.getDevicesIDs(ctx, allRecipients, sec, result) + if len(senderKeyRecipients) == 0 { + doUnlock() + log.Debug().Msg("No sender key recipients, falling back to normal send") + return cli.sendToGroup(ctx, allRecipients, content, messageTimestamp, result, groupID) + } ski, err := cli.Store.SenderKeyStore.GetSenderKeyInfo(ctx, groupIDStr) if err != nil { return nil, fmt.Errorf("failed to get sender key info: %w", err) From f01385849b0988d42a0744970f41465733a73471 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 28 Dec 2025 20:14:46 +0200 Subject: [PATCH 640/718] signalmeow/receiving: save PNI identity keys from sync messages --- pkg/signalmeow/receiving.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index a836893..1b4dce0 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -722,6 +722,19 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess } } } + for _, unident := range syncSent.GetUnidentifiedStatus() { + changed, err := cli.saveSyncPNIIdentityKey(ctx, unident.GetDestinationServiceId(), unident.GetDestinationPniIdentityKey()) + if err != nil { + log.Err(err). + Str("destination_service_id", unident.GetDestinationServiceId()). + Msg("Failed to save PNI identity key from sync message") + } else if changed { + log.Debug(). + Str("destination_service_id", unident.GetDestinationServiceId()). + Msg("Saved new PNI identity key from sync message") + } + } + if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { log.Warn().Msg("sync message sent destination is nil") } else if msg.Sent.Message != nil { @@ -812,6 +825,27 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess return } +func (cli *Client) saveSyncPNIIdentityKey(ctx context.Context, serviceIDString string, identityKeyBytes []byte) (bool, error) { + if identityKeyBytes == nil { + return false, nil + } + identityKey, err := libsignalgo.DeserializeIdentityKey(identityKeyBytes) + if err != nil { + return false, fmt.Errorf("failed to deserialize PNI identity key: %w", err) + } + serviceID, err := libsignalgo.ServiceIDFromString(serviceIDString) + if err != nil { + return false, fmt.Errorf("failed to parse PNI service ID: %w", err) + } else if serviceID.Type != libsignalgo.ServiceIDTypePNI { + return false, nil + } + changed, err := cli.Store.IdentityKeyStore.SaveIdentityKey(ctx, serviceID, identityKey) + if err != nil { + return false, fmt.Errorf("failed to save PNI identity key: %w", err) + } + return changed, nil +} + func (cli *Client) handlePNISignatureMessage(ctx context.Context, sender libsignalgo.ServiceID, msg *signalpb.PniSignatureMessage) error { if sender.Type != libsignalgo.ServiceIDTypeACI { return fmt.Errorf("PNI signature message sender is not an ACI") From 71af50b90cbfff70126ef88cdfd8fb33528308b4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 30 Dec 2025 23:00:49 +0200 Subject: [PATCH 641/718] chatinfo,handlematrix: fix handling room avatars --- pkg/connector/chatinfo.go | 4 ++-- pkg/connector/handlematrix.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 081c6d3..4ce1f9d 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -326,9 +326,9 @@ func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCr } var avatarBytes []byte var avatarMXC id.ContentURIString - if params.Avatar != nil { + if params.Avatar != nil && params.Avatar.URL != "" { avatarMXC = params.Avatar.URL - avatarBytes, err = s.Main.Bridge.Bot.DownloadMedia(ctx, params.Avatar.URL, params.Avatar.MSC3414File) + avatarBytes, err = s.Main.Bridge.Bot.DownloadMedia(ctx, params.Avatar.URL, nil) if err != nil { return nil, fmt.Errorf("failed to download avatar: %w", err) } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 0c47a08..610dd81 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -381,8 +381,8 @@ func (s *SignalClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2 } var avatarPath string var avatarHash [32]byte - if msg.Content.URL != "" || msg.Content.MSC3414File != nil { - data, err := s.Main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, msg.Content.MSC3414File) + if msg.Content.URL != "" { + data, err := s.Main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, nil) if err != nil { return false, fmt.Errorf("failed to download avatar: %w", err) } From b33d7c82462fe882245f332f7f36a5515c4ec4ff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 5 Jan 2026 01:08:18 +0200 Subject: [PATCH 642/718] signalmeow/sending: fix typing message envelope timestamps in DMs --- pkg/signalmeow/sending.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 9a523bd..404571c 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -691,12 +691,22 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.ServiceID, content *signalpb.Content) SendMessageResult { // Assemble the content to send var messageTimestamp uint64 - if content.GetDataMessage() != nil { + switch { + case content.DataMessage != nil: messageTimestamp = *content.DataMessage.Timestamp - } else if content.GetEditMessage().GetDataMessage() != nil { + case content.EditMessage != nil: messageTimestamp = *content.EditMessage.DataMessage.Timestamp - } else { + case content.TypingMessage != nil: + messageTimestamp = *content.TypingMessage.Timestamp + case content.SyncMessage != nil, + content.NullMessage != nil, + content.ReceiptMessage != nil, + content.PniSignatureMessage != nil, + content.SenderKeyDistributionMessage != nil, + content.DecryptionErrorMessage != nil: messageTimestamp = currentMessageTimestamp() + default: + panic(fmt.Errorf("unsupported payload in SendMessage")) } var aci, pni uuid.UUID if recipientID.Type == libsignalgo.ServiceIDTypeACI { From 880849def7edfd54bfac41558e7a2d3d4dc7d2e7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Jan 2026 14:21:59 +0200 Subject: [PATCH 643/718] signalmeow/web: fix response bodies not being closed --- pkg/signalmeow/attachments.go | 5 +++++ pkg/signalmeow/groups.go | 5 +++++ pkg/signalmeow/profile.go | 2 +- pkg/signalmeow/storageservice.go | 4 +++- pkg/signalmeow/web/web.go | 8 +++++++- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 22884fe..6b78c68 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -225,6 +225,7 @@ func (cli *Client) uploadAttachmentLegacy( Username: &username, Password: &password, }) + web.CloseBody(resp) if err != nil { return fmt.Errorf("failed to send allocate request: %w", err) } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { @@ -239,6 +240,7 @@ func (cli *Client) uploadAttachmentLegacy( Username: &username, Password: &password, }) + web.CloseBody(resp) if err != nil { return fmt.Errorf("failed to send upload request: %w", err) } else if resp.StatusCode < 200 || resp.StatusCode >= 300 { @@ -262,6 +264,7 @@ func (cli *Client) uploadAttachmentTUS( ContentType: web.ContentTypeOffsetOctetStream, Headers: uploadAttributes.Headers, }) + web.CloseBody(resp) // TODO actually support resuming on error if err != nil { return fmt.Errorf("failed to send upload request: %w", err) @@ -309,6 +312,7 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi return "", err } body, err := io.ReadAll(resp.Body) + web.CloseBody(resp) if err != nil { log.Err(err).Msg("Error decoding response body fetching upload attributes") return "", err @@ -338,6 +342,7 @@ func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gi Body: requestBody.Bytes(), ContentType: web.ContentType(w.FormDataContentType()), }) + web.CloseBody(resp) if err != nil { log.Err(err).Msg("Error sending request uploading attachment") return "", err diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index d8ba4b3..d956fcc 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -637,6 +637,7 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t ContentType: web.ContentTypeProtobuf, } response, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodGet, "/v2/groups", opts) + defer web.CloseBody(response) if err != nil { return nil, err } @@ -689,6 +690,7 @@ func (cli *Client) DownloadGroupAvatar(ctx context.Context, avatarPath string, g Password: &password, } resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodGet, avatarPath, opts) + defer web.CloseBody(resp) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } @@ -1473,6 +1475,7 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh Body: requestBody, } resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodPatch, path, opts) + defer web.CloseBody(resp) if err != nil { return nil, fmt.Errorf("SendRequest error: %w", err) } @@ -1706,6 +1709,7 @@ func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Grou Body: requestBody, } resp, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodPut, path, opts) + defer web.CloseBody(resp) if err != nil { return nil, fmt.Errorf("SendRequest error: %w", err) } @@ -1776,6 +1780,7 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent // highest known epoch seems to always be 5, but that may change in the future. includeLastState is always false path := fmt.Sprintf("/v2/groups/logs/%d?maxSupportedChangeEpoch=%d&includeFirstState=%t&includeLastState=false", fromRevision, 5, includeFirstState) response, err := web.SendHTTPRequest(ctx, web.StorageHostname, http.MethodGet, path, opts) + defer web.CloseBody(response) if err != nil { return nil, err } diff --git a/pkg/signalmeow/profile.go b/pkg/signalmeow/profile.go index f40d6ce..a515f5a 100644 --- a/pkg/signalmeow/profile.go +++ b/pkg/signalmeow/profile.go @@ -287,7 +287,7 @@ func (cli *Client) DownloadUserAvatar(ctx context.Context, avatarPath string, pr if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } - defer resp.Body.Close() + defer web.CloseBody(resp) if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, fmt.Errorf("unexpected response status %d", resp.StatusCode) } diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index 676fc7f..fcf6848 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -257,6 +257,7 @@ func (cli *Client) fetchStorageManifest(ctx context.Context, storageKey []byte, Password: &storageCreds.Password, ContentType: web.ContentTypeProtobuf, }) + defer web.CloseBody(resp) if err != nil { return nil, fmt.Errorf("failed to fetch storage manifest: %w", err) } else if resp.StatusCode == http.StatusNoContent { @@ -363,11 +364,12 @@ func (cli *Client) fetchStorageItemsChunk(ctx context.Context, recordKeys [][]by Body: body, ContentType: web.ContentTypeProtobuf, }) + defer web.CloseBody(resp) if err != nil { return nil, fmt.Errorf("failed to fetch storage records: %w", err) } else if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code %d fetching storage records", resp.StatusCode) - } else if body, err := io.ReadAll(resp.Body); err != nil { + } else if body, err = io.ReadAll(resp.Body); err != nil { return nil, fmt.Errorf("failed to read storage manifest response: %w", err) } else if err = proto.Unmarshal(body, &storageItems); err != nil { return nil, fmt.Errorf("failed to unmarshal encrypted storage manifest: %w", err) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index f6c6743..e18ee5a 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -168,6 +168,12 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe return resp, nil } +func CloseBody(resp *http.Response) { + if resp != nil && resp.Body != nil { + _ = resp.Body.Close() + } +} + func DecodeWSResponseBody(ctx context.Context, out any, resp *signalpb.WebSocketResponseMessage) error { if resp == nil { return nil @@ -189,7 +195,7 @@ func DecodeWSResponseBody(ctx context.Context, out any, resp *signalpb.WebSocket // DecodeHTTPResponseBody checks status code, reads an http.Response's Body and decodes it into the provided interface. func DecodeHTTPResponseBody(ctx context.Context, out any, resp *http.Response) error { - defer resp.Body.Close() + defer CloseBody(resp) // Check if status code indicates success if resp.StatusCode < 200 || resp.StatusCode >= 300 { From a2264b2bcac4d262d408450c825c82bb80faedb8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 7 Jan 2026 15:23:42 +0200 Subject: [PATCH 644/718] client: only sync contacts on startup every 3 days --- pkg/connector/connector.go | 4 +++- pkg/connector/handlesignal.go | 6 ++++++ pkg/signalid/dbmeta.go | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 0debb30..f9bdd68 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -32,6 +32,7 @@ import ( "maunium.net/go/mautrix/id" "go.mau.fi/mautrix-signal/pkg/msgconv" + "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" ) @@ -101,7 +102,8 @@ func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.Use sc.UserLogin.Log.With().Str("component", "signalmeow").Logger(), sc.handleSignalEvent, ) - sc.Client.SyncContactsOnConnect = s.Config.SyncContactsOnStartup + sc.Client.SyncContactsOnConnect = s.Config.SyncContactsOnStartup && + time.Since(login.Metadata.(*signalid.UserLoginMetadata).LastContactSync.Time) > 3*24*time.Hour } login.Client = sc return nil diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 0ad8555..c9f16c1 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -26,6 +26,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exzerolog" + "go.mau.fi/util/jsontime" "go.mau.fi/util/ptr" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" @@ -732,6 +733,11 @@ func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { } } } + s.UserLogin.Metadata.(*signalid.UserLoginMetadata).LastContactSync = jsontime.UnixMilliNow() + err := s.UserLogin.Save(ctx) + if err != nil { + log.Err(err).Msg("Failed to update last contact sync time") + } } func (s *SignalClient) updateRemoteProfile(ctx context.Context, resendState bool) { diff --git a/pkg/signalid/dbmeta.go b/pkg/signalid/dbmeta.go index bbbcc92..8f42e6f 100644 --- a/pkg/signalid/dbmeta.go +++ b/pkg/signalid/dbmeta.go @@ -33,7 +33,8 @@ type MessageMetadata struct { } type UserLoginMetadata struct { - ChatsSynced bool `json:"chats_synced,omitempty"` + ChatsSynced bool `json:"chats_synced,omitempty"` + LastContactSync jsontime.UnixMilli `json:"last_contact_sync,omitempty"` } type GhostMetadata struct { From 9921199fa8ae7cf0e504ae54b8f30eabc8abfef7 Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Fri, 9 Jan 2026 12:08:09 +0000 Subject: [PATCH 645/718] signalmeow/web: expose websocket ping timeouts --- pkg/signalmeow/web/signalwebsocket.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 8a0c845..272acbb 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -37,6 +37,10 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/wspb" ) +var WebsocketPingInterval = 30 * time.Second +var WebsocketPingTimeout = 20 * time.Second +var WebsocketPingTimeoutLimit = 5 + const WebsocketProvisioningPath = "/v1/websocket/provisioning/" const WebsocketPath = "/v1/websocket/" @@ -342,20 +346,20 @@ func (s *SignalWebsocket) connectLoop( // Ping loop (send a keepalive Ping every 30s) go func() { defer wg.Done() - ticker := time.NewTicker(30 * time.Second) + ticker := time.NewTicker(WebsocketPingInterval) defer ticker.Stop() pingTimeoutCount := 0 for { select { case <-ticker.C: - pingCtx, cancel := context.WithTimeout(loopCtx, 20*time.Second) + pingCtx, cancel := context.WithTimeout(loopCtx, WebsocketPingTimeout) err := ws.Ping(pingCtx) cancel() if err != nil { pingTimeoutCount++ log.Err(err).Msg("Failed to send ping") - if pingTimeoutCount >= 5 { + if pingTimeoutCount >= WebsocketPingTimeoutLimit { log.Warn().Msg("Ping timeout count exceeded, closing websocket") err = ws.Close(websocket.StatusNormalClosure, "Ping timeout") if err != nil { From f62599145fe836e75835ede91b95400bf3a88f09 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Jan 2026 14:08:00 +0200 Subject: [PATCH 646/718] connector,signalmeow: implement network connection resetting (#629) --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/connector/connector.go | 23 ++++++++++++++++++++++ pkg/signalmeow/receiving.go | 5 +++++ pkg/signalmeow/web/signalwebsocket.go | 20 +++++++++++++++++++ pkg/signalmeow/web/web.go | 28 ++++----------------------- 6 files changed, 58 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index f898ff1..05dfac3 100644 --- a/go.mod +++ b/go.mod @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.4 + go.mau.fi/util v0.9.5-0.20260114152041-9f2e2b82b503 golang.org/x/crypto v0.46.0 golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 golang.org/x/net v0.48.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.1 + maunium.net/go/mautrix v0.26.2-0.20260115120200-34bcd027e54c ) require ( diff --git a/go.sum b/go.sum index 62da235..dfd2ccc 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.4 h1:gWdUff+K2rCynRPysXalqqQyr2ahkSWaestH6YhSpso= -go.mau.fi/util v0.9.4/go.mod h1:647nVfwUvuhlZFOnro3aRNPmRd2y3iDha9USb8aKSmM= +go.mau.fi/util v0.9.5-0.20260114152041-9f2e2b82b503 h1:L7ctH5wX8TrkZvIZmfxPkHQ1b8NZYw4fIr5WxXaewPw= +go.mau.fi/util v0.9.5-0.20260114152041-9f2e2b82b503/go.mod h1:647nVfwUvuhlZFOnro3aRNPmRd2y3iDha9USb8aKSmM= 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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= @@ -98,5 +98,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.26.1 h1:FWCC1xY5vwJ5ou3duEBjB6w9IIlwfc9el3q3Mju3Dlg= -maunium.net/go/mautrix v0.26.1/go.mod h1:UySSpb8OqXG1sMJ6dDqyzmfcqr2ayZK+KzwqOTAkAOM= +maunium.net/go/mautrix v0.26.2-0.20260115120200-34bcd027e54c h1:ZtJgvgFoH4hxNxFSavFXw7HUnjq49OyjxoEyGcjGk4k= +maunium.net/go/mautrix v0.26.2-0.20260115120200-34bcd027e54c/go.mod h1:vUvbzvY00Tbl8WjBdp5afvc69uIxujnfGHpAugxvR/Q= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index f9bdd68..0343d02 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -24,6 +24,7 @@ import ( "github.com/google/uuid" "go.mau.fi/util/dbutil" + "go.mau.fi/util/exhttp" "go.mau.fi/util/exsync" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/commands" @@ -35,6 +36,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/store" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" ) type SignalConnector struct { @@ -74,6 +76,7 @@ func (s *SignalConnector) SetMaxFileSize(maxSize int64) { } func (s *SignalConnector) Start(ctx context.Context) error { + s.ResetHTTPTransport() err := s.Store.Upgrade(ctx) if err != nil { return bridgev2.DBUpgradeError{Err: err, Section: "signalmeow"} @@ -81,6 +84,26 @@ func (s *SignalConnector) Start(ctx context.Context) error { return nil } +func (s *SignalConnector) ResetHTTPTransport() { + settings := exhttp.SensibleClientSettings + hs, ok := s.Bridge.Matrix.(bridgev2.MatrixConnectorWithHTTPSettings) + if ok { + settings = hs.GetHTTPClientSettings() + } + oldClient := web.SignalHTTPClient + web.SignalHTTPClient = settings.WithTLSConfig(web.SignalTLSConfig).Compile() + oldClient.CloseIdleConnections() +} + +func (s *SignalConnector) ResetNetworkConnections() { + for _, login := range s.Bridge.GetAllCachedUserLogins() { + c := login.Client.(*SignalClient) + if c.Client != nil { + c.Client.ForceReconnect() + } + } +} + func (s *SignalConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error { aci, err := uuid.Parse(string(login.ID)) if err != nil { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 1b4dce0..b802e06 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -280,6 +280,11 @@ func (cli *Client) StartReceiveLoops(ctx context.Context) (chan SignalConnection return statusChan, nil } +func (cli *Client) ForceReconnect() { + cli.AuthedWS.ForceReconnect() + cli.UnauthedWS.ForceReconnect() +} + func (cli *Client) StopReceiveLoops() error { defer func() { cli.AuthedWS = nil diff --git a/pkg/signalmeow/web/signalwebsocket.go b/pkg/signalmeow/web/signalwebsocket.go index 272acbb..a2153a1 100644 --- a/pkg/signalmeow/web/signalwebsocket.go +++ b/pkg/signalmeow/web/signalwebsocket.go @@ -59,6 +59,7 @@ type SignalWebsocket struct { closeEvt *exsync.Event closeCalled atomic.Bool cancel atomic.Pointer[context.CancelFunc] + cancelConn atomic.Pointer[context.CancelCauseFunc] } func NewSignalWebsocket(basicAuth *url.Userinfo) *SignalWebsocket { @@ -160,6 +161,19 @@ func (s *SignalWebsocket) pushOutgoing(ctx context.Context, send SignalWebsocket } } +var ErrForcedReconnect = errors.New("forced reconnect") + +func (s *SignalWebsocket) ForceReconnect() { + if s == nil { + return + } + cancelFn := s.cancelConn.Load() + if cancelFn == nil { + return + } + (*cancelFn)(ErrForcedReconnect) +} + func (s *SignalWebsocket) connectLoop( ctx context.Context, requestHandler RequestHandlerFunc, @@ -312,6 +326,7 @@ func (s *SignalWebsocket) connectLoop( responseChannels := exsync.NewMap[uint64, chan *signalpb.WebSocketResponseMessage]() loopCtx, loopCancel := context.WithCancelCause(ctx) + s.cancelConn.Store(&loopCancel) var wg sync.WaitGroup wg.Add(3) @@ -389,6 +404,11 @@ func (s *SignalWebsocket) connectLoop( } else { errorCount++ s.pushStatus(ctx, SignalWebsocketConnectionEventDisconnected, ctxCauseErr) + if errors.Is(ctxCauseErr, ErrForcedReconnect) { + // Skip the delay for forced reconnects + // TODO should the delay be lowered globally? + isFirstConnect = true + } } // Clean up diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index e18ee5a..d0fcd01 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -26,8 +26,6 @@ import ( "fmt" "io" "net/http" - "net/url" - "os" "runtime" "strings" @@ -37,9 +35,6 @@ import ( signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) -const proxyUrlStr = "" // Set this to proxy requests -const caCertPath = "" // Set this to trust a self-signed cert (ie. for mitmproxy) - var BaseUserAgent = "libsignal/" + libsignalgo.Version + " go/" + strings.TrimPrefix(runtime.Version(), "go") var UserAgent = "signalmeow/0.1.0 " + BaseUserAgent var SignalAgent = "MAU" @@ -61,11 +56,11 @@ var CDNHosts = []string{ //go:embed signal-root.crt.der var signalRootCertBytes []byte +var SignalCertPool = x509.NewCertPool() +var SignalTLSConfig = &tls.Config{RootCAs: SignalCertPool} var signalTransport = &http.Transport{ ForceAttemptHTTP2: true, - TLSClientConfig: &tls.Config{ - RootCAs: x509.NewCertPool(), - }, + TLSClientConfig: SignalTLSConfig, } var SignalHTTPClient = &http.Client{ Transport: signalTransport, @@ -76,22 +71,7 @@ func init() { if err != nil { panic(err) } - signalTransport.TLSClientConfig.RootCAs.AddCert(cert) - - if proxyUrlStr != "" { - proxyURL, err := url.Parse(proxyUrlStr) - if err != nil { - panic(err) - } - signalTransport.Proxy = http.ProxyURL(proxyURL) - } - if caCertPath != "" { - caCert, err := os.ReadFile(caCertPath) - if err != nil { - panic(err) - } - signalTransport.TLSClientConfig.RootCAs.AppendCertsFromPEM(caCert) - } + SignalCertPool.AddCert(cert) } type ContentType string From d19f3bdce3fdfc94aeaaea66eb9a3bcdc6555746 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Jan 2026 15:01:48 +0200 Subject: [PATCH 647/718] libsignal: update to v0.86.12 --- pkg/libsignalgo/error.go | 107 +++++++++--- pkg/libsignalgo/groupcipher.go | 2 +- pkg/libsignalgo/kyberprekeystore.go | 35 ++-- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 154 ++++++++++++------ .../senderkeydistributionmessage.go | 2 +- pkg/libsignalgo/serviceid.go | 6 - pkg/libsignalgo/version.go | 2 +- 8 files changed, 209 insertions(+), 101 deletions(-) diff --git a/pkg/libsignalgo/error.go b/pkg/libsignalgo/error.go index b0d79c8..b25130b 100644 --- a/pkg/libsignalgo/error.go +++ b/pkg/libsignalgo/error.go @@ -27,33 +27,86 @@ import ( type ErrorCode int const ( - ErrorCodeUnknownError ErrorCode = 1 - ErrorCodeInvalidState ErrorCode = 2 - ErrorCodeInternalError ErrorCode = 3 - ErrorCodeNullParameter ErrorCode = 4 - ErrorCodeInvalidArgument ErrorCode = 5 - ErrorCodeInvalidType ErrorCode = 6 - ErrorCodeInvalidUtf8String ErrorCode = 7 - ErrorCodeProtobufError ErrorCode = 10 - ErrorCodeLegacyCiphertextVersion ErrorCode = 21 - ErrorCodeUnknownCiphertextVersion ErrorCode = 22 - ErrorCodeUnrecognizedMessageVersion ErrorCode = 23 - ErrorCodeInvalidMessage ErrorCode = 30 - ErrorCodeSealedSenderSelfSend ErrorCode = 31 - ErrorCodeInvalidKey ErrorCode = 40 - ErrorCodeInvalidSignature ErrorCode = 41 - ErrorCodeInvalidAttestationData ErrorCode = 42 - ErrorCodeFingerprintVersionMismatch ErrorCode = 51 - ErrorCodeFingerprintParsingError ErrorCode = 52 - ErrorCodeUntrustedIdentity ErrorCode = 60 - ErrorCodeInvalidKeyIdentifier ErrorCode = 70 - ErrorCodeSessionNotFound ErrorCode = 80 - ErrorCodeInvalidRegistrationId ErrorCode = 81 - ErrorCodeInvalidSession ErrorCode = 82 - ErrorCodeInvalidSenderKeySession ErrorCode = 83 - ErrorCodeDuplicatedMessage ErrorCode = 90 - ErrorCodeCallbackError ErrorCode = 100 - ErrorCodeVerificationFailure ErrorCode = 110 + ErrorCodeUnknownError ErrorCode = 1 + ErrorCodeInvalidState ErrorCode = 2 + ErrorCodeInternalError ErrorCode = 3 + ErrorCodeNullParameter ErrorCode = 4 + ErrorCodeInvalidArgument ErrorCode = 5 + ErrorCodeInvalidType ErrorCode = 6 + ErrorCodeInvalidUtf8String ErrorCode = 7 + ErrorCodeCancelled ErrorCode = 8 + ErrorCodeProtobufError ErrorCode = 10 + ErrorCodeLegacyCiphertextVersion ErrorCode = 21 + ErrorCodeUnknownCiphertextVersion ErrorCode = 22 + ErrorCodeUnrecognizedMessageVersion ErrorCode = 23 + ErrorCodeInvalidMessage ErrorCode = 30 + ErrorCodeSealedSenderSelfSend ErrorCode = 31 + ErrorCodeInvalidKey ErrorCode = 40 + ErrorCodeInvalidSignature ErrorCode = 41 + ErrorCodeInvalidAttestationData ErrorCode = 42 + ErrorCodeFingerprintVersionMismatch ErrorCode = 51 + ErrorCodeFingerprintParsingError ErrorCode = 52 + ErrorCodeUntrustedIdentity ErrorCode = 60 + ErrorCodeInvalidKeyIdentifier ErrorCode = 70 + ErrorCodeSessionNotFound ErrorCode = 80 + ErrorCodeInvalidRegistrationId ErrorCode = 81 + ErrorCodeInvalidSession ErrorCode = 82 + ErrorCodeInvalidSenderKeySession ErrorCode = 83 + ErrorCodeInvalidProtocolAddress ErrorCode = 84 + ErrorCodeDuplicatedMessage ErrorCode = 90 + ErrorCodeCallbackError ErrorCode = 100 + ErrorCodeVerificationFailure ErrorCode = 110 + ErrorCodeUsernameCannotBeEmpty ErrorCode = 120 + ErrorCodeUsernameCannotStartWithDigit ErrorCode = 121 + ErrorCodeUsernameMissingSeparator ErrorCode = 122 + ErrorCodeUsernameBadDiscriminatorCharacter ErrorCode = 123 + ErrorCodeUsernameBadNicknameCharacter ErrorCode = 124 + ErrorCodeUsernameTooShort ErrorCode = 125 + ErrorCodeUsernameTooLong ErrorCode = 126 + ErrorCodeUsernameLinkInvalidEntropyDataLength ErrorCode = 127 + ErrorCodeUsernameLinkInvalid ErrorCode = 128 + ErrorCodeUsernameDiscriminatorCannotBeEmpty ErrorCode = 130 + ErrorCodeUsernameDiscriminatorCannotBeZero ErrorCode = 131 + ErrorCodeUsernameDiscriminatorCannotBeSingleDigit ErrorCode = 132 + ErrorCodeUsernameDiscriminatorCannotHaveLeadingZeros ErrorCode = 133 + ErrorCodeUsernameDiscriminatorTooLarge ErrorCode = 134 + ErrorCodeIoError ErrorCode = 140 + ErrorCodeInvalidMediaInput ErrorCode = 141 + ErrorCodeUnsupportedMediaInput ErrorCode = 142 + ErrorCodeConnectionTimedOut ErrorCode = 143 + ErrorCodeNetworkProtocol ErrorCode = 144 + ErrorCodeRateLimited ErrorCode = 145 + ErrorCodeWebSocket ErrorCode = 146 + ErrorCodeCdsiInvalidToken ErrorCode = 147 + ErrorCodeConnectionFailed ErrorCode = 148 + ErrorCodeChatServiceInactive ErrorCode = 149 + ErrorCodeRequestTimedOut ErrorCode = 150 + ErrorCodeRateLimitChallenge ErrorCode = 151 + ErrorCodePossibleCaptiveNetwork ErrorCode = 152 + ErrorCodeSvrDataMissing ErrorCode = 160 + ErrorCodeSvrRestoreFailed ErrorCode = 161 + ErrorCodeSvrRotationMachineTooManySteps ErrorCode = 162 + ErrorCodeSvrRequestFailed ErrorCode = 163 + ErrorCodeAppExpired ErrorCode = 170 + ErrorCodeDeviceDeregistered ErrorCode = 171 + ErrorCodeConnectionInvalidated ErrorCode = 172 + ErrorCodeConnectedElsewhere ErrorCode = 173 + ErrorCodeBackupValidation ErrorCode = 180 + ErrorCodeRegistrationInvalidSessionId ErrorCode = 190 + ErrorCodeRegistrationUnknown ErrorCode = 192 + ErrorCodeRegistrationSessionNotFound ErrorCode = 193 + ErrorCodeRegistrationNotReadyForVerification ErrorCode = 194 + ErrorCodeRegistrationSendVerificationCodeFailed ErrorCode = 195 + ErrorCodeRegistrationCodeNotDeliverable ErrorCode = 196 + ErrorCodeRegistrationSessionUpdateRejected ErrorCode = 197 + ErrorCodeRegistrationCredentialsCouldNotBeParsed ErrorCode = 198 + ErrorCodeRegistrationDeviceTransferPossible ErrorCode = 199 + ErrorCodeRegistrationRecoveryVerificationFailed ErrorCode = 200 + ErrorCodeRegistrationLock ErrorCode = 201 + ErrorCodeKeyTransparencyError ErrorCode = 210 + ErrorCodeKeyTransparencyVerificationFailed ErrorCode = 211 + ErrorCodeRequestUnauthorized ErrorCode = 220 + ErrorCodeMismatchedDevices ErrorCode = 221 ) type SignalError struct { diff --git a/pkg/libsignalgo/groupcipher.go b/pkg/libsignalgo/groupcipher.go index 7b58207..9ec5997 100644 --- a/pkg/libsignalgo/groupcipher.go +++ b/pkg/libsignalgo/groupcipher.go @@ -36,7 +36,7 @@ func GroupEncrypt(ctx context.Context, ptext []byte, sender *Address, distributi signalFfiError := C.signal_group_encrypt_message( &ciphertextMessage, sender.constPtr(), - (*[C.SignalUUID_LEN]C.uchar)(unsafe.Pointer(&distributionID)), + *(*C.SignalUuid)(unsafe.Pointer(&distributionID)), BytesToBuffer(ptext), callbackCtx.wrapSenderKeyStore(store)) runtime.KeepAlive(ptext) diff --git a/pkg/libsignalgo/kyberprekeystore.go b/pkg/libsignalgo/kyberprekeystore.go index 072db99..ebb5a9f 100644 --- a/pkg/libsignalgo/kyberprekeystore.go +++ b/pkg/libsignalgo/kyberprekeystore.go @@ -20,11 +20,10 @@ package libsignalgo /* #include "./libsignal-ffi.h" -typedef const SignalKyberPreKeyRecord const_kyber_pre_key_record; - -extern int signal_load_kyber_pre_key_callback(void *store_ctx, SignalKyberPreKeyRecord **recordp, uint32_t id); -extern int signal_store_kyber_pre_key_callback(void *store_ctx, uint32_t id, const_kyber_pre_key_record *record); -extern int signal_mark_kyber_pre_key_used_callback(void *store_ctx, uint32_t id); +extern int signal_load_kyber_pre_key_callback(void *store_ctx, SignalMutPointerKyberPreKeyRecord *recordp, uint32_t id); +extern int signal_store_kyber_pre_key_callback(void *store_ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); +extern int signal_mark_kyber_pre_key_used_callback(void *store_ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); +extern void signal_destroy_kyber_pre_key_store_callback(void *store_ctx); */ import "C" import ( @@ -39,21 +38,21 @@ type KyberPreKeyStore interface { } //export signal_load_kyber_pre_key_callback -func signal_load_kyber_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalKyberPreKeyRecord, id C.uint32_t) C.int { +func signal_load_kyber_pre_key_callback(storeCtx unsafe.Pointer, keyp *C.SignalMutPointerKyberPreKeyRecord, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store KyberPreKeyStore, ctx context.Context) error { key, err := store.LoadKyberPreKey(ctx, uint32(id)) if err == nil && key != nil { key.CancelFinalizer() - *keyp = key.ptr + keyp.raw = key.ptr } return err }) } //export signal_store_kyber_pre_key_callback -func signal_store_kyber_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord *C.const_kyber_pre_key_record) C.int { +func signal_store_kyber_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord C.SignalMutPointerKyberPreKeyRecord) C.int { return wrapStoreCallback(storeCtx, func(store KyberPreKeyStore, ctx context.Context) error { - record := KyberPreKeyRecord{ptr: (*C.SignalKyberPreKeyRecord)(unsafe.Pointer(preKeyRecord))} + record := KyberPreKeyRecord{ptr: preKeyRecord.raw} cloned, err := record.Clone() if err != nil { return err @@ -63,18 +62,24 @@ func signal_store_kyber_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, } //export signal_mark_kyber_pre_key_used_callback -func signal_mark_kyber_pre_key_used_callback(storeCtx unsafe.Pointer, id C.uint32_t) C.int { +func signal_mark_kyber_pre_key_used_callback(storeCtx unsafe.Pointer, id C.uint32_t, ecPrekeyID C.uint32_t, baseKey C.SignalMutPointerPublicKey) C.int { return wrapStoreCallback(storeCtx, func(store KyberPreKeyStore, ctx context.Context) error { - err := store.MarkKyberPreKeyUsed(ctx, uint32(id)) - return err + // TODO use ecPrekeyID and baseKey? + return store.MarkKyberPreKeyUsed(ctx, uint32(id)) }) } +//export signal_destroy_kyber_pre_key_store_callback +func signal_destroy_kyber_pre_key_store_callback(storeCtx unsafe.Pointer) { + // No-op: Go's garbage collector handles cleanup +} + func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) C.SignalConstPointerFfiKyberPreKeyStoreStruct { return C.SignalConstPointerFfiKyberPreKeyStoreStruct{&C.SignalKyberPreKeyStore{ ctx: wrapStore(ctx, store), - load_kyber_pre_key: C.SignalLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), - store_kyber_pre_key: C.SignalStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), - mark_kyber_pre_key_used: C.SignalMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), + load_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), + store_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), + mark_kyber_pre_key_used: C.SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), + destroy: C.SignalFfiBridgeKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index ace4048..0480b16 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit ace404879f5dc146a512d88f696115715095a841 +Subproject commit 0480b16ac3c4ca9d641bc160b1b231f89d2e5fe3 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 26cbb6b..e2ddc02 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -233,6 +233,7 @@ typedef enum { SignalErrorCodeChatServiceInactive = 149, SignalErrorCodeRequestTimedOut = 150, SignalErrorCodeRateLimitChallenge = 151, + SignalErrorCodePossibleCaptiveNetwork = 152, SignalErrorCodeSvrDataMissing = 160, SignalErrorCodeSvrRestoreFailed = 161, SignalErrorCodeSvrRotationMachineTooManySteps = 162, @@ -341,6 +342,8 @@ typedef struct SignalPrivateKey SignalPrivateKey; */ typedef struct SignalProtocolAddress SignalProtocolAddress; +typedef struct SignalProvisioningChatConnection SignalProvisioningChatConnection; + typedef struct SignalPublicKey SignalPublicKey; typedef struct SignalRegisterAccountRequest SignalRegisterAccountRequest; @@ -511,9 +514,13 @@ typedef struct { SignalChatConnectionInfo *raw; } SignalMutPointerChatConnectionInfo; -typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envelope, uint64_t timestamp_millis, SignalServerMessageAck *cleanup); +typedef struct { + SignalServerMessageAck *raw; +} SignalMutPointerServerMessageAck; -typedef void (*SignalReceivedQueueEmpty)(void *ctx); +typedef int (*SignalFfiChatListenerReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envelope, uint64_t timestamp, SignalMutPointerServerMessageAck ack); + +typedef int (*SignalFfiChatListenerReceivedQueueEmpty)(void *ctx); /** * A representation of a array allocated on the Rust heap for use in C code. @@ -533,34 +540,19 @@ typedef struct { typedef SignalBytestringArray SignalStringArray; -typedef void (*SignalReceivedAlerts)(void *ctx, SignalStringArray alerts); +typedef int (*SignalFfiChatListenerReceivedAlerts)(void *ctx, SignalStringArray alerts); -typedef void (*SignalConnectionInterrupted)(void *ctx, SignalFfiError *error); +typedef int (*SignalFfiChatListenerConnectionInterrupted)(void *ctx, SignalFfiError *disconnect_cause); -typedef void (*SignalDestroyChatListener)(void *ctx); +typedef void (*SignalFfiChatListenerDestroy)(void *ctx); -/** - * Callbacks for [`ChatListener`]. - * - * Callbacks will be serialized (i.e. two calls will not come in at the same time), but may not - * always happen on the same thread. Calls should be responded to promptly to avoid blocking later - * messages. - * - * # Safety - * - * This type contains raw pointers. Code that constructs an instance of this type must ensure - * memory safety assuming that - * - the callback function pointer fields are called with `ctx` as an argument; - * - the `destroy` function pointer field is called with `ctx` as an argument; - * - no function pointer fields are called after `destroy` is called. - */ typedef struct { void *ctx; - SignalReceivedIncomingMessage received_incoming_message; - SignalReceivedQueueEmpty received_queue_empty; - SignalReceivedAlerts received_alerts; - SignalConnectionInterrupted connection_interrupted; - SignalDestroyChatListener destroy; + SignalFfiChatListenerReceivedIncomingMessage received_incoming_message; + SignalFfiChatListenerReceivedQueueEmpty received_queue_empty; + SignalFfiChatListenerReceivedAlerts received_alerts; + SignalFfiChatListenerConnectionInterrupted connection_interrupted; + SignalFfiChatListenerDestroy destroy; } SignalFfiChatListenerStruct; typedef struct { @@ -610,6 +602,13 @@ typedef struct { const SignalHttpRequest *raw; } SignalConstPointerHttpRequest; +/** + * A wrapper type for raw UUIDs, because C treats arrays specially in argument position. + */ +typedef struct { + uint8_t bytes[16]; +} SignalUuid; + /** * The fixed-width binary representation of a ServiceId. * @@ -860,22 +859,23 @@ typedef struct { SignalKyberPreKeyRecord *raw; } SignalMutPointerKyberPreKeyRecord; -typedef int (*SignalLoadKyberPreKey)(void *store_ctx, SignalMutPointerKyberPreKeyRecord *recordp, uint32_t id); +typedef int (*SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id); -typedef struct { - const SignalKyberPreKeyRecord *raw; -} SignalConstPointerKyberPreKeyRecord; +typedef int (*SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); -typedef int (*SignalStoreKyberPreKey)(void *store_ctx, uint32_t id, SignalConstPointerKyberPreKeyRecord record); +typedef int (*SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); -typedef int (*SignalMarkKyberPreKeyUsed)(void *store_ctx, uint32_t id, uint32_t signed_prekey_id, SignalConstPointerPublicKey base_key); +typedef void (*SignalFfiBridgeKyberPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalLoadKyberPreKey load_kyber_pre_key; - SignalStoreKyberPreKey store_kyber_pre_key; - SignalMarkKyberPreKeyUsed mark_kyber_pre_key_used; -} SignalKyberPreKeyStore; + SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; + SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; + SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; + SignalFfiBridgeKyberPreKeyStoreDestroy destroy; +} SignalFfiBridgeKyberPreKeyStoreStruct; + +typedef SignalFfiBridgeKyberPreKeyStoreStruct SignalKyberPreKeyStore; typedef struct { const SignalKyberPreKeyStore *raw; @@ -1104,6 +1104,10 @@ typedef struct { SignalKyberSecretKey *raw; } SignalMutPointerKyberSecretKey; +typedef struct { + const SignalKyberPreKeyRecord *raw; +} SignalConstPointerKyberPreKeyRecord; + typedef struct { const SignalKyberPublicKey *raw; } SignalConstPointerKyberPublicKey; @@ -1186,6 +1190,49 @@ typedef struct { const SignalSenderKeyDistributionMessage *raw; } SignalConstPointerSenderKeyDistributionMessage; +typedef struct { + SignalProvisioningChatConnection *raw; +} SignalMutPointerProvisioningChatConnection; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalMutPointerProvisioningChatConnection *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseMutPointerProvisioningChatConnection; + +typedef struct { + const SignalProvisioningChatConnection *raw; +} SignalConstPointerProvisioningChatConnection; + +typedef int (*SignalFfiProvisioningListenerReceivedAddress)(void *ctx, const char *address, SignalMutPointerServerMessageAck send_ack); + +typedef int (*SignalFfiProvisioningListenerReceivedEnvelope)(void *ctx, SignalOwnedBuffer envelope, SignalMutPointerServerMessageAck send_ack); + +typedef int (*SignalFfiProvisioningListenerConnectionInterrupted)(void *ctx, SignalFfiError *disconnect_cause); + +typedef void (*SignalFfiProvisioningListenerDestroy)(void *ctx); + +typedef struct { + void *ctx; + SignalFfiProvisioningListenerReceivedAddress received_address; + SignalFfiProvisioningListenerReceivedEnvelope received_envelope; + SignalFfiProvisioningListenerConnectionInterrupted connection_interrupted; + SignalFfiProvisioningListenerDestroy destroy; +} SignalFfiProvisioningListenerStruct; + +typedef struct { + const SignalFfiProvisioningListenerStruct *raw; +} SignalConstPointerFfiProvisioningListenerStruct; + typedef struct { SignalRegisterAccountRequest *raw; } SignalMutPointerRegisterAccountRequest; @@ -1209,7 +1256,10 @@ typedef struct { const SignalRegisterAccountResponse *raw; } SignalConstPointerRegisterAccountResponse; -typedef uint8_t SignalOptionalUuid[17]; +typedef struct { + bool present; + uint8_t bytes[16]; +} SignalOptionalUuid; typedef SignalAccountAttributes SignalRegistrationAccountAttributes; @@ -1402,10 +1452,6 @@ typedef struct { const SignalSenderKeyMessage *raw; } SignalConstPointerSenderKeyMessage; -typedef struct { - SignalServerMessageAck *raw; -} SignalMutPointerServerMessageAck; - typedef struct { const SignalServerMessageAck *raw; } SignalConstPointerServerMessageAck; @@ -1606,7 +1652,7 @@ SignalFfiError *signal_backup_auth_credential_request_context_check_valid_conten SignalFfiError *signal_backup_auth_credential_request_context_get_request(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes); -SignalFfiError *signal_backup_auth_credential_request_context_new(SignalOwnedBuffer *out, const uint8_t (*backup_key)[32], const uint8_t (*uuid)[16]); +SignalFfiError *signal_backup_auth_credential_request_context_new(SignalOwnedBuffer *out, const uint8_t (*backup_key)[32], SignalUuid uuid); SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, uint64_t expected_redemption_time, SignalBorrowedBuffer params_bytes); @@ -1804,7 +1850,7 @@ uint32_t signal_error_get_type(const SignalFfiError *err); SignalFfiError *signal_error_get_unknown_fields(SignalStringArray *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_uuid(uint8_t (*out)[16], SignalUnwindSafeArgSignalFfiError err); +SignalFfiError *signal_error_get_uuid(SignalUuid *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_expiring_profile_key_credential_check_valid_contents(SignalBorrowedBuffer buffer); @@ -1850,7 +1896,7 @@ SignalFfiError *signal_generic_server_secret_params_get_public_params(SignalOwne SignalFfiError *signal_group_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerProtocolAddress sender, SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); -SignalFfiError *signal_group_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); +SignalFfiError *signal_group_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalConstPointerProtocolAddress sender, SignalUuid distribution_id, SignalBorrowedBuffer message, SignalConstPointerFfiSenderKeyStoreStruct store); SignalFfiError *signal_group_master_key_check_valid_contents(SignalBorrowedBuffer buffer); @@ -2226,6 +2272,16 @@ SignalFfiError *signal_profile_key_get_commitment(unsigned char (*out)[SignalPRO SignalFfiError *signal_profile_key_get_profile_key_version(uint8_t (*out)[SignalPROFILE_KEY_VERSION_ENCODED_LEN], const unsigned char (*profile_key)[SignalPROFILE_KEY_LEN], const SignalServiceIdFixedWidthBinaryBytes *user_id); +SignalFfiError *signal_provisioning_chat_connection_connect(SignalCPromiseMutPointerProvisioningChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager); + +SignalFfiError *signal_provisioning_chat_connection_destroy(SignalMutPointerProvisioningChatConnection p); + +SignalFfiError *signal_provisioning_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerProvisioningChatConnection chat); + +SignalFfiError *signal_provisioning_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerProvisioningChatConnection chat); + +SignalFfiError *signal_provisioning_chat_connection_init_listener(SignalConstPointerProvisioningChatConnection chat, SignalConstPointerFfiProvisioningListenerStruct listener); + SignalFfiError *signal_publickey_clone(SignalMutPointerPublicKey *new_obj, SignalConstPointerPublicKey obj); SignalFfiError *signal_publickey_compare(int32_t *out, SignalConstPointerPublicKey key1, SignalConstPointerPublicKey key2); @@ -2402,7 +2458,7 @@ SignalFfiError *signal_sender_certificate_validate(bool *out, SignalConstPointer SignalFfiError *signal_sender_key_distribution_message_clone(SignalMutPointerSenderKeyDistributionMessage *new_obj, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_create(SignalMutPointerSenderKeyDistributionMessage *out, SignalConstPointerProtocolAddress sender, const uint8_t (*distribution_id)[16], SignalConstPointerFfiSenderKeyStoreStruct store); +SignalFfiError *signal_sender_key_distribution_message_create(SignalMutPointerSenderKeyDistributionMessage *out, SignalConstPointerProtocolAddress sender, SignalUuid distribution_id, SignalConstPointerFfiSenderKeyStoreStruct store); SignalFfiError *signal_sender_key_distribution_message_deserialize(SignalMutPointerSenderKeyDistributionMessage *out, SignalBorrowedBuffer data); @@ -2412,13 +2468,13 @@ SignalFfiError *signal_sender_key_distribution_message_get_chain_id(uint32_t *ou SignalFfiError *signal_sender_key_distribution_message_get_chain_key(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); -SignalFfiError *signal_sender_key_distribution_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyDistributionMessage obj); +SignalFfiError *signal_sender_key_distribution_message_get_distribution_id(SignalUuid *out, SignalConstPointerSenderKeyDistributionMessage obj); SignalFfiError *signal_sender_key_distribution_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyDistributionMessage obj); SignalFfiError *signal_sender_key_distribution_message_get_signature_key(SignalMutPointerPublicKey *out, SignalConstPointerSenderKeyDistributionMessage m); -SignalFfiError *signal_sender_key_distribution_message_new(SignalMutPointerSenderKeyDistributionMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer chainkey, SignalConstPointerPublicKey pk); +SignalFfiError *signal_sender_key_distribution_message_new(SignalMutPointerSenderKeyDistributionMessage *out, uint8_t message_version, SignalUuid distribution_id, uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer chainkey, SignalConstPointerPublicKey pk); SignalFfiError *signal_sender_key_distribution_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyDistributionMessage obj); @@ -2432,11 +2488,11 @@ SignalFfiError *signal_sender_key_message_get_chain_id(uint32_t *out, SignalCons SignalFfiError *signal_sender_key_message_get_cipher_text(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_get_distribution_id(uint8_t (*out)[16], SignalConstPointerSenderKeyMessage obj); +SignalFfiError *signal_sender_key_message_get_distribution_id(SignalUuid *out, SignalConstPointerSenderKeyMessage obj); SignalFfiError *signal_sender_key_message_get_iteration(uint32_t *out, SignalConstPointerSenderKeyMessage obj); -SignalFfiError *signal_sender_key_message_new(SignalMutPointerSenderKeyMessage *out, uint8_t message_version, const uint8_t (*distribution_id)[16], uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer ciphertext, SignalConstPointerPrivateKey pk); +SignalFfiError *signal_sender_key_message_new(SignalMutPointerSenderKeyMessage *out, uint8_t message_version, SignalUuid distribution_id, uint32_t chain_id, uint32_t iteration, SignalBorrowedBuffer ciphertext, SignalConstPointerPrivateKey pk); SignalFfiError *signal_sender_key_message_serialize(SignalOwnedBuffer *out, SignalConstPointerSenderKeyMessage obj); @@ -2602,7 +2658,7 @@ SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConst SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_hash(SignalCPromiseOptionalUuid *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer hash); -SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_link(SignalCPromiseOptionalPairOfc_charu832 *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const uint8_t (*uuid)[16], SignalBorrowedBuffer entropy); +SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_link(SignalCPromiseOptionalPairOfc_charu832 *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalUuid uuid, SignalBorrowedBuffer entropy); SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); diff --git a/pkg/libsignalgo/senderkeydistributionmessage.go b/pkg/libsignalgo/senderkeydistributionmessage.go index d07c558..c9f6099 100644 --- a/pkg/libsignalgo/senderkeydistributionmessage.go +++ b/pkg/libsignalgo/senderkeydistributionmessage.go @@ -60,7 +60,7 @@ func NewSenderKeyDistributionMessage(ctx context.Context, sender *Address, distr signalFfiError := C.signal_sender_key_distribution_message_create( &skdm, sender.constPtr(), - (*[C.SignalUUID_LEN]C.uchar)(unsafe.Pointer(&distributionID)), + *(*C.SignalUuid)(unsafe.Pointer(&distributionID)), callbackCtx.wrapSenderKeyStore(store), ) runtime.KeepAlive(sender) diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index 6b0c864..ae7cea7 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -31,12 +31,6 @@ import ( "github.com/rs/zerolog" ) -func init() { - if C.SignalUUID_LEN != 16 { - panic("libsignal-ffi uuid type size mismatch") - } -} - type ServiceIDType byte const ( diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index f690184..fddfaa8 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.86.8" +const Version = "v0.86.12" From f0c6cc1e0466662a8a8762ebddf7c76364a9e4aa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Jan 2026 15:03:08 +0200 Subject: [PATCH 648/718] dependencies: update --- go.mod | 24 ++++++++++++------------ go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 05dfac3..ff53eb1 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.24.0 -toolchain go1.25.5 +toolchain go1.25.6 tool go.mau.fi/util/cmd/maubuild @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.5-0.20260114152041-9f2e2b82b503 - golang.org/x/crypto v0.46.0 - golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 - golang.org/x/net v0.48.0 + go.mau.fi/util v0.9.5 + golang.org/x/crypto v0.47.0 + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 + golang.org/x/net v0.49.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.2-0.20260115120200-34bcd027e54c + maunium.net/go/mautrix v0.26.2 ) require ( @@ -31,8 +31,8 @@ require ( github.com/lib/pq v1.10.9 // 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.32 // indirect - github.com/petermattis/goid v0.0.0-20251121121749-a11dd1a45f9a // indirect + github.com/mattn/go-sqlite3 v1.14.33 // indirect + github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -40,12 +40,12 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/yuin/goldmark v1.7.13 // indirect + github.com/yuin/goldmark v1.7.16 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/mod v0.31.0 // indirect + golang.org/x/mod v0.32.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // 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 diff --git a/go.sum b/go.sum index dfd2ccc..3c13426 100644 --- a/go.sum +++ b/go.sum @@ -35,10 +35,10 @@ 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.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= -github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20251121121749-a11dd1a45f9a h1:VweslR2akb/ARhXfqSfRbj1vpWwYXf3eeAUyw/ndms0= -github.com/petermattis/goid v0.0.0-20251121121749-a11dd1a45f9a/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0= +github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= +github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -64,29 +64,29 @@ 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.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= -github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.5-0.20260114152041-9f2e2b82b503 h1:L7ctH5wX8TrkZvIZmfxPkHQ1b8NZYw4fIr5WxXaewPw= -go.mau.fi/util v0.9.5-0.20260114152041-9f2e2b82b503/go.mod h1:647nVfwUvuhlZFOnro3aRNPmRd2y3iDha9USb8aKSmM= +github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= +github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +go.mau.fi/util v0.9.5 h1:7AoWPCIZJGv4jvtFEuCe3GhAbI7uF9ckIooaXvwlIR4= +go.mau.fi/util v0.9.5/go.mod h1:g1uvZ03VQhtTt2BgaRGVytS/Zj67NV0YNIECch0sQCQ= 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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= -golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= -golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= -golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -98,5 +98,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.26.2-0.20260115120200-34bcd027e54c h1:ZtJgvgFoH4hxNxFSavFXw7HUnjq49OyjxoEyGcjGk4k= -maunium.net/go/mautrix v0.26.2-0.20260115120200-34bcd027e54c/go.mod h1:vUvbzvY00Tbl8WjBdp5afvc69uIxujnfGHpAugxvR/Q= +maunium.net/go/mautrix v0.26.2 h1:rLiZLQoSKCJDZ+mF1gBQS4p74h3jZXs83g8D4W6Te8g= +maunium.net/go/mautrix v0.26.2/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= From b425489845e5de7e3320614de9531d914d6ee5be Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Jan 2026 15:08:11 +0200 Subject: [PATCH 649/718] Bump version to v26.01 --- CHANGELOG.md | 9 +++++++++ cmd/mautrix-signal/main.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a5d207..29f2299 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# v26.01 + +* Updated libsignal to v0.86.12. +* Changed automatic contact list sync option to only sync every 3 days rather + than on every restart. +* Fixed sending messages to groups with no other registered members. +* Fixed sender key sends failing if some users had changed devices. +* Fixed timestamps of outgoing typing notifications in DMs. + # v25.12 * Updated libsignal to v0.86.8. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 130e307..5391084 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -37,7 +37,7 @@ var m = mxmain.BridgeMain{ Name: "mautrix-signal", URL: "https://github.com/mautrix/signal", Description: "A Matrix-Signal puppeting bridge.", - Version: "25.12", + Version: "26.01", SemCalVer: true, Connector: &connector.SignalConnector{}, From 6b66216d24d8a7ec3e1f1dc6f47add3d26105c2a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 19 Jan 2026 15:17:21 +0200 Subject: [PATCH 650/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ff53eb1..d135335 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.49.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.2 + maunium.net/go/mautrix v0.26.3-0.20260119125818-e28f7170bc4b ) require ( diff --git a/go.sum b/go.sum index 3c13426..05055d0 100644 --- a/go.sum +++ b/go.sum @@ -98,5 +98,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.26.2 h1:rLiZLQoSKCJDZ+mF1gBQS4p74h3jZXs83g8D4W6Te8g= -maunium.net/go/mautrix v0.26.2/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= +maunium.net/go/mautrix v0.26.3-0.20260119125818-e28f7170bc4b h1:OaZ5Y1l4XACFlgy4BmZcCLdYPJZzgZWqZJnpdSITmoM= +maunium.net/go/mautrix v0.26.3-0.20260119125818-e28f7170bc4b/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= From a820c16ab6adffeac18c86b0f160e0cc7876f6de Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 20 Jan 2026 12:14:00 +0200 Subject: [PATCH 651/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d135335..d430a07 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.49.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.3-0.20260119125818-e28f7170bc4b + maunium.net/go/mautrix v0.26.3-0.20260120100901-a55693bbd7c6 ) require ( diff --git a/go.sum b/go.sum index 05055d0..64cbfa9 100644 --- a/go.sum +++ b/go.sum @@ -98,5 +98,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.26.3-0.20260119125818-e28f7170bc4b h1:OaZ5Y1l4XACFlgy4BmZcCLdYPJZzgZWqZJnpdSITmoM= -maunium.net/go/mautrix v0.26.3-0.20260119125818-e28f7170bc4b/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= +maunium.net/go/mautrix v0.26.3-0.20260120100901-a55693bbd7c6 h1:Xi2JR5xkAs1tdvL/qNYK/koLaPwi8/ZbWAKXOe3q2tI= +maunium.net/go/mautrix v0.26.3-0.20260120100901-a55693bbd7c6/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= From 45690972cd60867c00fc7def38524d8e61c00592 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Fri, 23 Jan 2026 16:46:10 +0100 Subject: [PATCH 652/718] handlesignal: assign beeper action message content for incoming calls (#632) --- go.mod | 4 ++-- go.sum | 7 ++++--- pkg/connector/handlesignal.go | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index d430a07..5f90925 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.49.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.3-0.20260120100901-a55693bbd7c6 + maunium.net/go/mautrix v0.26.3-0.20260123143817-d057f1c6732e ) require ( @@ -37,7 +37,7 @@ require ( 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.1.1 // 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.7.16 // indirect diff --git a/go.sum b/go.sum index 64cbfa9..cb0c5ee 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,9 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -98,5 +99,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.26.3-0.20260120100901-a55693bbd7c6 h1:Xi2JR5xkAs1tdvL/qNYK/koLaPwi8/ZbWAKXOe3q2tI= -maunium.net/go/mautrix v0.26.3-0.20260120100901-a55693bbd7c6/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= +maunium.net/go/mautrix v0.26.3-0.20260123143817-d057f1c6732e h1:lV73mGcvK73DWiAjZY4HBCo/Wr9R5Q8OgQ7U2Giraww= +maunium.net/go/mautrix v0.26.3-0.20260123143817-d057f1c6732e/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index c9f16c1..fb1a3ce 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -102,6 +102,9 @@ func convertCallEvent(ctx context.Context, portal *bridgev2.Portal, intent bridg if userID, _, _ := signalid.ParsePortalID(portal.ID); !userID.IsEmpty() { content.MsgType = event.MsgText } + content.BeeperActionMessage = &event.BeeperActionMessage{ + Type: event.BeeperActionMessageCall, + } } else { content.Body = "Call ended" } From 30d983192206f42ce546c3933b6af0d02610f9e4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 29 Jan 2026 18:30:26 +0200 Subject: [PATCH 653/718] signalmeow/senderkey: log removed devices when resetting --- pkg/signalmeow/senderkey.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pkg/signalmeow/senderkey.go b/pkg/signalmeow/senderkey.go index 096d524..48a3203 100644 --- a/pkg/signalmeow/senderkey.go +++ b/pkg/signalmeow/senderkey.go @@ -125,9 +125,11 @@ func (cli *Client) sendToGroupWithSenderKey( } else { log.Debug().Any("sender_key_info", ski).Msg("Reusing existing sender key") } - xak, devicesAddedTo, reset := diffRecipients(ski.SharedWith, deviceIDs) - if reset { - log.Debug().Msg("Resetting sender key due to recipient device changes") + xak, devicesAddedTo, removedDevices := diffRecipients(ski.SharedWith, deviceIDs) + if len(removedDevices) > 0 { + log.Debug(). + Any("removed_devices", removedDevices). + Msg("Resetting sender key due to recipient device changes") devicesAddedTo = slices.Collect(maps.Keys(deviceIDs)) err = cli.Store.SenderKeyStore.DeleteSenderKey(ctx, myAddress, ski.DistributionID) if err != nil { @@ -304,9 +306,12 @@ func (cli *Client) encryptWithSenderKey( } func diffRecipients( - prevDevices map[libsignalgo.ServiceID][]int, newDevices map[libsignalgo.ServiceID]senderKeySendMeta, + prevDevices map[libsignalgo.ServiceID][]int, + newDevices map[libsignalgo.ServiceID]senderKeySendMeta, ) ( - xak *libsignalgo.AccessKey, devicesAddedTo []libsignalgo.ServiceID, reset bool, + xak *libsignalgo.AccessKey, + devicesAddedTo []libsignalgo.ServiceID, + globalRemovedDevices map[libsignalgo.ServiceID][]int, ) { collector := make(map[libsignalgo.ServiceID]uint8, max(len(prevDevices), len(newDevices))) for key := range prevDevices { @@ -315,6 +320,7 @@ func diffRecipients( for key := range newDevices { collector[key] |= 0b10 } + globalRemovedDevices = make(map[libsignalgo.ServiceID][]int) for serviceID, mask := range collector { if mask != 0b01 { xak = xak.Xor(newDevices[serviceID].AccessKey) @@ -322,7 +328,7 @@ func diffRecipients( switch mask { case 0b01: // Someone left the group - reset = true + globalRemovedDevices[serviceID] = prevDevices[serviceID] case 0b10: // Someone was added to the group devicesAddedTo = append(devicesAddedTo, serviceID) @@ -330,7 +336,7 @@ func diffRecipients( removedDevices, addedDevices := exslices.Diff(prevDevices[serviceID], newDevices[serviceID].DeviceIDs) if len(removedDevices) > 0 { // Device was removed - reset = true + globalRemovedDevices[serviceID] = removedDevices } else if len(addedDevices) > 0 { // User got new devices devicesAddedTo = append(devicesAddedTo, serviceID) From c90be170f490cda593a270dcfdf7fb7a204d7178 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 29 Jan 2026 18:45:34 +0200 Subject: [PATCH 654/718] signalmeow/sending: refetch prekeys on error 80 --- pkg/libsignalgo/error.go | 8 ++++++++ pkg/signalmeow/sending.go | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/error.go b/pkg/libsignalgo/error.go index b25130b..888f8ea 100644 --- a/pkg/libsignalgo/error.go +++ b/pkg/libsignalgo/error.go @@ -26,6 +26,10 @@ import ( type ErrorCode int +func (e ErrorCode) Error() string { + return fmt.Sprintf("libsignalgo.ErrorCode(%d)", int(e)) +} + const ( ErrorCodeUnknownError ErrorCode = 1 ErrorCodeInvalidState ErrorCode = 2 @@ -118,6 +122,10 @@ func (e *SignalError) Error() string { return fmt.Sprintf("%d: %s", e.Code, e.Message) } +func (e *SignalError) Unwrap() error { + return e.Code +} + func (ctx *CallbackContext) wrapError(signalError *C.SignalFfiError) error { if signalError == nil { return nil diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 404571c..8e6b892 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -150,6 +150,7 @@ func (cli *Client) buildMessagesToSend( unauthenticated bool, groupID *libsignalgo.GroupIdentifier, ctmOverride *libsignalgo.CiphertextMessage, + forceResync bool, ) ([]MyMessage, error) { if ctx.Value(contextKeyEncryptionLock) != true { cli.encryptionLock.Lock() @@ -157,7 +158,7 @@ func (cli *Client) buildMessagesToSend( } sessions, err := cli.Store.ACISessionStore.AllSessionsForServiceID(ctx, recipient) - if err == nil && len(sessions) == 0 { + if err == nil && (len(sessions) == 0 || forceResync) { // No sessions, make one with prekey err = cli.FetchAndProcessPreKey(ctx, recipient, -1) if err != nil { @@ -900,7 +901,11 @@ func (cli *Client) sendContent( } var messages []MyMessage - messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, groupID, ctmOverride) + messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, groupID, ctmOverride, false) + if errors.Is(err, libsignalgo.ErrorCodeSessionNotFound) { + log.Err(err).Msg("Got session not found error from libsignal, trying to refetch prekeys") + messages, err = cli.buildMessagesToSend(ctx, recipient, content, useUnidentifiedSender, groupID, ctmOverride, true) + } if err != nil { log.Err(err).Msg("Error building messages to send") return false, err From 93da772584b20ac1975e872e26739b273314b73e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 29 Jan 2026 19:47:37 +0200 Subject: [PATCH 655/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5f90925..728ffb7 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.49.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.3-0.20260123143817-d057f1c6732e + maunium.net/go/mautrix v0.26.3-0.20260129174719-d2364b382275 ) require ( diff --git a/go.sum b/go.sum index cb0c5ee..8dba58f 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.26.3-0.20260123143817-d057f1c6732e h1:lV73mGcvK73DWiAjZY4HBCo/Wr9R5Q8OgQ7U2Giraww= -maunium.net/go/mautrix v0.26.3-0.20260123143817-d057f1c6732e/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= +maunium.net/go/mautrix v0.26.3-0.20260129174719-d2364b382275 h1:r8BL0+HW4Dar1xV7Fc7NV/LxGH6VCvffkCUGe9ZfJg8= +maunium.net/go/mautrix v0.26.3-0.20260129174719-d2364b382275/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= From d603b7665d15b5514a115c4d77d7d4525976a5a2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Feb 2026 13:54:02 +0200 Subject: [PATCH 656/718] libsignal: update to v0.87.1 --- pkg/libsignalgo/identitykey.go | 3 +- pkg/libsignalgo/identitykeystore.go | 80 +++++------ pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 150 +++++++++++++-------- pkg/libsignalgo/prekeystore.go | 27 ++-- pkg/libsignalgo/publickey.go | 10 +- pkg/libsignalgo/senderkeystore.go | 34 ++--- pkg/libsignalgo/sessionstore.go | 30 +++-- pkg/libsignalgo/signedprekeystore.go | 25 ++-- pkg/libsignalgo/update-ffi-docker-inner.sh | 2 +- pkg/libsignalgo/version.go | 2 +- 11 files changed, 207 insertions(+), 158 deletions(-) diff --git a/pkg/libsignalgo/identitykey.go b/pkg/libsignalgo/identitykey.go index f35d116..0226e11 100644 --- a/pkg/libsignalgo/identitykey.go +++ b/pkg/libsignalgo/identitykey.go @@ -84,8 +84,7 @@ func (i *IdentityKey) VerifyAlternateIdentity(other *IdentityKey, signature []by } func (i *IdentityKey) Equal(other *IdentityKey) (bool, error) { - result, err := i.publicKey.Compare(other.publicKey) - return result == 0, err + return i.publicKey.Equal(other.publicKey) } type IdentityKeyPair struct { diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index c59b660..6a425e8 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -20,14 +20,12 @@ package libsignalgo /* #include "./libsignal-ffi.h" -typedef const SignalProtocolAddress const_address; -typedef const SignalPublicKey const_public_key; - -extern int signal_get_identity_key_pair_callback(void *store_ctx, SignalPrivateKey **keyp); +extern int signal_get_identity_key_pair_callback(void *store_ctx, SignalMutPointerPrivateKey *keyp); extern int signal_get_local_registration_id_callback(void *store_ctx, uint32_t *idp); -extern int signal_save_identity_key_callback(void *store_ctx, const_address *address, const_public_key *public_key); -extern int signal_get_identity_key_callback(void *store_ctx, SignalPublicKey **public_keyp, const_address *address); -extern int signal_is_trusted_identity_callback(void *store_ctx, const_address *address, const_public_key *public_key, unsigned int direction); +extern int signal_save_identity_key_callback(void *store_ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); +extern int signal_get_identity_key_callback(void *store_ctx, SignalMutPointerPublicKey *public_keyp, SignalMutPointerProtocolAddress address); +extern int signal_is_trusted_identity_callback(void *store_ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); +extern void signal_destroy_identity_key_store_callback(void *store_ctx); */ import "C" import ( @@ -51,21 +49,21 @@ type IdentityKeyStore interface { } //export signal_get_identity_key_pair_callback -func signal_get_identity_key_pair_callback(storeCtx unsafe.Pointer, keyp **C.SignalPrivateKey) C.int { +func signal_get_identity_key_pair_callback(storeCtx unsafe.Pointer, keyp *C.SignalMutPointerPrivateKey) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { key, err := store.GetIdentityKeyPair(ctx) if err != nil { return err } if key == nil { - *keyp = nil + keyp.raw = nil } else { clone, err := key.privateKey.Clone() if err != nil { return err } clone.CancelFinalizer() - *keyp = clone.ptr + keyp.raw = clone.ptr } return err }) @@ -83,17 +81,17 @@ func signal_get_local_registration_id_callback(storeCtx unsafe.Pointer, idp *C.u } //export signal_save_identity_key_callback -func signal_save_identity_key_callback(storeCtx unsafe.Pointer, address *C.const_address, publicKey *C.const_public_key) C.int { - return wrapStoreCallbackCustomReturn(storeCtx, func(store IdentityKeyStore, ctx context.Context) (int, error) { - publicKeyStruct := PublicKey{ptr: (*C.SignalPublicKey)(unsafe.Pointer(publicKey))} +func signal_save_identity_key_callback(storeCtx unsafe.Pointer, out *C.uint8_t, address C.SignalMutPointerProtocolAddress, publicKey C.SignalMutPointerPublicKey) C.int { + return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { + publicKeyStruct := PublicKey{ptr: publicKey.raw} cloned, err := publicKeyStruct.Clone() if err != nil { - return -1, err + return err } - addr := &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))} + addr := &Address{ptr: address.raw} theirServiceID, err := addr.NameServiceID() if err != nil { - return -1, err + return err } replaced, err := store.SaveIdentityKey( ctx, @@ -101,20 +99,21 @@ func signal_save_identity_key_callback(storeCtx unsafe.Pointer, address *C.const &IdentityKey{cloned}, ) if err != nil { - return -1, err + return err } if replaced { - return 1, nil + *out = 1 } else { - return 0, nil + *out = 0 } + return nil }) } //export signal_get_identity_key_callback -func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp **C.SignalPublicKey, address *C.const_address) C.int { +func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp *C.SignalMutPointerPublicKey, address C.SignalMutPointerProtocolAddress) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { - addr := &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))} + addr := &Address{ptr: address.raw} theirServiceID, err := addr.NameServiceID() if err != nil { return err @@ -122,39 +121,42 @@ func signal_get_identity_key_callback(storeCtx unsafe.Pointer, public_keyp **C.S key, err := store.GetIdentityKey(ctx, theirServiceID) if err == nil && key != nil { key.publicKey.CancelFinalizer() - *public_keyp = key.publicKey.ptr + public_keyp.raw = key.publicKey.ptr } return err }) } //export signal_is_trusted_identity_callback -func signal_is_trusted_identity_callback(storeCtx unsafe.Pointer, address *C.const_address, public_key *C.const_public_key, direction C.uint) C.int { - return wrapStoreCallbackCustomReturn(storeCtx, func(store IdentityKeyStore, ctx context.Context) (int, error) { - addr := &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))} +func signal_is_trusted_identity_callback(storeCtx unsafe.Pointer, out *C.bool, address C.SignalMutPointerProtocolAddress, public_key C.SignalMutPointerPublicKey, direction C.uint32_t) C.int { + return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { + addr := &Address{ptr: address.raw} theirServiceID, err := addr.NameServiceID() if err != nil { - return -1, err + return err } - trusted, err := store.IsTrustedIdentity(ctx, theirServiceID, &IdentityKey{&PublicKey{ptr: (*C.SignalPublicKey)(unsafe.Pointer(public_key))}}, SignalDirection(direction)) + trusted, err := store.IsTrustedIdentity(ctx, theirServiceID, &IdentityKey{&PublicKey{ptr: public_key.raw}}, SignalDirection(direction)) if err != nil { - return -1, err - } - if trusted { - return 1, nil - } else { - return 0, nil + return err } + *out = C.bool(trusted) + return nil }) } +//export signal_destroy_identity_key_store_callback +func signal_destroy_identity_key_store_callback(storeCtx unsafe.Pointer) { + // No-op: Go's garbage collector handles cleanup +} + func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct { return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{ - ctx: wrapStore(ctx, store), - get_identity_key_pair: C.SignalGetIdentityKeyPair(C.signal_get_identity_key_pair_callback), - get_local_registration_id: C.SignalGetLocalRegistrationId(C.signal_get_local_registration_id_callback), - save_identity: C.SignalSaveIdentityKey(C.signal_save_identity_key_callback), - get_identity: C.SignalGetIdentityKey(C.signal_get_identity_key_callback), - is_trusted_identity: C.SignalIsTrustedIdentity(C.signal_is_trusted_identity_callback), + ctx: wrapStore(ctx, store), + get_local_identity_private_key: C.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityPrivateKey(C.signal_get_identity_key_pair_callback), + get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), + get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), + save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), + is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), + destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), }} } diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index 0480b16..f08390b 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit 0480b16ac3c4ca9d641bc160b1b231f89d2e5fe3 +Subproject commit f08390b0e2f67d5faf47bb9d1a3db191314db93c diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index e2ddc02..deb72cd 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -29,6 +29,8 @@ SPDX-License-Identifier: AGPL-3.0-only #define SignalBackupId_LEN 16 +#define SignalCallLinkSecretParams_ROOT_KEY_MAX_BYTES_FOR_SHO 16 + #define SignalNUM_AUTH_CRED_ATTRIBUTES 3 #define SignalNUM_PROFILE_KEY_CRED_ATTRIBUTES 4 @@ -755,50 +757,52 @@ typedef struct { SignalSessionRecord *raw; } SignalMutPointerSessionRecord; -typedef int (*SignalLoadSession)(void *store_ctx, SignalMutPointerSessionRecord *recordp, SignalConstPointerProtocolAddress address); +typedef int (*SignalFfiBridgeSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address); -typedef struct { - const SignalSessionRecord *raw; -} SignalConstPointerSessionRecord; +typedef int (*SignalFfiBridgeSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); -typedef int (*SignalStoreSession)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerSessionRecord record); +typedef void (*SignalFfiBridgeSessionStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalLoadSession load_session; - SignalStoreSession store_session; -} SignalSessionStore; + SignalFfiBridgeSessionStoreLoadSession load_session; + SignalFfiBridgeSessionStoreStoreSession store_session; + SignalFfiBridgeSessionStoreDestroy destroy; +} SignalFfiBridgeSessionStoreStruct; + +typedef SignalFfiBridgeSessionStoreStruct SignalSessionStore; typedef struct { const SignalSessionStore *raw; } SignalConstPointerFfiSessionStoreStruct; -typedef int (*SignalGetIdentityKeyPair)(void *store_ctx, SignalMutPointerPrivateKey *keyp); +typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalIdentityPrivateKey)(void *ctx, SignalMutPointerPrivateKey *out); -typedef int (*SignalGetLocalRegistrationId)(void *store_ctx, uint32_t *idp); - -typedef struct { - const SignalPublicKey *raw; -} SignalConstPointerPublicKey; - -typedef int (*SignalSaveIdentityKey)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerPublicKey public_key); +typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); typedef struct { SignalPublicKey *raw; } SignalMutPointerPublicKey; -typedef int (*SignalGetIdentityKey)(void *store_ctx, SignalMutPointerPublicKey *public_keyp, SignalConstPointerProtocolAddress address); +typedef int (*SignalFfiBridgeIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); -typedef int (*SignalIsTrustedIdentity)(void *store_ctx, SignalConstPointerProtocolAddress address, SignalConstPointerPublicKey public_key, unsigned int direction); +typedef int (*SignalFfiBridgeIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); + +typedef int (*SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); + +typedef void (*SignalFfiBridgeIdentityKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalGetIdentityKeyPair get_identity_key_pair; - SignalGetLocalRegistrationId get_local_registration_id; - SignalSaveIdentityKey save_identity; - SignalGetIdentityKey get_identity; - SignalIsTrustedIdentity is_trusted_identity; -} SignalIdentityKeyStore; + SignalFfiBridgeIdentityKeyStoreGetLocalIdentityPrivateKey get_local_identity_private_key; + SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; + SignalFfiBridgeIdentityKeyStoreGetIdentityKey get_identity_key; + SignalFfiBridgeIdentityKeyStoreSaveIdentityKey save_identity_key; + SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity is_trusted_identity; + SignalFfiBridgeIdentityKeyStoreDestroy destroy; +} SignalFfiBridgeIdentityKeyStoreStruct; + +typedef SignalFfiBridgeIdentityKeyStoreStruct SignalIdentityKeyStore; typedef struct { const SignalIdentityKeyStore *raw; @@ -812,22 +816,23 @@ typedef struct { SignalPreKeyRecord *raw; } SignalMutPointerPreKeyRecord; -typedef int (*SignalLoadPreKey)(void *store_ctx, SignalMutPointerPreKeyRecord *recordp, uint32_t id); +typedef int (*SignalFfiBridgePreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id); -typedef struct { - const SignalPreKeyRecord *raw; -} SignalConstPointerPreKeyRecord; +typedef int (*SignalFfiBridgePreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record); -typedef int (*SignalStorePreKey)(void *store_ctx, uint32_t id, SignalConstPointerPreKeyRecord record); +typedef int (*SignalFfiBridgePreKeyStoreRemovePreKey)(void *ctx, uint32_t id); -typedef int (*SignalRemovePreKey)(void *store_ctx, uint32_t id); +typedef void (*SignalFfiBridgePreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalLoadPreKey load_pre_key; - SignalStorePreKey store_pre_key; - SignalRemovePreKey remove_pre_key; -} SignalPreKeyStore; + SignalFfiBridgePreKeyStoreLoadPreKey load_pre_key; + SignalFfiBridgePreKeyStoreStorePreKey store_pre_key; + SignalFfiBridgePreKeyStoreRemovePreKey remove_pre_key; + SignalFfiBridgePreKeyStoreDestroy destroy; +} SignalFfiBridgePreKeyStoreStruct; + +typedef SignalFfiBridgePreKeyStoreStruct SignalPreKeyStore; typedef struct { const SignalPreKeyStore *raw; @@ -837,19 +842,20 @@ typedef struct { SignalSignedPreKeyRecord *raw; } SignalMutPointerSignedPreKeyRecord; -typedef int (*SignalLoadSignedPreKey)(void *store_ctx, SignalMutPointerSignedPreKeyRecord *recordp, uint32_t id); +typedef int (*SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id); -typedef struct { - const SignalSignedPreKeyRecord *raw; -} SignalConstPointerSignedPreKeyRecord; +typedef int (*SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); -typedef int (*SignalStoreSignedPreKey)(void *store_ctx, uint32_t id, SignalConstPointerSignedPreKeyRecord record); +typedef void (*SignalFfiBridgeSignedPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalLoadSignedPreKey load_signed_pre_key; - SignalStoreSignedPreKey store_signed_pre_key; -} SignalSignedPreKeyStore; + SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; + SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; + SignalFfiBridgeSignedPreKeyStoreDestroy destroy; +} SignalFfiBridgeSignedPreKeyStoreStruct; + +typedef SignalFfiBridgeSignedPreKeyStoreStruct SignalSignedPreKeyStore; typedef struct { const SignalSignedPreKeyStore *raw; @@ -946,6 +952,10 @@ typedef struct { const SignalFingerprint *raw; } SignalConstPointerFingerprint; +typedef struct { + const SignalPublicKey *raw; +} SignalConstPointerPublicKey; + typedef struct { /** * The badge ID. @@ -987,19 +997,20 @@ typedef struct { SignalSenderKeyRecord *raw; } SignalMutPointerSenderKeyRecord; -typedef int (*SignalLoadSenderKey)(void *store_ctx, SignalMutPointerSenderKeyRecord*, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16]); +typedef int (*SignalFfiBridgeSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); -typedef struct { - const SignalSenderKeyRecord *raw; -} SignalConstPointerSenderKeyRecord; +typedef int (*SignalFfiBridgeSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); -typedef int (*SignalStoreSenderKey)(void *store_ctx, SignalConstPointerProtocolAddress, const uint8_t (*distribution_id)[16], SignalConstPointerSenderKeyRecord); +typedef void (*SignalFfiBridgeSenderKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalLoadSenderKey load_sender_key; - SignalStoreSenderKey store_sender_key; -} SignalSenderKeyStore; + SignalFfiBridgeSenderKeyStoreLoadSenderKey load_sender_key; + SignalFfiBridgeSenderKeyStoreStoreSenderKey store_sender_key; + SignalFfiBridgeSenderKeyStoreDestroy destroy; +} SignalFfiBridgeSenderKeyStoreStruct; + +typedef SignalFfiBridgeSenderKeyStoreStruct SignalSenderKeyStore; typedef struct { const SignalSenderKeyStore *raw; @@ -1136,15 +1147,20 @@ typedef struct { const SignalMessageBackupValidationOutcome *raw; } SignalConstPointerMessageBackupValidationOutcome; -typedef int (*SignalRead)(void *ctx, uint8_t *buf, size_t buf_len, size_t *amount_read); +typedef int (*SignalFfiBridgeInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf); -typedef int (*SignalSkip)(void *ctx, uint64_t amount); +typedef int (*SignalFfiBridgeInputStreamSkip)(void *ctx, uint64_t amount); + +typedef void (*SignalFfiBridgeInputStreamDestroy)(void *ctx); typedef struct { void *ctx; - SignalRead read; - SignalSkip skip; -} SignalInputStream; + SignalFfiBridgeInputStreamRead read; + SignalFfiBridgeInputStreamSkip skip; + SignalFfiBridgeInputStreamDestroy destroy; +} SignalFfiBridgeInputStreamStruct; + +typedef SignalFfiBridgeInputStreamStruct SignalInputStream; typedef struct { const SignalInputStream *raw; @@ -1182,6 +1198,10 @@ typedef struct { const SignalPreKeyBundle *raw; } SignalConstPointerPreKeyBundle; +typedef struct { + const SignalPreKeyRecord *raw; +} SignalConstPointerPreKeyRecord; + typedef struct { SignalPreKeySignalMessage *raw; } SignalMutPointerPreKeySignalMessage; @@ -1374,6 +1394,10 @@ typedef struct { size_t length; } SignalBorrowedSliceOfConstPointerProtocolAddress; +typedef struct { + const SignalSessionRecord *raw; +} SignalConstPointerSessionRecord; + typedef struct { const SignalConstPointerSessionRecord *base; size_t length; @@ -1452,6 +1476,10 @@ typedef struct { const SignalSenderKeyMessage *raw; } SignalConstPointerSenderKeyMessage; +typedef struct { + const SignalSenderKeyRecord *raw; +} SignalConstPointerSenderKeyRecord; + typedef struct { const SignalServerMessageAck *raw; } SignalConstPointerServerMessageAck; @@ -1468,6 +1496,10 @@ typedef struct { const SignalSgxClientState *raw; } SignalConstPointerSgxClientState; +typedef struct { + const SignalSignedPreKeyRecord *raw; +} SignalConstPointerSignedPreKeyRecord; + typedef struct { SignalTokioAsyncContext *raw; } SignalMutPointerTokioAsyncContext; @@ -1546,7 +1578,9 @@ typedef struct { SignalValidatingMac *raw; } SignalMutPointerValidatingMac; -typedef SignalInputStream SignalSyncInputStream; +typedef SignalFfiBridgeInputStreamStruct SignalFfiBridgeSyncInputStreamStruct; + +typedef SignalFfiBridgeSyncInputStreamStruct SignalSyncInputStream; typedef struct { const SignalSyncInputStream *raw; @@ -2284,8 +2318,6 @@ SignalFfiError *signal_provisioning_chat_connection_init_listener(SignalConstPoi SignalFfiError *signal_publickey_clone(SignalMutPointerPublicKey *new_obj, SignalConstPointerPublicKey obj); -SignalFfiError *signal_publickey_compare(int32_t *out, SignalConstPointerPublicKey key1, SignalConstPointerPublicKey key2); - SignalFfiError *signal_publickey_deserialize(SignalMutPointerPublicKey *out, SignalBorrowedBuffer data); SignalFfiError *signal_publickey_destroy(SignalMutPointerPublicKey p); @@ -2646,6 +2678,8 @@ SignalFfiError *signal_tokio_async_context_destroy(SignalMutPointerTokioAsyncCon SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext *out); +SignalFfiError *signal_unauthenticated_chat_connection_account_exists(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *account); + SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, SignalBorrowedBytestringArray languages); SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); diff --git a/pkg/libsignalgo/prekeystore.go b/pkg/libsignalgo/prekeystore.go index 643e286..ed8ea21 100644 --- a/pkg/libsignalgo/prekeystore.go +++ b/pkg/libsignalgo/prekeystore.go @@ -20,11 +20,10 @@ package libsignalgo /* #include "./libsignal-ffi.h" -typedef const SignalPreKeyRecord const_pre_key_record; - -extern int signal_load_pre_key_callback(void *store_ctx, SignalPreKeyRecord **recordp, uint32_t id); -extern int signal_store_pre_key_callback(void *store_ctx, uint32_t id, const_pre_key_record *record); +extern int signal_load_pre_key_callback(void *store_ctx, SignalMutPointerPreKeyRecord *recordp, uint32_t id); +extern int signal_store_pre_key_callback(void *store_ctx, uint32_t id, SignalMutPointerPreKeyRecord record); extern int signal_remove_pre_key_callback(void *store_ctx, uint32_t id); +extern void signal_destroy_pre_key_store_callback(void *store_ctx); */ import "C" import ( @@ -39,21 +38,21 @@ type PreKeyStore interface { } //export signal_load_pre_key_callback -func signal_load_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalPreKeyRecord, id C.uint32_t) C.int { +func signal_load_pre_key_callback(storeCtx unsafe.Pointer, keyp *C.SignalMutPointerPreKeyRecord, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store PreKeyStore, ctx context.Context) error { key, err := store.LoadPreKey(ctx, uint32(id)) if err == nil && key != nil { key.CancelFinalizer() - *keyp = key.ptr + keyp.raw = key.ptr } return err }) } //export signal_store_pre_key_callback -func signal_store_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord *C.const_pre_key_record) C.int { +func signal_store_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord C.SignalMutPointerPreKeyRecord) C.int { return wrapStoreCallback(storeCtx, func(store PreKeyStore, ctx context.Context) error { - record := PreKeyRecord{ptr: (*C.SignalPreKeyRecord)(unsafe.Pointer(preKeyRecord))} + record := PreKeyRecord{ptr: preKeyRecord.raw} cloned, err := record.Clone() if err != nil { return err @@ -69,11 +68,17 @@ func signal_remove_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t) C.in }) } +//export signal_destroy_pre_key_store_callback +func signal_destroy_pre_key_store_callback(storeCtx unsafe.Pointer) { + // No-op: Go's garbage collector handles cleanup +} + func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) C.SignalConstPointerFfiPreKeyStoreStruct { return C.SignalConstPointerFfiPreKeyStoreStruct{&C.SignalPreKeyStore{ ctx: wrapStore(ctx, store), - load_pre_key: C.SignalLoadPreKey(C.signal_load_pre_key_callback), - store_pre_key: C.SignalStorePreKey(C.signal_store_pre_key_callback), - remove_pre_key: C.SignalRemovePreKey(C.signal_remove_pre_key_callback), + load_pre_key: C.SignalFfiBridgePreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), + store_pre_key: C.SignalFfiBridgePreKeyStoreStorePreKey(C.signal_store_pre_key_callback), + remove_pre_key: C.SignalFfiBridgePreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), + destroy: C.SignalFfiBridgePreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/publickey.go b/pkg/libsignalgo/publickey.go index bd7452e..fdd76e5 100644 --- a/pkg/libsignalgo/publickey.go +++ b/pkg/libsignalgo/publickey.go @@ -84,15 +84,15 @@ func (k *PublicKey) CancelFinalizer() { runtime.SetFinalizer(k, nil) } -func (k *PublicKey) Compare(other *PublicKey) (int, error) { - var comparison C.int - signalFfiError := C.signal_publickey_compare(&comparison, k.constPtr(), other.constPtr()) +func (k *PublicKey) Equal(other *PublicKey) (bool, error) { + var comparison C.bool + signalFfiError := C.signal_publickey_equals(&comparison, k.constPtr(), other.constPtr()) runtime.KeepAlive(k) runtime.KeepAlive(other) if signalFfiError != nil { - return 0, wrapError(signalFfiError) + return false, wrapError(signalFfiError) } - return int(comparison), nil + return bool(comparison), nil } func (k *PublicKey) Bytes() ([]byte, error) { diff --git a/pkg/libsignalgo/senderkeystore.go b/pkg/libsignalgo/senderkeystore.go index 30df4ad..a07a287 100644 --- a/pkg/libsignalgo/senderkeystore.go +++ b/pkg/libsignalgo/senderkeystore.go @@ -20,13 +20,9 @@ package libsignalgo /* #include "./libsignal-ffi.h" -typedef const SignalProtocolAddress const_address; - -typedef const SignalSenderKeyRecord const_sender_key_record; -typedef const uint8_t const_uuid_bytes[16]; - -extern int signal_load_sender_key_callback(void *store_ctx, SignalSenderKeyRecord**, const_address*, const_uuid_bytes*); -extern int signal_store_sender_key_callback(void *store_ctx, const_address*, const_uuid_bytes*, const_sender_key_record*); +extern int signal_load_sender_key_callback(void *store_ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); +extern int signal_store_sender_key_callback(void *store_ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); +extern void signal_destroy_sender_key_store_callback(void *store_ctx); */ import "C" import ( @@ -42,36 +38,40 @@ type SenderKeyStore interface { } //export signal_load_sender_key_callback -func signal_load_sender_key_callback(storeCtx unsafe.Pointer, recordp **C.SignalSenderKeyRecord, address *C.const_address, distributionIDBytes *C.const_uuid_bytes) C.int { +func signal_load_sender_key_callback(storeCtx unsafe.Pointer, recordp *C.SignalMutPointerSenderKeyRecord, address C.SignalMutPointerProtocolAddress, distributionID C.SignalUuid) C.int { return wrapStoreCallback(storeCtx, func(store SenderKeyStore, ctx context.Context) error { - distributionID := uuid.UUID(*(*[16]byte)(unsafe.Pointer(distributionIDBytes))) - record, err := store.LoadSenderKey(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, distributionID) + record, err := store.LoadSenderKey(ctx, &Address{ptr: address.raw}, *(*uuid.UUID)(unsafe.Pointer(&distributionID))) if err == nil && record != nil { record.CancelFinalizer() - *recordp = record.ptr + recordp.raw = record.ptr } return err }) } //export signal_store_sender_key_callback -func signal_store_sender_key_callback(storeCtx unsafe.Pointer, address *C.const_address, distributionIDBytes *C.const_uuid_bytes, senderKeyRecord *C.const_sender_key_record) C.int { +func signal_store_sender_key_callback(storeCtx unsafe.Pointer, address C.SignalMutPointerProtocolAddress, distributionID C.SignalUuid, senderKeyRecord C.SignalMutPointerSenderKeyRecord) C.int { return wrapStoreCallback(storeCtx, func(store SenderKeyStore, ctx context.Context) error { - distributionID := uuid.UUID(*(*[16]byte)(unsafe.Pointer(distributionIDBytes))) - record := SenderKeyRecord{ptr: (*C.SignalSenderKeyRecord)(unsafe.Pointer(senderKeyRecord))} + record := SenderKeyRecord{ptr: senderKeyRecord.raw} cloned, err := record.Clone() if err != nil { return err } - return store.StoreSenderKey(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, distributionID, cloned) + return store.StoreSenderKey(ctx, &Address{ptr: address.raw}, *(*uuid.UUID)(unsafe.Pointer(&distributionID)), cloned) }) } +//export signal_destroy_sender_key_store_callback +func signal_destroy_sender_key_store_callback(storeCtx unsafe.Pointer) { + // No-op: Go's garbage collector handles cleanup +} + func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) C.SignalConstPointerFfiSenderKeyStoreStruct { return C.SignalConstPointerFfiSenderKeyStoreStruct{&C.SignalSenderKeyStore{ ctx: wrapStore(ctx, store), - load_sender_key: C.SignalLoadSenderKey(C.signal_load_sender_key_callback), - store_sender_key: C.SignalStoreSenderKey(C.signal_store_sender_key_callback), + load_sender_key: C.SignalFfiBridgeSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), + store_sender_key: C.SignalFfiBridgeSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), + destroy: C.SignalFfiBridgeSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), }} } diff --git a/pkg/libsignalgo/sessionstore.go b/pkg/libsignalgo/sessionstore.go index da430c1..2515232 100644 --- a/pkg/libsignalgo/sessionstore.go +++ b/pkg/libsignalgo/sessionstore.go @@ -20,11 +20,9 @@ package libsignalgo /* #include "./libsignal-ffi.h" -typedef const SignalSessionRecord const_session_record; -typedef const SignalProtocolAddress const_address; - -extern int signal_load_session_callback(void *store_ctx, SignalSessionRecord **recordp, const_address *address); -extern int signal_store_session_callback(void *store_ctx, const_address *address, const_session_record *record); +extern int signal_load_session_callback(void *store_ctx, SignalMutPointerSessionRecord *recordp, SignalMutPointerProtocolAddress address); +extern int signal_store_session_callback(void *store_ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); +extern void signal_destroy_session_store_callback(void *store_ctx); */ import "C" import ( @@ -38,33 +36,39 @@ type SessionStore interface { } //export signal_load_session_callback -func signal_load_session_callback(storeCtx unsafe.Pointer, recordp **C.SignalSessionRecord, address *C.const_address) C.int { +func signal_load_session_callback(storeCtx unsafe.Pointer, recordp *C.SignalMutPointerSessionRecord, address C.SignalMutPointerProtocolAddress) C.int { return wrapStoreCallback(storeCtx, func(store SessionStore, ctx context.Context) error { - record, err := store.LoadSession(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}) + record, err := store.LoadSession(ctx, &Address{ptr: address.raw}) if err == nil && record != nil { record.CancelFinalizer() - *recordp = record.ptr + recordp.raw = record.ptr } return err }) } //export signal_store_session_callback -func signal_store_session_callback(storeCtx unsafe.Pointer, address *C.const_address, sessionRecord *C.const_session_record) C.int { +func signal_store_session_callback(storeCtx unsafe.Pointer, address C.SignalMutPointerProtocolAddress, sessionRecord C.SignalMutPointerSessionRecord) C.int { return wrapStoreCallback(storeCtx, func(store SessionStore, ctx context.Context) error { - record := SessionRecord{ptr: (*C.SignalSessionRecord)(unsafe.Pointer(sessionRecord))} + record := SessionRecord{ptr: sessionRecord.raw} cloned, err := record.Clone() if err != nil { return err } - return store.StoreSession(ctx, &Address{ptr: (*C.SignalProtocolAddress)(unsafe.Pointer(address))}, cloned) + return store.StoreSession(ctx, &Address{ptr: address.raw}, cloned) }) } +//export signal_destroy_session_store_callback +func signal_destroy_session_store_callback(storeCtx unsafe.Pointer) { + // No-op: Go's garbage collector handles cleanup +} + func (ctx *CallbackContext) wrapSessionStore(store SessionStore) C.SignalConstPointerFfiSessionStoreStruct { return C.SignalConstPointerFfiSessionStoreStruct{&C.SignalSessionStore{ ctx: wrapStore(ctx, store), - load_session: C.SignalLoadSession(C.signal_load_session_callback), - store_session: C.SignalStoreSession(C.signal_store_session_callback), + load_session: C.SignalFfiBridgeSessionStoreLoadSession(C.signal_load_session_callback), + store_session: C.SignalFfiBridgeSessionStoreStoreSession(C.signal_store_session_callback), + destroy: C.SignalFfiBridgeSessionStoreDestroy(C.signal_destroy_session_store_callback), }} } diff --git a/pkg/libsignalgo/signedprekeystore.go b/pkg/libsignalgo/signedprekeystore.go index b595578..cfb3015 100644 --- a/pkg/libsignalgo/signedprekeystore.go +++ b/pkg/libsignalgo/signedprekeystore.go @@ -20,10 +20,9 @@ package libsignalgo /* #include "./libsignal-ffi.h" -typedef const SignalSignedPreKeyRecord const_signed_pre_key_record; - -extern int signal_load_signed_pre_key_callback(void *store_ctx, SignalSignedPreKeyRecord **recordp, uint32_t id); -extern int signal_store_signed_pre_key_callback(void *store_ctx, uint32_t id, const_signed_pre_key_record *record); +extern int signal_load_signed_pre_key_callback(void *store_ctx, SignalMutPointerSignedPreKeyRecord *recordp, uint32_t id); +extern int signal_store_signed_pre_key_callback(void *store_ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); +extern void signal_destroy_signed_pre_key_store_callback(void *store_ctx); */ import "C" import ( @@ -37,21 +36,21 @@ type SignedPreKeyStore interface { } //export signal_load_signed_pre_key_callback -func signal_load_signed_pre_key_callback(storeCtx unsafe.Pointer, keyp **C.SignalSignedPreKeyRecord, id C.uint32_t) C.int { +func signal_load_signed_pre_key_callback(storeCtx unsafe.Pointer, keyp *C.SignalMutPointerSignedPreKeyRecord, id C.uint32_t) C.int { return wrapStoreCallback(storeCtx, func(store SignedPreKeyStore, ctx context.Context) error { key, err := store.LoadSignedPreKey(ctx, uint32(id)) if err == nil && key != nil { key.CancelFinalizer() - *keyp = key.ptr + keyp.raw = key.ptr } return err }) } //export signal_store_signed_pre_key_callback -func signal_store_signed_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord *C.const_signed_pre_key_record) C.int { +func signal_store_signed_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t, preKeyRecord C.SignalMutPointerSignedPreKeyRecord) C.int { return wrapStoreCallback(storeCtx, func(store SignedPreKeyStore, ctx context.Context) error { - record := SignedPreKeyRecord{ptr: (*C.SignalSignedPreKeyRecord)(unsafe.Pointer(preKeyRecord))} + record := SignedPreKeyRecord{ptr: preKeyRecord.raw} cloned, err := record.Clone() if err != nil { return err @@ -60,10 +59,16 @@ func signal_store_signed_pre_key_callback(storeCtx unsafe.Pointer, id C.uint32_t }) } +//export signal_destroy_signed_pre_key_store_callback +func signal_destroy_signed_pre_key_store_callback(storeCtx unsafe.Pointer) { + // No-op: Go's garbage collector handles cleanup +} + func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) C.SignalConstPointerFfiSignedPreKeyStoreStruct { return C.SignalConstPointerFfiSignedPreKeyStoreStruct{&C.SignalSignedPreKeyStore{ ctx: wrapStore(ctx, store), - load_signed_pre_key: C.SignalLoadSignedPreKey(C.signal_load_signed_pre_key_callback), - store_signed_pre_key: C.SignalStoreSignedPreKey(C.signal_store_signed_pre_key_callback), + load_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), + store_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), + destroy: C.SignalFfiBridgeSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/update-ffi-docker-inner.sh b/pkg/libsignalgo/update-ffi-docker-inner.sh index 7641701..e343887 100755 --- a/pkg/libsignalgo/update-ffi-docker-inner.sh +++ b/pkg/libsignalgo/update-ffi-docker-inner.sh @@ -1,7 +1,7 @@ #!/bin/sh cd /data export RUSTFLAGS="-Ctarget-feature=-crt-static" RUSTC_WRAPPER="" -apk add --no-cache git make cmake protoc musl-dev g++ clang-dev cbindgen +apk add --no-cache git make cmake protobuf-dev musl-dev g++ clang-dev cbindgen cd libsignal cargo build -p libsignal-ffi --release cbindgen --profile release rust/bridge/ffi -o libsignal-ffi.h diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index fddfaa8..8f445ad 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.86.12" +const Version = "v0.87.1" From eb955598253755732e0de57880f535ad6bfdd922 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Feb 2026 14:13:18 +0200 Subject: [PATCH 657/718] signalmeow: update protobufs --- pkg/signalmeow/groups.go | 94 +- .../protobuf/ContactDiscovery.pb.go | 4 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 4 +- pkg/signalmeow/protobuf/Groups.pb.go | 1857 ++++++++-------- pkg/signalmeow/protobuf/Groups.proto | 325 +-- pkg/signalmeow/protobuf/Provisioning.pb.go | 4 +- pkg/signalmeow/protobuf/SignalService.pb.go | 1147 ++++++---- pkg/signalmeow/protobuf/SignalService.proto | 46 +- .../protobuf/StickerResources.pb.go | 4 +- pkg/signalmeow/protobuf/StorageService.pb.go | 129 +- pkg/signalmeow/protobuf/StorageService.proto | 29 +- .../protobuf/UnidentifiedDelivery.pb.go | 4 +- .../protobuf/WebSocketResources.pb.go | 4 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 1897 ++++++++++++----- pkg/signalmeow/protobuf/backuppb/Backup.proto | 78 + pkg/signalmeow/protobuf/update-protos.sh | 6 +- 16 files changed, 3547 insertions(+), 2085 deletions(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index d956fcc..dcdfe7d 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -106,8 +106,8 @@ func (group *Group) GetInviteLink() (string, error) { if err != nil { return "", fmt.Errorf("couldn't decode invite link password") } - inviteLinkContents := signalpb.GroupInviteLink_V1Contents{ - V1Contents: &signalpb.GroupInviteLink_GroupInviteLinkContentsV1{ + inviteLinkContents := signalpb.GroupInviteLink_ContentsV1{ + ContentsV1: &signalpb.GroupInviteLink_GroupInviteLinkContentsV1{ GroupMasterKey: masterKeyBytes[:], InviteLinkPassword: inviteLinkPasswordBytes, }, @@ -471,7 +471,7 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast descriptionBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedGroup.Description) if err == nil { // treat a failure in obtaining the description as non-fatal - decryptedGroup.Description = cleanupStringProperty(descriptionBlob.GetDescription()) + decryptedGroup.Description = cleanupStringProperty(descriptionBlob.GetDescriptionText()) } if encryptedGroup.DisappearingMessagesTimer != nil && len(encryptedGroup.DisappearingMessagesTimer) > 0 { @@ -483,8 +483,8 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast } // These aren't encrypted - decryptedGroup.AvatarPath = encryptedGroup.Avatar - decryptedGroup.Revision = encryptedGroup.Revision + decryptedGroup.AvatarPath = encryptedGroup.AvatarUrl + decryptedGroup.Revision = encryptedGroup.Version // Decrypt members for _, member := range encryptedGroup.Members { @@ -498,7 +498,7 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast decryptedGroup.Members = append(decryptedGroup.Members, decryptedMember) } - for _, pendingMember := range encryptedGroup.PendingMembers { + for _, pendingMember := range encryptedGroup.MembersPendingProfileKey { if pendingMember == nil { continue } @@ -510,7 +510,7 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast decryptedGroup.PendingMembers = append(decryptedGroup.PendingMembers, decryptedPendingMember) } - for _, requestingMember := range encryptedGroup.RequestingMembers { + for _, requestingMember := range encryptedGroup.MembersPendingAdminApproval { if requestingMember == nil { continue } @@ -521,7 +521,7 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast decryptedGroup.RequestingMembers = append(decryptedGroup.RequestingMembers, decryptedRequestingMember) } - for _, bannedMember := range encryptedGroup.BannedMembers { + for _, bannedMember := range encryptedGroup.MembersBanned { if bannedMember == nil { continue } @@ -789,14 +789,14 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange return nil, err } - sourceServiceID, err := groupSecretParams.DecryptServiceID(libsignalgo.UUIDCiphertext(encryptedActions.SourceServiceId)) + sourceServiceID, err := groupSecretParams.DecryptServiceID(libsignalgo.UUIDCiphertext(encryptedActions.SourceUserId)) if err != nil { log.Err(err).Msg("Couldn't decrypt source serviceID") return nil, err } decryptedGroupChange := &GroupChange{ GroupMasterKey: groupMasterKey, - Revision: encryptedActions.Revision, + Revision: encryptedActions.Version, SourceServiceID: sourceServiceID, } @@ -816,7 +816,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange descriptionBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedActions.ModifyDescription.Description) if err == nil { // treat a failure in obtaining the description as non-fatal - newDescription := cleanupStringProperty(descriptionBlob.GetDescription()) + newDescription := cleanupStringProperty(descriptionBlob.GetDescriptionText()) decryptedGroupChange.ModifyDescription = &newDescription } } @@ -891,7 +891,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange } } - for _, addPendingMember := range encryptedActions.AddPendingMembers { + for _, addPendingMember := range encryptedActions.AddMembersPendingProfileKey { if addPendingMember == nil { continue } @@ -904,7 +904,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange decryptedGroupChange.AddPendingMembers = append(decryptedGroupChange.AddPendingMembers, decryptedPendingMember) } - for _, deletePendingMember := range encryptedActions.DeletePendingMembers { + for _, deletePendingMember := range encryptedActions.DeleteMembersPendingProfileKey { if deletePendingMember == nil { continue } @@ -917,7 +917,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange decryptedGroupChange.DeletePendingMembers = append(decryptedGroupChange.DeletePendingMembers, &userID) } - for _, promotePendingMember := range encryptedActions.PromotePendingMembers { + for _, promotePendingMember := range encryptedActions.PromoteMembersPendingProfileKey { if promotePendingMember == nil { continue } @@ -936,7 +936,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange } } - for _, promotePendingPniAciMember := range encryptedActions.PromotePendingPniAciMembers { + for _, promotePendingPniAciMember := range encryptedActions.PromoteMembersPendingPniAciProfileKey { // TODO: pretending this is a PendingMember should do for mautrix-signal, but we probably want to treat them separately at some point if promotePendingPniAciMember == nil { continue @@ -966,7 +966,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange } } - for _, addRequestingMember := range encryptedActions.AddRequestingMembers { + for _, addRequestingMember := range encryptedActions.AddMembersPendingAdminApproval { if addRequestingMember == nil { continue } @@ -982,7 +982,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange } } - for _, deleteRequestingMember := range encryptedActions.DeleteRequestingMembers { + for _, deleteRequestingMember := range encryptedActions.DeleteMembersPendingAdminApproval { if deleteRequestingMember == nil { continue } @@ -995,7 +995,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &serviceID.UUID) } - for _, promoteRequestingMember := range encryptedActions.PromoteRequestingMembers { + for _, promoteRequestingMember := range encryptedActions.PromoteMembersPendingAdminApproval { if promoteRequestingMember == nil { continue } @@ -1011,7 +1011,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange }) } - for _, addBannedMember := range encryptedActions.AddBannedMembers { + for _, addBannedMember := range encryptedActions.AddMembersBanned { if addBannedMember == nil { continue } @@ -1028,7 +1028,7 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange }) } - for _, deleteBannedMember := range encryptedActions.DeleteBannedMembers { + for _, deleteBannedMember := range encryptedActions.DeleteMembersBanned { if deleteBannedMember == nil { continue } @@ -1056,8 +1056,8 @@ func (cli *Client) decryptGroupChange(ctx context.Context, encryptedGroupChange if encryptedActions.ModifyAnnouncementsOnly != nil { decryptedGroupChange.ModifyAnnouncementsOnly = &encryptedActions.ModifyAnnouncementsOnly.AnnouncementsOnly } - if encryptedActions.ModifyDisappearingMessagesTimer != nil && len(encryptedActions.ModifyDisappearingMessagesTimer.Timer) > 0 { - timerBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedActions.ModifyDisappearingMessagesTimer.Timer) + if encryptedActions.ModifyDisappearingMessageTimer != nil && len(encryptedActions.ModifyDisappearingMessageTimer.Timer) > 0 { + timerBlob, err := decryptGroupPropertyIntoBlob(groupSecretParams, encryptedActions.ModifyDisappearingMessageTimer.Timer) if err != nil { return nil, err } @@ -1128,11 +1128,11 @@ func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretPara ACI: *aci, ProfileKey: *profileKey, Role: GroupMemberRole(member.Role), - JoinedAtRevision: member.JoinedAtRevision, + JoinedAtRevision: member.JoinedAtVersion, }, nil } -func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMember, groupSecretParams libsignalgo.GroupSecretParams) (*PendingMember, error) { +func decryptPendingMember(ctx context.Context, pendingMember *signalpb.MemberPendingProfileKey, groupSecretParams libsignalgo.GroupSecretParams) (*PendingMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) @@ -1155,7 +1155,7 @@ func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMe }, nil } -func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.RequestingMember, groupSecretParams libsignalgo.GroupSecretParams) (*RequestingMember, error) { +func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.MemberPendingAdminApproval, groupSecretParams libsignalgo.GroupSecretParams) (*RequestingMember, error) { aci, profileKey, err := decryptPKeyAndIDorPresentation(ctx, requestingMember.UserId, requestingMember.ProfileKey, requestingMember.Presentation, groupSecretParams) if err != nil { return nil, err @@ -1176,7 +1176,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Could not get groupSecretParams from master key") return nil, err } - groupChangeActions := &signalpb.GroupChange_Actions{Revision: decryptedGroupChange.Revision} + groupChangeActions := &signalpb.GroupChange_Actions{Version: decryptedGroupChange.Revision} if decryptedGroupChange.ModifyTitle != nil { attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Title{Title: *decryptedGroupChange.ModifyTitle}} encryptedTitle, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) @@ -1187,7 +1187,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup groupChangeActions.ModifyTitle = &signalpb.GroupChange_Actions_ModifyTitleAction{Title: *encryptedTitle} } if decryptedGroupChange.ModifyDescription != nil { - attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Description{Description: *decryptedGroupChange.ModifyDescription}} + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_DescriptionText{DescriptionText: *decryptedGroupChange.ModifyDescription}} encryptedDescription, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) if err != nil { log.Err(err).Msg("Could not get encrypt description") @@ -1209,7 +1209,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup JoinFromInviteLink: addMember.JoinFromInviteLink, }) } else { - groupChangeActions.AddPendingMembers = append(groupChangeActions.AddPendingMembers, &signalpb.GroupChange_Actions_AddPendingMemberAction{ + groupChangeActions.AddMembersPendingProfileKey = append(groupChangeActions.AddMembersPendingProfileKey, &signalpb.GroupChange_Actions_AddMemberPendingProfileKeyAction{ Added: encryptedPendingMember, }) } @@ -1241,7 +1241,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Failed to encrypt pendingMember") return nil, err } - groupChangeActions.AddPendingMembers = append(groupChangeActions.AddPendingMembers, &signalpb.GroupChange_Actions_AddPendingMemberAction{ + groupChangeActions.AddMembersPendingProfileKey = append(groupChangeActions.AddMembersPendingProfileKey, &signalpb.GroupChange_Actions_AddMemberPendingProfileKeyAction{ Added: encryptedPendingMember, }) } @@ -1251,7 +1251,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Encrypt UserId error for deletePendingMember") return nil, err } - groupChangeActions.DeletePendingMembers = append(groupChangeActions.DeletePendingMembers, &signalpb.GroupChange_Actions_DeletePendingMemberAction{ + groupChangeActions.DeleteMembersPendingProfileKey = append(groupChangeActions.DeleteMembersPendingProfileKey, &signalpb.GroupChange_Actions_DeleteMemberPendingProfileKeyAction{ DeletedUserId: encryptedUserID[:], }) } @@ -1269,7 +1269,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") return nil, err } - groupChangeActions.PromotePendingMembers = append(groupChangeActions.PromotePendingMembers, &signalpb.GroupChange_Actions_PromotePendingMemberAction{ + groupChangeActions.PromoteMembersPendingProfileKey = append(groupChangeActions.PromoteMembersPendingProfileKey, &signalpb.GroupChange_Actions_PromoteMemberPendingProfileKeyAction{ Presentation: *presentation, }) } @@ -1287,8 +1287,8 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") return nil, err } - groupChangeActions.AddRequestingMembers = append(groupChangeActions.AddRequestingMembers, &signalpb.GroupChange_Actions_AddRequestingMemberAction{ - Added: &signalpb.RequestingMember{ + groupChangeActions.AddMembersPendingAdminApproval = append(groupChangeActions.AddMembersPendingAdminApproval, &signalpb.GroupChange_Actions_AddMemberPendingAdminApprovalAction{ + Added: &signalpb.MemberPendingAdminApproval{ Presentation: *presentation, }, }) @@ -1299,7 +1299,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Encrypt UserId error for deleteRequestingMember") return nil, err } - groupChangeActions.DeleteRequestingMembers = append(groupChangeActions.DeleteRequestingMembers, &signalpb.GroupChange_Actions_DeleteRequestingMemberAction{ + groupChangeActions.DeleteMembersPendingAdminApproval = append(groupChangeActions.DeleteMembersPendingAdminApproval, &signalpb.GroupChange_Actions_DeleteMemberPendingAdminApprovalAction{ DeletedUserId: encryptedUserID[:], }) } @@ -1310,7 +1310,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup return nil, err } - groupChangeActions.PromoteRequestingMembers = append(groupChangeActions.PromoteRequestingMembers, &signalpb.GroupChange_Actions_PromoteRequestingMemberAction{ + groupChangeActions.PromoteMembersPendingAdminApproval = append(groupChangeActions.PromoteMembersPendingAdminApproval, &signalpb.GroupChange_Actions_PromoteMemberPendingAdminApprovalAction{ UserId: encryptedUserID[:], Role: signalpb.Member_Role(promoteRequestingMember.Role), }) @@ -1321,8 +1321,8 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err } - groupChangeActions.AddBannedMembers = append(groupChangeActions.AddBannedMembers, &signalpb.GroupChange_Actions_AddBannedMemberAction{ - Added: &signalpb.BannedMember{ + groupChangeActions.AddMembersBanned = append(groupChangeActions.AddMembersBanned, &signalpb.GroupChange_Actions_AddMemberBannedAction{ + Added: &signalpb.MemberBanned{ UserId: encryptedUserID[:], Timestamp: addBannedMember.Timestamp, }, @@ -1334,7 +1334,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err } - groupChangeActions.DeleteBannedMembers = append(groupChangeActions.DeleteBannedMembers, &signalpb.GroupChange_Actions_DeleteBannedMemberAction{ + groupChangeActions.DeleteMembersBanned = append(groupChangeActions.DeleteMembersBanned, &signalpb.GroupChange_Actions_DeleteMemberBannedAction{ DeletedUserId: encryptedUserID[:], }) } @@ -1365,7 +1365,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup log.Err(err).Msg("Could not get encrypt Title") return nil, err } - groupChangeActions.ModifyDisappearingMessagesTimer = &signalpb.GroupChange_Actions_ModifyDisappearingMessagesTimerAction{Timer: *encryptedTimer} + groupChangeActions.ModifyDisappearingMessageTimer = &signalpb.GroupChange_Actions_ModifyDisappearingMessageTimerAction{Timer: *encryptedTimer} } if decryptedGroupChange.ModifyInviteLinkPassword != nil { inviteLinkPasswordBytes, err := inviteLinkPasswordToBytes(*decryptedGroupChange.ModifyInviteLinkPassword) @@ -1380,7 +1380,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup return cli.patchGroup(ctx, groupChangeActions, groupMasterKey, nil) } -func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, *signalpb.PendingMember, error) { +func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, *signalpb.MemberPendingProfileKey, error) { log := zerolog.Ctx(ctx) expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, member.ACI) if err != nil { @@ -1408,7 +1408,7 @@ func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, group return &encryptedMember, nil, nil } -func (cli *Client) encryptPendingMember(ctx context.Context, pendingMember *PendingMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.PendingMember, error) { +func (cli *Client) encryptPendingMember(ctx context.Context, pendingMember *PendingMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.MemberPendingProfileKey, error) { log := zerolog.Ctx(ctx) encryptedUserID, err := groupSecretParams.EncryptServiceID(pendingMember.ServiceID) if err != nil { @@ -1420,7 +1420,7 @@ func (cli *Client) encryptPendingMember(ctx context.Context, pendingMember *Pend log.Err(err).Msg("Encrypt AddedByUserId error for addPendingMember") return nil, err } - encryptedPendingMember := signalpb.PendingMember{ + encryptedPendingMember := signalpb.MemberPendingProfileKey{ AddedByUserId: encryptedAddedByUserID[:], Member: &signalpb.Member{ UserId: encryptedUserID[:], @@ -1600,12 +1600,12 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou encryptedGroup := &signalpb.Group{ PublicKey: groupPublicParams[:], Title: *encryptedTitle, - Avatar: decryptedGroup.AvatarPath, + AvatarUrl: decryptedGroup.AvatarPath, AnnouncementsOnly: decryptedGroup.AnnouncementsOnly, - Revision: 0, + Version: 0, } if decryptedGroup.Description != "" { - attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_Description{Description: decryptedGroup.Description}} + attributeBlob := signalpb.GroupAttributeBlob{Content: &signalpb.GroupAttributeBlob_DescriptionText{DescriptionText: decryptedGroup.Description}} encryptedDescription, err := encryptBlobIntoGroupProperty(groupSecretParams, &attributeBlob) if err != nil { log.Err(err).Msg("Could not get encrypt Description") @@ -1631,7 +1631,7 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou if encryptedMember != nil { encryptedGroup.Members = append(encryptedGroup.Members, encryptedMember) } else { - encryptedGroup.PendingMembers = append(encryptedGroup.PendingMembers, encryptedPendingMember) + encryptedGroup.MembersPendingProfileKey = append(encryptedGroup.MembersPendingProfileKey, encryptedPendingMember) } } for _, pendingMember := range decryptedGroup.PendingMembers { @@ -1640,7 +1640,7 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou log.Err(err).Msg("Failed to encrypt pendingMember") return nil, err } - encryptedGroup.PendingMembers = append(encryptedGroup.PendingMembers, encryptedPendingMember) + encryptedGroup.MembersPendingProfileKey = append(encryptedGroup.MembersPendingProfileKey, encryptedPendingMember) } return encryptedGroup, nil } diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 5523a0e..637a2d2 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: ContactDiscovery.proto // Copyright 2021 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 144428d..5666b7e 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: DeviceName.proto // Copyright 2018 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 3e5cc7a..c7717ff 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -1,12 +1,11 @@ -//* -// Copyright (C) 2019 Open Whisper Systems // -// Licensed according to the LICENSE file in this repository. +// Copyright 2020 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.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: Groups.proto package signalpb @@ -223,14 +222,16 @@ func (x *AvatarUploadAttributes) GetSignature() string { } type Member struct { - state protoimpl.MessageState `protogen:"open.v1"` - UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` - ProfileKey []byte `protobuf:"bytes,3,opt,name=profileKey,proto3" json:"profileKey,omitempty"` - Presentation []byte `protobuf:"bytes,4,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - JoinedAtRevision uint32 `protobuf:"varint,5,opt,name=joinedAtRevision,proto3" json:"joinedAtRevision,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=signal.Member_Role" json:"role,omitempty"` + ProfileKey []byte `protobuf:"bytes,3,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + Presentation []byte `protobuf:"bytes,4,opt,name=presentation,proto3" json:"presentation,omitempty"` + JoinedAtVersion uint32 `protobuf:"varint,5,opt,name=joinedAtVersion,proto3" json:"joinedAtVersion,omitempty"` + LabelEmoji []byte `protobuf:"bytes,6,opt,name=labelEmoji,proto3" json:"labelEmoji,omitempty"` // decrypts to a UTF-8 string + LabelString []byte `protobuf:"bytes,7,opt,name=labelString,proto3" json:"labelString,omitempty"` // decrypts to a UTF-8 string + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Member) Reset() { @@ -291,36 +292,50 @@ func (x *Member) GetPresentation() []byte { return nil } -func (x *Member) GetJoinedAtRevision() uint32 { +func (x *Member) GetJoinedAtVersion() uint32 { if x != nil { - return x.JoinedAtRevision + return x.JoinedAtVersion } return 0 } -type PendingMember struct { +func (x *Member) GetLabelEmoji() []byte { + if x != nil { + return x.LabelEmoji + } + return nil +} + +func (x *Member) GetLabelString() []byte { + if x != nil { + return x.LabelString + } + return nil +} + +type MemberPendingProfileKey struct { state protoimpl.MessageState `protogen:"open.v1"` Member *Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` AddedByUserId []byte `protobuf:"bytes,2,opt,name=addedByUserId,proto3" json:"addedByUserId,omitempty"` - Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // ms since epoch unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PendingMember) Reset() { - *x = PendingMember{} +func (x *MemberPendingProfileKey) Reset() { + *x = MemberPendingProfileKey{} mi := &file_Groups_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PendingMember) String() string { +func (x *MemberPendingProfileKey) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PendingMember) ProtoMessage() {} +func (*MemberPendingProfileKey) ProtoMessage() {} -func (x *PendingMember) ProtoReflect() protoreflect.Message { +func (x *MemberPendingProfileKey) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -332,56 +347,56 @@ func (x *PendingMember) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PendingMember.ProtoReflect.Descriptor instead. -func (*PendingMember) Descriptor() ([]byte, []int) { +// Deprecated: Use MemberPendingProfileKey.ProtoReflect.Descriptor instead. +func (*MemberPendingProfileKey) Descriptor() ([]byte, []int) { return file_Groups_proto_rawDescGZIP(), []int{2} } -func (x *PendingMember) GetMember() *Member { +func (x *MemberPendingProfileKey) GetMember() *Member { if x != nil { return x.Member } return nil } -func (x *PendingMember) GetAddedByUserId() []byte { +func (x *MemberPendingProfileKey) GetAddedByUserId() []byte { if x != nil { return x.AddedByUserId } return nil } -func (x *PendingMember) GetTimestamp() uint64 { +func (x *MemberPendingProfileKey) GetTimestamp() uint64 { if x != nil { return x.Timestamp } return 0 } -type RequestingMember struct { +type MemberPendingAdminApproval struct { state protoimpl.MessageState `protogen:"open.v1"` UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` ProfileKey []byte `protobuf:"bytes,2,opt,name=profileKey,proto3" json:"profileKey,omitempty"` - Presentation []byte `protobuf:"bytes,3,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Presentation []byte `protobuf:"bytes,3,opt,name=presentation,proto3" json:"presentation,omitempty"` + Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // ms since epoch unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *RequestingMember) Reset() { - *x = RequestingMember{} +func (x *MemberPendingAdminApproval) Reset() { + *x = MemberPendingAdminApproval{} mi := &file_Groups_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *RequestingMember) String() string { +func (x *MemberPendingAdminApproval) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RequestingMember) ProtoMessage() {} +func (*MemberPendingAdminApproval) ProtoMessage() {} -func (x *RequestingMember) ProtoReflect() protoreflect.Message { +func (x *MemberPendingAdminApproval) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -393,61 +408,61 @@ func (x *RequestingMember) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use RequestingMember.ProtoReflect.Descriptor instead. -func (*RequestingMember) Descriptor() ([]byte, []int) { +// Deprecated: Use MemberPendingAdminApproval.ProtoReflect.Descriptor instead. +func (*MemberPendingAdminApproval) Descriptor() ([]byte, []int) { return file_Groups_proto_rawDescGZIP(), []int{3} } -func (x *RequestingMember) GetUserId() []byte { +func (x *MemberPendingAdminApproval) GetUserId() []byte { if x != nil { return x.UserId } return nil } -func (x *RequestingMember) GetProfileKey() []byte { +func (x *MemberPendingAdminApproval) GetProfileKey() []byte { if x != nil { return x.ProfileKey } return nil } -func (x *RequestingMember) GetPresentation() []byte { +func (x *MemberPendingAdminApproval) GetPresentation() []byte { if x != nil { return x.Presentation } return nil } -func (x *RequestingMember) GetTimestamp() uint64 { +func (x *MemberPendingAdminApproval) GetTimestamp() uint64 { if x != nil { return x.Timestamp } return 0 } -type BannedMember struct { +type MemberBanned struct { state protoimpl.MessageState `protogen:"open.v1"` UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // ms since epoch unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *BannedMember) Reset() { - *x = BannedMember{} +func (x *MemberBanned) Reset() { + *x = MemberBanned{} mi := &file_Groups_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *BannedMember) String() string { +func (x *MemberBanned) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BannedMember) ProtoMessage() {} +func (*MemberBanned) ProtoMessage() {} -func (x *BannedMember) ProtoReflect() protoreflect.Message { +func (x *MemberBanned) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -459,19 +474,19 @@ func (x *BannedMember) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BannedMember.ProtoReflect.Descriptor instead. -func (*BannedMember) Descriptor() ([]byte, []int) { +// Deprecated: Use MemberBanned.ProtoReflect.Descriptor instead. +func (*MemberBanned) Descriptor() ([]byte, []int) { return file_Groups_proto_rawDescGZIP(), []int{4} } -func (x *BannedMember) GetUserId() []byte { +func (x *MemberBanned) GetUserId() []byte { if x != nil { return x.UserId } return nil } -func (x *BannedMember) GetTimestamp() uint64 { +func (x *MemberBanned) GetTimestamp() uint64 { if x != nil { return x.Timestamp } @@ -480,9 +495,9 @@ func (x *BannedMember) GetTimestamp() uint64 { type AccessControl struct { state protoimpl.MessageState `protogen:"open.v1"` - Attributes AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=AccessControl_AccessRequired" json:"attributes,omitempty"` - Members AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=AccessControl_AccessRequired" json:"members,omitempty"` - AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` + Attributes AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=signal.AccessControl_AccessRequired" json:"attributes,omitempty"` + Members AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=signal.AccessControl_AccessRequired" json:"members,omitempty"` + AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=signal.AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -539,22 +554,24 @@ func (x *AccessControl) GetAddFromInviteLink() AccessControl_AccessRequired { } type Group struct { - state protoimpl.MessageState `protogen:"open.v1"` - PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` - Title []byte `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` - DisappearingMessagesTimer []byte `protobuf:"bytes,4,opt,name=disappearingMessagesTimer,proto3" json:"disappearingMessagesTimer,omitempty"` - AccessControl *AccessControl `protobuf:"bytes,5,opt,name=accessControl,proto3" json:"accessControl,omitempty"` - Revision uint32 `protobuf:"varint,6,opt,name=revision,proto3" json:"revision,omitempty"` - Members []*Member `protobuf:"bytes,7,rep,name=members,proto3" json:"members,omitempty"` - PendingMembers []*PendingMember `protobuf:"bytes,8,rep,name=pendingMembers,proto3" json:"pendingMembers,omitempty"` - RequestingMembers []*RequestingMember `protobuf:"bytes,9,rep,name=requestingMembers,proto3" json:"requestingMembers,omitempty"` - InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` - Description []byte `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` - AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcementsOnly,proto3" json:"announcementsOnly,omitempty"` - BannedMembers []*BannedMember `protobuf:"bytes,13,rep,name=bannedMembers,proto3" json:"bannedMembers,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` + Title []byte `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Description []byte `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` + // The URL for this group's avatar. The content at this URL can be + // decrypted/deserialized into a `GroupAttributeBlob`. + AvatarUrl string `protobuf:"bytes,3,opt,name=avatarUrl,proto3" json:"avatarUrl,omitempty"` + DisappearingMessagesTimer []byte `protobuf:"bytes,4,opt,name=disappearingMessagesTimer,proto3" json:"disappearingMessagesTimer,omitempty"` + AccessControl *AccessControl `protobuf:"bytes,5,opt,name=accessControl,proto3" json:"accessControl,omitempty"` + Version uint32 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` + Members []*Member `protobuf:"bytes,7,rep,name=members,proto3" json:"members,omitempty"` + MembersPendingProfileKey []*MemberPendingProfileKey `protobuf:"bytes,8,rep,name=membersPendingProfileKey,proto3" json:"membersPendingProfileKey,omitempty"` + MembersPendingAdminApproval []*MemberPendingAdminApproval `protobuf:"bytes,9,rep,name=membersPendingAdminApproval,proto3" json:"membersPendingAdminApproval,omitempty"` + InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"` + MembersBanned []*MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"` // next: 14 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Group) Reset() { @@ -601,9 +618,16 @@ func (x *Group) GetTitle() []byte { return nil } -func (x *Group) GetAvatar() string { +func (x *Group) GetDescription() []byte { if x != nil { - return x.Avatar + return x.Description + } + return nil +} + +func (x *Group) GetAvatarUrl() string { + if x != nil { + return x.AvatarUrl } return "" } @@ -622,9 +646,9 @@ func (x *Group) GetAccessControl() *AccessControl { return nil } -func (x *Group) GetRevision() uint32 { +func (x *Group) GetVersion() uint32 { if x != nil { - return x.Revision + return x.Version } return 0 } @@ -636,16 +660,16 @@ func (x *Group) GetMembers() []*Member { return nil } -func (x *Group) GetPendingMembers() []*PendingMember { +func (x *Group) GetMembersPendingProfileKey() []*MemberPendingProfileKey { if x != nil { - return x.PendingMembers + return x.MembersPendingProfileKey } return nil } -func (x *Group) GetRequestingMembers() []*RequestingMember { +func (x *Group) GetMembersPendingAdminApproval() []*MemberPendingAdminApproval { if x != nil { - return x.RequestingMembers + return x.MembersPendingAdminApproval } return nil } @@ -657,13 +681,6 @@ func (x *Group) GetInviteLinkPassword() []byte { return nil } -func (x *Group) GetDescription() []byte { - if x != nil { - return x.Description - } - return nil -} - func (x *Group) GetAnnouncementsOnly() bool { if x != nil { return x.AnnouncementsOnly @@ -671,225 +688,9 @@ func (x *Group) GetAnnouncementsOnly() bool { return false } -func (x *Group) GetBannedMembers() []*BannedMember { +func (x *Group) GetMembersBanned() []*MemberBanned { if x != nil { - return x.BannedMembers - } - return nil -} - -type GroupChange struct { - state protoimpl.MessageState `protogen:"open.v1"` - Actions []byte `protobuf:"bytes,1,opt,name=actions,proto3" json:"actions,omitempty"` - ServerSignature []byte `protobuf:"bytes,2,opt,name=serverSignature,proto3" json:"serverSignature,omitempty"` - ChangeEpoch uint32 `protobuf:"varint,3,opt,name=changeEpoch,proto3" json:"changeEpoch,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupChange) Reset() { - *x = GroupChange{} - mi := &file_Groups_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupChange) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupChange) ProtoMessage() {} - -func (x *GroupChange) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[7] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GroupChange.ProtoReflect.Descriptor instead. -func (*GroupChange) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7} -} - -func (x *GroupChange) GetActions() []byte { - if x != nil { - return x.Actions - } - return nil -} - -func (x *GroupChange) GetServerSignature() []byte { - if x != nil { - return x.ServerSignature - } - return nil -} - -func (x *GroupChange) GetChangeEpoch() uint32 { - if x != nil { - return x.ChangeEpoch - } - return 0 -} - -type GroupResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupResponse) Reset() { - *x = GroupResponse{} - mi := &file_Groups_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupResponse) ProtoMessage() {} - -func (x *GroupResponse) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[8] - 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 GroupResponse.ProtoReflect.Descriptor instead. -func (*GroupResponse) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{8} -} - -func (x *GroupResponse) GetGroup() *Group { - if x != nil { - return x.Group - } - return nil -} - -func (x *GroupResponse) GetGroupSendEndorsementsResponse() []byte { - if x != nil { - return x.GroupSendEndorsementsResponse - } - return nil -} - -type GroupChanges struct { - state protoimpl.MessageState `protogen:"open.v1"` - GroupChanges []*GroupChanges_GroupChangeState `protobuf:"bytes,1,rep,name=groupChanges,proto3" json:"groupChanges,omitempty"` - GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupChanges) Reset() { - *x = GroupChanges{} - mi := &file_Groups_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupChanges) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupChanges) ProtoMessage() {} - -func (x *GroupChanges) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[9] - 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 GroupChanges.ProtoReflect.Descriptor instead. -func (*GroupChanges) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{9} -} - -func (x *GroupChanges) GetGroupChanges() []*GroupChanges_GroupChangeState { - if x != nil { - return x.GroupChanges - } - return nil -} - -func (x *GroupChanges) GetGroupSendEndorsementsResponse() []byte { - if x != nil { - return x.GroupSendEndorsementsResponse - } - return nil -} - -type GroupChangeResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` - GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=groupSendEndorsementsResponse,proto3" json:"groupSendEndorsementsResponse,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupChangeResponse) Reset() { - *x = GroupChangeResponse{} - mi := &file_Groups_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupChangeResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupChangeResponse) ProtoMessage() {} - -func (x *GroupChangeResponse) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[10] - 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 GroupChangeResponse.ProtoReflect.Descriptor instead. -func (*GroupChangeResponse) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{10} -} - -func (x *GroupChangeResponse) GetGroupChange() *GroupChange { - if x != nil { - return x.GroupChange - } - return nil -} - -func (x *GroupChangeResponse) GetGroupSendEndorsementsResponse() []byte { - if x != nil { - return x.GroupSendEndorsementsResponse + return x.MembersBanned } return nil } @@ -901,7 +702,7 @@ type GroupAttributeBlob struct { // *GroupAttributeBlob_Title // *GroupAttributeBlob_Avatar // *GroupAttributeBlob_DisappearingMessagesDuration - // *GroupAttributeBlob_Description + // *GroupAttributeBlob_DescriptionText Content isGroupAttributeBlob_Content `protobuf_oneof:"content"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -909,7 +710,7 @@ type GroupAttributeBlob struct { func (x *GroupAttributeBlob) Reset() { *x = GroupAttributeBlob{} - mi := &file_Groups_proto_msgTypes[11] + mi := &file_Groups_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -921,7 +722,7 @@ func (x *GroupAttributeBlob) String() string { func (*GroupAttributeBlob) ProtoMessage() {} func (x *GroupAttributeBlob) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[11] + mi := &file_Groups_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -934,7 +735,7 @@ func (x *GroupAttributeBlob) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupAttributeBlob.ProtoReflect.Descriptor instead. func (*GroupAttributeBlob) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{11} + return file_Groups_proto_rawDescGZIP(), []int{7} } func (x *GroupAttributeBlob) GetContent() isGroupAttributeBlob_Content { @@ -971,10 +772,10 @@ func (x *GroupAttributeBlob) GetDisappearingMessagesDuration() uint32 { return 0 } -func (x *GroupAttributeBlob) GetDescription() string { +func (x *GroupAttributeBlob) GetDescriptionText() string { if x != nil { - if x, ok := x.Content.(*GroupAttributeBlob_Description); ok { - return x.Description + if x, ok := x.Content.(*GroupAttributeBlob_DescriptionText); ok { + return x.DescriptionText } } return "" @@ -996,8 +797,8 @@ type GroupAttributeBlob_DisappearingMessagesDuration struct { DisappearingMessagesDuration uint32 `protobuf:"varint,3,opt,name=disappearingMessagesDuration,proto3,oneof"` } -type GroupAttributeBlob_Description struct { - Description string `protobuf:"bytes,4,opt,name=description,proto3,oneof"` +type GroupAttributeBlob_DescriptionText struct { + DescriptionText string `protobuf:"bytes,4,opt,name=descriptionText,proto3,oneof"` } func (*GroupAttributeBlob_Title) isGroupAttributeBlob_Content() {} @@ -1006,13 +807,13 @@ func (*GroupAttributeBlob_Avatar) isGroupAttributeBlob_Content() {} func (*GroupAttributeBlob_DisappearingMessagesDuration) isGroupAttributeBlob_Content() {} -func (*GroupAttributeBlob_Description) isGroupAttributeBlob_Content() {} +func (*GroupAttributeBlob_DescriptionText) isGroupAttributeBlob_Content() {} type GroupInviteLink struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Contents: // - // *GroupInviteLink_V1Contents + // *GroupInviteLink_ContentsV1 Contents isGroupInviteLink_Contents `protobuf_oneof:"contents"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -1020,7 +821,7 @@ type GroupInviteLink struct { func (x *GroupInviteLink) Reset() { *x = GroupInviteLink{} - mi := &file_Groups_proto_msgTypes[12] + mi := &file_Groups_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1032,7 +833,7 @@ func (x *GroupInviteLink) String() string { func (*GroupInviteLink) ProtoMessage() {} func (x *GroupInviteLink) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[12] + mi := &file_Groups_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1045,7 +846,7 @@ func (x *GroupInviteLink) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLink.ProtoReflect.Descriptor instead. func (*GroupInviteLink) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{12} + return file_Groups_proto_rawDescGZIP(), []int{8} } func (x *GroupInviteLink) GetContents() isGroupInviteLink_Contents { @@ -1055,10 +856,10 @@ func (x *GroupInviteLink) GetContents() isGroupInviteLink_Contents { return nil } -func (x *GroupInviteLink) GetV1Contents() *GroupInviteLink_GroupInviteLinkContentsV1 { +func (x *GroupInviteLink) GetContentsV1() *GroupInviteLink_GroupInviteLinkContentsV1 { if x != nil { - if x, ok := x.Contents.(*GroupInviteLink_V1Contents); ok { - return x.V1Contents + if x, ok := x.Contents.(*GroupInviteLink_ContentsV1); ok { + return x.ContentsV1 } } return nil @@ -1068,29 +869,29 @@ type isGroupInviteLink_Contents interface { isGroupInviteLink_Contents() } -type GroupInviteLink_V1Contents struct { - V1Contents *GroupInviteLink_GroupInviteLinkContentsV1 `protobuf:"bytes,1,opt,name=v1Contents,proto3,oneof"` +type GroupInviteLink_ContentsV1 struct { + ContentsV1 *GroupInviteLink_GroupInviteLinkContentsV1 `protobuf:"bytes,1,opt,name=contentsV1,proto3,oneof"` } -func (*GroupInviteLink_V1Contents) isGroupInviteLink_Contents() {} +func (*GroupInviteLink_ContentsV1) isGroupInviteLink_Contents() {} type GroupJoinInfo struct { state protoimpl.MessageState `protogen:"open.v1"` PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` Title []byte `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Description []byte `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"` Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` MemberCount uint32 `protobuf:"varint,4,opt,name=memberCount,proto3" json:"memberCount,omitempty"` - AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,5,opt,name=addFromInviteLink,proto3,enum=AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` - Revision uint32 `protobuf:"varint,6,opt,name=revision,proto3" json:"revision,omitempty"` + AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,5,opt,name=addFromInviteLink,proto3,enum=signal.AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` + Version uint32 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` PendingAdminApproval bool `protobuf:"varint,7,opt,name=pendingAdminApproval,proto3" json:"pendingAdminApproval,omitempty"` - Description []byte `protobuf:"bytes,8,opt,name=description,proto3" json:"description,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupJoinInfo) Reset() { *x = GroupJoinInfo{} - mi := &file_Groups_proto_msgTypes[13] + mi := &file_Groups_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1102,7 +903,7 @@ func (x *GroupJoinInfo) String() string { func (*GroupJoinInfo) ProtoMessage() {} func (x *GroupJoinInfo) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[13] + mi := &file_Groups_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1115,7 +916,7 @@ func (x *GroupJoinInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinInfo.ProtoReflect.Descriptor instead. func (*GroupJoinInfo) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{13} + return file_Groups_proto_rawDescGZIP(), []int{9} } func (x *GroupJoinInfo) GetPublicKey() []byte { @@ -1132,6 +933,13 @@ func (x *GroupJoinInfo) GetTitle() []byte { return nil } +func (x *GroupJoinInfo) GetDescription() []byte { + if x != nil { + return x.Description + } + return nil +} + func (x *GroupJoinInfo) GetAvatar() string { if x != nil { return x.Avatar @@ -1153,9 +961,9 @@ func (x *GroupJoinInfo) GetAddFromInviteLink() AccessControl_AccessRequired { return AccessControl_UNKNOWN } -func (x *GroupJoinInfo) GetRevision() uint32 { +func (x *GroupJoinInfo) GetVersion() uint32 { if x != nil { - return x.Revision + return x.Version } return 0 } @@ -1167,34 +975,236 @@ func (x *GroupJoinInfo) GetPendingAdminApproval() bool { return false } -func (x *GroupJoinInfo) GetDescription() []byte { +type GroupChange struct { + state protoimpl.MessageState `protogen:"open.v1"` + Actions []byte `protobuf:"bytes,1,opt,name=actions,proto3" json:"actions,omitempty"` + ServerSignature []byte `protobuf:"bytes,2,opt,name=serverSignature,proto3" json:"serverSignature,omitempty"` + ChangeEpoch uint32 `protobuf:"varint,3,opt,name=changeEpoch,proto3" json:"changeEpoch,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChange) Reset() { + *x = GroupChange{} + mi := &file_Groups_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChange) ProtoMessage() {} + +func (x *GroupChange) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[10] if x != nil { - return x.Description + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupChange.ProtoReflect.Descriptor instead. +func (*GroupChange) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10} +} + +func (x *GroupChange) GetActions() []byte { + if x != nil { + return x.Actions } return nil } -type GroupExternalCredential struct { +func (x *GroupChange) GetServerSignature() []byte { + if x != nil { + return x.ServerSignature + } + return nil +} + +func (x *GroupChange) GetChangeEpoch() uint32 { + if x != nil { + return x.ChangeEpoch + } + return 0 +} + +type ExternalGroupCredential struct { state protoimpl.MessageState `protogen:"open.v1"` Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupExternalCredential) Reset() { - *x = GroupExternalCredential{} +func (x *ExternalGroupCredential) Reset() { + *x = ExternalGroupCredential{} + mi := &file_Groups_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExternalGroupCredential) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExternalGroupCredential) ProtoMessage() {} + +func (x *ExternalGroupCredential) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[11] + 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 ExternalGroupCredential.ProtoReflect.Descriptor instead. +func (*ExternalGroupCredential) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{11} +} + +func (x *ExternalGroupCredential) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type GroupResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=group_send_endorsements_response,json=groupSendEndorsementsResponse,proto3" json:"group_send_endorsements_response,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupResponse) Reset() { + *x = GroupResponse{} + mi := &file_Groups_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupResponse) ProtoMessage() {} + +func (x *GroupResponse) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[12] + 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 GroupResponse.ProtoReflect.Descriptor instead. +func (*GroupResponse) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{12} +} + +func (x *GroupResponse) GetGroup() *Group { + if x != nil { + return x.Group + } + return nil +} + +func (x *GroupResponse) GetGroupSendEndorsementsResponse() []byte { + if x != nil { + return x.GroupSendEndorsementsResponse + } + return nil +} + +type GroupChanges struct { + state protoimpl.MessageState `protogen:"open.v1"` + GroupChanges []*GroupChanges_GroupChangeState `protobuf:"bytes,1,rep,name=groupChanges,proto3" json:"groupChanges,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=group_send_endorsements_response,json=groupSendEndorsementsResponse,proto3" json:"group_send_endorsements_response,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChanges) Reset() { + *x = GroupChanges{} + mi := &file_Groups_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChanges) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChanges) ProtoMessage() {} + +func (x *GroupChanges) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[13] + 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 GroupChanges.ProtoReflect.Descriptor instead. +func (*GroupChanges) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{13} +} + +func (x *GroupChanges) GetGroupChanges() []*GroupChanges_GroupChangeState { + if x != nil { + return x.GroupChanges + } + return nil +} + +func (x *GroupChanges) GetGroupSendEndorsementsResponse() []byte { + if x != nil { + return x.GroupSendEndorsementsResponse + } + return nil +} + +type GroupChangeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + GroupChange *GroupChange `protobuf:"bytes,1,opt,name=group_change,json=groupChange,proto3" json:"group_change,omitempty"` + GroupSendEndorsementsResponse []byte `protobuf:"bytes,2,opt,name=group_send_endorsements_response,json=groupSendEndorsementsResponse,proto3" json:"group_send_endorsements_response,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChangeResponse) Reset() { + *x = GroupChangeResponse{} mi := &file_Groups_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupExternalCredential) String() string { +func (x *GroupChangeResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupExternalCredential) ProtoMessage() {} +func (*GroupChangeResponse) ProtoMessage() {} -func (x *GroupExternalCredential) ProtoReflect() protoreflect.Message { +func (x *GroupChangeResponse) ProtoReflect() protoreflect.Message { mi := &file_Groups_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1206,52 +1216,114 @@ func (x *GroupExternalCredential) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GroupExternalCredential.ProtoReflect.Descriptor instead. -func (*GroupExternalCredential) Descriptor() ([]byte, []int) { +// Deprecated: Use GroupChangeResponse.ProtoReflect.Descriptor instead. +func (*GroupChangeResponse) Descriptor() ([]byte, []int) { return file_Groups_proto_rawDescGZIP(), []int{14} } -func (x *GroupExternalCredential) GetToken() string { +func (x *GroupChangeResponse) GetGroupChange() *GroupChange { if x != nil { - return x.Token + return x.GroupChange } - return "" + return nil +} + +func (x *GroupChangeResponse) GetGroupSendEndorsementsResponse() []byte { + if x != nil { + return x.GroupSendEndorsementsResponse + } + return nil +} + +type GroupInviteLink_GroupInviteLinkContentsV1 struct { + state protoimpl.MessageState `protogen:"open.v1"` + GroupMasterKey []byte `protobuf:"bytes,1,opt,name=groupMasterKey,proto3" json:"groupMasterKey,omitempty"` + InviteLinkPassword []byte `protobuf:"bytes,2,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupInviteLink_GroupInviteLinkContentsV1) Reset() { + *x = GroupInviteLink_GroupInviteLinkContentsV1{} + mi := &file_Groups_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupInviteLink_GroupInviteLinkContentsV1) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupInviteLink_GroupInviteLinkContentsV1) ProtoMessage() {} + +func (x *GroupInviteLink_GroupInviteLinkContentsV1) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[15] + 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 GroupInviteLink_GroupInviteLinkContentsV1.ProtoReflect.Descriptor instead. +func (*GroupInviteLink_GroupInviteLinkContentsV1) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{8, 0} +} + +func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetGroupMasterKey() []byte { + if x != nil { + return x.GroupMasterKey + } + return nil +} + +func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetInviteLinkPassword() []byte { + if x != nil { + return x.InviteLinkPassword + } + return nil } type GroupChange_Actions struct { - state protoimpl.MessageState `protogen:"open.v1"` - SourceServiceId []byte `protobuf:"bytes,1,opt,name=sourceServiceId,proto3" json:"sourceServiceId,omitempty"` - GroupId []byte `protobuf:"bytes,25,opt,name=groupId,proto3" json:"groupId,omitempty"` // Only set when receiving from server - Revision uint32 `protobuf:"varint,2,opt,name=revision,proto3" json:"revision,omitempty"` - AddMembers []*GroupChange_Actions_AddMemberAction `protobuf:"bytes,3,rep,name=addMembers,proto3" json:"addMembers,omitempty"` - DeleteMembers []*GroupChange_Actions_DeleteMemberAction `protobuf:"bytes,4,rep,name=deleteMembers,proto3" json:"deleteMembers,omitempty"` - ModifyMemberRoles []*GroupChange_Actions_ModifyMemberRoleAction `protobuf:"bytes,5,rep,name=modifyMemberRoles,proto3" json:"modifyMemberRoles,omitempty"` - ModifyMemberProfileKeys []*GroupChange_Actions_ModifyMemberProfileKeyAction `protobuf:"bytes,6,rep,name=modifyMemberProfileKeys,proto3" json:"modifyMemberProfileKeys,omitempty"` - AddPendingMembers []*GroupChange_Actions_AddPendingMemberAction `protobuf:"bytes,7,rep,name=addPendingMembers,proto3" json:"addPendingMembers,omitempty"` - DeletePendingMembers []*GroupChange_Actions_DeletePendingMemberAction `protobuf:"bytes,8,rep,name=deletePendingMembers,proto3" json:"deletePendingMembers,omitempty"` - PromotePendingMembers []*GroupChange_Actions_PromotePendingMemberAction `protobuf:"bytes,9,rep,name=promotePendingMembers,proto3" json:"promotePendingMembers,omitempty"` - ModifyTitle *GroupChange_Actions_ModifyTitleAction `protobuf:"bytes,10,opt,name=modifyTitle,proto3" json:"modifyTitle,omitempty"` - ModifyAvatar *GroupChange_Actions_ModifyAvatarAction `protobuf:"bytes,11,opt,name=modifyAvatar,proto3" json:"modifyAvatar,omitempty"` - ModifyDisappearingMessagesTimer *GroupChange_Actions_ModifyDisappearingMessagesTimerAction `protobuf:"bytes,12,opt,name=modifyDisappearingMessagesTimer,proto3" json:"modifyDisappearingMessagesTimer,omitempty"` - ModifyAttributesAccess *GroupChange_Actions_ModifyAttributesAccessControlAction `protobuf:"bytes,13,opt,name=modifyAttributesAccess,proto3" json:"modifyAttributesAccess,omitempty"` - ModifyMemberAccess *GroupChange_Actions_ModifyMembersAccessControlAction `protobuf:"bytes,14,opt,name=modifyMemberAccess,proto3" json:"modifyMemberAccess,omitempty"` - ModifyAddFromInviteLinkAccess *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction `protobuf:"bytes,15,opt,name=modifyAddFromInviteLinkAccess,proto3" json:"modifyAddFromInviteLinkAccess,omitempty"` - AddRequestingMembers []*GroupChange_Actions_AddRequestingMemberAction `protobuf:"bytes,16,rep,name=addRequestingMembers,proto3" json:"addRequestingMembers,omitempty"` - DeleteRequestingMembers []*GroupChange_Actions_DeleteRequestingMemberAction `protobuf:"bytes,17,rep,name=deleteRequestingMembers,proto3" json:"deleteRequestingMembers,omitempty"` - PromoteRequestingMembers []*GroupChange_Actions_PromoteRequestingMemberAction `protobuf:"bytes,18,rep,name=promoteRequestingMembers,proto3" json:"promoteRequestingMembers,omitempty"` - ModifyInviteLinkPassword *GroupChange_Actions_ModifyInviteLinkPasswordAction `protobuf:"bytes,19,opt,name=modifyInviteLinkPassword,proto3" json:"modifyInviteLinkPassword,omitempty"` - ModifyDescription *GroupChange_Actions_ModifyDescriptionAction `protobuf:"bytes,20,opt,name=modifyDescription,proto3" json:"modifyDescription,omitempty"` - ModifyAnnouncementsOnly *GroupChange_Actions_ModifyAnnouncementsOnlyAction `protobuf:"bytes,21,opt,name=modifyAnnouncementsOnly,proto3" json:"modifyAnnouncementsOnly,omitempty"` - AddBannedMembers []*GroupChange_Actions_AddBannedMemberAction `protobuf:"bytes,22,rep,name=addBannedMembers,proto3" json:"addBannedMembers,omitempty"` - DeleteBannedMembers []*GroupChange_Actions_DeleteBannedMemberAction `protobuf:"bytes,23,rep,name=deleteBannedMembers,proto3" json:"deleteBannedMembers,omitempty"` - PromotePendingPniAciMembers []*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction `protobuf:"bytes,24,rep,name=promotePendingPniAciMembers,proto3" json:"promotePendingPniAciMembers,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SourceUserId []byte `protobuf:"bytes,1,opt,name=sourceUserId,proto3" json:"sourceUserId,omitempty"` + // clients should not provide this value; the server will provide it in the response buffer to ensure the signature is binding to a particular group + // if clients set it during a request the server will respond with 400. + GroupId []byte `protobuf:"bytes,25,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + AddMembers []*GroupChange_Actions_AddMemberAction `protobuf:"bytes,3,rep,name=addMembers,proto3" json:"addMembers,omitempty"` + DeleteMembers []*GroupChange_Actions_DeleteMemberAction `protobuf:"bytes,4,rep,name=deleteMembers,proto3" json:"deleteMembers,omitempty"` + ModifyMemberRoles []*GroupChange_Actions_ModifyMemberRoleAction `protobuf:"bytes,5,rep,name=modifyMemberRoles,proto3" json:"modifyMemberRoles,omitempty"` + ModifyMemberProfileKeys []*GroupChange_Actions_ModifyMemberProfileKeyAction `protobuf:"bytes,6,rep,name=modifyMemberProfileKeys,proto3" json:"modifyMemberProfileKeys,omitempty"` + AddMembersPendingProfileKey []*GroupChange_Actions_AddMemberPendingProfileKeyAction `protobuf:"bytes,7,rep,name=addMembersPendingProfileKey,proto3" json:"addMembersPendingProfileKey,omitempty"` + DeleteMembersPendingProfileKey []*GroupChange_Actions_DeleteMemberPendingProfileKeyAction `protobuf:"bytes,8,rep,name=deleteMembersPendingProfileKey,proto3" json:"deleteMembersPendingProfileKey,omitempty"` + PromoteMembersPendingProfileKey []*GroupChange_Actions_PromoteMemberPendingProfileKeyAction `protobuf:"bytes,9,rep,name=promoteMembersPendingProfileKey,proto3" json:"promoteMembersPendingProfileKey,omitempty"` + ModifyTitle *GroupChange_Actions_ModifyTitleAction `protobuf:"bytes,10,opt,name=modifyTitle,proto3" json:"modifyTitle,omitempty"` + ModifyAvatar *GroupChange_Actions_ModifyAvatarAction `protobuf:"bytes,11,opt,name=modifyAvatar,proto3" json:"modifyAvatar,omitempty"` + ModifyDisappearingMessageTimer *GroupChange_Actions_ModifyDisappearingMessageTimerAction `protobuf:"bytes,12,opt,name=modifyDisappearingMessageTimer,proto3" json:"modifyDisappearingMessageTimer,omitempty"` + ModifyAttributesAccess *GroupChange_Actions_ModifyAttributesAccessControlAction `protobuf:"bytes,13,opt,name=modifyAttributesAccess,proto3" json:"modifyAttributesAccess,omitempty"` + ModifyMemberAccess *GroupChange_Actions_ModifyMembersAccessControlAction `protobuf:"bytes,14,opt,name=modifyMemberAccess,proto3" json:"modifyMemberAccess,omitempty"` + ModifyAddFromInviteLinkAccess *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction `protobuf:"bytes,15,opt,name=modifyAddFromInviteLinkAccess,proto3" json:"modifyAddFromInviteLinkAccess,omitempty"` // change epoch = 1 + AddMembersPendingAdminApproval []*GroupChange_Actions_AddMemberPendingAdminApprovalAction `protobuf:"bytes,16,rep,name=addMembersPendingAdminApproval,proto3" json:"addMembersPendingAdminApproval,omitempty"` // change epoch = 1 + DeleteMembersPendingAdminApproval []*GroupChange_Actions_DeleteMemberPendingAdminApprovalAction `protobuf:"bytes,17,rep,name=deleteMembersPendingAdminApproval,proto3" json:"deleteMembersPendingAdminApproval,omitempty"` // change epoch = 1 + PromoteMembersPendingAdminApproval []*GroupChange_Actions_PromoteMemberPendingAdminApprovalAction `protobuf:"bytes,18,rep,name=promoteMembersPendingAdminApproval,proto3" json:"promoteMembersPendingAdminApproval,omitempty"` // change epoch = 1 + ModifyInviteLinkPassword *GroupChange_Actions_ModifyInviteLinkPasswordAction `protobuf:"bytes,19,opt,name=modifyInviteLinkPassword,proto3" json:"modifyInviteLinkPassword,omitempty"` // change epoch = 1 + ModifyDescription *GroupChange_Actions_ModifyDescriptionAction `protobuf:"bytes,20,opt,name=modifyDescription,proto3" json:"modifyDescription,omitempty"` // change epoch = 2 + ModifyAnnouncementsOnly *GroupChange_Actions_ModifyAnnouncementsOnlyAction `protobuf:"bytes,21,opt,name=modify_announcements_only,json=modifyAnnouncementsOnly,proto3" json:"modify_announcements_only,omitempty"` // change epoch = 3 + AddMembersBanned []*GroupChange_Actions_AddMemberBannedAction `protobuf:"bytes,22,rep,name=add_members_banned,json=addMembersBanned,proto3" json:"add_members_banned,omitempty"` // change epoch = 4 + DeleteMembersBanned []*GroupChange_Actions_DeleteMemberBannedAction `protobuf:"bytes,23,rep,name=delete_members_banned,json=deleteMembersBanned,proto3" json:"delete_members_banned,omitempty"` // change epoch = 4 + PromoteMembersPendingPniAciProfileKey []*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction `protobuf:"bytes,24,rep,name=promote_members_pending_pni_aci_profile_key,json=promoteMembersPendingPniAciProfileKey,proto3" json:"promote_members_pending_pni_aci_profile_key,omitempty"` // change epoch = 5 + ModifyMemberLabels []*GroupChange_Actions_ModifyMemberLabelAction `protobuf:"bytes,26,rep,name=modifyMemberLabels,proto3" json:"modifyMemberLabels,omitempty"` // change epoch = 6; + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions) Reset() { *x = GroupChange_Actions{} - mi := &file_Groups_proto_msgTypes[15] + mi := &file_Groups_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1263,7 +1335,7 @@ func (x *GroupChange_Actions) String() string { func (*GroupChange_Actions) ProtoMessage() {} func (x *GroupChange_Actions) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[15] + mi := &file_Groups_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1276,12 +1348,12 @@ func (x *GroupChange_Actions) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChange_Actions.ProtoReflect.Descriptor instead. func (*GroupChange_Actions) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0} + return file_Groups_proto_rawDescGZIP(), []int{10, 0} } -func (x *GroupChange_Actions) GetSourceServiceId() []byte { +func (x *GroupChange_Actions) GetSourceUserId() []byte { if x != nil { - return x.SourceServiceId + return x.SourceUserId } return nil } @@ -1293,9 +1365,9 @@ func (x *GroupChange_Actions) GetGroupId() []byte { return nil } -func (x *GroupChange_Actions) GetRevision() uint32 { +func (x *GroupChange_Actions) GetVersion() uint32 { if x != nil { - return x.Revision + return x.Version } return 0 } @@ -1328,23 +1400,23 @@ func (x *GroupChange_Actions) GetModifyMemberProfileKeys() []*GroupChange_Action return nil } -func (x *GroupChange_Actions) GetAddPendingMembers() []*GroupChange_Actions_AddPendingMemberAction { +func (x *GroupChange_Actions) GetAddMembersPendingProfileKey() []*GroupChange_Actions_AddMemberPendingProfileKeyAction { if x != nil { - return x.AddPendingMembers + return x.AddMembersPendingProfileKey } return nil } -func (x *GroupChange_Actions) GetDeletePendingMembers() []*GroupChange_Actions_DeletePendingMemberAction { +func (x *GroupChange_Actions) GetDeleteMembersPendingProfileKey() []*GroupChange_Actions_DeleteMemberPendingProfileKeyAction { if x != nil { - return x.DeletePendingMembers + return x.DeleteMembersPendingProfileKey } return nil } -func (x *GroupChange_Actions) GetPromotePendingMembers() []*GroupChange_Actions_PromotePendingMemberAction { +func (x *GroupChange_Actions) GetPromoteMembersPendingProfileKey() []*GroupChange_Actions_PromoteMemberPendingProfileKeyAction { if x != nil { - return x.PromotePendingMembers + return x.PromoteMembersPendingProfileKey } return nil } @@ -1363,9 +1435,9 @@ func (x *GroupChange_Actions) GetModifyAvatar() *GroupChange_Actions_ModifyAvata return nil } -func (x *GroupChange_Actions) GetModifyDisappearingMessagesTimer() *GroupChange_Actions_ModifyDisappearingMessagesTimerAction { +func (x *GroupChange_Actions) GetModifyDisappearingMessageTimer() *GroupChange_Actions_ModifyDisappearingMessageTimerAction { if x != nil { - return x.ModifyDisappearingMessagesTimer + return x.ModifyDisappearingMessageTimer } return nil } @@ -1391,23 +1463,23 @@ func (x *GroupChange_Actions) GetModifyAddFromInviteLinkAccess() *GroupChange_Ac return nil } -func (x *GroupChange_Actions) GetAddRequestingMembers() []*GroupChange_Actions_AddRequestingMemberAction { +func (x *GroupChange_Actions) GetAddMembersPendingAdminApproval() []*GroupChange_Actions_AddMemberPendingAdminApprovalAction { if x != nil { - return x.AddRequestingMembers + return x.AddMembersPendingAdminApproval } return nil } -func (x *GroupChange_Actions) GetDeleteRequestingMembers() []*GroupChange_Actions_DeleteRequestingMemberAction { +func (x *GroupChange_Actions) GetDeleteMembersPendingAdminApproval() []*GroupChange_Actions_DeleteMemberPendingAdminApprovalAction { if x != nil { - return x.DeleteRequestingMembers + return x.DeleteMembersPendingAdminApproval } return nil } -func (x *GroupChange_Actions) GetPromoteRequestingMembers() []*GroupChange_Actions_PromoteRequestingMemberAction { +func (x *GroupChange_Actions) GetPromoteMembersPendingAdminApproval() []*GroupChange_Actions_PromoteMemberPendingAdminApprovalAction { if x != nil { - return x.PromoteRequestingMembers + return x.PromoteMembersPendingAdminApproval } return nil } @@ -1433,23 +1505,30 @@ func (x *GroupChange_Actions) GetModifyAnnouncementsOnly() *GroupChange_Actions_ return nil } -func (x *GroupChange_Actions) GetAddBannedMembers() []*GroupChange_Actions_AddBannedMemberAction { +func (x *GroupChange_Actions) GetAddMembersBanned() []*GroupChange_Actions_AddMemberBannedAction { if x != nil { - return x.AddBannedMembers + return x.AddMembersBanned } return nil } -func (x *GroupChange_Actions) GetDeleteBannedMembers() []*GroupChange_Actions_DeleteBannedMemberAction { +func (x *GroupChange_Actions) GetDeleteMembersBanned() []*GroupChange_Actions_DeleteMemberBannedAction { if x != nil { - return x.DeleteBannedMembers + return x.DeleteMembersBanned } return nil } -func (x *GroupChange_Actions) GetPromotePendingPniAciMembers() []*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction { +func (x *GroupChange_Actions) GetPromoteMembersPendingPniAciProfileKey() []*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction { if x != nil { - return x.PromotePendingPniAciMembers + return x.PromoteMembersPendingPniAciProfileKey + } + return nil +} + +func (x *GroupChange_Actions) GetModifyMemberLabels() []*GroupChange_Actions_ModifyMemberLabelAction { + if x != nil { + return x.ModifyMemberLabels } return nil } @@ -1464,7 +1543,7 @@ type GroupChange_Actions_AddMemberAction struct { func (x *GroupChange_Actions_AddMemberAction) Reset() { *x = GroupChange_Actions_AddMemberAction{} - mi := &file_Groups_proto_msgTypes[16] + mi := &file_Groups_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1476,7 +1555,7 @@ func (x *GroupChange_Actions_AddMemberAction) String() string { func (*GroupChange_Actions_AddMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_AddMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[16] + mi := &file_Groups_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1489,7 +1568,7 @@ func (x *GroupChange_Actions_AddMemberAction) ProtoReflect() protoreflect.Messag // Deprecated: Use GroupChange_Actions_AddMemberAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_AddMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 0} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 0} } func (x *GroupChange_Actions_AddMemberAction) GetAdded() *Member { @@ -1515,7 +1594,7 @@ type GroupChange_Actions_DeleteMemberAction struct { func (x *GroupChange_Actions_DeleteMemberAction) Reset() { *x = GroupChange_Actions_DeleteMemberAction{} - mi := &file_Groups_proto_msgTypes[17] + mi := &file_Groups_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1527,7 +1606,7 @@ func (x *GroupChange_Actions_DeleteMemberAction) String() string { func (*GroupChange_Actions_DeleteMemberAction) ProtoMessage() {} func (x *GroupChange_Actions_DeleteMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[17] + mi := &file_Groups_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1540,7 +1619,7 @@ func (x *GroupChange_Actions_DeleteMemberAction) ProtoReflect() protoreflect.Mes // Deprecated: Use GroupChange_Actions_DeleteMemberAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_DeleteMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 1} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 1} } func (x *GroupChange_Actions_DeleteMemberAction) GetDeletedUserId() []byte { @@ -1553,14 +1632,14 @@ func (x *GroupChange_Actions_DeleteMemberAction) GetDeletedUserId() []byte { type GroupChange_Actions_ModifyMemberRoleAction struct { state protoimpl.MessageState `protogen:"open.v1"` UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` + Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=signal.Member_Role" json:"role,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyMemberRoleAction) Reset() { *x = GroupChange_Actions_ModifyMemberRoleAction{} - mi := &file_Groups_proto_msgTypes[18] + mi := &file_Groups_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1572,7 +1651,7 @@ func (x *GroupChange_Actions_ModifyMemberRoleAction) String() string { func (*GroupChange_Actions_ModifyMemberRoleAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMemberRoleAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[18] + mi := &file_Groups_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1585,7 +1664,7 @@ func (x *GroupChange_Actions_ModifyMemberRoleAction) ProtoReflect() protoreflect // Deprecated: Use GroupChange_Actions_ModifyMemberRoleAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyMemberRoleAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 2} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 2} } func (x *GroupChange_Actions_ModifyMemberRoleAction) GetUserId() []byte { @@ -1602,18 +1681,78 @@ func (x *GroupChange_Actions_ModifyMemberRoleAction) GetRole() Member_Role { return Member_UNKNOWN } +type GroupChange_Actions_ModifyMemberLabelAction struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + LabelEmoji []byte `protobuf:"bytes,2,opt,name=labelEmoji,proto3" json:"labelEmoji,omitempty"` // decrypts to a UTF-8 string + LabelString []byte `protobuf:"bytes,3,opt,name=labelString,proto3" json:"labelString,omitempty"` // decrypts to a UTF-8 string + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChange_Actions_ModifyMemberLabelAction) Reset() { + *x = GroupChange_Actions_ModifyMemberLabelAction{} + mi := &file_Groups_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChange_Actions_ModifyMemberLabelAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChange_Actions_ModifyMemberLabelAction) ProtoMessage() {} + +func (x *GroupChange_Actions_ModifyMemberLabelAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupChange_Actions_ModifyMemberLabelAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_ModifyMemberLabelAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 3} +} + +func (x *GroupChange_Actions_ModifyMemberLabelAction) GetUserId() []byte { + if x != nil { + return x.UserId + } + return nil +} + +func (x *GroupChange_Actions_ModifyMemberLabelAction) GetLabelEmoji() []byte { + if x != nil { + return x.LabelEmoji + } + return nil +} + +func (x *GroupChange_Actions_ModifyMemberLabelAction) GetLabelString() []byte { + if x != nil { + return x.LabelString + } + return nil +} + type GroupChange_Actions_ModifyMemberProfileKeyAction struct { state protoimpl.MessageState `protogen:"open.v1"` - Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // Only set when receiving from server - ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` // Only set when receiving from server + Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` + UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) Reset() { *x = GroupChange_Actions_ModifyMemberProfileKeyAction{} - mi := &file_Groups_proto_msgTypes[19] + mi := &file_Groups_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1625,7 +1764,7 @@ func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) String() string { func (*GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[19] + mi := &file_Groups_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1638,7 +1777,7 @@ func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) ProtoReflect() protor // Deprecated: Use GroupChange_Actions_ModifyMemberProfileKeyAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyMemberProfileKeyAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 3} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 4} } func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) GetPresentation() []byte { @@ -1662,28 +1801,28 @@ func (x *GroupChange_Actions_ModifyMemberProfileKeyAction) GetProfileKey() []byt return nil } -type GroupChange_Actions_AddPendingMemberAction struct { - state protoimpl.MessageState `protogen:"open.v1"` - Added *PendingMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` +type GroupChange_Actions_AddMemberPendingProfileKeyAction struct { + state protoimpl.MessageState `protogen:"open.v1"` + Added *MemberPendingProfileKey `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_AddPendingMemberAction) Reset() { - *x = GroupChange_Actions_AddPendingMemberAction{} - mi := &file_Groups_proto_msgTypes[20] +func (x *GroupChange_Actions_AddMemberPendingProfileKeyAction) Reset() { + *x = GroupChange_Actions_AddMemberPendingProfileKeyAction{} + mi := &file_Groups_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_AddPendingMemberAction) String() string { +func (x *GroupChange_Actions_AddMemberPendingProfileKeyAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_AddPendingMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_AddMemberPendingProfileKeyAction) ProtoMessage() {} -func (x *GroupChange_Actions_AddPendingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[20] +func (x *GroupChange_Actions_AddMemberPendingProfileKeyAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1694,40 +1833,40 @@ func (x *GroupChange_Actions_AddPendingMemberAction) ProtoReflect() protoreflect return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_AddPendingMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_AddPendingMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 4} +// Deprecated: Use GroupChange_Actions_AddMemberPendingProfileKeyAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_AddMemberPendingProfileKeyAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 5} } -func (x *GroupChange_Actions_AddPendingMemberAction) GetAdded() *PendingMember { +func (x *GroupChange_Actions_AddMemberPendingProfileKeyAction) GetAdded() *MemberPendingProfileKey { if x != nil { return x.Added } return nil } -type GroupChange_Actions_DeletePendingMemberAction struct { +type GroupChange_Actions_DeleteMemberPendingProfileKeyAction struct { state protoimpl.MessageState `protogen:"open.v1"` DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_DeletePendingMemberAction) Reset() { - *x = GroupChange_Actions_DeletePendingMemberAction{} - mi := &file_Groups_proto_msgTypes[21] +func (x *GroupChange_Actions_DeleteMemberPendingProfileKeyAction) Reset() { + *x = GroupChange_Actions_DeleteMemberPendingProfileKeyAction{} + mi := &file_Groups_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_DeletePendingMemberAction) String() string { +func (x *GroupChange_Actions_DeleteMemberPendingProfileKeyAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_DeletePendingMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_DeleteMemberPendingProfileKeyAction) ProtoMessage() {} -func (x *GroupChange_Actions_DeletePendingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[21] +func (x *GroupChange_Actions_DeleteMemberPendingProfileKeyAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1738,42 +1877,42 @@ func (x *GroupChange_Actions_DeletePendingMemberAction) ProtoReflect() protorefl return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_DeletePendingMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_DeletePendingMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 5} +// Deprecated: Use GroupChange_Actions_DeleteMemberPendingProfileKeyAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_DeleteMemberPendingProfileKeyAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 6} } -func (x *GroupChange_Actions_DeletePendingMemberAction) GetDeletedUserId() []byte { +func (x *GroupChange_Actions_DeleteMemberPendingProfileKeyAction) GetDeletedUserId() []byte { if x != nil { return x.DeletedUserId } return nil } -type GroupChange_Actions_PromotePendingMemberAction struct { +type GroupChange_Actions_PromoteMemberPendingProfileKeyAction struct { state protoimpl.MessageState `protogen:"open.v1"` - Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` // Only set when receiving from server - ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` // Only set when receiving from server + Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` + UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProfileKey []byte `protobuf:"bytes,3,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_PromotePendingMemberAction) Reset() { - *x = GroupChange_Actions_PromotePendingMemberAction{} - mi := &file_Groups_proto_msgTypes[22] +func (x *GroupChange_Actions_PromoteMemberPendingProfileKeyAction) Reset() { + *x = GroupChange_Actions_PromoteMemberPendingProfileKeyAction{} + mi := &file_Groups_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_PromotePendingMemberAction) String() string { +func (x *GroupChange_Actions_PromoteMemberPendingProfileKeyAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_PromotePendingMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_PromoteMemberPendingProfileKeyAction) ProtoMessage() {} -func (x *GroupChange_Actions_PromotePendingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[22] +func (x *GroupChange_Actions_PromoteMemberPendingProfileKeyAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1784,57 +1923,57 @@ func (x *GroupChange_Actions_PromotePendingMemberAction) ProtoReflect() protoref return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_PromotePendingMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_PromotePendingMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 6} +// Deprecated: Use GroupChange_Actions_PromoteMemberPendingProfileKeyAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_PromoteMemberPendingProfileKeyAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 7} } -func (x *GroupChange_Actions_PromotePendingMemberAction) GetPresentation() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingProfileKeyAction) GetPresentation() []byte { if x != nil { return x.Presentation } return nil } -func (x *GroupChange_Actions_PromotePendingMemberAction) GetUserId() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingProfileKeyAction) GetUserId() []byte { if x != nil { return x.UserId } return nil } -func (x *GroupChange_Actions_PromotePendingMemberAction) GetProfileKey() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingProfileKeyAction) GetProfileKey() []byte { if x != nil { return x.ProfileKey } return nil } -type GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction struct { +type GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction struct { state protoimpl.MessageState `protogen:"open.v1"` - Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` // Only set when sending to server - UserId []byte `protobuf:"bytes,2,opt,name=userId,proto3" json:"userId,omitempty"` // Only set when receiving from server - Pni []byte `protobuf:"bytes,3,opt,name=pni,proto3" json:"pni,omitempty"` // Only set when receiving from server - ProfileKey []byte `protobuf:"bytes,4,opt,name=profileKey,proto3" json:"profileKey,omitempty"` // Only set when receiving from server + Presentation []byte `protobuf:"bytes,1,opt,name=presentation,proto3" json:"presentation,omitempty"` + UserId []byte `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Pni []byte `protobuf:"bytes,3,opt,name=pni,proto3" json:"pni,omitempty"` + ProfileKey []byte `protobuf:"bytes,4,opt,name=profile_key,json=profileKey,proto3" json:"profile_key,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) Reset() { - *x = GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction{} - mi := &file_Groups_proto_msgTypes[23] +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) Reset() { + *x = GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction{} + mi := &file_Groups_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) String() string { +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoMessage() {} +func (*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) ProtoMessage() {} -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[23] +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1845,61 +1984,61 @@ func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) ProtoRe return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 7} +// Deprecated: Use GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 8} } -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) GetPresentation() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) GetPresentation() []byte { if x != nil { return x.Presentation } return nil } -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) GetUserId() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) GetUserId() []byte { if x != nil { return x.UserId } return nil } -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) GetPni() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) GetPni() []byte { if x != nil { return x.Pni } return nil } -func (x *GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction) GetProfileKey() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction) GetProfileKey() []byte { if x != nil { return x.ProfileKey } return nil } -type GroupChange_Actions_AddRequestingMemberAction struct { - state protoimpl.MessageState `protogen:"open.v1"` - Added *RequestingMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` +type GroupChange_Actions_AddMemberPendingAdminApprovalAction struct { + state protoimpl.MessageState `protogen:"open.v1"` + Added *MemberPendingAdminApproval `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_AddRequestingMemberAction) Reset() { - *x = GroupChange_Actions_AddRequestingMemberAction{} - mi := &file_Groups_proto_msgTypes[24] +func (x *GroupChange_Actions_AddMemberPendingAdminApprovalAction) Reset() { + *x = GroupChange_Actions_AddMemberPendingAdminApprovalAction{} + mi := &file_Groups_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_AddRequestingMemberAction) String() string { +func (x *GroupChange_Actions_AddMemberPendingAdminApprovalAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_AddRequestingMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_AddMemberPendingAdminApprovalAction) ProtoMessage() {} -func (x *GroupChange_Actions_AddRequestingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[24] +func (x *GroupChange_Actions_AddMemberPendingAdminApprovalAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1910,40 +2049,40 @@ func (x *GroupChange_Actions_AddRequestingMemberAction) ProtoReflect() protorefl return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_AddRequestingMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_AddRequestingMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 8} +// Deprecated: Use GroupChange_Actions_AddMemberPendingAdminApprovalAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_AddMemberPendingAdminApprovalAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 9} } -func (x *GroupChange_Actions_AddRequestingMemberAction) GetAdded() *RequestingMember { +func (x *GroupChange_Actions_AddMemberPendingAdminApprovalAction) GetAdded() *MemberPendingAdminApproval { if x != nil { return x.Added } return nil } -type GroupChange_Actions_DeleteRequestingMemberAction struct { +type GroupChange_Actions_DeleteMemberPendingAdminApprovalAction struct { state protoimpl.MessageState `protogen:"open.v1"` DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_DeleteRequestingMemberAction) Reset() { - *x = GroupChange_Actions_DeleteRequestingMemberAction{} - mi := &file_Groups_proto_msgTypes[25] +func (x *GroupChange_Actions_DeleteMemberPendingAdminApprovalAction) Reset() { + *x = GroupChange_Actions_DeleteMemberPendingAdminApprovalAction{} + mi := &file_Groups_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_DeleteRequestingMemberAction) String() string { +func (x *GroupChange_Actions_DeleteMemberPendingAdminApprovalAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_DeleteRequestingMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_DeleteMemberPendingAdminApprovalAction) ProtoMessage() {} -func (x *GroupChange_Actions_DeleteRequestingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[25] +func (x *GroupChange_Actions_DeleteMemberPendingAdminApprovalAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1954,41 +2093,41 @@ func (x *GroupChange_Actions_DeleteRequestingMemberAction) ProtoReflect() protor return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_DeleteRequestingMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_DeleteRequestingMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 9} +// Deprecated: Use GroupChange_Actions_DeleteMemberPendingAdminApprovalAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_DeleteMemberPendingAdminApprovalAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 10} } -func (x *GroupChange_Actions_DeleteRequestingMemberAction) GetDeletedUserId() []byte { +func (x *GroupChange_Actions_DeleteMemberPendingAdminApprovalAction) GetDeletedUserId() []byte { if x != nil { return x.DeletedUserId } return nil } -type GroupChange_Actions_PromoteRequestingMemberAction struct { +type GroupChange_Actions_PromoteMemberPendingAdminApprovalAction struct { state protoimpl.MessageState `protogen:"open.v1"` UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=Member_Role" json:"role,omitempty"` + Role Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=signal.Member_Role" json:"role,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_PromoteRequestingMemberAction) Reset() { - *x = GroupChange_Actions_PromoteRequestingMemberAction{} - mi := &file_Groups_proto_msgTypes[26] +func (x *GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) Reset() { + *x = GroupChange_Actions_PromoteMemberPendingAdminApprovalAction{} + mi := &file_Groups_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_PromoteRequestingMemberAction) String() string { +func (x *GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_PromoteRequestingMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) ProtoMessage() {} -func (x *GroupChange_Actions_PromoteRequestingMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[26] +func (x *GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1999,47 +2138,47 @@ func (x *GroupChange_Actions_PromoteRequestingMemberAction) ProtoReflect() proto return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_PromoteRequestingMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_PromoteRequestingMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 10} +// Deprecated: Use GroupChange_Actions_PromoteMemberPendingAdminApprovalAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 11} } -func (x *GroupChange_Actions_PromoteRequestingMemberAction) GetUserId() []byte { +func (x *GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) GetUserId() []byte { if x != nil { return x.UserId } return nil } -func (x *GroupChange_Actions_PromoteRequestingMemberAction) GetRole() Member_Role { +func (x *GroupChange_Actions_PromoteMemberPendingAdminApprovalAction) GetRole() Member_Role { if x != nil { return x.Role } return Member_UNKNOWN } -type GroupChange_Actions_AddBannedMemberAction struct { +type GroupChange_Actions_AddMemberBannedAction struct { state protoimpl.MessageState `protogen:"open.v1"` - Added *BannedMember `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` + Added *MemberBanned `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_AddBannedMemberAction) Reset() { - *x = GroupChange_Actions_AddBannedMemberAction{} - mi := &file_Groups_proto_msgTypes[27] +func (x *GroupChange_Actions_AddMemberBannedAction) Reset() { + *x = GroupChange_Actions_AddMemberBannedAction{} + mi := &file_Groups_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_AddBannedMemberAction) String() string { +func (x *GroupChange_Actions_AddMemberBannedAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_AddBannedMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_AddMemberBannedAction) ProtoMessage() {} -func (x *GroupChange_Actions_AddBannedMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[27] +func (x *GroupChange_Actions_AddMemberBannedAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2050,40 +2189,40 @@ func (x *GroupChange_Actions_AddBannedMemberAction) ProtoReflect() protoreflect. return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_AddBannedMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_AddBannedMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 11} +// Deprecated: Use GroupChange_Actions_AddMemberBannedAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_AddMemberBannedAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 12} } -func (x *GroupChange_Actions_AddBannedMemberAction) GetAdded() *BannedMember { +func (x *GroupChange_Actions_AddMemberBannedAction) GetAdded() *MemberBanned { if x != nil { return x.Added } return nil } -type GroupChange_Actions_DeleteBannedMemberAction struct { +type GroupChange_Actions_DeleteMemberBannedAction struct { state protoimpl.MessageState `protogen:"open.v1"` DeletedUserId []byte `protobuf:"bytes,1,opt,name=deletedUserId,proto3" json:"deletedUserId,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_DeleteBannedMemberAction) Reset() { - *x = GroupChange_Actions_DeleteBannedMemberAction{} - mi := &file_Groups_proto_msgTypes[28] +func (x *GroupChange_Actions_DeleteMemberBannedAction) Reset() { + *x = GroupChange_Actions_DeleteMemberBannedAction{} + mi := &file_Groups_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_DeleteBannedMemberAction) String() string { +func (x *GroupChange_Actions_DeleteMemberBannedAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_DeleteBannedMemberAction) ProtoMessage() {} +func (*GroupChange_Actions_DeleteMemberBannedAction) ProtoMessage() {} -func (x *GroupChange_Actions_DeleteBannedMemberAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[28] +func (x *GroupChange_Actions_DeleteMemberBannedAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2094,12 +2233,12 @@ func (x *GroupChange_Actions_DeleteBannedMemberAction) ProtoReflect() protorefle return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_DeleteBannedMemberAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_DeleteBannedMemberAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 12} +// Deprecated: Use GroupChange_Actions_DeleteMemberBannedAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_DeleteMemberBannedAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 13} } -func (x *GroupChange_Actions_DeleteBannedMemberAction) GetDeletedUserId() []byte { +func (x *GroupChange_Actions_DeleteMemberBannedAction) GetDeletedUserId() []byte { if x != nil { return x.DeletedUserId } @@ -2115,7 +2254,7 @@ type GroupChange_Actions_ModifyTitleAction struct { func (x *GroupChange_Actions_ModifyTitleAction) Reset() { *x = GroupChange_Actions_ModifyTitleAction{} - mi := &file_Groups_proto_msgTypes[29] + mi := &file_Groups_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2127,7 +2266,7 @@ func (x *GroupChange_Actions_ModifyTitleAction) String() string { func (*GroupChange_Actions_ModifyTitleAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyTitleAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[29] + mi := &file_Groups_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2140,7 +2279,7 @@ func (x *GroupChange_Actions_ModifyTitleAction) ProtoReflect() protoreflect.Mess // Deprecated: Use GroupChange_Actions_ModifyTitleAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyTitleAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 13} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 14} } func (x *GroupChange_Actions_ModifyTitleAction) GetTitle() []byte { @@ -2159,7 +2298,7 @@ type GroupChange_Actions_ModifyDescriptionAction struct { func (x *GroupChange_Actions_ModifyDescriptionAction) Reset() { *x = GroupChange_Actions_ModifyDescriptionAction{} - mi := &file_Groups_proto_msgTypes[30] + mi := &file_Groups_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2171,7 +2310,7 @@ func (x *GroupChange_Actions_ModifyDescriptionAction) String() string { func (*GroupChange_Actions_ModifyDescriptionAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyDescriptionAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[30] + mi := &file_Groups_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2184,7 +2323,7 @@ func (x *GroupChange_Actions_ModifyDescriptionAction) ProtoReflect() protoreflec // Deprecated: Use GroupChange_Actions_ModifyDescriptionAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyDescriptionAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 14} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 15} } func (x *GroupChange_Actions_ModifyDescriptionAction) GetDescription() []byte { @@ -2203,7 +2342,7 @@ type GroupChange_Actions_ModifyAvatarAction struct { func (x *GroupChange_Actions_ModifyAvatarAction) Reset() { *x = GroupChange_Actions_ModifyAvatarAction{} - mi := &file_Groups_proto_msgTypes[31] + mi := &file_Groups_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2215,7 +2354,7 @@ func (x *GroupChange_Actions_ModifyAvatarAction) String() string { func (*GroupChange_Actions_ModifyAvatarAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAvatarAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[31] + mi := &file_Groups_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2228,7 +2367,7 @@ func (x *GroupChange_Actions_ModifyAvatarAction) ProtoReflect() protoreflect.Mes // Deprecated: Use GroupChange_Actions_ModifyAvatarAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyAvatarAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 15} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 16} } func (x *GroupChange_Actions_ModifyAvatarAction) GetAvatar() string { @@ -2238,28 +2377,28 @@ func (x *GroupChange_Actions_ModifyAvatarAction) GetAvatar() string { return "" } -type GroupChange_Actions_ModifyDisappearingMessagesTimerAction struct { +type GroupChange_Actions_ModifyDisappearingMessageTimerAction struct { state protoimpl.MessageState `protogen:"open.v1"` Timer []byte `protobuf:"bytes,1,opt,name=timer,proto3" json:"timer,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) Reset() { - *x = GroupChange_Actions_ModifyDisappearingMessagesTimerAction{} - mi := &file_Groups_proto_msgTypes[32] +func (x *GroupChange_Actions_ModifyDisappearingMessageTimerAction) Reset() { + *x = GroupChange_Actions_ModifyDisappearingMessageTimerAction{} + mi := &file_Groups_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) String() string { +func (x *GroupChange_Actions_ModifyDisappearingMessageTimerAction) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoMessage() {} +func (*GroupChange_Actions_ModifyDisappearingMessageTimerAction) ProtoMessage() {} -func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[32] +func (x *GroupChange_Actions_ModifyDisappearingMessageTimerAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2270,12 +2409,12 @@ func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) ProtoReflect return mi.MessageOf(x) } -// Deprecated: Use GroupChange_Actions_ModifyDisappearingMessagesTimerAction.ProtoReflect.Descriptor instead. -func (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 16} +// Deprecated: Use GroupChange_Actions_ModifyDisappearingMessageTimerAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_ModifyDisappearingMessageTimerAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 17} } -func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) GetTimer() []byte { +func (x *GroupChange_Actions_ModifyDisappearingMessageTimerAction) GetTimer() []byte { if x != nil { return x.Timer } @@ -2284,14 +2423,14 @@ func (x *GroupChange_Actions_ModifyDisappearingMessagesTimerAction) GetTimer() [ type GroupChange_Actions_ModifyAttributesAccessControlAction struct { state protoimpl.MessageState `protogen:"open.v1"` - AttributesAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributesAccess,proto3,enum=AccessControl_AccessRequired" json:"attributesAccess,omitempty"` + AttributesAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributesAccess,proto3,enum=signal.AccessControl_AccessRequired" json:"attributesAccess,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyAttributesAccessControlAction{} - mi := &file_Groups_proto_msgTypes[33] + mi := &file_Groups_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2303,7 +2442,7 @@ func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) String() strin func (*GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[33] + mi := &file_Groups_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2316,7 +2455,7 @@ func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) ProtoReflect() // Deprecated: Use GroupChange_Actions_ModifyAttributesAccessControlAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyAttributesAccessControlAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 17} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 18} } func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) GetAttributesAccess() AccessControl_AccessRequired { @@ -2328,14 +2467,14 @@ func (x *GroupChange_Actions_ModifyAttributesAccessControlAction) GetAttributesA type GroupChange_Actions_ModifyMembersAccessControlAction struct { state protoimpl.MessageState `protogen:"open.v1"` - MembersAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=membersAccess,proto3,enum=AccessControl_AccessRequired" json:"membersAccess,omitempty"` + MembersAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=membersAccess,proto3,enum=signal.AccessControl_AccessRequired" json:"membersAccess,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyMembersAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyMembersAccessControlAction{} - mi := &file_Groups_proto_msgTypes[34] + mi := &file_Groups_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2347,7 +2486,7 @@ func (x *GroupChange_Actions_ModifyMembersAccessControlAction) String() string { func (*GroupChange_Actions_ModifyMembersAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyMembersAccessControlAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[34] + mi := &file_Groups_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2360,7 +2499,7 @@ func (x *GroupChange_Actions_ModifyMembersAccessControlAction) ProtoReflect() pr // Deprecated: Use GroupChange_Actions_ModifyMembersAccessControlAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyMembersAccessControlAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 18} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 19} } func (x *GroupChange_Actions_ModifyMembersAccessControlAction) GetMembersAccess() AccessControl_AccessRequired { @@ -2372,14 +2511,14 @@ func (x *GroupChange_Actions_ModifyMembersAccessControlAction) GetMembersAccess( type GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction struct { state protoimpl.MessageState `protogen:"open.v1"` - AddFromInviteLinkAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=addFromInviteLinkAccess,proto3,enum=AccessControl_AccessRequired" json:"addFromInviteLinkAccess,omitempty"` + AddFromInviteLinkAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=addFromInviteLinkAccess,proto3,enum=signal.AccessControl_AccessRequired" json:"addFromInviteLinkAccess,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) Reset() { *x = GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction{} - mi := &file_Groups_proto_msgTypes[35] + mi := &file_Groups_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2391,7 +2530,7 @@ func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) String( func (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[35] + mi := &file_Groups_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2404,7 +2543,7 @@ func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) ProtoRe // Deprecated: Use GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 19} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 20} } func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) GetAddFromInviteLinkAccess() AccessControl_AccessRequired { @@ -2423,7 +2562,7 @@ type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() { *x = GroupChange_Actions_ModifyInviteLinkPasswordAction{} - mi := &file_Groups_proto_msgTypes[36] + mi := &file_Groups_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2435,7 +2574,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) String() string { func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[36] + mi := &file_Groups_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2448,7 +2587,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() prot // Deprecated: Use GroupChange_Actions_ModifyInviteLinkPasswordAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 20} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 21} } func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) GetInviteLinkPassword() []byte { @@ -2460,14 +2599,14 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) GetInviteLinkPasswo type GroupChange_Actions_ModifyAnnouncementsOnlyAction struct { state protoimpl.MessageState `protogen:"open.v1"` - AnnouncementsOnly bool `protobuf:"varint,1,opt,name=announcementsOnly,proto3" json:"announcementsOnly,omitempty"` + AnnouncementsOnly bool `protobuf:"varint,1,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() { *x = GroupChange_Actions_ModifyAnnouncementsOnlyAction{} - mi := &file_Groups_proto_msgTypes[37] + mi := &file_Groups_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2479,7 +2618,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) String() string { func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[37] + mi := &file_Groups_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2492,7 +2631,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() proto // Deprecated: Use GroupChange_Actions_ModifyAnnouncementsOnlyAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{7, 0, 21} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 22} } func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly() bool { @@ -2512,7 +2651,7 @@ type GroupChanges_GroupChangeState struct { func (x *GroupChanges_GroupChangeState) Reset() { *x = GroupChanges_GroupChangeState{} - mi := &file_Groups_proto_msgTypes[38] + mi := &file_Groups_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2524,7 +2663,7 @@ func (x *GroupChanges_GroupChangeState) String() string { func (*GroupChanges_GroupChangeState) ProtoMessage() {} func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[38] + mi := &file_Groups_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2537,7 +2676,7 @@ func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChanges_GroupChangeState.ProtoReflect.Descriptor instead. func (*GroupChanges_GroupChangeState) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{9, 0} + return file_Groups_proto_rawDescGZIP(), []int{13, 0} } func (x *GroupChanges_GroupChangeState) GetGroupChange() *GroupChange { @@ -2554,63 +2693,11 @@ func (x *GroupChanges_GroupChangeState) GetGroupState() *Group { return nil } -type GroupInviteLink_GroupInviteLinkContentsV1 struct { - state protoimpl.MessageState `protogen:"open.v1"` - GroupMasterKey []byte `protobuf:"bytes,1,opt,name=groupMasterKey,proto3" json:"groupMasterKey,omitempty"` - InviteLinkPassword []byte `protobuf:"bytes,2,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GroupInviteLink_GroupInviteLinkContentsV1) Reset() { - *x = GroupInviteLink_GroupInviteLinkContentsV1{} - mi := &file_Groups_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GroupInviteLink_GroupInviteLinkContentsV1) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GroupInviteLink_GroupInviteLinkContentsV1) ProtoMessage() {} - -func (x *GroupInviteLink_GroupInviteLinkContentsV1) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[39] - 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 GroupInviteLink_GroupInviteLinkContentsV1.ProtoReflect.Descriptor instead. -func (*GroupInviteLink_GroupInviteLinkContentsV1) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{12, 0} -} - -func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetGroupMasterKey() []byte { - if x != nil { - return x.GroupMasterKey - } - return nil -} - -func (x *GroupInviteLink_GroupInviteLinkContentsV1) GetInviteLinkPassword() []byte { - if x != nil { - return x.InviteLinkPassword - } - return nil -} - var File_Groups_proto protoreflect.FileDescriptor const file_Groups_proto_rawDesc = "" + "\n" + - "\fGroups.proto\"\xc4\x01\n" + + "\fGroups.proto\x12\x06signal\"\xc4\x01\n" + "\x16AvatarUploadAttributes\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x1e\n" + "\n" + @@ -2620,193 +2707,203 @@ const file_Groups_proto_rawDesc = "" + "\talgorithm\x18\x04 \x01(\tR\talgorithm\x12\x12\n" + "\x04date\x18\x05 \x01(\tR\x04date\x12\x16\n" + "\x06policy\x18\x06 \x01(\tR\x06policy\x12\x1c\n" + - "\tsignature\x18\a \x01(\tR\tsignature\"\xe7\x01\n" + + "\tsignature\x18\a \x01(\tR\tsignature\"\xae\x02\n" + "\x06Member\x12\x16\n" + - "\x06userId\x18\x01 \x01(\fR\x06userId\x12 \n" + - "\x04role\x18\x02 \x01(\x0e2\f.Member.RoleR\x04role\x12\x1e\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12'\n" + + "\x04role\x18\x02 \x01(\x0e2\x13.signal.Member.RoleR\x04role\x12\x1e\n" + "\n" + "profileKey\x18\x03 \x01(\fR\n" + "profileKey\x12\"\n" + - "\fpresentation\x18\x04 \x01(\fR\fpresentation\x12*\n" + - "\x10joinedAtRevision\x18\x05 \x01(\rR\x10joinedAtRevision\"3\n" + + "\fpresentation\x18\x04 \x01(\fR\fpresentation\x12(\n" + + "\x0fjoinedAtVersion\x18\x05 \x01(\rR\x0fjoinedAtVersion\x12\x1e\n" + + "\n" + + "labelEmoji\x18\x06 \x01(\fR\n" + + "labelEmoji\x12 \n" + + "\vlabelString\x18\a \x01(\fR\vlabelString\"3\n" + "\x04Role\x12\v\n" + "\aUNKNOWN\x10\x00\x12\v\n" + "\aDEFAULT\x10\x01\x12\x11\n" + - "\rADMINISTRATOR\x10\x02\"t\n" + - "\rPendingMember\x12\x1f\n" + - "\x06member\x18\x01 \x01(\v2\a.MemberR\x06member\x12$\n" + + "\rADMINISTRATOR\x10\x02\"\x85\x01\n" + + "\x17MemberPendingProfileKey\x12&\n" + + "\x06member\x18\x01 \x01(\v2\x0e.signal.MemberR\x06member\x12$\n" + "\raddedByUserId\x18\x02 \x01(\fR\raddedByUserId\x12\x1c\n" + - "\ttimestamp\x18\x03 \x01(\x04R\ttimestamp\"\x8c\x01\n" + - "\x10RequestingMember\x12\x16\n" + + "\ttimestamp\x18\x03 \x01(\x04R\ttimestamp\"\x96\x01\n" + + "\x1aMemberPendingAdminApproval\x12\x16\n" + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1e\n" + "\n" + "profileKey\x18\x02 \x01(\fR\n" + "profileKey\x12\"\n" + "\fpresentation\x18\x03 \x01(\fR\fpresentation\x12\x1c\n" + "\ttimestamp\x18\x04 \x01(\x04R\ttimestamp\"D\n" + - "\fBannedMember\x12\x16\n" + + "\fMemberBanned\x12\x16\n" + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + - "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\xae\x02\n" + - "\rAccessControl\x12=\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\xc3\x02\n" + + "\rAccessControl\x12D\n" + "\n" + - "attributes\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\n" + - "attributes\x127\n" + - "\amembers\x18\x02 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\amembers\x12K\n" + - "\x11addFromInviteLink\x18\x03 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + + "attributes\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\n" + + "attributes\x12>\n" + + "\amembers\x18\x02 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\amembers\x12R\n" + + "\x11addFromInviteLink\x18\x03 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + "\x0eAccessRequired\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ANY\x10\x01\x12\n" + "\n" + "\x06MEMBER\x10\x02\x12\x11\n" + "\rADMINISTRATOR\x10\x03\x12\x11\n" + - "\rUNSATISFIABLE\x10\x04\"\xb4\x04\n" + + "\rUNSATISFIABLE\x10\x04\"\x99\x05\n" + "\x05Group\x12\x1c\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + - "\x05title\x18\x02 \x01(\fR\x05title\x12\x16\n" + - "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12<\n" + - "\x19disappearingMessagesTimer\x18\x04 \x01(\fR\x19disappearingMessagesTimer\x124\n" + - "\raccessControl\x18\x05 \x01(\v2\x0e.AccessControlR\raccessControl\x12\x1a\n" + - "\brevision\x18\x06 \x01(\rR\brevision\x12!\n" + - "\amembers\x18\a \x03(\v2\a.MemberR\amembers\x126\n" + - "\x0ependingMembers\x18\b \x03(\v2\x0e.PendingMemberR\x0ependingMembers\x12?\n" + - "\x11requestingMembers\x18\t \x03(\v2\x11.RequestingMemberR\x11requestingMembers\x12.\n" + + "\x05title\x18\x02 \x01(\fR\x05title\x12 \n" + + "\vdescription\x18\v \x01(\fR\vdescription\x12\x1c\n" + + "\tavatarUrl\x18\x03 \x01(\tR\tavatarUrl\x12<\n" + + "\x19disappearingMessagesTimer\x18\x04 \x01(\fR\x19disappearingMessagesTimer\x12;\n" + + "\raccessControl\x18\x05 \x01(\v2\x15.signal.AccessControlR\raccessControl\x12\x18\n" + + "\aversion\x18\x06 \x01(\rR\aversion\x12(\n" + + "\amembers\x18\a \x03(\v2\x0e.signal.MemberR\amembers\x12[\n" + + "\x18membersPendingProfileKey\x18\b \x03(\v2\x1f.signal.MemberPendingProfileKeyR\x18membersPendingProfileKey\x12d\n" + + "\x1bmembersPendingAdminApproval\x18\t \x03(\v2\".signal.MemberPendingAdminApprovalR\x1bmembersPendingAdminApproval\x12.\n" + "\x12inviteLinkPassword\x18\n" + - " \x01(\fR\x12inviteLinkPassword\x12 \n" + - "\vdescription\x18\v \x01(\fR\vdescription\x12,\n" + - "\x11announcementsOnly\x18\f \x01(\bR\x11announcementsOnly\x123\n" + - "\rbannedMembers\x18\r \x03(\v2\r.BannedMemberR\rbannedMembers\"\xe6!\n" + + " \x01(\fR\x12inviteLinkPassword\x12-\n" + + "\x12announcements_only\x18\f \x01(\bR\x11announcementsOnly\x12;\n" + + "\x0emembers_banned\x18\r \x03(\v2\x14.signal.MemberBannedR\rmembersBanned\"\xc3\x01\n" + + "\x12GroupAttributeBlob\x12\x16\n" + + "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + + "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + + "\x1cdisappearingMessagesDuration\x18\x03 \x01(\rH\x00R\x1cdisappearingMessagesDuration\x12*\n" + + "\x0fdescriptionText\x18\x04 \x01(\tH\x00R\x0fdescriptionTextB\t\n" + + "\acontent\"\xe7\x01\n" + + "\x0fGroupInviteLink\x12S\n" + + "\n" + + "contentsV1\x18\x01 \x01(\v21.signal.GroupInviteLink.GroupInviteLinkContentsV1H\x00R\n" + + "contentsV1\x1as\n" + + "\x19GroupInviteLinkContentsV1\x12&\n" + + "\x0egroupMasterKey\x18\x01 \x01(\fR\x0egroupMasterKey\x12.\n" + + "\x12inviteLinkPassword\x18\x02 \x01(\fR\x12inviteLinkPasswordB\n" + + "\n" + + "\bcontents\"\xc1\x02\n" + + "\rGroupJoinInfo\x12\x1c\n" + + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + + "\x05title\x18\x02 \x01(\fR\x05title\x12 \n" + + "\vdescription\x18\b \x01(\fR\vdescription\x12\x16\n" + + "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12 \n" + + "\vmemberCount\x18\x04 \x01(\rR\vmemberCount\x12R\n" + + "\x11addFromInviteLink\x18\x05 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\x12\x18\n" + + "\aversion\x18\x06 \x01(\rR\aversion\x122\n" + + "\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\"\xbb'\n" + "\vGroupChange\x12\x18\n" + "\aactions\x18\x01 \x01(\fR\aactions\x12(\n" + "\x0fserverSignature\x18\x02 \x01(\fR\x0fserverSignature\x12 \n" + - "\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xf0 \n" + - "\aActions\x12(\n" + - "\x0fsourceServiceId\x18\x01 \x01(\fR\x0fsourceServiceId\x12\x18\n" + - "\agroupId\x18\x19 \x01(\fR\agroupId\x12\x1a\n" + - "\brevision\x18\x02 \x01(\rR\brevision\x12D\n" + + "\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xc5&\n" + + "\aActions\x12\"\n" + + "\fsourceUserId\x18\x01 \x01(\fR\fsourceUserId\x12\x19\n" + + "\bgroup_id\x18\x19 \x01(\fR\agroupId\x12\x18\n" + + "\aversion\x18\x02 \x01(\rR\aversion\x12K\n" + "\n" + - "addMembers\x18\x03 \x03(\v2$.GroupChange.Actions.AddMemberActionR\n" + - "addMembers\x12M\n" + - "\rdeleteMembers\x18\x04 \x03(\v2'.GroupChange.Actions.DeleteMemberActionR\rdeleteMembers\x12Y\n" + - "\x11modifyMemberRoles\x18\x05 \x03(\v2+.GroupChange.Actions.ModifyMemberRoleActionR\x11modifyMemberRoles\x12k\n" + - "\x17modifyMemberProfileKeys\x18\x06 \x03(\v21.GroupChange.Actions.ModifyMemberProfileKeyActionR\x17modifyMemberProfileKeys\x12Y\n" + - "\x11addPendingMembers\x18\a \x03(\v2+.GroupChange.Actions.AddPendingMemberActionR\x11addPendingMembers\x12b\n" + - "\x14deletePendingMembers\x18\b \x03(\v2..GroupChange.Actions.DeletePendingMemberActionR\x14deletePendingMembers\x12e\n" + - "\x15promotePendingMembers\x18\t \x03(\v2/.GroupChange.Actions.PromotePendingMemberActionR\x15promotePendingMembers\x12H\n" + + "addMembers\x18\x03 \x03(\v2+.signal.GroupChange.Actions.AddMemberActionR\n" + + "addMembers\x12T\n" + + "\rdeleteMembers\x18\x04 \x03(\v2..signal.GroupChange.Actions.DeleteMemberActionR\rdeleteMembers\x12`\n" + + "\x11modifyMemberRoles\x18\x05 \x03(\v22.signal.GroupChange.Actions.ModifyMemberRoleActionR\x11modifyMemberRoles\x12r\n" + + "\x17modifyMemberProfileKeys\x18\x06 \x03(\v28.signal.GroupChange.Actions.ModifyMemberProfileKeyActionR\x17modifyMemberProfileKeys\x12~\n" + + "\x1baddMembersPendingProfileKey\x18\a \x03(\v2<.signal.GroupChange.Actions.AddMemberPendingProfileKeyActionR\x1baddMembersPendingProfileKey\x12\x87\x01\n" + + "\x1edeleteMembersPendingProfileKey\x18\b \x03(\v2?.signal.GroupChange.Actions.DeleteMemberPendingProfileKeyActionR\x1edeleteMembersPendingProfileKey\x12\x8a\x01\n" + + "\x1fpromoteMembersPendingProfileKey\x18\t \x03(\v2@.signal.GroupChange.Actions.PromoteMemberPendingProfileKeyActionR\x1fpromoteMembersPendingProfileKey\x12O\n" + "\vmodifyTitle\x18\n" + - " \x01(\v2&.GroupChange.Actions.ModifyTitleActionR\vmodifyTitle\x12K\n" + - "\fmodifyAvatar\x18\v \x01(\v2'.GroupChange.Actions.ModifyAvatarActionR\fmodifyAvatar\x12\x84\x01\n" + - "\x1fmodifyDisappearingMessagesTimer\x18\f \x01(\v2:.GroupChange.Actions.ModifyDisappearingMessagesTimerActionR\x1fmodifyDisappearingMessagesTimer\x12p\n" + - "\x16modifyAttributesAccess\x18\r \x01(\v28.GroupChange.Actions.ModifyAttributesAccessControlActionR\x16modifyAttributesAccess\x12e\n" + - "\x12modifyMemberAccess\x18\x0e \x01(\v25.GroupChange.Actions.ModifyMembersAccessControlActionR\x12modifyMemberAccess\x12\x85\x01\n" + - "\x1dmodifyAddFromInviteLinkAccess\x18\x0f \x01(\v2?.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlActionR\x1dmodifyAddFromInviteLinkAccess\x12b\n" + - "\x14addRequestingMembers\x18\x10 \x03(\v2..GroupChange.Actions.AddRequestingMemberActionR\x14addRequestingMembers\x12k\n" + - "\x17deleteRequestingMembers\x18\x11 \x03(\v21.GroupChange.Actions.DeleteRequestingMemberActionR\x17deleteRequestingMembers\x12n\n" + - "\x18promoteRequestingMembers\x18\x12 \x03(\v22.GroupChange.Actions.PromoteRequestingMemberActionR\x18promoteRequestingMembers\x12o\n" + - "\x18modifyInviteLinkPassword\x18\x13 \x01(\v23.GroupChange.Actions.ModifyInviteLinkPasswordActionR\x18modifyInviteLinkPassword\x12Z\n" + - "\x11modifyDescription\x18\x14 \x01(\v2,.GroupChange.Actions.ModifyDescriptionActionR\x11modifyDescription\x12l\n" + - "\x17modifyAnnouncementsOnly\x18\x15 \x01(\v22.GroupChange.Actions.ModifyAnnouncementsOnlyActionR\x17modifyAnnouncementsOnly\x12V\n" + - "\x10addBannedMembers\x18\x16 \x03(\v2*.GroupChange.Actions.AddBannedMemberActionR\x10addBannedMembers\x12_\n" + - "\x13deleteBannedMembers\x18\x17 \x03(\v2-.GroupChange.Actions.DeleteBannedMemberActionR\x13deleteBannedMembers\x12\x81\x01\n" + - "\x1bpromotePendingPniAciMembers\x18\x18 \x03(\v2?.GroupChange.Actions.PromotePendingPniAciMemberProfileKeyActionR\x1bpromotePendingPniAciMembers\x1a`\n" + - "\x0fAddMemberAction\x12\x1d\n" + - "\x05added\x18\x01 \x01(\v2\a.MemberR\x05added\x12.\n" + + " \x01(\v2-.signal.GroupChange.Actions.ModifyTitleActionR\vmodifyTitle\x12R\n" + + "\fmodifyAvatar\x18\v \x01(\v2..signal.GroupChange.Actions.ModifyAvatarActionR\fmodifyAvatar\x12\x88\x01\n" + + "\x1emodifyDisappearingMessageTimer\x18\f \x01(\v2@.signal.GroupChange.Actions.ModifyDisappearingMessageTimerActionR\x1emodifyDisappearingMessageTimer\x12w\n" + + "\x16modifyAttributesAccess\x18\r \x01(\v2?.signal.GroupChange.Actions.ModifyAttributesAccessControlActionR\x16modifyAttributesAccess\x12l\n" + + "\x12modifyMemberAccess\x18\x0e \x01(\v2<.signal.GroupChange.Actions.ModifyMembersAccessControlActionR\x12modifyMemberAccess\x12\x8c\x01\n" + + "\x1dmodifyAddFromInviteLinkAccess\x18\x0f \x01(\v2F.signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlActionR\x1dmodifyAddFromInviteLinkAccess\x12\x87\x01\n" + + "\x1eaddMembersPendingAdminApproval\x18\x10 \x03(\v2?.signal.GroupChange.Actions.AddMemberPendingAdminApprovalActionR\x1eaddMembersPendingAdminApproval\x12\x90\x01\n" + + "!deleteMembersPendingAdminApproval\x18\x11 \x03(\v2B.signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalActionR!deleteMembersPendingAdminApproval\x12\x93\x01\n" + + "\"promoteMembersPendingAdminApproval\x18\x12 \x03(\v2C.signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalActionR\"promoteMembersPendingAdminApproval\x12v\n" + + "\x18modifyInviteLinkPassword\x18\x13 \x01(\v2:.signal.GroupChange.Actions.ModifyInviteLinkPasswordActionR\x18modifyInviteLinkPassword\x12a\n" + + "\x11modifyDescription\x18\x14 \x01(\v23.signal.GroupChange.Actions.ModifyDescriptionActionR\x11modifyDescription\x12u\n" + + "\x19modify_announcements_only\x18\x15 \x01(\v29.signal.GroupChange.Actions.ModifyAnnouncementsOnlyActionR\x17modifyAnnouncementsOnly\x12_\n" + + "\x12add_members_banned\x18\x16 \x03(\v21.signal.GroupChange.Actions.AddMemberBannedActionR\x10addMembersBanned\x12h\n" + + "\x15delete_members_banned\x18\x17 \x03(\v24.signal.GroupChange.Actions.DeleteMemberBannedActionR\x13deleteMembersBanned\x12\xa2\x01\n" + + "+promote_members_pending_pni_aci_profile_key\x18\x18 \x03(\v2F.signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyActionR%promoteMembersPendingPniAciProfileKey\x12c\n" + + "\x12modifyMemberLabels\x18\x1a \x03(\v23.signal.GroupChange.Actions.ModifyMemberLabelActionR\x12modifyMemberLabels\x1ag\n" + + "\x0fAddMemberAction\x12$\n" + + "\x05added\x18\x01 \x01(\v2\x0e.signal.MemberR\x05added\x12.\n" + "\x12joinFromInviteLink\x18\x02 \x01(\bR\x12joinFromInviteLink\x1a:\n" + "\x12DeleteMemberAction\x12$\n" + - "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1aR\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1aY\n" + "\x16ModifyMemberRoleAction\x12\x16\n" + - "\x06userId\x18\x01 \x01(\fR\x06userId\x12 \n" + - "\x04role\x18\x02 \x01(\x0e2\f.Member.RoleR\x04role\x1a|\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12'\n" + + "\x04role\x18\x02 \x01(\x0e2\x13.signal.Member.RoleR\x04role\x1as\n" + + "\x17ModifyMemberLabelAction\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1e\n" + + "\n" + + "labelEmoji\x18\x02 \x01(\fR\n" + + "labelEmoji\x12 \n" + + "\vlabelString\x18\x03 \x01(\fR\vlabelString\x1a|\n" + "\x1cModifyMemberProfileKeyAction\x12\"\n" + "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x17\n" + "\auser_id\x18\x02 \x01(\fR\x06userId\x12\x1f\n" + "\vprofile_key\x18\x03 \x01(\fR\n" + - "profileKey\x1a>\n" + - "\x16AddPendingMemberAction\x12$\n" + - "\x05added\x18\x01 \x01(\v2\x0e.PendingMemberR\x05added\x1aA\n" + - "\x19DeletePendingMemberAction\x12$\n" + - "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1az\n" + - "\x1aPromotePendingMemberAction\x12\"\n" + + "profileKey\x1aY\n" + + " AddMemberPendingProfileKeyAction\x125\n" + + "\x05added\x18\x01 \x01(\v2\x1f.signal.MemberPendingProfileKeyR\x05added\x1aK\n" + + "#DeleteMemberPendingProfileKeyAction\x12$\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1a\x84\x01\n" + + "$PromoteMemberPendingProfileKeyAction\x12\"\n" + "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x17\n" + "\auser_id\x18\x02 \x01(\fR\x06userId\x12\x1f\n" + "\vprofile_key\x18\x03 \x01(\fR\n" + - "profileKey\x1a\x9a\x01\n" + - "*PromotePendingPniAciMemberProfileKeyAction\x12\"\n" + - "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x16\n" + - "\x06userId\x18\x02 \x01(\fR\x06userId\x12\x10\n" + - "\x03pni\x18\x03 \x01(\fR\x03pni\x12\x1e\n" + - "\n" + - "profileKey\x18\x04 \x01(\fR\n" + - "profileKey\x1aD\n" + - "\x19AddRequestingMemberAction\x12'\n" + - "\x05added\x18\x01 \x01(\v2\x11.RequestingMemberR\x05added\x1aD\n" + - "\x1cDeleteRequestingMemberAction\x12$\n" + - "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1aY\n" + - "\x1dPromoteRequestingMemberAction\x12\x16\n" + - "\x06userId\x18\x01 \x01(\fR\x06userId\x12 \n" + - "\x04role\x18\x02 \x01(\x0e2\f.Member.RoleR\x04role\x1a<\n" + - "\x15AddBannedMemberAction\x12#\n" + - "\x05added\x18\x01 \x01(\v2\r.BannedMemberR\x05added\x1a@\n" + - "\x18DeleteBannedMemberAction\x12$\n" + + "profileKey\x1a\x9c\x01\n" + + "*PromoteMemberPendingPniAciProfileKeyAction\x12\"\n" + + "\fpresentation\x18\x01 \x01(\fR\fpresentation\x12\x17\n" + + "\auser_id\x18\x02 \x01(\fR\x06userId\x12\x10\n" + + "\x03pni\x18\x03 \x01(\fR\x03pni\x12\x1f\n" + + "\vprofile_key\x18\x04 \x01(\fR\n" + + "profileKey\x1a_\n" + + "#AddMemberPendingAdminApprovalAction\x128\n" + + "\x05added\x18\x01 \x01(\v2\".signal.MemberPendingAdminApprovalR\x05added\x1aN\n" + + "&DeleteMemberPendingAdminApprovalAction\x12$\n" + + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1aj\n" + + "'PromoteMemberPendingAdminApprovalAction\x12\x16\n" + + "\x06userId\x18\x01 \x01(\fR\x06userId\x12'\n" + + "\x04role\x18\x02 \x01(\x0e2\x13.signal.Member.RoleR\x04role\x1aC\n" + + "\x15AddMemberBannedAction\x12*\n" + + "\x05added\x18\x01 \x01(\v2\x14.signal.MemberBannedR\x05added\x1a@\n" + + "\x18DeleteMemberBannedAction\x12$\n" + "\rdeletedUserId\x18\x01 \x01(\fR\rdeletedUserId\x1a)\n" + "\x11ModifyTitleAction\x12\x14\n" + "\x05title\x18\x01 \x01(\fR\x05title\x1a;\n" + "\x17ModifyDescriptionAction\x12 \n" + "\vdescription\x18\x01 \x01(\fR\vdescription\x1a,\n" + "\x12ModifyAvatarAction\x12\x16\n" + - "\x06avatar\x18\x01 \x01(\tR\x06avatar\x1a=\n" + - "%ModifyDisappearingMessagesTimerAction\x12\x14\n" + - "\x05timer\x18\x01 \x01(\fR\x05timer\x1ap\n" + - "#ModifyAttributesAccessControlAction\x12I\n" + - "\x10attributesAccess\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x10attributesAccess\x1ag\n" + - " ModifyMembersAccessControlAction\x12C\n" + - "\rmembersAccess\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\rmembersAccess\x1a\x85\x01\n" + - "*ModifyAddFromInviteLinkAccessControlAction\x12W\n" + - "\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1aP\n" + + "\x06avatar\x18\x01 \x01(\tR\x06avatar\x1a<\n" + + "$ModifyDisappearingMessageTimerAction\x12\x14\n" + + "\x05timer\x18\x01 \x01(\fR\x05timer\x1aw\n" + + "#ModifyAttributesAccessControlAction\x12P\n" + + "\x10attributesAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x10attributesAccess\x1an\n" + + " ModifyMembersAccessControlAction\x12J\n" + + "\rmembersAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\rmembersAccess\x1a\x8c\x01\n" + + "*ModifyAddFromInviteLinkAccessControlAction\x12^\n" + + "\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1aP\n" + "\x1eModifyInviteLinkPasswordAction\x12.\n" + - "\x12inviteLinkPassword\x18\x01 \x01(\fR\x12inviteLinkPassword\x1aM\n" + - "\x1dModifyAnnouncementsOnlyAction\x12,\n" + - "\x11announcementsOnly\x18\x01 \x01(\bR\x11announcementsOnly\"s\n" + - "\rGroupResponse\x12\x1c\n" + - "\x05group\x18\x01 \x01(\v2\x06.GroupR\x05group\x12D\n" + - "\x1dgroupSendEndorsementsResponse\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\"\x84\x02\n" + - "\fGroupChanges\x12B\n" + - "\fgroupChanges\x18\x01 \x03(\v2\x1e.GroupChanges.GroupChangeStateR\fgroupChanges\x12D\n" + - "\x1dgroupSendEndorsementsResponse\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\x1aj\n" + - "\x10GroupChangeState\x12.\n" + - "\vgroupChange\x18\x01 \x01(\v2\f.GroupChangeR\vgroupChange\x12&\n" + + "\x12inviteLinkPassword\x18\x01 \x01(\fR\x12inviteLinkPassword\x1aN\n" + + "\x1dModifyAnnouncementsOnlyAction\x12-\n" + + "\x12announcements_only\x18\x01 \x01(\bR\x11announcementsOnly\"/\n" + + "\x17ExternalGroupCredential\x12\x14\n" + + "\x05token\x18\x01 \x01(\tR\x05token\"}\n" + + "\rGroupResponse\x12#\n" + + "\x05group\x18\x01 \x01(\v2\r.signal.GroupR\x05group\x12G\n" + + " group_send_endorsements_response\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\"\x9c\x02\n" + + "\fGroupChanges\x12I\n" + + "\fgroupChanges\x18\x01 \x03(\v2%.signal.GroupChanges.GroupChangeStateR\fgroupChanges\x12G\n" + + " group_send_endorsements_response\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\x1ax\n" + + "\x10GroupChangeState\x125\n" + + "\vgroupChange\x18\x01 \x01(\v2\x13.signal.GroupChangeR\vgroupChange\x12-\n" + "\n" + - "groupState\x18\x02 \x01(\v2\x06.GroupR\n" + - "groupState\"\x8b\x01\n" + - "\x13GroupChangeResponse\x12.\n" + - "\vgroupChange\x18\x01 \x01(\v2\f.GroupChangeR\vgroupChange\x12D\n" + - "\x1dgroupSendEndorsementsResponse\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponse\"\xbb\x01\n" + - "\x12GroupAttributeBlob\x12\x16\n" + - "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + - "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + - "\x1cdisappearingMessagesDuration\x18\x03 \x01(\rH\x00R\x1cdisappearingMessagesDuration\x12\"\n" + - "\vdescription\x18\x04 \x01(\tH\x00R\vdescriptionB\t\n" + - "\acontent\"\xe0\x01\n" + - "\x0fGroupInviteLink\x12L\n" + - "\n" + - "v1Contents\x18\x01 \x01(\v2*.GroupInviteLink.GroupInviteLinkContentsV1H\x00R\n" + - "v1Contents\x1as\n" + - "\x19GroupInviteLinkContentsV1\x12&\n" + - "\x0egroupMasterKey\x18\x01 \x01(\fR\x0egroupMasterKey\x12.\n" + - "\x12inviteLinkPassword\x18\x02 \x01(\fR\x12inviteLinkPasswordB\n" + - "\n" + - "\bcontents\"\xbc\x02\n" + - "\rGroupJoinInfo\x12\x1c\n" + - "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + - "\x05title\x18\x02 \x01(\fR\x05title\x12\x16\n" + - "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12 \n" + - "\vmemberCount\x18\x04 \x01(\rR\vmemberCount\x12K\n" + - "\x11addFromInviteLink\x18\x05 \x01(\x0e2\x1d.AccessControl.AccessRequiredR\x11addFromInviteLink\x12\x1a\n" + - "\brevision\x18\x06 \x01(\rR\brevision\x122\n" + - "\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\x12 \n" + - "\vdescription\x18\b \x01(\fR\vdescription\"/\n" + - "\x17GroupExternalCredential\x12\x14\n" + - "\x05token\x18\x01 \x01(\tR\x05tokenB+\n" + - "'org.signal.storageservice.protos.groupsP\x01b\x06proto3" + "groupState\x18\x02 \x01(\v2\r.signal.GroupR\n" + + "groupState\"\x96\x01\n" + + "\x13GroupChangeResponse\x126\n" + + "\fgroup_change\x18\x01 \x01(\v2\x13.signal.GroupChangeR\vgroupChange\x12G\n" + + " group_send_endorsements_response\x18\x02 \x01(\fR\x1dgroupSendEndorsementsResponseB@\n" + + "/org.signal.storageservice.storage.protos.groupsB\vGroupProtosP\x01b\x06proto3" var ( file_Groups_proto_rawDescOnce sync.Once @@ -2821,105 +2918,107 @@ func file_Groups_proto_rawDescGZIP() []byte { } var file_Groups_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 40) +var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 41) var file_Groups_proto_goTypes = []any{ - (Member_Role)(0), // 0: Member.Role - (AccessControl_AccessRequired)(0), // 1: AccessControl.AccessRequired - (*AvatarUploadAttributes)(nil), // 2: AvatarUploadAttributes - (*Member)(nil), // 3: Member - (*PendingMember)(nil), // 4: PendingMember - (*RequestingMember)(nil), // 5: RequestingMember - (*BannedMember)(nil), // 6: BannedMember - (*AccessControl)(nil), // 7: AccessControl - (*Group)(nil), // 8: Group - (*GroupChange)(nil), // 9: GroupChange - (*GroupResponse)(nil), // 10: GroupResponse - (*GroupChanges)(nil), // 11: GroupChanges - (*GroupChangeResponse)(nil), // 12: GroupChangeResponse - (*GroupAttributeBlob)(nil), // 13: GroupAttributeBlob - (*GroupInviteLink)(nil), // 14: GroupInviteLink - (*GroupJoinInfo)(nil), // 15: GroupJoinInfo - (*GroupExternalCredential)(nil), // 16: GroupExternalCredential - (*GroupChange_Actions)(nil), // 17: GroupChange.Actions - (*GroupChange_Actions_AddMemberAction)(nil), // 18: GroupChange.Actions.AddMemberAction - (*GroupChange_Actions_DeleteMemberAction)(nil), // 19: GroupChange.Actions.DeleteMemberAction - (*GroupChange_Actions_ModifyMemberRoleAction)(nil), // 20: GroupChange.Actions.ModifyMemberRoleAction - (*GroupChange_Actions_ModifyMemberProfileKeyAction)(nil), // 21: GroupChange.Actions.ModifyMemberProfileKeyAction - (*GroupChange_Actions_AddPendingMemberAction)(nil), // 22: GroupChange.Actions.AddPendingMemberAction - (*GroupChange_Actions_DeletePendingMemberAction)(nil), // 23: GroupChange.Actions.DeletePendingMemberAction - (*GroupChange_Actions_PromotePendingMemberAction)(nil), // 24: GroupChange.Actions.PromotePendingMemberAction - (*GroupChange_Actions_PromotePendingPniAciMemberProfileKeyAction)(nil), // 25: GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction - (*GroupChange_Actions_AddRequestingMemberAction)(nil), // 26: GroupChange.Actions.AddRequestingMemberAction - (*GroupChange_Actions_DeleteRequestingMemberAction)(nil), // 27: GroupChange.Actions.DeleteRequestingMemberAction - (*GroupChange_Actions_PromoteRequestingMemberAction)(nil), // 28: GroupChange.Actions.PromoteRequestingMemberAction - (*GroupChange_Actions_AddBannedMemberAction)(nil), // 29: GroupChange.Actions.AddBannedMemberAction - (*GroupChange_Actions_DeleteBannedMemberAction)(nil), // 30: GroupChange.Actions.DeleteBannedMemberAction - (*GroupChange_Actions_ModifyTitleAction)(nil), // 31: GroupChange.Actions.ModifyTitleAction - (*GroupChange_Actions_ModifyDescriptionAction)(nil), // 32: GroupChange.Actions.ModifyDescriptionAction - (*GroupChange_Actions_ModifyAvatarAction)(nil), // 33: GroupChange.Actions.ModifyAvatarAction - (*GroupChange_Actions_ModifyDisappearingMessagesTimerAction)(nil), // 34: GroupChange.Actions.ModifyDisappearingMessagesTimerAction - (*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 35: GroupChange.Actions.ModifyAttributesAccessControlAction - (*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 36: GroupChange.Actions.ModifyMembersAccessControlAction - (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 37: GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 38: GroupChange.Actions.ModifyInviteLinkPasswordAction - (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 39: GroupChange.Actions.ModifyAnnouncementsOnlyAction - (*GroupChanges_GroupChangeState)(nil), // 40: GroupChanges.GroupChangeState - (*GroupInviteLink_GroupInviteLinkContentsV1)(nil), // 41: GroupInviteLink.GroupInviteLinkContentsV1 + (Member_Role)(0), // 0: signal.Member.Role + (AccessControl_AccessRequired)(0), // 1: signal.AccessControl.AccessRequired + (*AvatarUploadAttributes)(nil), // 2: signal.AvatarUploadAttributes + (*Member)(nil), // 3: signal.Member + (*MemberPendingProfileKey)(nil), // 4: signal.MemberPendingProfileKey + (*MemberPendingAdminApproval)(nil), // 5: signal.MemberPendingAdminApproval + (*MemberBanned)(nil), // 6: signal.MemberBanned + (*AccessControl)(nil), // 7: signal.AccessControl + (*Group)(nil), // 8: signal.Group + (*GroupAttributeBlob)(nil), // 9: signal.GroupAttributeBlob + (*GroupInviteLink)(nil), // 10: signal.GroupInviteLink + (*GroupJoinInfo)(nil), // 11: signal.GroupJoinInfo + (*GroupChange)(nil), // 12: signal.GroupChange + (*ExternalGroupCredential)(nil), // 13: signal.ExternalGroupCredential + (*GroupResponse)(nil), // 14: signal.GroupResponse + (*GroupChanges)(nil), // 15: signal.GroupChanges + (*GroupChangeResponse)(nil), // 16: signal.GroupChangeResponse + (*GroupInviteLink_GroupInviteLinkContentsV1)(nil), // 17: signal.GroupInviteLink.GroupInviteLinkContentsV1 + (*GroupChange_Actions)(nil), // 18: signal.GroupChange.Actions + (*GroupChange_Actions_AddMemberAction)(nil), // 19: signal.GroupChange.Actions.AddMemberAction + (*GroupChange_Actions_DeleteMemberAction)(nil), // 20: signal.GroupChange.Actions.DeleteMemberAction + (*GroupChange_Actions_ModifyMemberRoleAction)(nil), // 21: signal.GroupChange.Actions.ModifyMemberRoleAction + (*GroupChange_Actions_ModifyMemberLabelAction)(nil), // 22: signal.GroupChange.Actions.ModifyMemberLabelAction + (*GroupChange_Actions_ModifyMemberProfileKeyAction)(nil), // 23: signal.GroupChange.Actions.ModifyMemberProfileKeyAction + (*GroupChange_Actions_AddMemberPendingProfileKeyAction)(nil), // 24: signal.GroupChange.Actions.AddMemberPendingProfileKeyAction + (*GroupChange_Actions_DeleteMemberPendingProfileKeyAction)(nil), // 25: signal.GroupChange.Actions.DeleteMemberPendingProfileKeyAction + (*GroupChange_Actions_PromoteMemberPendingProfileKeyAction)(nil), // 26: signal.GroupChange.Actions.PromoteMemberPendingProfileKeyAction + (*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction)(nil), // 27: signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyAction + (*GroupChange_Actions_AddMemberPendingAdminApprovalAction)(nil), // 28: signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction + (*GroupChange_Actions_DeleteMemberPendingAdminApprovalAction)(nil), // 29: signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalAction + (*GroupChange_Actions_PromoteMemberPendingAdminApprovalAction)(nil), // 30: signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction + (*GroupChange_Actions_AddMemberBannedAction)(nil), // 31: signal.GroupChange.Actions.AddMemberBannedAction + (*GroupChange_Actions_DeleteMemberBannedAction)(nil), // 32: signal.GroupChange.Actions.DeleteMemberBannedAction + (*GroupChange_Actions_ModifyTitleAction)(nil), // 33: signal.GroupChange.Actions.ModifyTitleAction + (*GroupChange_Actions_ModifyDescriptionAction)(nil), // 34: signal.GroupChange.Actions.ModifyDescriptionAction + (*GroupChange_Actions_ModifyAvatarAction)(nil), // 35: signal.GroupChange.Actions.ModifyAvatarAction + (*GroupChange_Actions_ModifyDisappearingMessageTimerAction)(nil), // 36: signal.GroupChange.Actions.ModifyDisappearingMessageTimerAction + (*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 37: signal.GroupChange.Actions.ModifyAttributesAccessControlAction + (*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 38: signal.GroupChange.Actions.ModifyMembersAccessControlAction + (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 39: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction + (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 40: signal.GroupChange.Actions.ModifyInviteLinkPasswordAction + (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 41: signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction + (*GroupChanges_GroupChangeState)(nil), // 42: signal.GroupChanges.GroupChangeState } var file_Groups_proto_depIdxs = []int32{ - 0, // 0: Member.role:type_name -> Member.Role - 3, // 1: PendingMember.member:type_name -> Member - 1, // 2: AccessControl.attributes:type_name -> AccessControl.AccessRequired - 1, // 3: AccessControl.members:type_name -> AccessControl.AccessRequired - 1, // 4: AccessControl.addFromInviteLink:type_name -> AccessControl.AccessRequired - 7, // 5: Group.accessControl:type_name -> AccessControl - 3, // 6: Group.members:type_name -> Member - 4, // 7: Group.pendingMembers:type_name -> PendingMember - 5, // 8: Group.requestingMembers:type_name -> RequestingMember - 6, // 9: Group.bannedMembers:type_name -> BannedMember - 8, // 10: GroupResponse.group:type_name -> Group - 40, // 11: GroupChanges.groupChanges:type_name -> GroupChanges.GroupChangeState - 9, // 12: GroupChangeResponse.groupChange:type_name -> GroupChange - 41, // 13: GroupInviteLink.v1Contents:type_name -> GroupInviteLink.GroupInviteLinkContentsV1 - 1, // 14: GroupJoinInfo.addFromInviteLink:type_name -> AccessControl.AccessRequired - 18, // 15: GroupChange.Actions.addMembers:type_name -> GroupChange.Actions.AddMemberAction - 19, // 16: GroupChange.Actions.deleteMembers:type_name -> GroupChange.Actions.DeleteMemberAction - 20, // 17: GroupChange.Actions.modifyMemberRoles:type_name -> GroupChange.Actions.ModifyMemberRoleAction - 21, // 18: GroupChange.Actions.modifyMemberProfileKeys:type_name -> GroupChange.Actions.ModifyMemberProfileKeyAction - 22, // 19: GroupChange.Actions.addPendingMembers:type_name -> GroupChange.Actions.AddPendingMemberAction - 23, // 20: GroupChange.Actions.deletePendingMembers:type_name -> GroupChange.Actions.DeletePendingMemberAction - 24, // 21: GroupChange.Actions.promotePendingMembers:type_name -> GroupChange.Actions.PromotePendingMemberAction - 31, // 22: GroupChange.Actions.modifyTitle:type_name -> GroupChange.Actions.ModifyTitleAction - 33, // 23: GroupChange.Actions.modifyAvatar:type_name -> GroupChange.Actions.ModifyAvatarAction - 34, // 24: GroupChange.Actions.modifyDisappearingMessagesTimer:type_name -> GroupChange.Actions.ModifyDisappearingMessagesTimerAction - 35, // 25: GroupChange.Actions.modifyAttributesAccess:type_name -> GroupChange.Actions.ModifyAttributesAccessControlAction - 36, // 26: GroupChange.Actions.modifyMemberAccess:type_name -> GroupChange.Actions.ModifyMembersAccessControlAction - 37, // 27: GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - 26, // 28: GroupChange.Actions.addRequestingMembers:type_name -> GroupChange.Actions.AddRequestingMemberAction - 27, // 29: GroupChange.Actions.deleteRequestingMembers:type_name -> GroupChange.Actions.DeleteRequestingMemberAction - 28, // 30: GroupChange.Actions.promoteRequestingMembers:type_name -> GroupChange.Actions.PromoteRequestingMemberAction - 38, // 31: GroupChange.Actions.modifyInviteLinkPassword:type_name -> GroupChange.Actions.ModifyInviteLinkPasswordAction - 32, // 32: GroupChange.Actions.modifyDescription:type_name -> GroupChange.Actions.ModifyDescriptionAction - 39, // 33: GroupChange.Actions.modifyAnnouncementsOnly:type_name -> GroupChange.Actions.ModifyAnnouncementsOnlyAction - 29, // 34: GroupChange.Actions.addBannedMembers:type_name -> GroupChange.Actions.AddBannedMemberAction - 30, // 35: GroupChange.Actions.deleteBannedMembers:type_name -> GroupChange.Actions.DeleteBannedMemberAction - 25, // 36: GroupChange.Actions.promotePendingPniAciMembers:type_name -> GroupChange.Actions.PromotePendingPniAciMemberProfileKeyAction - 3, // 37: GroupChange.Actions.AddMemberAction.added:type_name -> Member - 0, // 38: GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> Member.Role - 4, // 39: GroupChange.Actions.AddPendingMemberAction.added:type_name -> PendingMember - 5, // 40: GroupChange.Actions.AddRequestingMemberAction.added:type_name -> RequestingMember - 0, // 41: GroupChange.Actions.PromoteRequestingMemberAction.role:type_name -> Member.Role - 6, // 42: GroupChange.Actions.AddBannedMemberAction.added:type_name -> BannedMember - 1, // 43: GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> AccessControl.AccessRequired - 1, // 44: GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> AccessControl.AccessRequired - 1, // 45: GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> AccessControl.AccessRequired - 9, // 46: GroupChanges.GroupChangeState.groupChange:type_name -> GroupChange - 8, // 47: GroupChanges.GroupChangeState.groupState:type_name -> Group - 48, // [48:48] is the sub-list for method output_type - 48, // [48:48] is the sub-list for method input_type - 48, // [48:48] is the sub-list for extension type_name - 48, // [48:48] is the sub-list for extension extendee - 0, // [0:48] is the sub-list for field type_name + 0, // 0: signal.Member.role:type_name -> signal.Member.Role + 3, // 1: signal.MemberPendingProfileKey.member:type_name -> signal.Member + 1, // 2: signal.AccessControl.attributes:type_name -> signal.AccessControl.AccessRequired + 1, // 3: signal.AccessControl.members:type_name -> signal.AccessControl.AccessRequired + 1, // 4: signal.AccessControl.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired + 7, // 5: signal.Group.accessControl:type_name -> signal.AccessControl + 3, // 6: signal.Group.members:type_name -> signal.Member + 4, // 7: signal.Group.membersPendingProfileKey:type_name -> signal.MemberPendingProfileKey + 5, // 8: signal.Group.membersPendingAdminApproval:type_name -> signal.MemberPendingAdminApproval + 6, // 9: signal.Group.members_banned:type_name -> signal.MemberBanned + 17, // 10: signal.GroupInviteLink.contentsV1:type_name -> signal.GroupInviteLink.GroupInviteLinkContentsV1 + 1, // 11: signal.GroupJoinInfo.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired + 8, // 12: signal.GroupResponse.group:type_name -> signal.Group + 42, // 13: signal.GroupChanges.groupChanges:type_name -> signal.GroupChanges.GroupChangeState + 12, // 14: signal.GroupChangeResponse.group_change:type_name -> signal.GroupChange + 19, // 15: signal.GroupChange.Actions.addMembers:type_name -> signal.GroupChange.Actions.AddMemberAction + 20, // 16: signal.GroupChange.Actions.deleteMembers:type_name -> signal.GroupChange.Actions.DeleteMemberAction + 21, // 17: signal.GroupChange.Actions.modifyMemberRoles:type_name -> signal.GroupChange.Actions.ModifyMemberRoleAction + 23, // 18: signal.GroupChange.Actions.modifyMemberProfileKeys:type_name -> signal.GroupChange.Actions.ModifyMemberProfileKeyAction + 24, // 19: signal.GroupChange.Actions.addMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.AddMemberPendingProfileKeyAction + 25, // 20: signal.GroupChange.Actions.deleteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.DeleteMemberPendingProfileKeyAction + 26, // 21: signal.GroupChange.Actions.promoteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.PromoteMemberPendingProfileKeyAction + 33, // 22: signal.GroupChange.Actions.modifyTitle:type_name -> signal.GroupChange.Actions.ModifyTitleAction + 35, // 23: signal.GroupChange.Actions.modifyAvatar:type_name -> signal.GroupChange.Actions.ModifyAvatarAction + 36, // 24: signal.GroupChange.Actions.modifyDisappearingMessageTimer:type_name -> signal.GroupChange.Actions.ModifyDisappearingMessageTimerAction + 37, // 25: signal.GroupChange.Actions.modifyAttributesAccess:type_name -> signal.GroupChange.Actions.ModifyAttributesAccessControlAction + 38, // 26: signal.GroupChange.Actions.modifyMemberAccess:type_name -> signal.GroupChange.Actions.ModifyMembersAccessControlAction + 39, // 27: signal.GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction + 28, // 28: signal.GroupChange.Actions.addMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction + 29, // 29: signal.GroupChange.Actions.deleteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalAction + 30, // 30: signal.GroupChange.Actions.promoteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction + 40, // 31: signal.GroupChange.Actions.modifyInviteLinkPassword:type_name -> signal.GroupChange.Actions.ModifyInviteLinkPasswordAction + 34, // 32: signal.GroupChange.Actions.modifyDescription:type_name -> signal.GroupChange.Actions.ModifyDescriptionAction + 41, // 33: signal.GroupChange.Actions.modify_announcements_only:type_name -> signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction + 31, // 34: signal.GroupChange.Actions.add_members_banned:type_name -> signal.GroupChange.Actions.AddMemberBannedAction + 32, // 35: signal.GroupChange.Actions.delete_members_banned:type_name -> signal.GroupChange.Actions.DeleteMemberBannedAction + 27, // 36: signal.GroupChange.Actions.promote_members_pending_pni_aci_profile_key:type_name -> signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyAction + 22, // 37: signal.GroupChange.Actions.modifyMemberLabels:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAction + 3, // 38: signal.GroupChange.Actions.AddMemberAction.added:type_name -> signal.Member + 0, // 39: signal.GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> signal.Member.Role + 4, // 40: signal.GroupChange.Actions.AddMemberPendingProfileKeyAction.added:type_name -> signal.MemberPendingProfileKey + 5, // 41: signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction.added:type_name -> signal.MemberPendingAdminApproval + 0, // 42: signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction.role:type_name -> signal.Member.Role + 6, // 43: signal.GroupChange.Actions.AddMemberBannedAction.added:type_name -> signal.MemberBanned + 1, // 44: signal.GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> signal.AccessControl.AccessRequired + 1, // 45: signal.GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> signal.AccessControl.AccessRequired + 1, // 46: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> signal.AccessControl.AccessRequired + 12, // 47: signal.GroupChanges.GroupChangeState.groupChange:type_name -> signal.GroupChange + 8, // 48: signal.GroupChanges.GroupChangeState.groupState:type_name -> signal.Group + 49, // [49:49] is the sub-list for method output_type + 49, // [49:49] is the sub-list for method input_type + 49, // [49:49] is the sub-list for extension type_name + 49, // [49:49] is the sub-list for extension extendee + 0, // [0:49] is the sub-list for field type_name } func init() { file_Groups_proto_init() } @@ -2927,14 +3026,14 @@ func file_Groups_proto_init() { if File_Groups_proto != nil { return } - file_Groups_proto_msgTypes[11].OneofWrappers = []any{ + file_Groups_proto_msgTypes[7].OneofWrappers = []any{ (*GroupAttributeBlob_Title)(nil), (*GroupAttributeBlob_Avatar)(nil), (*GroupAttributeBlob_DisappearingMessagesDuration)(nil), - (*GroupAttributeBlob_Description)(nil), + (*GroupAttributeBlob_DescriptionText)(nil), } - file_Groups_proto_msgTypes[12].OneofWrappers = []any{ - (*GroupInviteLink_V1Contents)(nil), + file_Groups_proto_msgTypes[8].OneofWrappers = []any{ + (*GroupInviteLink_ContentsV1)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -2942,7 +3041,7 @@ func file_Groups_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_Groups_proto_rawDesc), len(file_Groups_proto_rawDesc)), NumEnums: 2, - NumMessages: 40, + NumMessages: 41, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/Groups.proto b/pkg/signalmeow/protobuf/Groups.proto index e202eb2..448846a 100644 --- a/pkg/signalmeow/protobuf/Groups.proto +++ b/pkg/signalmeow/protobuf/Groups.proto @@ -1,92 +1,137 @@ -/** - * Copyright (C) 2019 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. +/* + * Copyright 2020 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only */ + syntax = "proto3"; -option java_package = "org.signal.storageservice.protos.groups"; +package signal; + +option java_package = "org.signal.storageservice.storage.protos.groups"; +option java_outer_classname = "GroupProtos"; option java_multiple_files = true; message AvatarUploadAttributes { - string key = 1; + string key = 1; string credential = 2; - string acl = 3; - string algorithm = 4; - string date = 5; - string policy = 6; - string signature = 7; + string acl = 3; + string algorithm = 4; + string date = 5; + string policy = 6; + string signature = 7; } +// Stored data + message Member { enum Role { - UNKNOWN = 0; - DEFAULT = 1; + UNKNOWN = 0; + DEFAULT = 1; ADMINISTRATOR = 2; } - bytes userId = 1; - Role role = 2; - bytes profileKey = 3; - bytes presentation = 4; // Only set when sending to server - uint32 joinedAtRevision = 5; + bytes userId = 1; + Role role = 2; + bytes profileKey = 3; + bytes presentation = 4; + uint32 joinedAtVersion = 5; + bytes labelEmoji = 6; // decrypts to a UTF-8 string + bytes labelString = 7; // decrypts to a UTF-8 string } -message PendingMember { - Member member = 1; - bytes addedByUserId = 2; - uint64 timestamp = 3; +message MemberPendingProfileKey { + Member member = 1; + bytes addedByUserId = 2; + uint64 timestamp = 3; // ms since epoch } -message RequestingMember { - bytes userId = 1; - bytes profileKey = 2; - bytes presentation = 3; // Only set when sending to server - uint64 timestamp = 4; +message MemberPendingAdminApproval { + bytes userId = 1; + bytes profileKey = 2; + bytes presentation = 3; + uint64 timestamp = 4; // ms since epoch } -message BannedMember { - bytes userId = 1; - uint64 timestamp = 2; +message MemberBanned { + bytes userId = 1; + uint64 timestamp = 2; // ms since epoch } message AccessControl { enum AccessRequired { - UNKNOWN = 0; - ANY = 1; - MEMBER = 2; + UNKNOWN = 0; + ANY = 1; + MEMBER = 2; ADMINISTRATOR = 3; UNSATISFIABLE = 4; } - AccessRequired attributes = 1; - AccessRequired members = 2; + AccessRequired attributes = 1; + AccessRequired members = 2; AccessRequired addFromInviteLink = 3; } message Group { - bytes publicKey = 1; - bytes title = 2; - string avatar = 3; - bytes disappearingMessagesTimer = 4; - AccessControl accessControl = 5; - uint32 revision = 6; - repeated Member members = 7; - repeated PendingMember pendingMembers = 8; - repeated RequestingMember requestingMembers = 9; - bytes inviteLinkPassword = 10; - bytes description = 11; - bool announcementsOnly = 12; - repeated BannedMember bannedMembers = 13; + bytes publicKey = 1; + bytes title = 2; + bytes description = 11; + // The URL for this group's avatar. The content at this URL can be + // decrypted/deserialized into a `GroupAttributeBlob`. + string avatarUrl = 3; + bytes disappearingMessagesTimer = 4; + AccessControl accessControl = 5; + uint32 version = 6; + repeated Member members = 7; + repeated MemberPendingProfileKey membersPendingProfileKey = 8; + repeated MemberPendingAdminApproval membersPendingAdminApproval = 9; + bytes inviteLinkPassword = 10; + bool announcements_only = 12; + repeated MemberBanned members_banned = 13; + // next: 14 } +message GroupAttributeBlob { + oneof content { + string title = 1; + bytes avatar = 2; + uint32 disappearingMessagesDuration = 3; + string descriptionText = 4; + } +} + +message GroupInviteLink { + message GroupInviteLinkContentsV1 { + bytes groupMasterKey = 1; + bytes inviteLinkPassword = 2; + } + + oneof contents { + GroupInviteLinkContentsV1 contentsV1 = 1; + } +} + +message GroupJoinInfo { + bytes publicKey = 1; + bytes title = 2; + bytes description = 8; + string avatar = 3; + uint32 memberCount = 4; + AccessControl.AccessRequired addFromInviteLink = 5; + uint32 version = 6; + bool pendingAdminApproval = 7; + // bool pendingAdminApprovalFull = 9; + // next: 10 +} + +// Deltas + message GroupChange { message Actions { message AddMemberAction { - Member added = 1; - bool joinFromInviteLink = 2; + Member added = 1; + bool joinFromInviteLink = 2; } message DeleteMemberAction { @@ -94,55 +139,61 @@ message GroupChange { } message ModifyMemberRoleAction { - bytes userId = 1; - Member.Role role = 2; + bytes userId = 1; + Member.Role role = 2; + } + + message ModifyMemberLabelAction { + bytes userId = 1; + bytes labelEmoji = 2; // decrypts to a UTF-8 string + bytes labelString = 3; // decrypts to a UTF-8 string } message ModifyMemberProfileKeyAction { - bytes presentation = 1; // Only set when sending to server - bytes user_id = 2; // Only set when receiving from server - bytes profile_key = 3; // Only set when receiving from server + bytes presentation = 1; + bytes user_id = 2; + bytes profile_key = 3; } - message AddPendingMemberAction { - PendingMember added = 1; + message AddMemberPendingProfileKeyAction { + MemberPendingProfileKey added = 1; } - message DeletePendingMemberAction { + message DeleteMemberPendingProfileKeyAction { bytes deletedUserId = 1; } - message PromotePendingMemberAction { - bytes presentation = 1; // Only set when sending to server - bytes user_id = 2; // Only set when receiving from server - bytes profile_key = 3; // Only set when receiving from server + message PromoteMemberPendingProfileKeyAction { + bytes presentation = 1; + bytes user_id = 2; + bytes profile_key = 3; } - message PromotePendingPniAciMemberProfileKeyAction { - bytes presentation = 1; // Only set when sending to server - bytes userId = 2; // Only set when receiving from server - bytes pni = 3; // Only set when receiving from server - bytes profileKey = 4; // Only set when receiving from server + message PromoteMemberPendingPniAciProfileKeyAction { + bytes presentation = 1; + bytes user_id = 2; + bytes pni = 3; + bytes profile_key = 4; } - message AddRequestingMemberAction { - RequestingMember added = 1; + message AddMemberPendingAdminApprovalAction { + MemberPendingAdminApproval added = 1; } - message DeleteRequestingMemberAction { + message DeleteMemberPendingAdminApprovalAction { bytes deletedUserId = 1; } - message PromoteRequestingMemberAction { - bytes userId = 1; - Member.Role role = 2; + message PromoteMemberPendingAdminApprovalAction { + bytes userId = 1; + Member.Role role = 2; } - message AddBannedMemberAction { - BannedMember added = 1; + message AddMemberBannedAction { + MemberBanned added = 1; } - message DeleteBannedMemberAction { + message DeleteMemberBannedAction { bytes deletedUserId = 1; } @@ -158,7 +209,7 @@ message GroupChange { string avatar = 1; } - message ModifyDisappearingMessagesTimerAction { + message ModifyDisappearingMessageTimerAction { bytes timer = 1; } @@ -179,92 +230,70 @@ message GroupChange { } message ModifyAnnouncementsOnlyAction { - bool announcementsOnly = 1; + bool announcements_only = 1; } - bytes sourceServiceId = 1; - bytes groupId = 25; // Only set when receiving from server - uint32 revision = 2; - repeated AddMemberAction addMembers = 3; - repeated DeleteMemberAction deleteMembers = 4; - repeated ModifyMemberRoleAction modifyMemberRoles = 5; - repeated ModifyMemberProfileKeyAction modifyMemberProfileKeys = 6; - repeated AddPendingMemberAction addPendingMembers = 7; - repeated DeletePendingMemberAction deletePendingMembers = 8; - repeated PromotePendingMemberAction promotePendingMembers = 9; - ModifyTitleAction modifyTitle = 10; - ModifyAvatarAction modifyAvatar = 11; - ModifyDisappearingMessagesTimerAction modifyDisappearingMessagesTimer = 12; - ModifyAttributesAccessControlAction modifyAttributesAccess = 13; - ModifyMembersAccessControlAction modifyMemberAccess = 14; - ModifyAddFromInviteLinkAccessControlAction modifyAddFromInviteLinkAccess = 15; - repeated AddRequestingMemberAction addRequestingMembers = 16; - repeated DeleteRequestingMemberAction deleteRequestingMembers = 17; - repeated PromoteRequestingMemberAction promoteRequestingMembers = 18; - ModifyInviteLinkPasswordAction modifyInviteLinkPassword = 19; - ModifyDescriptionAction modifyDescription = 20; - ModifyAnnouncementsOnlyAction modifyAnnouncementsOnly = 21; - repeated AddBannedMemberAction addBannedMembers = 22; - repeated DeleteBannedMemberAction deleteBannedMembers = 23; - repeated PromotePendingPniAciMemberProfileKeyAction promotePendingPniAciMembers = 24; + bytes sourceUserId = 1; + // clients should not provide this value; the server will provide it in the response buffer to ensure the signature is binding to a particular group + // if clients set it during a request the server will respond with 400. + bytes group_id = 25; + uint32 version = 2; + + repeated AddMemberAction addMembers = 3; + repeated DeleteMemberAction deleteMembers = 4; + repeated ModifyMemberRoleAction modifyMemberRoles = 5; + repeated ModifyMemberProfileKeyAction modifyMemberProfileKeys = 6; + repeated AddMemberPendingProfileKeyAction addMembersPendingProfileKey = 7; + repeated DeleteMemberPendingProfileKeyAction deleteMembersPendingProfileKey = 8; + repeated PromoteMemberPendingProfileKeyAction promoteMembersPendingProfileKey = 9; + ModifyTitleAction modifyTitle = 10; + ModifyAvatarAction modifyAvatar = 11; + ModifyDisappearingMessageTimerAction modifyDisappearingMessageTimer = 12; + ModifyAttributesAccessControlAction modifyAttributesAccess = 13; + ModifyMembersAccessControlAction modifyMemberAccess = 14; + ModifyAddFromInviteLinkAccessControlAction modifyAddFromInviteLinkAccess = 15; // change epoch = 1 + repeated AddMemberPendingAdminApprovalAction addMembersPendingAdminApproval = 16; // change epoch = 1 + repeated DeleteMemberPendingAdminApprovalAction deleteMembersPendingAdminApproval = 17; // change epoch = 1 + repeated PromoteMemberPendingAdminApprovalAction promoteMembersPendingAdminApproval = 18; // change epoch = 1 + ModifyInviteLinkPasswordAction modifyInviteLinkPassword = 19; // change epoch = 1 + ModifyDescriptionAction modifyDescription = 20; // change epoch = 2 + ModifyAnnouncementsOnlyAction modify_announcements_only = 21; // change epoch = 3 + repeated AddMemberBannedAction add_members_banned = 22; // change epoch = 4 + repeated DeleteMemberBannedAction delete_members_banned = 23; // change epoch = 4 + repeated PromoteMemberPendingPniAciProfileKeyAction promote_members_pending_pni_aci_profile_key = 24; // change epoch = 5 + repeated ModifyMemberLabelAction modifyMemberLabels = 26; // change epoch = 6; + // next: 27 } - bytes actions = 1; - bytes serverSignature = 2; - uint32 changeEpoch = 3; + bytes actions = 1; + bytes serverSignature = 2; + uint32 changeEpoch = 3; } +// External credentials + +message ExternalGroupCredential { + string token = 1; +} + +// API responses + message GroupResponse { - Group group = 1; - bytes groupSendEndorsementsResponse = 2; + Group group = 1; + bytes group_send_endorsements_response = 2; } message GroupChanges { message GroupChangeState { GroupChange groupChange = 1; - Group groupState = 2; + Group groupState = 2; } - repeated GroupChangeState groupChanges = 1; - bytes groupSendEndorsementsResponse = 2; + repeated GroupChangeState groupChanges = 1; + bytes group_send_endorsements_response = 2; } message GroupChangeResponse { - GroupChange groupChange = 1; - bytes groupSendEndorsementsResponse = 2; -} - -message GroupAttributeBlob { - oneof content { - string title = 1; - bytes avatar = 2; - uint32 disappearingMessagesDuration = 3; - string description = 4; - } -} - -message GroupInviteLink { - message GroupInviteLinkContentsV1 { - bytes groupMasterKey = 1; - bytes inviteLinkPassword = 2; - } - - oneof contents { - GroupInviteLinkContentsV1 v1Contents = 1; - } -} - -message GroupJoinInfo { - bytes publicKey = 1; - bytes title = 2; - string avatar = 3; - uint32 memberCount = 4; - AccessControl.AccessRequired addFromInviteLink = 5; - uint32 revision = 6; - bool pendingAdminApproval = 7; - bytes description = 8; -} - -message GroupExternalCredential { - string token = 1; + GroupChange group_change = 1; + bytes group_send_endorsements_response = 2; } diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index d2f0a4d..0231512 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -4,8 +4,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: Provisioning.proto package signalpb diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index ae5bd18..5866dbb 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -4,8 +4,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: SignalService.proto package signalpb @@ -347,7 +347,7 @@ const ( DataMessage_MENTIONS DataMessage_ProtocolVersion = 6 DataMessage_PAYMENTS DataMessage_ProtocolVersion = 7 DataMessage_POLLS DataMessage_ProtocolVersion = 8 - DataMessage_CURRENT DataMessage_ProtocolVersion = 7 + DataMessage_CURRENT DataMessage_ProtocolVersion = 8 ) // Enum value maps for DataMessage_ProtocolVersion. @@ -362,7 +362,7 @@ var ( 6: "MENTIONS", 7: "PAYMENTS", 8: "POLLS", - // Duplicate value: 7: "CURRENT", + // Duplicate value: 8: "CURRENT", } DataMessage_ProtocolVersion_value = map[string]int32{ "INITIAL": 0, @@ -374,7 +374,7 @@ var ( "MENTIONS": 6, "PAYMENTS": 7, "POLLS": 8, - "CURRENT": 7, + "CURRENT": 8, } ) @@ -1750,22 +1750,26 @@ func (BodyRange_Style) EnumDescriptor() ([]byte, []int) { } type Envelope struct { - state protoimpl.MessageState `protogen:"open.v1"` - Type *Envelope_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.Envelope_Type" json:"type,omitempty"` - SourceServiceId *string `protobuf:"bytes,11,opt,name=sourceServiceId" json:"sourceServiceId,omitempty"` - SourceDevice *uint32 `protobuf:"varint,7,opt,name=sourceDevice" json:"sourceDevice,omitempty"` - DestinationServiceId *string `protobuf:"bytes,13,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Timestamp *uint64 `protobuf:"varint,5,opt,name=timestamp" json:"timestamp,omitempty"` - Content []byte `protobuf:"bytes,8,opt,name=content" json:"content,omitempty"` // Contains an encrypted Content - ServerGuid *string `protobuf:"bytes,9,opt,name=serverGuid" json:"serverGuid,omitempty"` - ServerTimestamp *uint64 `protobuf:"varint,10,opt,name=serverTimestamp" json:"serverTimestamp,omitempty"` - Ephemeral *bool `protobuf:"varint,12,opt,name=ephemeral" json:"ephemeral,omitempty"` // indicates that the message should not be persisted if the recipient is offline - Urgent *bool `protobuf:"varint,14,opt,name=urgent,def=1" json:"urgent,omitempty"` // indicates that the content is considered timely by the sender; defaults to true so senders have to opt-out to say something isn't time critical - UpdatedPni *string `protobuf:"bytes,15,opt,name=updatedPni" json:"updatedPni,omitempty"` // for number-change synchronization messages, provides the new server-assigned phone number identifier associated with the changed number - Story *bool `protobuf:"varint,16,opt,name=story" json:"story,omitempty"` // indicates that the content is a story. - ReportSpamToken []byte `protobuf:"bytes,17,opt,name=report_spam_token,json=reportSpamToken" json:"report_spam_token,omitempty"` // token sent when reporting spam - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *Envelope_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.Envelope_Type" json:"type,omitempty"` + SourceServiceId *string `protobuf:"bytes,11,opt,name=sourceServiceId" json:"sourceServiceId,omitempty"` + SourceDevice *uint32 `protobuf:"varint,7,opt,name=sourceDevice" json:"sourceDevice,omitempty"` + DestinationServiceId *string `protobuf:"bytes,13,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Timestamp *uint64 `protobuf:"varint,5,opt,name=timestamp" json:"timestamp,omitempty"` + Content []byte `protobuf:"bytes,8,opt,name=content" json:"content,omitempty"` // Contains an encrypted Content + ServerGuid *string `protobuf:"bytes,9,opt,name=serverGuid" json:"serverGuid,omitempty"` + ServerTimestamp *uint64 `protobuf:"varint,10,opt,name=serverTimestamp" json:"serverTimestamp,omitempty"` + Ephemeral *bool `protobuf:"varint,12,opt,name=ephemeral" json:"ephemeral,omitempty"` // indicates that the message should not be persisted if the recipient is offline + Urgent *bool `protobuf:"varint,14,opt,name=urgent,def=1" json:"urgent,omitempty"` // indicates that the content is considered timely by the sender; defaults to true so senders have to opt-out to say something isn't time critical + UpdatedPni *string `protobuf:"bytes,15,opt,name=updatedPni" json:"updatedPni,omitempty"` // for number-change synchronization messages, provides the new server-assigned phone number identifier associated with the changed number + Story *bool `protobuf:"varint,16,opt,name=story" json:"story,omitempty"` // indicates that the content is a story. + ReportSpamToken []byte `protobuf:"bytes,17,opt,name=report_spam_token,json=reportSpamToken" json:"report_spam_token,omitempty"` // token sent when reporting spam + SourceServiceIdBinary []byte `protobuf:"bytes,19,opt,name=sourceServiceIdBinary" json:"sourceServiceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + DestinationServiceIdBinary []byte `protobuf:"bytes,20,opt,name=destinationServiceIdBinary" json:"destinationServiceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + ServerGuidBinary []byte `protobuf:"bytes,21,opt,name=serverGuidBinary" json:"serverGuidBinary,omitempty"` // 16-byte UUID + UpdatedPniBinary []byte `protobuf:"bytes,22,opt,name=updatedPniBinary" json:"updatedPniBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } // Default values for Envelope fields. @@ -1894,6 +1898,34 @@ func (x *Envelope) GetReportSpamToken() []byte { return nil } +func (x *Envelope) GetSourceServiceIdBinary() []byte { + if x != nil { + return x.SourceServiceIdBinary + } + return nil +} + +func (x *Envelope) GetDestinationServiceIdBinary() []byte { + if x != nil { + return x.DestinationServiceIdBinary + } + return nil +} + +func (x *Envelope) GetServerGuidBinary() []byte { + if x != nil { + return x.ServerGuidBinary + } + return nil +} + +func (x *Envelope) GetUpdatedPniBinary() []byte { + if x != nil { + return x.UpdatedPniBinary + } + return nil +} + type Content struct { state protoimpl.MessageState `protogen:"open.v1"` DataMessage *DataMessage `protobuf:"bytes,1,opt,name=dataMessage" json:"dataMessage,omitempty"` @@ -2135,7 +2167,9 @@ type DataMessage struct { GiftBadge *DataMessage_GiftBadge `protobuf:"bytes,22,opt,name=giftBadge" json:"giftBadge,omitempty"` PollCreate *DataMessage_PollCreate `protobuf:"bytes,24,opt,name=pollCreate" json:"pollCreate,omitempty"` PollTerminate *DataMessage_PollTerminate `protobuf:"bytes,25,opt,name=pollTerminate" json:"pollTerminate,omitempty"` - PollVote *DataMessage_PollVote `protobuf:"bytes,26,opt,name=pollVote" json:"pollVote,omitempty"` // NEXT ID: 27 + PollVote *DataMessage_PollVote `protobuf:"bytes,26,opt,name=pollVote" json:"pollVote,omitempty"` + PinMessage *DataMessage_PinMessage `protobuf:"bytes,27,opt,name=pinMessage" json:"pinMessage,omitempty"` + UnpinMessage *DataMessage_UnpinMessage `protobuf:"bytes,28,opt,name=unpinMessage" json:"unpinMessage,omitempty"` // NEXT ID: 29 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2338,6 +2372,20 @@ func (x *DataMessage) GetPollVote() *DataMessage_PollVote { return nil } +func (x *DataMessage) GetPinMessage() *DataMessage_PinMessage { + if x != nil { + return x.PinMessage + } + return nil +} + +func (x *DataMessage) GetUnpinMessage() *DataMessage_UnpinMessage { + if x != nil { + return x.UnpinMessage + } + return nil +} + type NullMessage struct { state protoimpl.MessageState `protogen:"open.v1"` Padding []byte `protobuf:"bytes,1,opt,name=padding" json:"padding,omitempty"` @@ -2807,13 +2855,14 @@ func (*TextAttachment_Gradient_) isTextAttachment_Background() {} func (*TextAttachment_Color) isTextAttachment_Background() {} type Verified struct { - state protoimpl.MessageState `protogen:"open.v1"` - DestinationAci *string `protobuf:"bytes,5,opt,name=destinationAci" json:"destinationAci,omitempty"` - IdentityKey []byte `protobuf:"bytes,2,opt,name=identityKey" json:"identityKey,omitempty"` - State *Verified_State `protobuf:"varint,3,opt,name=state,enum=signalservice.Verified_State" json:"state,omitempty"` - NullMessage []byte `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DestinationAci *string `protobuf:"bytes,5,opt,name=destinationAci" json:"destinationAci,omitempty"` + IdentityKey []byte `protobuf:"bytes,2,opt,name=identityKey" json:"identityKey,omitempty"` + State *Verified_State `protobuf:"varint,3,opt,name=state,enum=signalservice.Verified_State" json:"state,omitempty"` + NullMessage []byte `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` + DestinationAciBinary []byte `protobuf:"bytes,6,opt,name=destinationAciBinary" json:"destinationAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Verified) Reset() { @@ -2874,6 +2923,13 @@ func (x *Verified) GetNullMessage() []byte { return nil } +func (x *Verified) GetDestinationAciBinary() []byte { + if x != nil { + return x.DestinationAciBinary + } + return nil +} + type SyncMessage struct { state protoimpl.MessageState `protogen:"open.v1"` Sent *SyncMessage_Sent `protobuf:"bytes,1,opt,name=sent" json:"sent,omitempty"` @@ -3370,6 +3426,7 @@ type ContactDetails struct { state protoimpl.MessageState `protogen:"open.v1"` Number *string `protobuf:"bytes,1,opt,name=number" json:"number,omitempty"` Aci *string `protobuf:"bytes,9,opt,name=aci" json:"aci,omitempty"` + AciBinary []byte `protobuf:"bytes,13,opt,name=aciBinary" json:"aciBinary,omitempty"` // 16-byte UUID Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` Avatar *ContactDetails_Avatar `protobuf:"bytes,3,opt,name=avatar" json:"avatar,omitempty"` ExpireTimer *uint32 `protobuf:"varint,8,opt,name=expireTimer" json:"expireTimer,omitempty"` @@ -3423,6 +3480,13 @@ func (x *ContactDetails) GetAci() string { return "" } +func (x *ContactDetails) GetAciBinary() []byte { + if x != nil { + return x.AciBinary + } + return nil +} + func (x *ContactDetails) GetName() string { if x != nil && x.Name != nil { return *x.Name @@ -3697,6 +3761,7 @@ type BodyRange struct { // // *BodyRange_MentionAci // *BodyRange_Style_ + // *BodyRange_MentionAciBinary AssociatedValue isBodyRange_AssociatedValue `protobuf_oneof:"associatedValue"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -3771,6 +3836,15 @@ func (x *BodyRange) GetStyle() BodyRange_Style { return BodyRange_NONE } +func (x *BodyRange) GetMentionAciBinary() []byte { + if x != nil { + if x, ok := x.AssociatedValue.(*BodyRange_MentionAciBinary); ok { + return x.MentionAciBinary + } + } + return nil +} + type isBodyRange_AssociatedValue interface { isBodyRange_AssociatedValue() } @@ -3783,16 +3857,23 @@ type BodyRange_Style_ struct { Style BodyRange_Style `protobuf:"varint,4,opt,name=style,enum=signalservice.BodyRange_Style,oneof"` } +type BodyRange_MentionAciBinary struct { + MentionAciBinary []byte `protobuf:"bytes,5,opt,name=mentionAciBinary,oneof"` // 16-byte UUID +} + func (*BodyRange_MentionAci) isBodyRange_AssociatedValue() {} func (*BodyRange_Style_) isBodyRange_AssociatedValue() {} +func (*BodyRange_MentionAciBinary) isBodyRange_AssociatedValue() {} + type AddressableMessage struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Author: // // *AddressableMessage_AuthorServiceId // *AddressableMessage_AuthorE164 + // *AddressableMessage_AuthorServiceIdBinary Author isAddressableMessage_Author `protobuf_oneof:"author"` SentTimestamp *uint64 `protobuf:"varint,3,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` unknownFields protoimpl.UnknownFields @@ -3854,6 +3935,15 @@ func (x *AddressableMessage) GetAuthorE164() string { return "" } +func (x *AddressableMessage) GetAuthorServiceIdBinary() []byte { + if x != nil { + if x, ok := x.Author.(*AddressableMessage_AuthorServiceIdBinary); ok { + return x.AuthorServiceIdBinary + } + } + return nil +} + func (x *AddressableMessage) GetSentTimestamp() uint64 { if x != nil && x.SentTimestamp != nil { return *x.SentTimestamp @@ -3873,10 +3963,16 @@ type AddressableMessage_AuthorE164 struct { AuthorE164 string `protobuf:"bytes,2,opt,name=authorE164,oneof"` } +type AddressableMessage_AuthorServiceIdBinary struct { + AuthorServiceIdBinary []byte `protobuf:"bytes,4,opt,name=authorServiceIdBinary,oneof"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) +} + func (*AddressableMessage_AuthorServiceId) isAddressableMessage_Author() {} func (*AddressableMessage_AuthorE164) isAddressableMessage_Author() {} +func (*AddressableMessage_AuthorServiceIdBinary) isAddressableMessage_Author() {} + type ConversationIdentifier struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Identifier: @@ -3884,6 +3980,7 @@ type ConversationIdentifier struct { // *ConversationIdentifier_ThreadServiceId // *ConversationIdentifier_ThreadGroupId // *ConversationIdentifier_ThreadE164 + // *ConversationIdentifier_ThreadServiceIdBinary Identifier isConversationIdentifier_Identifier `protobuf_oneof:"identifier"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -3953,6 +4050,15 @@ func (x *ConversationIdentifier) GetThreadE164() string { return "" } +func (x *ConversationIdentifier) GetThreadServiceIdBinary() []byte { + if x != nil { + if x, ok := x.Identifier.(*ConversationIdentifier_ThreadServiceIdBinary); ok { + return x.ThreadServiceIdBinary + } + } + return nil +} + type isConversationIdentifier_Identifier interface { isConversationIdentifier_Identifier() } @@ -3969,12 +4075,18 @@ type ConversationIdentifier_ThreadE164 struct { ThreadE164 string `protobuf:"bytes,3,opt,name=threadE164,oneof"` } +type ConversationIdentifier_ThreadServiceIdBinary struct { + ThreadServiceIdBinary []byte `protobuf:"bytes,4,opt,name=threadServiceIdBinary,oneof"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) +} + func (*ConversationIdentifier_ThreadServiceId) isConversationIdentifier_Identifier() {} func (*ConversationIdentifier_ThreadGroupId) isConversationIdentifier_Identifier() {} func (*ConversationIdentifier_ThreadE164) isConversationIdentifier_Identifier() {} +func (*ConversationIdentifier_ThreadServiceIdBinary) isConversationIdentifier_Identifier() {} + type CallMessage_Offer struct { state protoimpl.MessageState `protogen:"open.v1"` Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` @@ -4378,15 +4490,16 @@ func (*DataMessage_Payment_Notification_) isDataMessage_Payment_Item() {} func (*DataMessage_Payment_Activation_) isDataMessage_Payment_Item() {} type DataMessage_Quote struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` - AuthorAci *string `protobuf:"bytes,5,opt,name=authorAci" json:"authorAci,omitempty"` - Text *string `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"` - Attachments []*DataMessage_Quote_QuotedAttachment `protobuf:"bytes,4,rep,name=attachments" json:"attachments,omitempty"` - BodyRanges []*BodyRange `protobuf:"bytes,6,rep,name=bodyRanges" json:"bodyRanges,omitempty"` - Type *DataMessage_Quote_Type `protobuf:"varint,7,opt,name=type,enum=signalservice.DataMessage_Quote_Type" json:"type,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id *uint64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + AuthorAci *string `protobuf:"bytes,5,opt,name=authorAci" json:"authorAci,omitempty"` + Text *string `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"` + Attachments []*DataMessage_Quote_QuotedAttachment `protobuf:"bytes,4,rep,name=attachments" json:"attachments,omitempty"` + BodyRanges []*BodyRange `protobuf:"bytes,6,rep,name=bodyRanges" json:"bodyRanges,omitempty"` + Type *DataMessage_Quote_Type `protobuf:"varint,7,opt,name=type,enum=signalservice.DataMessage_Quote_Type" json:"type,omitempty"` + AuthorAciBinary []byte `protobuf:"bytes,8,opt,name=authorAciBinary" json:"authorAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Quote) Reset() { @@ -4461,6 +4574,13 @@ func (x *DataMessage_Quote) GetType() DataMessage_Quote_Type { return DataMessage_Quote_NORMAL } +func (x *DataMessage_Quote) GetAuthorAciBinary() []byte { + if x != nil { + return x.AuthorAciBinary + } + return nil +} + type DataMessage_Contact struct { state protoimpl.MessageState `protogen:"open.v1"` Name *DataMessage_Contact_Name `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -4622,13 +4742,14 @@ func (x *DataMessage_Sticker) GetEmoji() string { } type DataMessage_Reaction struct { - state protoimpl.MessageState `protogen:"open.v1"` - Emoji *string `protobuf:"bytes,1,opt,name=emoji" json:"emoji,omitempty"` - Remove *bool `protobuf:"varint,2,opt,name=remove" json:"remove,omitempty"` - TargetAuthorAci *string `protobuf:"bytes,4,opt,name=targetAuthorAci" json:"targetAuthorAci,omitempty"` - TargetSentTimestamp *uint64 `protobuf:"varint,5,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Emoji *string `protobuf:"bytes,1,opt,name=emoji" json:"emoji,omitempty"` + Remove *bool `protobuf:"varint,2,opt,name=remove" json:"remove,omitempty"` + TargetAuthorAci *string `protobuf:"bytes,4,opt,name=targetAuthorAci" json:"targetAuthorAci,omitempty"` + TargetSentTimestamp *uint64 `protobuf:"varint,5,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + TargetAuthorAciBinary []byte `protobuf:"bytes,6,opt,name=targetAuthorAciBinary" json:"targetAuthorAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_Reaction) Reset() { @@ -4689,6 +4810,13 @@ func (x *DataMessage_Reaction) GetTargetSentTimestamp() uint64 { return 0 } +func (x *DataMessage_Reaction) GetTargetAuthorAciBinary() []byte { + if x != nil { + return x.TargetAuthorAciBinary + } + return nil +} + type DataMessage_Delete struct { state protoimpl.MessageState `protogen:"open.v1"` TargetSentTimestamp *uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` @@ -4778,11 +4906,12 @@ func (x *DataMessage_GroupCallUpdate) GetEraId() string { } type DataMessage_StoryContext struct { - state protoimpl.MessageState `protogen:"open.v1"` - AuthorAci *string `protobuf:"bytes,1,opt,name=authorAci" json:"authorAci,omitempty"` - SentTimestamp *uint64 `protobuf:"varint,2,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + AuthorAci *string `protobuf:"bytes,1,opt,name=authorAci" json:"authorAci,omitempty"` + SentTimestamp *uint64 `protobuf:"varint,2,opt,name=sentTimestamp" json:"sentTimestamp,omitempty"` + AuthorAciBinary []byte `protobuf:"bytes,3,opt,name=authorAciBinary" json:"authorAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DataMessage_StoryContext) Reset() { @@ -4829,6 +4958,13 @@ func (x *DataMessage_StoryContext) GetSentTimestamp() uint64 { return 0 } +func (x *DataMessage_StoryContext) GetAuthorAciBinary() []byte { + if x != nil { + return x.AuthorAciBinary + } + return nil +} + type DataMessage_GiftBadge struct { state protoimpl.MessageState `protogen:"open.v1"` ReceiptCredentialPresentation []byte `protobuf:"bytes,1,opt,name=receiptCredentialPresentation" json:"receiptCredentialPresentation,omitempty"` @@ -5045,6 +5181,156 @@ func (x *DataMessage_PollVote) GetVoteCount() uint32 { return 0 } +type DataMessage_PinMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetAuthorAciBinary []byte `protobuf:"bytes,1,opt,name=targetAuthorAciBinary" json:"targetAuthorAciBinary,omitempty"` // 16-byte UUID + TargetSentTimestamp *uint64 `protobuf:"varint,2,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + // Types that are valid to be assigned to PinDuration: + // + // *DataMessage_PinMessage_PinDurationSeconds + // *DataMessage_PinMessage_PinDurationForever + PinDuration isDataMessage_PinMessage_PinDuration `protobuf_oneof:"pinDuration"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_PinMessage) Reset() { + *x = DataMessage_PinMessage{} + mi := &file_SignalService_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_PinMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_PinMessage) ProtoMessage() {} + +func (x *DataMessage_PinMessage) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[40] + 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 DataMessage_PinMessage.ProtoReflect.Descriptor instead. +func (*DataMessage_PinMessage) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 12} +} + +func (x *DataMessage_PinMessage) GetTargetAuthorAciBinary() []byte { + if x != nil { + return x.TargetAuthorAciBinary + } + return nil +} + +func (x *DataMessage_PinMessage) GetTargetSentTimestamp() uint64 { + if x != nil && x.TargetSentTimestamp != nil { + return *x.TargetSentTimestamp + } + return 0 +} + +func (x *DataMessage_PinMessage) GetPinDuration() isDataMessage_PinMessage_PinDuration { + if x != nil { + return x.PinDuration + } + return nil +} + +func (x *DataMessage_PinMessage) GetPinDurationSeconds() uint32 { + if x != nil { + if x, ok := x.PinDuration.(*DataMessage_PinMessage_PinDurationSeconds); ok { + return x.PinDurationSeconds + } + } + return 0 +} + +func (x *DataMessage_PinMessage) GetPinDurationForever() bool { + if x != nil { + if x, ok := x.PinDuration.(*DataMessage_PinMessage_PinDurationForever); ok { + return x.PinDurationForever + } + } + return false +} + +type isDataMessage_PinMessage_PinDuration interface { + isDataMessage_PinMessage_PinDuration() +} + +type DataMessage_PinMessage_PinDurationSeconds struct { + PinDurationSeconds uint32 `protobuf:"varint,3,opt,name=pinDurationSeconds,oneof"` +} + +type DataMessage_PinMessage_PinDurationForever struct { + PinDurationForever bool `protobuf:"varint,4,opt,name=pinDurationForever,oneof"` +} + +func (*DataMessage_PinMessage_PinDurationSeconds) isDataMessage_PinMessage_PinDuration() {} + +func (*DataMessage_PinMessage_PinDurationForever) isDataMessage_PinMessage_PinDuration() {} + +type DataMessage_UnpinMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetAuthorAciBinary []byte `protobuf:"bytes,1,opt,name=targetAuthorAciBinary" json:"targetAuthorAciBinary,omitempty"` // 16-byte UUID + TargetSentTimestamp *uint64 `protobuf:"varint,2,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_UnpinMessage) Reset() { + *x = DataMessage_UnpinMessage{} + mi := &file_SignalService_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_UnpinMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_UnpinMessage) ProtoMessage() {} + +func (x *DataMessage_UnpinMessage) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DataMessage_UnpinMessage.ProtoReflect.Descriptor instead. +func (*DataMessage_UnpinMessage) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 13} +} + +func (x *DataMessage_UnpinMessage) GetTargetAuthorAciBinary() []byte { + if x != nil { + return x.TargetAuthorAciBinary + } + return nil +} + +func (x *DataMessage_UnpinMessage) GetTargetSentTimestamp() uint64 { + if x != nil && x.TargetSentTimestamp != nil { + return *x.TargetSentTimestamp + } + return 0 +} + type DataMessage_Payment_Amount struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Amount: @@ -5057,7 +5343,7 @@ type DataMessage_Payment_Amount struct { func (x *DataMessage_Payment_Amount) Reset() { *x = DataMessage_Payment_Amount{} - mi := &file_SignalService_proto_msgTypes[40] + mi := &file_SignalService_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5069,7 +5355,7 @@ func (x *DataMessage_Payment_Amount) String() string { func (*DataMessage_Payment_Amount) ProtoMessage() {} func (x *DataMessage_Payment_Amount) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[40] + mi := &file_SignalService_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5125,7 +5411,7 @@ type DataMessage_Payment_Notification struct { func (x *DataMessage_Payment_Notification) Reset() { *x = DataMessage_Payment_Notification{} - mi := &file_SignalService_proto_msgTypes[41] + mi := &file_SignalService_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5137,7 +5423,7 @@ func (x *DataMessage_Payment_Notification) String() string { func (*DataMessage_Payment_Notification) ProtoMessage() {} func (x *DataMessage_Payment_Notification) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[41] + mi := &file_SignalService_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5196,7 +5482,7 @@ type DataMessage_Payment_Activation struct { func (x *DataMessage_Payment_Activation) Reset() { *x = DataMessage_Payment_Activation{} - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5208,7 +5494,7 @@ func (x *DataMessage_Payment_Activation) String() string { func (*DataMessage_Payment_Activation) ProtoMessage() {} func (x *DataMessage_Payment_Activation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5240,7 +5526,7 @@ type DataMessage_Payment_Amount_MobileCoin struct { func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { *x = DataMessage_Payment_Amount_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[43] + mi := &file_SignalService_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5252,7 +5538,7 @@ func (x *DataMessage_Payment_Amount_MobileCoin) String() string { func (*DataMessage_Payment_Amount_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Amount_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[43] + mi := &file_SignalService_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5284,7 +5570,7 @@ type DataMessage_Payment_Notification_MobileCoin struct { func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { *x = DataMessage_Payment_Notification_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[44] + mi := &file_SignalService_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5296,7 +5582,7 @@ func (x *DataMessage_Payment_Notification_MobileCoin) String() string { func (*DataMessage_Payment_Notification_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Notification_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[44] + mi := &file_SignalService_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5330,7 +5616,7 @@ type DataMessage_Quote_QuotedAttachment struct { func (x *DataMessage_Quote_QuotedAttachment) Reset() { *x = DataMessage_Quote_QuotedAttachment{} - mi := &file_SignalService_proto_msgTypes[45] + mi := &file_SignalService_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5342,7 +5628,7 @@ func (x *DataMessage_Quote_QuotedAttachment) String() string { func (*DataMessage_Quote_QuotedAttachment) ProtoMessage() {} func (x *DataMessage_Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[45] + mi := &file_SignalService_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5393,7 +5679,7 @@ type DataMessage_Contact_Name struct { func (x *DataMessage_Contact_Name) Reset() { *x = DataMessage_Contact_Name{} - mi := &file_SignalService_proto_msgTypes[46] + mi := &file_SignalService_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5405,7 +5691,7 @@ func (x *DataMessage_Contact_Name) String() string { func (*DataMessage_Contact_Name) ProtoMessage() {} func (x *DataMessage_Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[46] + mi := &file_SignalService_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5474,7 +5760,7 @@ type DataMessage_Contact_Phone struct { func (x *DataMessage_Contact_Phone) Reset() { *x = DataMessage_Contact_Phone{} - mi := &file_SignalService_proto_msgTypes[47] + mi := &file_SignalService_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5486,7 +5772,7 @@ func (x *DataMessage_Contact_Phone) String() string { func (*DataMessage_Contact_Phone) ProtoMessage() {} func (x *DataMessage_Contact_Phone) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[47] + mi := &file_SignalService_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5534,7 +5820,7 @@ type DataMessage_Contact_Email struct { func (x *DataMessage_Contact_Email) Reset() { *x = DataMessage_Contact_Email{} - mi := &file_SignalService_proto_msgTypes[48] + mi := &file_SignalService_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5546,7 +5832,7 @@ func (x *DataMessage_Contact_Email) String() string { func (*DataMessage_Contact_Email) ProtoMessage() {} func (x *DataMessage_Contact_Email) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[48] + mi := &file_SignalService_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5600,7 +5886,7 @@ type DataMessage_Contact_PostalAddress struct { func (x *DataMessage_Contact_PostalAddress) Reset() { *x = DataMessage_Contact_PostalAddress{} - mi := &file_SignalService_proto_msgTypes[49] + mi := &file_SignalService_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5612,7 +5898,7 @@ func (x *DataMessage_Contact_PostalAddress) String() string { func (*DataMessage_Contact_PostalAddress) ProtoMessage() {} func (x *DataMessage_Contact_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[49] + mi := &file_SignalService_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5701,7 +5987,7 @@ type DataMessage_Contact_Avatar struct { func (x *DataMessage_Contact_Avatar) Reset() { *x = DataMessage_Contact_Avatar{} - mi := &file_SignalService_proto_msgTypes[50] + mi := &file_SignalService_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5713,7 +5999,7 @@ func (x *DataMessage_Contact_Avatar) String() string { func (*DataMessage_Contact_Avatar) ProtoMessage() {} func (x *DataMessage_Contact_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[50] + mi := &file_SignalService_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5756,7 +6042,7 @@ type TextAttachment_Gradient struct { func (x *TextAttachment_Gradient) Reset() { *x = TextAttachment_Gradient{} - mi := &file_SignalService_proto_msgTypes[51] + mi := &file_SignalService_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5768,7 +6054,7 @@ func (x *TextAttachment_Gradient) String() string { func (*TextAttachment_Gradient) ProtoMessage() {} func (x *TextAttachment_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[51] + mi := &file_SignalService_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5820,19 +6106,20 @@ func (x *TextAttachment_Gradient) GetPositions() []float32 { } type SyncMessage_Sent struct { - state protoimpl.MessageState `protogen:"open.v1"` - DestinationE164 *string `protobuf:"bytes,1,opt,name=destinationE164" json:"destinationE164,omitempty"` - DestinationServiceId *string `protobuf:"bytes,7,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` - Message *DataMessage `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` - ExpirationStartTimestamp *uint64 `protobuf:"varint,4,opt,name=expirationStartTimestamp" json:"expirationStartTimestamp,omitempty"` - UnidentifiedStatus []*SyncMessage_Sent_UnidentifiedDeliveryStatus `protobuf:"bytes,5,rep,name=unidentifiedStatus" json:"unidentifiedStatus,omitempty"` - IsRecipientUpdate *bool `protobuf:"varint,6,opt,name=isRecipientUpdate,def=0" json:"isRecipientUpdate,omitempty"` - StoryMessage *StoryMessage `protobuf:"bytes,8,opt,name=storyMessage" json:"storyMessage,omitempty"` - StoryMessageRecipients []*SyncMessage_Sent_StoryMessageRecipient `protobuf:"bytes,9,rep,name=storyMessageRecipients" json:"storyMessageRecipients,omitempty"` - EditMessage *EditMessage `protobuf:"bytes,10,opt,name=editMessage" json:"editMessage,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DestinationE164 *string `protobuf:"bytes,1,opt,name=destinationE164" json:"destinationE164,omitempty"` + DestinationServiceId *string `protobuf:"bytes,7,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + Message *DataMessage `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + ExpirationStartTimestamp *uint64 `protobuf:"varint,4,opt,name=expirationStartTimestamp" json:"expirationStartTimestamp,omitempty"` + UnidentifiedStatus []*SyncMessage_Sent_UnidentifiedDeliveryStatus `protobuf:"bytes,5,rep,name=unidentifiedStatus" json:"unidentifiedStatus,omitempty"` + IsRecipientUpdate *bool `protobuf:"varint,6,opt,name=isRecipientUpdate,def=0" json:"isRecipientUpdate,omitempty"` + StoryMessage *StoryMessage `protobuf:"bytes,8,opt,name=storyMessage" json:"storyMessage,omitempty"` + StoryMessageRecipients []*SyncMessage_Sent_StoryMessageRecipient `protobuf:"bytes,9,rep,name=storyMessageRecipients" json:"storyMessageRecipients,omitempty"` + EditMessage *EditMessage `protobuf:"bytes,10,opt,name=editMessage" json:"editMessage,omitempty"` + DestinationServiceIdBinary []byte `protobuf:"bytes,12,opt,name=destinationServiceIdBinary" json:"destinationServiceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } // Default values for SyncMessage_Sent fields. @@ -5842,7 +6129,7 @@ const ( func (x *SyncMessage_Sent) Reset() { *x = SyncMessage_Sent{} - mi := &file_SignalService_proto_msgTypes[52] + mi := &file_SignalService_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5854,7 +6141,7 @@ func (x *SyncMessage_Sent) String() string { func (*SyncMessage_Sent) ProtoMessage() {} func (x *SyncMessage_Sent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[52] + mi := &file_SignalService_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5940,6 +6227,13 @@ func (x *SyncMessage_Sent) GetEditMessage() *EditMessage { return nil } +func (x *SyncMessage_Sent) GetDestinationServiceIdBinary() []byte { + if x != nil { + return x.DestinationServiceIdBinary + } + return nil +} + type SyncMessage_Contacts struct { state protoimpl.MessageState `protogen:"open.v1"` Blob *AttachmentPointer `protobuf:"bytes,1,opt,name=blob" json:"blob,omitempty"` @@ -5955,7 +6249,7 @@ const ( func (x *SyncMessage_Contacts) Reset() { *x = SyncMessage_Contacts{} - mi := &file_SignalService_proto_msgTypes[53] + mi := &file_SignalService_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5967,7 +6261,7 @@ func (x *SyncMessage_Contacts) String() string { func (*SyncMessage_Contacts) ProtoMessage() {} func (x *SyncMessage_Contacts) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[53] + mi := &file_SignalService_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6002,13 +6296,14 @@ type SyncMessage_Blocked struct { Numbers []string `protobuf:"bytes,1,rep,name=numbers" json:"numbers,omitempty"` Acis []string `protobuf:"bytes,3,rep,name=acis" json:"acis,omitempty"` GroupIds [][]byte `protobuf:"bytes,2,rep,name=groupIds" json:"groupIds,omitempty"` + AcisBinary [][]byte `protobuf:"bytes,4,rep,name=acisBinary" json:"acisBinary,omitempty"` // 16-byte UUID unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_Blocked) Reset() { *x = SyncMessage_Blocked{} - mi := &file_SignalService_proto_msgTypes[54] + mi := &file_SignalService_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6020,7 +6315,7 @@ func (x *SyncMessage_Blocked) String() string { func (*SyncMessage_Blocked) ProtoMessage() {} func (x *SyncMessage_Blocked) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[54] + mi := &file_SignalService_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6057,6 +6352,13 @@ func (x *SyncMessage_Blocked) GetGroupIds() [][]byte { return nil } +func (x *SyncMessage_Blocked) GetAcisBinary() [][]byte { + if x != nil { + return x.AcisBinary + } + return nil +} + type SyncMessage_Request struct { state protoimpl.MessageState `protogen:"open.v1"` Type *SyncMessage_Request_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_Request_Type" json:"type,omitempty"` @@ -6066,7 +6368,7 @@ type SyncMessage_Request struct { func (x *SyncMessage_Request) Reset() { *x = SyncMessage_Request{} - mi := &file_SignalService_proto_msgTypes[55] + mi := &file_SignalService_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6078,7 +6380,7 @@ func (x *SyncMessage_Request) String() string { func (*SyncMessage_Request) ProtoMessage() {} func (x *SyncMessage_Request) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[55] + mi := &file_SignalService_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6102,16 +6404,17 @@ func (x *SyncMessage_Request) GetType() SyncMessage_Request_Type { } type SyncMessage_Read struct { - state protoimpl.MessageState `protogen:"open.v1"` - SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + SenderAciBinary []byte `protobuf:"bytes,4,opt,name=senderAciBinary" json:"senderAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Read) Reset() { *x = SyncMessage_Read{} - mi := &file_SignalService_proto_msgTypes[56] + mi := &file_SignalService_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6123,7 +6426,7 @@ func (x *SyncMessage_Read) String() string { func (*SyncMessage_Read) ProtoMessage() {} func (x *SyncMessage_Read) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[56] + mi := &file_SignalService_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6153,17 +6456,25 @@ func (x *SyncMessage_Read) GetTimestamp() uint64 { return 0 } +func (x *SyncMessage_Read) GetSenderAciBinary() []byte { + if x != nil { + return x.SenderAciBinary + } + return nil +} + type SyncMessage_Viewed struct { - state protoimpl.MessageState `protogen:"open.v1"` - SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + SenderAciBinary []byte `protobuf:"bytes,4,opt,name=senderAciBinary" json:"senderAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Viewed) Reset() { *x = SyncMessage_Viewed{} - mi := &file_SignalService_proto_msgTypes[57] + mi := &file_SignalService_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6175,7 +6486,7 @@ func (x *SyncMessage_Viewed) String() string { func (*SyncMessage_Viewed) ProtoMessage() {} func (x *SyncMessage_Viewed) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[57] + mi := &file_SignalService_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6205,6 +6516,13 @@ func (x *SyncMessage_Viewed) GetTimestamp() uint64 { return 0 } +func (x *SyncMessage_Viewed) GetSenderAciBinary() []byte { + if x != nil { + return x.SenderAciBinary + } + return nil +} + type SyncMessage_Configuration struct { state protoimpl.MessageState `protogen:"open.v1"` ReadReceipts *bool `protobuf:"varint,1,opt,name=readReceipts" json:"readReceipts,omitempty"` @@ -6218,7 +6536,7 @@ type SyncMessage_Configuration struct { func (x *SyncMessage_Configuration) Reset() { *x = SyncMessage_Configuration{} - mi := &file_SignalService_proto_msgTypes[58] + mi := &file_SignalService_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6230,7 +6548,7 @@ func (x *SyncMessage_Configuration) String() string { func (*SyncMessage_Configuration) ProtoMessage() {} func (x *SyncMessage_Configuration) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[58] + mi := &file_SignalService_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6292,7 +6610,7 @@ type SyncMessage_StickerPackOperation struct { func (x *SyncMessage_StickerPackOperation) Reset() { *x = SyncMessage_StickerPackOperation{} - mi := &file_SignalService_proto_msgTypes[59] + mi := &file_SignalService_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6304,7 +6622,7 @@ func (x *SyncMessage_StickerPackOperation) String() string { func (*SyncMessage_StickerPackOperation) ProtoMessage() {} func (x *SyncMessage_StickerPackOperation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[59] + mi := &file_SignalService_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6342,16 +6660,17 @@ func (x *SyncMessage_StickerPackOperation) GetType() SyncMessage_StickerPackOper } type SyncMessage_ViewOnceOpen struct { - state protoimpl.MessageState `protogen:"open.v1"` - SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` - Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SenderAci *string `protobuf:"bytes,3,opt,name=senderAci" json:"senderAci,omitempty"` + Timestamp *uint64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` + SenderAciBinary []byte `protobuf:"bytes,4,opt,name=senderAciBinary" json:"senderAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_ViewOnceOpen) Reset() { *x = SyncMessage_ViewOnceOpen{} - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6363,7 +6682,7 @@ func (x *SyncMessage_ViewOnceOpen) String() string { func (*SyncMessage_ViewOnceOpen) ProtoMessage() {} func (x *SyncMessage_ViewOnceOpen) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6393,6 +6712,13 @@ func (x *SyncMessage_ViewOnceOpen) GetTimestamp() uint64 { return 0 } +func (x *SyncMessage_ViewOnceOpen) GetSenderAciBinary() []byte { + if x != nil { + return x.SenderAciBinary + } + return nil +} + type SyncMessage_FetchLatest struct { state protoimpl.MessageState `protogen:"open.v1"` Type *SyncMessage_FetchLatest_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_FetchLatest_Type" json:"type,omitempty"` @@ -6402,7 +6728,7 @@ type SyncMessage_FetchLatest struct { func (x *SyncMessage_FetchLatest) Reset() { *x = SyncMessage_FetchLatest{} - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6414,7 +6740,7 @@ func (x *SyncMessage_FetchLatest) String() string { func (*SyncMessage_FetchLatest) ProtoMessage() {} func (x *SyncMessage_FetchLatest) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6448,7 +6774,7 @@ type SyncMessage_Keys struct { func (x *SyncMessage_Keys) Reset() { *x = SyncMessage_Keys{} - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6460,7 +6786,7 @@ func (x *SyncMessage_Keys) String() string { func (*SyncMessage_Keys) ProtoMessage() {} func (x *SyncMessage_Keys) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6507,7 +6833,7 @@ type SyncMessage_PniIdentity struct { func (x *SyncMessage_PniIdentity) Reset() { *x = SyncMessage_PniIdentity{} - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6519,7 +6845,7 @@ func (x *SyncMessage_PniIdentity) String() string { func (*SyncMessage_PniIdentity) ProtoMessage() {} func (x *SyncMessage_PniIdentity) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6550,17 +6876,18 @@ func (x *SyncMessage_PniIdentity) GetPrivateKey() []byte { } type SyncMessage_MessageRequestResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - ThreadAci *string `protobuf:"bytes,2,opt,name=threadAci" json:"threadAci,omitempty"` - GroupId []byte `protobuf:"bytes,3,opt,name=groupId" json:"groupId,omitempty"` - Type *SyncMessage_MessageRequestResponse_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_MessageRequestResponse_Type" json:"type,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ThreadAci *string `protobuf:"bytes,2,opt,name=threadAci" json:"threadAci,omitempty"` + GroupId []byte `protobuf:"bytes,3,opt,name=groupId" json:"groupId,omitempty"` + Type *SyncMessage_MessageRequestResponse_Type `protobuf:"varint,4,opt,name=type,enum=signalservice.SyncMessage_MessageRequestResponse_Type" json:"type,omitempty"` + ThreadAciBinary []byte `protobuf:"bytes,5,opt,name=threadAciBinary" json:"threadAciBinary,omitempty"` // 16-byte UUID + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_MessageRequestResponse) Reset() { *x = SyncMessage_MessageRequestResponse{} - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6572,7 +6899,7 @@ func (x *SyncMessage_MessageRequestResponse) String() string { func (*SyncMessage_MessageRequestResponse) ProtoMessage() {} func (x *SyncMessage_MessageRequestResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6609,6 +6936,13 @@ func (x *SyncMessage_MessageRequestResponse) GetType() SyncMessage_MessageReques return SyncMessage_MessageRequestResponse_UNKNOWN } +func (x *SyncMessage_MessageRequestResponse) GetThreadAciBinary() []byte { + if x != nil { + return x.ThreadAciBinary + } + return nil +} + type SyncMessage_OutgoingPayment struct { state protoimpl.MessageState `protogen:"open.v1"` RecipientServiceId *string `protobuf:"bytes,1,opt,name=recipientServiceId" json:"recipientServiceId,omitempty"` @@ -6623,7 +6957,7 @@ type SyncMessage_OutgoingPayment struct { func (x *SyncMessage_OutgoingPayment) Reset() { *x = SyncMessage_OutgoingPayment{} - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6635,7 +6969,7 @@ func (x *SyncMessage_OutgoingPayment) String() string { func (*SyncMessage_OutgoingPayment) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6705,7 +7039,7 @@ type SyncMessage_PniChangeNumber struct { func (x *SyncMessage_PniChangeNumber) Reset() { *x = SyncMessage_PniChangeNumber{} - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6717,7 +7051,7 @@ func (x *SyncMessage_PniChangeNumber) String() string { func (*SyncMessage_PniChangeNumber) ProtoMessage() {} func (x *SyncMessage_PniChangeNumber) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6787,7 +7121,7 @@ type SyncMessage_CallEvent struct { func (x *SyncMessage_CallEvent) Reset() { *x = SyncMessage_CallEvent{} - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6799,7 +7133,7 @@ func (x *SyncMessage_CallEvent) String() string { func (*SyncMessage_CallEvent) ProtoMessage() {} func (x *SyncMessage_CallEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6869,7 +7203,7 @@ type SyncMessage_CallLinkUpdate struct { func (x *SyncMessage_CallLinkUpdate) Reset() { *x = SyncMessage_CallLinkUpdate{} - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6881,7 +7215,7 @@ func (x *SyncMessage_CallLinkUpdate) String() string { func (*SyncMessage_CallLinkUpdate) ProtoMessage() {} func (x *SyncMessage_CallLinkUpdate) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6942,7 +7276,7 @@ type SyncMessage_CallLogEvent struct { func (x *SyncMessage_CallLogEvent) Reset() { *x = SyncMessage_CallLogEvent{} - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6954,7 +7288,7 @@ func (x *SyncMessage_CallLogEvent) String() string { func (*SyncMessage_CallLogEvent) ProtoMessage() {} func (x *SyncMessage_CallLogEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7010,7 +7344,7 @@ type SyncMessage_DeleteForMe struct { func (x *SyncMessage_DeleteForMe) Reset() { *x = SyncMessage_DeleteForMe{} - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7022,7 +7356,7 @@ func (x *SyncMessage_DeleteForMe) String() string { func (*SyncMessage_DeleteForMe) ProtoMessage() {} func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7075,7 +7409,7 @@ type SyncMessage_DeviceNameChange struct { func (x *SyncMessage_DeviceNameChange) Reset() { *x = SyncMessage_DeviceNameChange{} - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7087,7 +7421,7 @@ func (x *SyncMessage_DeviceNameChange) String() string { func (*SyncMessage_DeviceNameChange) ProtoMessage() {} func (x *SyncMessage_DeviceNameChange) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7120,7 +7454,7 @@ type SyncMessage_AttachmentBackfillRequest struct { func (x *SyncMessage_AttachmentBackfillRequest) Reset() { *x = SyncMessage_AttachmentBackfillRequest{} - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7132,7 +7466,7 @@ func (x *SyncMessage_AttachmentBackfillRequest) String() string { func (*SyncMessage_AttachmentBackfillRequest) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillRequest) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7177,7 +7511,7 @@ type SyncMessage_AttachmentBackfillResponse struct { func (x *SyncMessage_AttachmentBackfillResponse) Reset() { *x = SyncMessage_AttachmentBackfillResponse{} - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7189,7 +7523,7 @@ func (x *SyncMessage_AttachmentBackfillResponse) String() string { func (*SyncMessage_AttachmentBackfillResponse) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7263,17 +7597,18 @@ func (*SyncMessage_AttachmentBackfillResponse_Error_) isSyncMessage_AttachmentBa } type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { - state protoimpl.MessageState `protogen:"open.v1"` - DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` - DestinationPniIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationPniIdentityKey" json:"destinationPniIdentityKey,omitempty"` // Only set for PNI destinations - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DestinationServiceId *string `protobuf:"bytes,3,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + Unidentified *bool `protobuf:"varint,2,opt,name=unidentified" json:"unidentified,omitempty"` + DestinationPniIdentityKey []byte `protobuf:"bytes,5,opt,name=destinationPniIdentityKey" json:"destinationPniIdentityKey,omitempty"` // Only set for PNI destinations + DestinationServiceIdBinary []byte `protobuf:"bytes,6,opt,name=destinationServiceIdBinary" json:"destinationServiceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7285,7 +7620,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7322,18 +7657,26 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationPniIdentityK return nil } +func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) GetDestinationServiceIdBinary() []byte { + if x != nil { + return x.DestinationServiceIdBinary + } + return nil +} + type SyncMessage_Sent_StoryMessageRecipient struct { - state protoimpl.MessageState `protogen:"open.v1"` - DestinationServiceId *string `protobuf:"bytes,1,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - DistributionListIds []string `protobuf:"bytes,2,rep,name=distributionListIds" json:"distributionListIds,omitempty"` - IsAllowedToReply *bool `protobuf:"varint,3,opt,name=isAllowedToReply" json:"isAllowedToReply,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + DestinationServiceId *string `protobuf:"bytes,1,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` + DistributionListIds []string `protobuf:"bytes,2,rep,name=distributionListIds" json:"distributionListIds,omitempty"` + IsAllowedToReply *bool `protobuf:"varint,3,opt,name=isAllowedToReply" json:"isAllowedToReply,omitempty"` + DestinationServiceIdBinary []byte `protobuf:"bytes,5,opt,name=destinationServiceIdBinary" json:"destinationServiceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7345,7 +7688,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7382,6 +7725,13 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) GetIsAllowedToReply() bool { return false } +func (x *SyncMessage_Sent_StoryMessageRecipient) GetDestinationServiceIdBinary() []byte { + if x != nil { + return x.DestinationServiceIdBinary + } + return nil +} + type SyncMessage_OutgoingPayment_MobileCoin struct { state protoimpl.MessageState `protogen:"open.v1"` RecipientAddress []byte `protobuf:"bytes,1,opt,name=recipientAddress" json:"recipientAddress,omitempty"` @@ -7398,7 +7748,7 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7410,7 +7760,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7492,7 +7842,7 @@ type SyncMessage_DeleteForMe_MessageDeletes struct { func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { *x = SyncMessage_DeleteForMe_MessageDeletes{} - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7504,7 +7854,7 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7550,7 +7900,7 @@ type SyncMessage_DeleteForMe_AttachmentDelete struct { func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { *x = SyncMessage_DeleteForMe_AttachmentDelete{} - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7562,7 +7912,7 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7625,7 +7975,7 @@ type SyncMessage_DeleteForMe_ConversationDelete struct { func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7637,7 +7987,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7690,7 +8040,7 @@ type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7702,7 +8052,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7738,7 +8088,7 @@ type SyncMessage_AttachmentBackfillResponse_AttachmentData struct { func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) Reset() { *x = SyncMessage_AttachmentBackfillResponse_AttachmentData{} - mi := &file_SignalService_proto_msgTypes[81] + mi := &file_SignalService_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7750,7 +8100,7 @@ func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) String() string func (*SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[81] + mi := &file_SignalService_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7819,7 +8169,7 @@ type SyncMessage_AttachmentBackfillResponse_AttachmentDataList struct { func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) Reset() { *x = SyncMessage_AttachmentBackfillResponse_AttachmentDataList{} - mi := &file_SignalService_proto_msgTypes[82] + mi := &file_SignalService_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7831,7 +8181,7 @@ func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) String() str func (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[82] + mi := &file_SignalService_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7871,7 +8221,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[83] + mi := &file_SignalService_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7883,7 +8233,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[83] + mi := &file_SignalService_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7923,7 +8273,7 @@ type PaymentAddress_MobileCoin struct { func (x *PaymentAddress_MobileCoin) Reset() { *x = PaymentAddress_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[84] + mi := &file_SignalService_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7935,7 +8285,7 @@ func (x *PaymentAddress_MobileCoin) String() string { func (*PaymentAddress_MobileCoin) ProtoMessage() {} func (x *PaymentAddress_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[84] + mi := &file_SignalService_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7969,7 +8319,7 @@ var File_SignalService_proto protoreflect.FileDescriptor const file_SignalService_proto_rawDesc = "" + "\n" + - "\x13SignalService.proto\x12\rsignalservice\"\xa7\x05\n" + + "\x13SignalService.proto\x12\rsignalservice\"\xf5\x06\n" + "\bEnvelope\x120\n" + "\x04type\x18\x01 \x01(\x0e2\x1c.signalservice.Envelope.TypeR\x04type\x12(\n" + "\x0fsourceServiceId\x18\v \x01(\tR\x0fsourceServiceId\x12\"\n" + @@ -7988,7 +8338,11 @@ const file_SignalService_proto_rawDesc = "" + "updatedPni\x18\x0f \x01(\tR\n" + "updatedPni\x12\x14\n" + "\x05story\x18\x10 \x01(\bR\x05story\x12*\n" + - "\x11report_spam_token\x18\x11 \x01(\fR\x0freportSpamToken\"\xae\x01\n" + + "\x11report_spam_token\x18\x11 \x01(\fR\x0freportSpamToken\x124\n" + + "\x15sourceServiceIdBinary\x18\x13 \x01(\fR\x15sourceServiceIdBinary\x12>\n" + + "\x1adestinationServiceIdBinary\x18\x14 \x01(\fR\x1adestinationServiceIdBinary\x12*\n" + + "\x10serverGuidBinary\x18\x15 \x01(\fR\x10serverGuidBinary\x12*\n" + + "\x10updatedPniBinary\x18\x16 \x01(\fR\x10updatedPniBinary\"\xae\x01\n" + "\x04Type\x12\v\n" + "\aUNKNOWN\x10\x00\x12\x0e\n" + "\n" + @@ -8050,7 +8404,7 @@ const file_SignalService_proto_rawDesc = "" + "\aurgency\x18\x02 \x01(\x0e2).signalservice.CallMessage.Opaque.UrgencyR\aurgency\"0\n" + "\aUrgency\x12\r\n" + "\tDROPPABLE\x10\x00\x12\x16\n" + - "\x12HANDLE_IMMEDIATELY\x10\x01J\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"\xca'\n" + + "\x12HANDLE_IMMEDIATELY\x10\x01J\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"\xca,\n" + "\vDataMessage\x12\x12\n" + "\x04body\x18\x01 \x01(\tR\x04body\x12B\n" + "\vattachments\x18\x02 \x03(\v2 .signalservice.AttachmentPointerR\vattachments\x127\n" + @@ -8084,7 +8438,11 @@ const file_SignalService_proto_rawDesc = "" + "pollCreate\x18\x18 \x01(\v2%.signalservice.DataMessage.PollCreateR\n" + "pollCreate\x12N\n" + "\rpollTerminate\x18\x19 \x01(\v2(.signalservice.DataMessage.PollTerminateR\rpollTerminate\x12?\n" + - "\bpollVote\x18\x1a \x01(\v2#.signalservice.DataMessage.PollVoteR\bpollVote\x1a\x9a\x05\n" + + "\bpollVote\x18\x1a \x01(\v2#.signalservice.DataMessage.PollVoteR\bpollVote\x12E\n" + + "\n" + + "pinMessage\x18\x1b \x01(\v2%.signalservice.DataMessage.PinMessageR\n" + + "pinMessage\x12K\n" + + "\funpinMessage\x18\x1c \x01(\v2'.signalservice.DataMessage.UnpinMessageR\funpinMessage\x1a\x9a\x05\n" + "\aPayment\x12U\n" + "\fnotification\x18\x01 \x01(\v2/.signalservice.DataMessage.Payment.NotificationH\x00R\fnotification\x12O\n" + "\n" + @@ -8113,7 +8471,7 @@ const file_SignalService_proto_rawDesc = "" + "\x04Type\x12\v\n" + "\aREQUEST\x10\x00\x12\r\n" + "\tACTIVATED\x10\x01B\x06\n" + - "\x04ItemJ\x06\b\xea\a\x10\xeb\aJ\x06\b\xeb\a\x10\xec\a\x1a\xda\x03\n" + + "\x04ItemJ\x06\b\xea\a\x10\xeb\aJ\x06\b\xeb\a\x10\xec\a\x1a\x84\x04\n" + "\x05Quote\x12\x0e\n" + "\x02id\x18\x01 \x01(\x04R\x02id\x12\x1c\n" + "\tauthorAci\x18\x05 \x01(\tR\tauthorAci\x12\x12\n" + @@ -8122,7 +8480,8 @@ const file_SignalService_proto_rawDesc = "" + "\n" + "bodyRanges\x18\x06 \x03(\v2\x18.signalservice.BodyRangeR\n" + "bodyRanges\x129\n" + - "\x04type\x18\a \x01(\x0e2%.signalservice.DataMessage.Quote.TypeR\x04type\x1a\x90\x01\n" + + "\x04type\x18\a \x01(\x0e2%.signalservice.DataMessage.Quote.TypeR\x04type\x12(\n" + + "\x0fauthorAciBinary\x18\b \x01(\fR\x0fauthorAciBinary\x1a\x90\x01\n" + "\x10QuotedAttachment\x12 \n" + "\vcontentType\x18\x01 \x01(\tR\vcontentType\x12\x1a\n" + "\bfileName\x18\x02 \x01(\tR\bfileName\x12>\n" + @@ -8197,19 +8556,21 @@ const file_SignalService_proto_rawDesc = "" + "\apackKey\x18\x02 \x01(\fR\apackKey\x12\x1c\n" + "\tstickerId\x18\x03 \x01(\rR\tstickerId\x124\n" + "\x04data\x18\x04 \x01(\v2 .signalservice.AttachmentPointerR\x04data\x12\x14\n" + - "\x05emoji\x18\x05 \x01(\tR\x05emoji\x1a\x9a\x01\n" + + "\x05emoji\x18\x05 \x01(\tR\x05emoji\x1a\xd0\x01\n" + "\bReaction\x12\x14\n" + "\x05emoji\x18\x01 \x01(\tR\x05emoji\x12\x16\n" + "\x06remove\x18\x02 \x01(\bR\x06remove\x12(\n" + "\x0ftargetAuthorAci\x18\x04 \x01(\tR\x0ftargetAuthorAci\x120\n" + - "\x13targetSentTimestamp\x18\x05 \x01(\x04R\x13targetSentTimestampJ\x04\b\x03\x10\x04\x1a:\n" + + "\x13targetSentTimestamp\x18\x05 \x01(\x04R\x13targetSentTimestamp\x124\n" + + "\x15targetAuthorAciBinary\x18\x06 \x01(\fR\x15targetAuthorAciBinaryJ\x04\b\x03\x10\x04\x1a:\n" + "\x06Delete\x120\n" + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x1a'\n" + "\x0fGroupCallUpdate\x12\x14\n" + - "\x05eraId\x18\x01 \x01(\tR\x05eraId\x1aR\n" + + "\x05eraId\x18\x01 \x01(\tR\x05eraId\x1a|\n" + "\fStoryContext\x12\x1c\n" + "\tauthorAci\x18\x01 \x01(\tR\tauthorAci\x12$\n" + - "\rsentTimestamp\x18\x02 \x01(\x04R\rsentTimestamp\x1aQ\n" + + "\rsentTimestamp\x18\x02 \x01(\x04R\rsentTimestamp\x12(\n" + + "\x0fauthorAciBinary\x18\x03 \x01(\fR\x0fauthorAciBinary\x1aQ\n" + "\tGiftBadge\x12D\n" + "\x1dreceiptCredentialPresentation\x18\x01 \x01(\fR\x1dreceiptCredentialPresentation\x1ah\n" + "\n" + @@ -8223,7 +8584,17 @@ const file_SignalService_proto_rawDesc = "" + "\x15targetAuthorAciBinary\x18\x01 \x01(\fR\x15targetAuthorAciBinary\x120\n" + "\x13targetSentTimestamp\x18\x02 \x01(\x04R\x13targetSentTimestamp\x12$\n" + "\roptionIndexes\x18\x03 \x03(\rR\roptionIndexes\x12\x1c\n" + - "\tvoteCount\x18\x04 \x01(\rR\tvoteCount\"Z\n" + + "\tvoteCount\x18\x04 \x01(\rR\tvoteCount\x1a\xe7\x01\n" + + "\n" + + "PinMessage\x124\n" + + "\x15targetAuthorAciBinary\x18\x01 \x01(\fR\x15targetAuthorAciBinary\x120\n" + + "\x13targetSentTimestamp\x18\x02 \x01(\x04R\x13targetSentTimestamp\x120\n" + + "\x12pinDurationSeconds\x18\x03 \x01(\rH\x00R\x12pinDurationSeconds\x120\n" + + "\x12pinDurationForever\x18\x04 \x01(\bH\x00R\x12pinDurationForeverB\r\n" + + "\vpinDuration\x1av\n" + + "\fUnpinMessage\x124\n" + + "\x15targetAuthorAciBinary\x18\x01 \x01(\fR\x15targetAuthorAciBinary\x120\n" + + "\x13targetSentTimestamp\x18\x02 \x01(\x04R\x13targetSentTimestamp\"Z\n" + "\x05Flags\x12\x0f\n" + "\vEND_SESSION\x10\x01\x12\x1b\n" + "\x17EXPIRATION_TIMER_UPDATE\x10\x02\x12\x16\n" + @@ -8239,7 +8610,7 @@ const file_SignalService_proto_rawDesc = "" + "\bMENTIONS\x10\x06\x12\f\n" + "\bPAYMENTS\x10\a\x12\t\n" + "\x05POLLS\x10\b\x12\v\n" + - "\aCURRENT\x10\a\x1a\x02\x10\x01J\x04\b\x03\x10\x04\"'\n" + + "\aCURRENT\x10\b\x1a\x02\x10\x01J\x04\b\x03\x10\x04\"'\n" + "\vNullMessage\x12\x18\n" + "\apadding\x18\x01 \x01(\fR\apadding\"\x92\x01\n" + "\x0eReceiptMessage\x126\n" + @@ -8301,17 +8672,18 @@ const file_SignalService_proto_rawDesc = "" + "\x06SCRIPT\x10\x04\x12\r\n" + "\tCONDENSED\x10\x05B\f\n" + "\n" + - "background\"\xe5\x01\n" + + "background\"\x99\x02\n" + "\bVerified\x12&\n" + "\x0edestinationAci\x18\x05 \x01(\tR\x0edestinationAci\x12 \n" + "\videntityKey\x18\x02 \x01(\fR\videntityKey\x123\n" + "\x05state\x18\x03 \x01(\x0e2\x1d.signalservice.Verified.StateR\x05state\x12 \n" + - "\vnullMessage\x18\x04 \x01(\fR\vnullMessage\"2\n" + + "\vnullMessage\x18\x04 \x01(\fR\vnullMessage\x122\n" + + "\x14destinationAciBinary\x18\x06 \x01(\fR\x14destinationAciBinary\"2\n" + "\x05State\x12\v\n" + "\aDEFAULT\x10\x00\x12\f\n" + "\bVERIFIED\x10\x01\x12\x0e\n" + "\n" + - "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\x87D\n" + + "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\x8fG\n" + "\vSyncMessage\x123\n" + "\x04sent\x18\x01 \x01(\v2\x1f.signalservice.SyncMessage.SentR\x04sent\x12?\n" + "\bcontacts\x18\x02 \x01(\v2#.signalservice.SyncMessage.ContactsR\bcontacts\x12<\n" + @@ -8336,7 +8708,7 @@ const file_SignalService_proto_rawDesc = "" + "\vdeleteForMe\x18\x16 \x01(\v2&.signalservice.SyncMessage.DeleteForMeR\vdeleteForMe\x12W\n" + "\x10deviceNameChange\x18\x17 \x01(\v2+.signalservice.SyncMessage.DeviceNameChangeR\x10deviceNameChange\x12r\n" + "\x19attachmentBackfillRequest\x18\x18 \x01(\v24.signalservice.SyncMessage.AttachmentBackfillRequestR\x19attachmentBackfillRequest\x12u\n" + - "\x1aattachmentBackfillResponse\x18\x19 \x01(\v25.signalservice.SyncMessage.AttachmentBackfillResponseR\x1aattachmentBackfillResponse\x1a\xfc\a\n" + + "\x1aattachmentBackfillResponse\x18\x19 \x01(\v25.signalservice.SyncMessage.AttachmentBackfillResponseR\x1aattachmentBackfillResponse\x1a\xbc\t\n" + "\x04Sent\x12(\n" + "\x0fdestinationE164\x18\x01 \x01(\tR\x0fdestinationE164\x122\n" + "\x14destinationServiceId\x18\a \x01(\tR\x14destinationServiceId\x12\x1c\n" + @@ -8348,22 +8720,28 @@ const file_SignalService_proto_rawDesc = "" + "\fstoryMessage\x18\b \x01(\v2\x1b.signalservice.StoryMessageR\fstoryMessage\x12m\n" + "\x16storyMessageRecipients\x18\t \x03(\v25.signalservice.SyncMessage.Sent.StoryMessageRecipientR\x16storyMessageRecipients\x12<\n" + "\veditMessage\x18\n" + - " \x01(\v2\x1a.signalservice.EditMessageR\veditMessage\x1a\xbe\x01\n" + + " \x01(\v2\x1a.signalservice.EditMessageR\veditMessage\x12>\n" + + "\x1adestinationServiceIdBinary\x18\f \x01(\fR\x1adestinationServiceIdBinary\x1a\xfe\x01\n" + "\x1aUnidentifiedDeliveryStatus\x122\n" + "\x14destinationServiceId\x18\x03 \x01(\tR\x14destinationServiceId\x12\"\n" + "\funidentified\x18\x02 \x01(\bR\funidentified\x12<\n" + - "\x19destinationPniIdentityKey\x18\x05 \x01(\fR\x19destinationPniIdentityKeyJ\x04\b\x01\x10\x02J\x04\b\x04\x10\x05\x1a\xaf\x01\n" + + "\x19destinationPniIdentityKey\x18\x05 \x01(\fR\x19destinationPniIdentityKey\x12>\n" + + "\x1adestinationServiceIdBinary\x18\x06 \x01(\fR\x1adestinationServiceIdBinaryJ\x04\b\x01\x10\x02J\x04\b\x04\x10\x05\x1a\xef\x01\n" + "\x15StoryMessageRecipient\x122\n" + "\x14destinationServiceId\x18\x01 \x01(\tR\x14destinationServiceId\x120\n" + "\x13distributionListIds\x18\x02 \x03(\tR\x13distributionListIds\x12*\n" + - "\x10isAllowedToReply\x18\x03 \x01(\bR\x10isAllowedToReplyJ\x04\b\x04\x10\x05J\x04\b\v\x10\f\x1ac\n" + + "\x10isAllowedToReply\x18\x03 \x01(\bR\x10isAllowedToReply\x12>\n" + + "\x1adestinationServiceIdBinary\x18\x05 \x01(\fR\x1adestinationServiceIdBinaryJ\x04\b\x04\x10\x05J\x04\b\v\x10\f\x1ac\n" + "\bContacts\x124\n" + "\x04blob\x18\x01 \x01(\v2 .signalservice.AttachmentPointerR\x04blob\x12!\n" + - "\bcomplete\x18\x02 \x01(\b:\x05falseR\bcomplete\x1aS\n" + + "\bcomplete\x18\x02 \x01(\b:\x05falseR\bcomplete\x1as\n" + "\aBlocked\x12\x18\n" + "\anumbers\x18\x01 \x03(\tR\anumbers\x12\x12\n" + "\x04acis\x18\x03 \x03(\tR\x04acis\x12\x1a\n" + - "\bgroupIds\x18\x02 \x03(\fR\bgroupIds\x1a\x9f\x01\n" + + "\bgroupIds\x18\x02 \x03(\fR\bgroupIds\x12\x1e\n" + + "\n" + + "acisBinary\x18\x04 \x03(\fR\n" + + "acisBinary\x1a\x9f\x01\n" + "\aRequest\x12;\n" + "\x04type\x18\x01 \x01(\x0e2'.signalservice.SyncMessage.Request.TypeR\x04type\"W\n" + "\x04Type\x12\v\n" + @@ -8371,13 +8749,15 @@ const file_SignalService_proto_rawDesc = "" + "\bCONTACTS\x10\x01\x12\v\n" + "\aBLOCKED\x10\x03\x12\x11\n" + "\rCONFIGURATION\x10\x04\x12\b\n" + - "\x04KEYS\x10\x05\"\x04\b\x02\x10\x02\"\x04\b\x06\x10\x06\x1aH\n" + + "\x04KEYS\x10\x05\"\x04\b\x02\x10\x02\"\x04\b\x06\x10\x06\x1ar\n" + "\x04Read\x12\x1c\n" + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + - "\ttimestamp\x18\x02 \x01(\x04R\ttimestampJ\x04\b\x01\x10\x02\x1aJ\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12(\n" + + "\x0fsenderAciBinary\x18\x04 \x01(\fR\x0fsenderAciBinaryJ\x04\b\x01\x10\x02\x1at\n" + "\x06Viewed\x12\x1c\n" + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + - "\ttimestamp\x18\x02 \x01(\x04R\ttimestampJ\x04\b\x01\x10\x02\x1a\x83\x02\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12(\n" + + "\x0fsenderAciBinary\x18\x04 \x01(\fR\x0fsenderAciBinaryJ\x04\b\x01\x10\x02\x1a\x83\x02\n" + "\rConfiguration\x12\"\n" + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x12F\n" + "\x1eunidentifiedDeliveryIndicators\x18\x02 \x01(\bR\x1eunidentifiedDeliveryIndicators\x12*\n" + @@ -8391,10 +8771,11 @@ const file_SignalService_proto_rawDesc = "" + "\x04Type\x12\v\n" + "\aINSTALL\x10\x00\x12\n" + "\n" + - "\x06REMOVE\x10\x01\x1aP\n" + + "\x06REMOVE\x10\x01\x1az\n" + "\fViewOnceOpen\x12\x1c\n" + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + - "\ttimestamp\x18\x02 \x01(\x04R\ttimestampJ\x04\b\x01\x10\x02\x1a\xa5\x01\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12(\n" + + "\x0fsenderAciBinary\x18\x04 \x01(\fR\x0fsenderAciBinaryJ\x04\b\x01\x10\x02\x1a\xa5\x01\n" + "\vFetchLatest\x12?\n" + "\x04type\x18\x01 \x01(\x0e2+.signalservice.SyncMessage.FetchLatest.TypeR\x04type\"U\n" + "\x04Type\x12\v\n" + @@ -8410,11 +8791,12 @@ const file_SignalService_proto_rawDesc = "" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x1e\n" + "\n" + "privateKey\x18\x02 \x01(\fR\n" + - "privateKey\x1a\x8e\x02\n" + + "privateKey\x1a\xb8\x02\n" + "\x16MessageRequestResponse\x12\x1c\n" + "\tthreadAci\x18\x02 \x01(\tR\tthreadAci\x12\x18\n" + "\agroupId\x18\x03 \x01(\fR\agroupId\x12J\n" + - "\x04type\x18\x04 \x01(\x0e26.signalservice.SyncMessage.MessageRequestResponse.TypeR\x04type\"j\n" + + "\x04type\x18\x04 \x01(\x0e26.signalservice.SyncMessage.MessageRequestResponse.TypeR\x04type\x12(\n" + + "\x0fthreadAciBinary\x18\x05 \x01(\fR\x0fthreadAciBinary\"j\n" + "\x04Type\x12\v\n" + "\aUNKNOWN\x10\x00\x12\n" + "\n" + @@ -8575,10 +8957,11 @@ const file_SignalService_proto_rawDesc = "" + "\x0eGroupContextV2\x12\x1c\n" + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x1a\n" + "\brevision\x18\x02 \x01(\rR\brevision\x12 \n" + - "\vgroupChange\x18\x03 \x01(\fR\vgroupChange\"\xe6\x02\n" + + "\vgroupChange\x18\x03 \x01(\fR\vgroupChange\"\x84\x03\n" + "\x0eContactDetails\x12\x16\n" + "\x06number\x18\x01 \x01(\tR\x06number\x12\x10\n" + - "\x03aci\x18\t \x01(\tR\x03aci\x12\x12\n" + + "\x03aci\x18\t \x01(\tR\x03aci\x12\x1c\n" + + "\taciBinary\x18\r \x01(\fR\taciBinary\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12<\n" + "\x06avatar\x18\x03 \x01(\v2$.signalservice.ContactDetails.AvatarR\x06avatar\x12 \n" + "\vexpireTimer\x18\b \x01(\rR\vexpireTimer\x12.\n" + @@ -8608,14 +8991,15 @@ const file_SignalService_proto_rawDesc = "" + "\tsignature\x18\x02 \x01(\fR\tsignature\"}\n" + "\vEditMessage\x120\n" + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x12<\n" + - "\vdataMessage\x18\x02 \x01(\v2\x1a.signalservice.DataMessageR\vdataMessage\"\xfe\x01\n" + + "\vdataMessage\x18\x02 \x01(\v2\x1a.signalservice.DataMessageR\vdataMessage\"\xac\x02\n" + "\tBodyRange\x12\x14\n" + "\x05start\x18\x01 \x01(\rR\x05start\x12\x16\n" + "\x06length\x18\x02 \x01(\rR\x06length\x12 \n" + "\n" + "mentionAci\x18\x03 \x01(\tH\x00R\n" + "mentionAci\x126\n" + - "\x05style\x18\x04 \x01(\x0e2\x1e.signalservice.BodyRange.StyleH\x00R\x05style\"V\n" + + "\x05style\x18\x04 \x01(\x0e2\x1e.signalservice.BodyRange.StyleH\x00R\x05style\x12,\n" + + "\x10mentionAciBinary\x18\x05 \x01(\fH\x00R\x10mentionAciBinary\"V\n" + "\x05Style\x12\b\n" + "\x04NONE\x10\x00\x12\b\n" + "\x04BOLD\x10\x01\x12\n" + @@ -8624,20 +9008,22 @@ const file_SignalService_proto_rawDesc = "" + "\aSPOILER\x10\x03\x12\x11\n" + "\rSTRIKETHROUGH\x10\x04\x12\r\n" + "\tMONOSPACE\x10\x05B\x11\n" + - "\x0fassociatedValue\"\x92\x01\n" + + "\x0fassociatedValue\"\xca\x01\n" + "\x12AddressableMessage\x12*\n" + "\x0fauthorServiceId\x18\x01 \x01(\tH\x00R\x0fauthorServiceId\x12 \n" + "\n" + "authorE164\x18\x02 \x01(\tH\x00R\n" + - "authorE164\x12$\n" + + "authorE164\x126\n" + + "\x15authorServiceIdBinary\x18\x04 \x01(\fH\x00R\x15authorServiceIdBinary\x12$\n" + "\rsentTimestamp\x18\x03 \x01(\x04R\rsentTimestampB\b\n" + - "\x06author\"\x9c\x01\n" + + "\x06author\"\xd4\x01\n" + "\x16ConversationIdentifier\x12*\n" + "\x0fthreadServiceId\x18\x01 \x01(\tH\x00R\x0fthreadServiceId\x12&\n" + "\rthreadGroupId\x18\x02 \x01(\fH\x00R\rthreadGroupId\x12 \n" + "\n" + "threadE164\x18\x03 \x01(\tH\x00R\n" + - "threadE164B\f\n" + + "threadE164\x126\n" + + "\x15threadServiceIdBinary\x18\x04 \x01(\fH\x00R\x15threadServiceIdBinaryB\f\n" + "\n" + "identifierBE\n" + ".org.whispersystems.signalservice.internal.pushB\x13SignalServiceProtos" @@ -8655,7 +9041,7 @@ func file_SignalService_proto_rawDescGZIP() []byte { } var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 28) -var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 85) +var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 87) var file_SignalService_proto_goTypes = []any{ (Envelope_Type)(0), // 0: signalservice.Envelope.Type (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type @@ -8725,51 +9111,53 @@ var file_SignalService_proto_goTypes = []any{ (*DataMessage_PollCreate)(nil), // 65: signalservice.DataMessage.PollCreate (*DataMessage_PollTerminate)(nil), // 66: signalservice.DataMessage.PollTerminate (*DataMessage_PollVote)(nil), // 67: signalservice.DataMessage.PollVote - (*DataMessage_Payment_Amount)(nil), // 68: signalservice.DataMessage.Payment.Amount - (*DataMessage_Payment_Notification)(nil), // 69: signalservice.DataMessage.Payment.Notification - (*DataMessage_Payment_Activation)(nil), // 70: signalservice.DataMessage.Payment.Activation - (*DataMessage_Payment_Amount_MobileCoin)(nil), // 71: signalservice.DataMessage.Payment.Amount.MobileCoin - (*DataMessage_Payment_Notification_MobileCoin)(nil), // 72: signalservice.DataMessage.Payment.Notification.MobileCoin - (*DataMessage_Quote_QuotedAttachment)(nil), // 73: signalservice.DataMessage.Quote.QuotedAttachment - (*DataMessage_Contact_Name)(nil), // 74: signalservice.DataMessage.Contact.Name - (*DataMessage_Contact_Phone)(nil), // 75: signalservice.DataMessage.Contact.Phone - (*DataMessage_Contact_Email)(nil), // 76: signalservice.DataMessage.Contact.Email - (*DataMessage_Contact_PostalAddress)(nil), // 77: signalservice.DataMessage.Contact.PostalAddress - (*DataMessage_Contact_Avatar)(nil), // 78: signalservice.DataMessage.Contact.Avatar - (*TextAttachment_Gradient)(nil), // 79: signalservice.TextAttachment.Gradient - (*SyncMessage_Sent)(nil), // 80: signalservice.SyncMessage.Sent - (*SyncMessage_Contacts)(nil), // 81: signalservice.SyncMessage.Contacts - (*SyncMessage_Blocked)(nil), // 82: signalservice.SyncMessage.Blocked - (*SyncMessage_Request)(nil), // 83: signalservice.SyncMessage.Request - (*SyncMessage_Read)(nil), // 84: signalservice.SyncMessage.Read - (*SyncMessage_Viewed)(nil), // 85: signalservice.SyncMessage.Viewed - (*SyncMessage_Configuration)(nil), // 86: signalservice.SyncMessage.Configuration - (*SyncMessage_StickerPackOperation)(nil), // 87: signalservice.SyncMessage.StickerPackOperation - (*SyncMessage_ViewOnceOpen)(nil), // 88: signalservice.SyncMessage.ViewOnceOpen - (*SyncMessage_FetchLatest)(nil), // 89: signalservice.SyncMessage.FetchLatest - (*SyncMessage_Keys)(nil), // 90: signalservice.SyncMessage.Keys - (*SyncMessage_PniIdentity)(nil), // 91: signalservice.SyncMessage.PniIdentity - (*SyncMessage_MessageRequestResponse)(nil), // 92: signalservice.SyncMessage.MessageRequestResponse - (*SyncMessage_OutgoingPayment)(nil), // 93: signalservice.SyncMessage.OutgoingPayment - (*SyncMessage_PniChangeNumber)(nil), // 94: signalservice.SyncMessage.PniChangeNumber - (*SyncMessage_CallEvent)(nil), // 95: signalservice.SyncMessage.CallEvent - (*SyncMessage_CallLinkUpdate)(nil), // 96: signalservice.SyncMessage.CallLinkUpdate - (*SyncMessage_CallLogEvent)(nil), // 97: signalservice.SyncMessage.CallLogEvent - (*SyncMessage_DeleteForMe)(nil), // 98: signalservice.SyncMessage.DeleteForMe - (*SyncMessage_DeviceNameChange)(nil), // 99: signalservice.SyncMessage.DeviceNameChange - (*SyncMessage_AttachmentBackfillRequest)(nil), // 100: signalservice.SyncMessage.AttachmentBackfillRequest - (*SyncMessage_AttachmentBackfillResponse)(nil), // 101: signalservice.SyncMessage.AttachmentBackfillResponse - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 102: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 103: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 104: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 105: signalservice.SyncMessage.DeleteForMe.MessageDeletes - (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 106: signalservice.SyncMessage.DeleteForMe.AttachmentDelete - (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 107: signalservice.SyncMessage.DeleteForMe.ConversationDelete - (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 108: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 109: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 110: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList - (*ContactDetails_Avatar)(nil), // 111: signalservice.ContactDetails.Avatar - (*PaymentAddress_MobileCoin)(nil), // 112: signalservice.PaymentAddress.MobileCoin + (*DataMessage_PinMessage)(nil), // 68: signalservice.DataMessage.PinMessage + (*DataMessage_UnpinMessage)(nil), // 69: signalservice.DataMessage.UnpinMessage + (*DataMessage_Payment_Amount)(nil), // 70: signalservice.DataMessage.Payment.Amount + (*DataMessage_Payment_Notification)(nil), // 71: signalservice.DataMessage.Payment.Notification + (*DataMessage_Payment_Activation)(nil), // 72: signalservice.DataMessage.Payment.Activation + (*DataMessage_Payment_Amount_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Amount.MobileCoin + (*DataMessage_Payment_Notification_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Notification.MobileCoin + (*DataMessage_Quote_QuotedAttachment)(nil), // 75: signalservice.DataMessage.Quote.QuotedAttachment + (*DataMessage_Contact_Name)(nil), // 76: signalservice.DataMessage.Contact.Name + (*DataMessage_Contact_Phone)(nil), // 77: signalservice.DataMessage.Contact.Phone + (*DataMessage_Contact_Email)(nil), // 78: signalservice.DataMessage.Contact.Email + (*DataMessage_Contact_PostalAddress)(nil), // 79: signalservice.DataMessage.Contact.PostalAddress + (*DataMessage_Contact_Avatar)(nil), // 80: signalservice.DataMessage.Contact.Avatar + (*TextAttachment_Gradient)(nil), // 81: signalservice.TextAttachment.Gradient + (*SyncMessage_Sent)(nil), // 82: signalservice.SyncMessage.Sent + (*SyncMessage_Contacts)(nil), // 83: signalservice.SyncMessage.Contacts + (*SyncMessage_Blocked)(nil), // 84: signalservice.SyncMessage.Blocked + (*SyncMessage_Request)(nil), // 85: signalservice.SyncMessage.Request + (*SyncMessage_Read)(nil), // 86: signalservice.SyncMessage.Read + (*SyncMessage_Viewed)(nil), // 87: signalservice.SyncMessage.Viewed + (*SyncMessage_Configuration)(nil), // 88: signalservice.SyncMessage.Configuration + (*SyncMessage_StickerPackOperation)(nil), // 89: signalservice.SyncMessage.StickerPackOperation + (*SyncMessage_ViewOnceOpen)(nil), // 90: signalservice.SyncMessage.ViewOnceOpen + (*SyncMessage_FetchLatest)(nil), // 91: signalservice.SyncMessage.FetchLatest + (*SyncMessage_Keys)(nil), // 92: signalservice.SyncMessage.Keys + (*SyncMessage_PniIdentity)(nil), // 93: signalservice.SyncMessage.PniIdentity + (*SyncMessage_MessageRequestResponse)(nil), // 94: signalservice.SyncMessage.MessageRequestResponse + (*SyncMessage_OutgoingPayment)(nil), // 95: signalservice.SyncMessage.OutgoingPayment + (*SyncMessage_PniChangeNumber)(nil), // 96: signalservice.SyncMessage.PniChangeNumber + (*SyncMessage_CallEvent)(nil), // 97: signalservice.SyncMessage.CallEvent + (*SyncMessage_CallLinkUpdate)(nil), // 98: signalservice.SyncMessage.CallLinkUpdate + (*SyncMessage_CallLogEvent)(nil), // 99: signalservice.SyncMessage.CallLogEvent + (*SyncMessage_DeleteForMe)(nil), // 100: signalservice.SyncMessage.DeleteForMe + (*SyncMessage_DeviceNameChange)(nil), // 101: signalservice.SyncMessage.DeviceNameChange + (*SyncMessage_AttachmentBackfillRequest)(nil), // 102: signalservice.SyncMessage.AttachmentBackfillRequest + (*SyncMessage_AttachmentBackfillResponse)(nil), // 103: signalservice.SyncMessage.AttachmentBackfillResponse + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 104: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 105: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 106: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 107: signalservice.SyncMessage.DeleteForMe.MessageDeletes + (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 108: signalservice.SyncMessage.DeleteForMe.AttachmentDelete + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 109: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 110: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 111: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 112: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + (*ContactDetails_Avatar)(nil), // 113: signalservice.ContactDetails.Avatar + (*PaymentAddress_MobileCoin)(nil), // 114: signalservice.PaymentAddress.MobileCoin } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type @@ -8804,108 +9192,110 @@ var file_SignalService_proto_depIdxs = []int32{ 65, // 29: signalservice.DataMessage.pollCreate:type_name -> signalservice.DataMessage.PollCreate 66, // 30: signalservice.DataMessage.pollTerminate:type_name -> signalservice.DataMessage.PollTerminate 67, // 31: signalservice.DataMessage.pollVote:type_name -> signalservice.DataMessage.PollVote - 11, // 32: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type - 12, // 33: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action - 41, // 34: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 - 40, // 35: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer - 37, // 36: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment - 47, // 37: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange - 40, // 38: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer - 13, // 39: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style - 36, // 40: signalservice.TextAttachment.preview:type_name -> signalservice.Preview - 79, // 41: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient - 14, // 42: signalservice.Verified.state:type_name -> signalservice.Verified.State - 80, // 43: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent - 81, // 44: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts - 83, // 45: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request - 84, // 46: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read - 82, // 47: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked - 38, // 48: signalservice.SyncMessage.verified:type_name -> signalservice.Verified - 86, // 49: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration - 87, // 50: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation - 88, // 51: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen - 89, // 52: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest - 90, // 53: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys - 92, // 54: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse - 93, // 55: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment - 85, // 56: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed - 94, // 57: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber - 95, // 58: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent - 96, // 59: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate - 97, // 60: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 98, // 61: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe - 99, // 62: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange - 100, // 63: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest - 101, // 64: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse - 111, // 65: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 112, // 66: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin - 31, // 67: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 27, // 68: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style - 1, // 69: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 70: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 71: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 69, // 72: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 70, // 73: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 73, // 74: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 47, // 75: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 76: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 74, // 77: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 75, // 78: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 76, // 79: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 77, // 80: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 78, // 81: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 40, // 82: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 71, // 83: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 72, // 84: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 6, // 85: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 40, // 86: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 87: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 88: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 89: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 40, // 90: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 31, // 91: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 102, // 92: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 35, // 93: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 103, // 94: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 46, // 95: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 40, // 96: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 15, // 97: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 16, // 98: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 17, // 99: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 18, // 100: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 104, // 101: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 19, // 102: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 20, // 103: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 21, // 104: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 22, // 105: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type - 23, // 106: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 105, // 107: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes - 107, // 108: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete - 108, // 109: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - 106, // 110: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete - 48, // 111: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 112: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier - 48, // 113: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 114: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier - 110, // 115: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList - 24, // 116: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error - 49, // 117: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 118: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage - 49, // 119: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 120: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 121: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 122: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage - 48, // 123: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage - 49, // 124: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier - 40, // 125: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer - 25, // 126: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status - 109, // 127: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - 109, // 128: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - 129, // [129:129] is the sub-list for method output_type - 129, // [129:129] is the sub-list for method input_type - 129, // [129:129] is the sub-list for extension type_name - 129, // [129:129] is the sub-list for extension extendee - 0, // [0:129] is the sub-list for field type_name + 68, // 32: signalservice.DataMessage.pinMessage:type_name -> signalservice.DataMessage.PinMessage + 69, // 33: signalservice.DataMessage.unpinMessage:type_name -> signalservice.DataMessage.UnpinMessage + 11, // 34: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type + 12, // 35: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action + 41, // 36: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 + 40, // 37: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer + 37, // 38: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment + 47, // 39: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange + 40, // 40: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer + 13, // 41: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style + 36, // 42: signalservice.TextAttachment.preview:type_name -> signalservice.Preview + 81, // 43: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient + 14, // 44: signalservice.Verified.state:type_name -> signalservice.Verified.State + 82, // 45: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent + 83, // 46: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts + 85, // 47: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request + 86, // 48: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read + 84, // 49: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked + 38, // 50: signalservice.SyncMessage.verified:type_name -> signalservice.Verified + 88, // 51: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration + 89, // 52: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation + 90, // 53: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen + 91, // 54: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest + 92, // 55: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys + 94, // 56: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse + 95, // 57: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment + 87, // 58: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed + 96, // 59: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber + 97, // 60: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent + 98, // 61: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate + 99, // 62: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent + 100, // 63: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe + 101, // 64: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange + 102, // 65: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest + 103, // 66: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse + 113, // 67: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 114, // 68: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin + 31, // 69: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 27, // 70: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style + 1, // 71: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 72: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 73: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 71, // 74: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 72, // 75: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 75, // 76: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 47, // 77: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 78: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 76, // 79: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 77, // 80: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 78, // 81: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 79, // 82: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 80, // 83: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 84: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 73, // 85: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 74, // 86: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 6, // 87: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 40, // 88: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 89: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 90: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 91: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 40, // 92: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 31, // 93: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 104, // 94: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 95: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 105, // 96: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 46, // 97: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 98: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 15, // 99: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 16, // 100: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 17, // 101: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 18, // 102: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 106, // 103: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 19, // 104: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 20, // 105: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 21, // 106: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 22, // 107: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 23, // 108: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 107, // 109: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes + 109, // 110: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 110, // 111: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 108, // 112: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete + 48, // 113: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 114: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier + 48, // 115: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 116: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier + 112, // 117: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + 24, // 118: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error + 49, // 119: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 120: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage + 49, // 121: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 122: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 123: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 124: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage + 48, // 125: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage + 49, // 126: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 40, // 127: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer + 25, // 128: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status + 111, // 129: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 111, // 130: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 131, // [131:131] is the sub-list for method output_type + 131, // [131:131] is the sub-list for method input_type + 131, // [131:131] is the sub-list for extension type_name + 131, // [131:131] is the sub-list for extension extendee + 0, // [0:131] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -8931,34 +9321,41 @@ func file_SignalService_proto_init() { file_SignalService_proto_msgTypes[19].OneofWrappers = []any{ (*BodyRange_MentionAci)(nil), (*BodyRange_Style_)(nil), + (*BodyRange_MentionAciBinary)(nil), } file_SignalService_proto_msgTypes[20].OneofWrappers = []any{ (*AddressableMessage_AuthorServiceId)(nil), (*AddressableMessage_AuthorE164)(nil), + (*AddressableMessage_AuthorServiceIdBinary)(nil), } file_SignalService_proto_msgTypes[21].OneofWrappers = []any{ (*ConversationIdentifier_ThreadServiceId)(nil), (*ConversationIdentifier_ThreadGroupId)(nil), (*ConversationIdentifier_ThreadE164)(nil), + (*ConversationIdentifier_ThreadServiceIdBinary)(nil), } file_SignalService_proto_msgTypes[28].OneofWrappers = []any{ (*DataMessage_Payment_Notification_)(nil), (*DataMessage_Payment_Activation_)(nil), } file_SignalService_proto_msgTypes[40].OneofWrappers = []any{ + (*DataMessage_PinMessage_PinDurationSeconds)(nil), + (*DataMessage_PinMessage_PinDurationForever)(nil), + } + file_SignalService_proto_msgTypes[42].OneofWrappers = []any{ (*DataMessage_Payment_Amount_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[41].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[43].OneofWrappers = []any{ (*DataMessage_Payment_Notification_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[65].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[67].OneofWrappers = []any{ (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[73].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[75].OneofWrappers = []any{ (*SyncMessage_AttachmentBackfillResponse_Attachments)(nil), (*SyncMessage_AttachmentBackfillResponse_Error_)(nil), } - file_SignalService_proto_msgTypes[81].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[83].OneofWrappers = []any{ (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment)(nil), (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_)(nil), } @@ -8968,7 +9365,7 @@ func file_SignalService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_SignalService_proto_rawDesc), len(file_SignalService_proto_rawDesc)), NumEnums: 28, - NumMessages: 85, + NumMessages: 87, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index 249c4eb..da4d44f 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -40,7 +40,11 @@ message Envelope { optional bool story = 16; // indicates that the content is a story. optional bytes report_spam_token = 17; // token sent when reporting spam reserved 18; // internal server use - // next: 19 + optional bytes sourceServiceIdBinary = 19; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + optional bytes destinationServiceIdBinary = 20; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + optional bytes serverGuidBinary = 21; // 16-byte UUID + optional bytes updatedPniBinary = 22; // 16-byte UUID + // next: 22 } message Content { @@ -193,6 +197,7 @@ message DataMessage { repeated QuotedAttachment attachments = 4; repeated BodyRange bodyRanges = 6; optional Type type = 7; + optional bytes authorAciBinary = 8; // 16-byte UUID } message Contact { @@ -277,6 +282,7 @@ message DataMessage { reserved /* targetAuthorE164 */ 3; optional string targetAuthorAci = 4; optional uint64 targetSentTimestamp = 5; + optional bytes targetAuthorAciBinary = 6; // 16-byte UUID } message Delete { @@ -290,6 +296,7 @@ message DataMessage { message StoryContext { optional string authorAci = 1; optional uint64 sentTimestamp = 2; + optional bytes authorAciBinary = 3; // 16-byte UUID } enum ProtocolVersion { @@ -304,7 +311,7 @@ message DataMessage { MENTIONS = 6; PAYMENTS = 7; POLLS = 8; - CURRENT = 7; + CURRENT = 8; } message GiftBadge { @@ -328,6 +335,20 @@ message DataMessage { optional uint32 voteCount = 4; // increment this by 1 each time you vote on a given poll } + message PinMessage { + optional bytes targetAuthorAciBinary = 1; // 16-byte UUID + optional uint64 targetSentTimestamp = 2; + oneof pinDuration { + uint32 pinDurationSeconds = 3; + bool pinDurationForever = 4; + } + } + + message UnpinMessage { + optional bytes targetAuthorAciBinary = 1; // 16-byte UUID + optional uint64 targetSentTimestamp = 2; + } + optional string body = 1; repeated AttachmentPointer attachments = 2; reserved /*groupV1*/ 3; @@ -353,7 +374,9 @@ message DataMessage { optional PollCreate pollCreate = 24; optional PollTerminate pollTerminate = 25; optional PollVote pollVote = 26; - // NEXT ID: 27 + optional PinMessage pinMessage = 27; + optional UnpinMessage unpinMessage = 28; + // NEXT ID: 29 } message NullMessage { @@ -442,6 +465,7 @@ message Verified { optional bytes identityKey = 2; optional State state = 3; optional bytes nullMessage = 4; + optional bytes destinationAciBinary = 6; // 16-byte UUID } message SyncMessage { @@ -452,6 +476,7 @@ message SyncMessage { optional bool unidentified = 2; reserved /*destinationPni */ 4; optional bytes destinationPniIdentityKey = 5; // Only set for PNI destinations + optional bytes destinationServiceIdBinary = 6; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } message StoryMessageRecipient { @@ -459,6 +484,7 @@ message SyncMessage { repeated string distributionListIds = 2; optional bool isAllowedToReply = 3; reserved /*destinationPni */ 4; + optional bytes destinationServiceIdBinary = 5; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } optional string destinationE164 = 1; @@ -472,7 +498,8 @@ message SyncMessage { repeated StoryMessageRecipient storyMessageRecipients = 9; optional EditMessage editMessage = 10; reserved /*destinationPni */ 11; - // Next ID: 12 + optional bytes destinationServiceIdBinary = 12; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + // Next ID: 13 } message Contacts { @@ -484,6 +511,7 @@ message SyncMessage { repeated string numbers = 1; repeated string acis = 3; repeated bytes groupIds = 2; + repeated bytes acisBinary = 4; // 16-byte UUID } message Request { @@ -504,12 +532,14 @@ message SyncMessage { reserved /*senderE164*/ 1; optional string senderAci = 3; optional uint64 timestamp = 2; + optional bytes senderAciBinary = 4; // 16-byte UUID } message Viewed { reserved /*senderE164*/ 1; optional string senderAci = 3; optional uint64 timestamp = 2; + optional bytes senderAciBinary = 4; // 16-byte UUID } message Configuration { @@ -536,6 +566,7 @@ message SyncMessage { reserved /*senderE164*/ 1; optional string senderAci = 3; optional uint64 timestamp = 2; + optional bytes senderAciBinary = 4; // 16-byte UUID } message FetchLatest { @@ -576,6 +607,7 @@ message SyncMessage { optional string threadAci = 2; optional bytes groupId = 3; optional Type type = 4; + optional bytes threadAciBinary = 5; // 16-byte UUID } message OutgoingPayment { @@ -823,6 +855,7 @@ message ContactDetails { optional string number = 1; optional string aci = 9; + optional bytes aciBinary = 13; // 16-byte UUID optional string name = 2; optional Avatar avatar = 3; reserved /* color */ 4; @@ -833,7 +866,7 @@ message ContactDetails { optional uint32 expireTimerVersion = 12; optional uint32 inboxPosition = 10; reserved /* archived */ 11; - // NEXT ID: 13 + // NEXT ID: 14 } message PaymentAddress { @@ -880,6 +913,7 @@ message BodyRange { oneof associatedValue { string mentionAci = 3; Style style = 4; + bytes mentionAciBinary = 5; // 16-byte UUID } } @@ -887,6 +921,7 @@ message AddressableMessage { oneof author { string authorServiceId = 1; string authorE164 = 2; + bytes authorServiceIdBinary = 4; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } optional uint64 sentTimestamp = 3; } @@ -896,5 +931,6 @@ message ConversationIdentifier { string threadServiceId = 1; bytes threadGroupId = 2; string threadE164 = 3; + bytes threadServiceIdBinary = 4; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } } diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index 52905c6..e83cda1 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -5,8 +5,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: StickerResources.proto package signalpb diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 1294a3f..9a27146 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -5,8 +5,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: StorageService.proto package signalpb @@ -1086,7 +1086,9 @@ type ContactRecord struct { PniSignatureVerified bool `protobuf:"varint,21,opt,name=pniSignatureVerified,proto3" json:"pniSignatureVerified,omitempty"` Nickname *ContactRecord_Name `protobuf:"bytes,22,opt,name=nickname,proto3" json:"nickname,omitempty"` Note string `protobuf:"bytes,23,opt,name=note,proto3" json:"note,omitempty"` - AvatarColor *AvatarColor `protobuf:"varint,24,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` // Next ID: 25 + AvatarColor *AvatarColor `protobuf:"varint,24,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` + AciBinary []byte `protobuf:"bytes,25,opt,name=aciBinary,proto3" json:"aciBinary,omitempty"` // 16-byte UUID + PniBinary []byte `protobuf:"bytes,26,opt,name=pniBinary,proto3" json:"pniBinary,omitempty"` // 16-byte UUID unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1289,6 +1291,20 @@ func (x *ContactRecord) GetAvatarColor() AvatarColor { return AvatarColor_A100 } +func (x *ContactRecord) GetAciBinary() []byte { + if x != nil { + return x.AciBinary + } + return nil +} + +func (x *ContactRecord) GetPniBinary() []byte { + if x != nil { + return x.PniBinary + } + return nil +} + type GroupV1Record struct { state protoimpl.MessageState `protogen:"open.v1"` Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -1580,6 +1596,8 @@ type AccountRecord struct { AvatarColor *AvatarColor `protobuf:"varint,42,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` BackupTierHistory *AccountRecord_BackupTierHistory `protobuf:"bytes,43,opt,name=backupTierHistory,proto3" json:"backupTierHistory,omitempty"` NotificationProfileManualOverride *AccountRecord_NotificationProfileManualOverride `protobuf:"bytes,44,opt,name=notificationProfileManualOverride,proto3" json:"notificationProfileManualOverride,omitempty"` + NotificationProfileSyncDisabled bool `protobuf:"varint,45,opt,name=notificationProfileSyncDisabled,proto3" json:"notificationProfileSyncDisabled,omitempty"` + AutomaticKeyVerificationDisabled bool `protobuf:"varint,46,opt,name=automaticKeyVerificationDisabled,proto3" json:"automaticKeyVerificationDisabled,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1873,16 +1891,31 @@ func (x *AccountRecord) GetNotificationProfileManualOverride() *AccountRecord_No return nil } +func (x *AccountRecord) GetNotificationProfileSyncDisabled() bool { + if x != nil { + return x.NotificationProfileSyncDisabled + } + return false +} + +func (x *AccountRecord) GetAutomaticKeyVerificationDisabled() bool { + if x != nil { + return x.AutomaticKeyVerificationDisabled + } + return false +} + type StoryDistributionListRecord struct { - state protoimpl.MessageState `protogen:"open.v1"` - Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - RecipientServiceIds []string `protobuf:"bytes,3,rep,name=recipientServiceIds,proto3" json:"recipientServiceIds,omitempty"` - DeletedAtTimestamp uint64 `protobuf:"varint,4,opt,name=deletedAtTimestamp,proto3" json:"deletedAtTimestamp,omitempty"` - AllowsReplies bool `protobuf:"varint,5,opt,name=allowsReplies,proto3" json:"allowsReplies,omitempty"` - IsBlockList bool `protobuf:"varint,6,opt,name=isBlockList,proto3" json:"isBlockList,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + RecipientServiceIds []string `protobuf:"bytes,3,rep,name=recipientServiceIds,proto3" json:"recipientServiceIds,omitempty"` + DeletedAtTimestamp uint64 `protobuf:"varint,4,opt,name=deletedAtTimestamp,proto3" json:"deletedAtTimestamp,omitempty"` + AllowsReplies bool `protobuf:"varint,5,opt,name=allowsReplies,proto3" json:"allowsReplies,omitempty"` + IsBlockList bool `protobuf:"varint,6,opt,name=isBlockList,proto3" json:"isBlockList,omitempty"` + RecipientServiceIdsBinary [][]byte `protobuf:"bytes,7,rep,name=recipientServiceIdsBinary,proto3" json:"recipientServiceIdsBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StoryDistributionListRecord) Reset() { @@ -1957,6 +1990,13 @@ func (x *StoryDistributionListRecord) GetIsBlockList() bool { return false } +func (x *StoryDistributionListRecord) GetRecipientServiceIdsBinary() [][]byte { + if x != nil { + return x.RecipientServiceIdsBinary + } + return nil +} + type CallLinkRecord struct { state protoimpl.MessageState `protogen:"open.v1"` RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` @@ -2883,11 +2923,12 @@ func (*AccountRecord_NotificationProfileManualOverride_Enabled) isAccountRecord_ } type AccountRecord_PinnedConversation_Contact struct { - state protoimpl.MessageState `protogen:"open.v1"` - ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` - E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` + E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` + ServiceIdBinary []byte `protobuf:"bytes,3,opt,name=serviceIdBinary,proto3" json:"serviceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountRecord_PinnedConversation_Contact) Reset() { @@ -2934,6 +2975,13 @@ func (x *AccountRecord_PinnedConversation_Contact) GetE164() string { return "" } +func (x *AccountRecord_PinnedConversation_Contact) GetServiceIdBinary() []byte { + if x != nil { + return x.ServiceIdBinary + } + return nil +} + type AccountRecord_NotificationProfileManualOverride_ManuallyEnabled struct { state protoimpl.MessageState `protogen:"open.v1"` Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -2988,11 +3036,12 @@ func (x *AccountRecord_NotificationProfileManualOverride_ManuallyEnabled) GetEnd } type Recipient_Contact struct { - state protoimpl.MessageState `protogen:"open.v1"` - ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` - E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ServiceId string `protobuf:"bytes,1,opt,name=serviceId,proto3" json:"serviceId,omitempty"` + E164 string `protobuf:"bytes,2,opt,name=e164,proto3" json:"e164,omitempty"` + ServiceIdBinary []byte `protobuf:"bytes,3,opt,name=serviceIdBinary,proto3" json:"serviceIdBinary,omitempty"` // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Recipient_Contact) Reset() { @@ -3039,6 +3088,13 @@ func (x *Recipient_Contact) GetE164() string { return "" } +func (x *Recipient_Contact) GetServiceIdBinary() []byte { + if x != nil { + return x.ServiceIdBinary + } + return nil +} + var File_StorageService_proto protoreflect.FileDescriptor const file_StorageService_proto_rawDesc = "" + @@ -3091,7 +3147,7 @@ const file_StorageService_proto_rawDesc = "" + "chatFolder\x18\b \x01(\v2\x1f.signalservice.ChatFolderRecordH\x00R\n" + "chatFolder\x12V\n" + "\x13notificationProfile\x18\t \x01(\v2\".signalservice.NotificationProfileH\x00R\x13notificationProfileB\b\n" + - "\x06record\"\x9d\b\n" + + "\x06record\"\xd9\b\n" + "\rContactRecord\x12\x10\n" + "\x03aci\x18\x01 \x01(\tR\x03aci\x12\x12\n" + "\x04e164\x18\x02 \x01(\tR\x04e164\x12\x10\n" + @@ -3121,7 +3177,9 @@ const file_StorageService_proto_rawDesc = "" + "\x14pniSignatureVerified\x18\x15 \x01(\bR\x14pniSignatureVerified\x12=\n" + "\bnickname\x18\x16 \x01(\v2!.signalservice.ContactRecord.NameR\bnickname\x12\x12\n" + "\x04note\x18\x17 \x01(\tR\x04note\x12A\n" + - "\vavatarColor\x18\x18 \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x1a4\n" + + "\vavatarColor\x18\x18 \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x12\x1c\n" + + "\taciBinary\x18\x19 \x01(\fR\taciBinary\x12\x1c\n" + + "\tpniBinary\x18\x1a \x01(\fR\tpniBinary\x1a4\n" + "\x04Name\x12\x14\n" + "\x05given\x18\x01 \x01(\tR\x05given\x12\x16\n" + "\x06family\x18\x02 \x01(\tR\x06family\":\n" + @@ -3158,7 +3216,7 @@ const file_StorageService_proto_rawDesc = "" + "\">\n" + "\bPayments\x12\x18\n" + "\aenabled\x18\x01 \x01(\bR\aenabled\x12\x18\n" + - "\aentropy\x18\x02 \x01(\fR\aentropy\"\x8b\x1b\n" + + "\aentropy\x18\x02 \x01(\fR\aentropy\"\xcb\x1c\n" + "\rAccountRecord\x12\x1e\n" + "\n" + "profileKey\x18\x01 \x01(\fR\n" + @@ -3203,14 +3261,17 @@ const file_StorageService_proto_rawDesc = "" + "\x14backupSubscriberData\x18) \x01(\v2..signalservice.AccountRecord.IAPSubscriberDataR\x14backupSubscriberData\x12A\n" + "\vavatarColor\x18* \x01(\x0e2\x1a.signalservice.AvatarColorH\x02R\vavatarColor\x88\x01\x01\x12\\\n" + "\x11backupTierHistory\x18+ \x01(\v2..signalservice.AccountRecord.BackupTierHistoryR\x11backupTierHistory\x12\x8c\x01\n" + - "!notificationProfileManualOverride\x18, \x01(\v2>.signalservice.AccountRecord.NotificationProfileManualOverrideR!notificationProfileManualOverride\x1a\x86\x02\n" + + "!notificationProfileManualOverride\x18, \x01(\v2>.signalservice.AccountRecord.NotificationProfileManualOverrideR!notificationProfileManualOverride\x12H\n" + + "\x1fnotificationProfileSyncDisabled\x18- \x01(\bR\x1fnotificationProfileSyncDisabled\x12J\n" + + " automaticKeyVerificationDisabled\x18. \x01(\bR automaticKeyVerificationDisabled\x1a\xb0\x02\n" + "\x12PinnedConversation\x12S\n" + "\acontact\x18\x01 \x01(\v27.signalservice.AccountRecord.PinnedConversation.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x03 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + - "\x0egroupMasterKey\x18\x04 \x01(\fH\x00R\x0egroupMasterKey\x1a;\n" + + "\x0egroupMasterKey\x18\x04 \x01(\fH\x00R\x0egroupMasterKey\x1ae\n" + "\aContact\x12\x1c\n" + "\tserviceId\x18\x01 \x01(\tR\tserviceId\x12\x12\n" + - "\x04e164\x18\x02 \x01(\tR\x04e164B\f\n" + + "\x04e164\x18\x02 \x01(\tR\x04e164\x12(\n" + + "\x0fserviceIdBinary\x18\x03 \x01(\fR\x0fserviceIdBinaryB\f\n" + "\n" + "identifier\x1a\xf8\x01\n" + "\fUsernameLink\x12\x18\n" + @@ -3258,7 +3319,7 @@ const file_StorageService_proto_rawDesc = "" + "_hasBackupB\r\n" + "\v_backupTierB\x0e\n" + "\f_avatarColorJ\x04\b\t\x10\n" + - "J\x04\b\x13\x10\x14J\x04\b\x1c\x10\x1dJ\x04\b\x1f\x10 J\x04\b$\x10%J\x04\b%\x10&J\x04\b&\x10'\"\xfb\x01\n" + + "J\x04\b\x13\x10\x14J\x04\b\x1c\x10\x1dJ\x04\b\x1f\x10 J\x04\b$\x10%J\x04\b%\x10&J\x04\b&\x10'\"\xb9\x02\n" + "\x1bStoryDistributionListRecord\x12\x1e\n" + "\n" + "identifier\x18\x01 \x01(\fR\n" + @@ -3267,20 +3328,22 @@ const file_StorageService_proto_rawDesc = "" + "\x13recipientServiceIds\x18\x03 \x03(\tR\x13recipientServiceIds\x12.\n" + "\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" + - "\visBlockList\x18\x06 \x01(\bR\visBlockList\"\xa7\x01\n" + + "\visBlockList\x18\x06 \x01(\bR\visBlockList\x12<\n" + + "\x19recipientServiceIdsBinary\x18\a \x03(\fR\x19recipientServiceIdsBinary\"\xa7\x01\n" + "\x0eCallLinkRecord\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\x12\x19\n" + "\x05epoch\x18\x04 \x01(\fH\x00R\x05epoch\x88\x01\x01B\b\n" + - "\x06_epoch\"\xe6\x01\n" + + "\x06_epoch\"\x90\x02\n" + "\tRecipient\x12<\n" + "\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + - "\x0egroupMasterKey\x18\x03 \x01(\fH\x00R\x0egroupMasterKey\x1a;\n" + + "\x0egroupMasterKey\x18\x03 \x01(\fH\x00R\x0egroupMasterKey\x1ae\n" + "\aContact\x12\x1c\n" + "\tserviceId\x18\x01 \x01(\tR\tserviceId\x12\x12\n" + - "\x04e164\x18\x02 \x01(\tR\x04e164B\f\n" + + "\x04e164\x18\x02 \x01(\tR\x04e164\x12(\n" + + "\x0fserviceIdBinary\x18\x03 \x01(\fR\x0fserviceIdBinaryB\f\n" + "\n" + "identifier\"\xe8\x04\n" + "\x10ChatFolderRecord\x12\x1e\n" + diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index 4258fba..95ec845 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -140,7 +140,9 @@ message ContactRecord { Name nickname = 22; string note = 23; optional AvatarColor avatarColor = 24; - // Next ID: 25 + bytes aciBinary = 25; // 16-byte UUID + bytes pniBinary = 26; // 16-byte UUID + // Next ID: 27 } message GroupV1Record { @@ -187,8 +189,9 @@ message AccountRecord { message PinnedConversation { message Contact { - string serviceId = 1; - string e164 = 2; + string serviceId = 1; + string e164 = 2; + bytes serviceIdBinary = 3; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } oneof identifier { @@ -291,15 +294,18 @@ message AccountRecord { optional AvatarColor avatarColor = 42; BackupTierHistory backupTierHistory = 43; NotificationProfileManualOverride notificationProfileManualOverride = 44; + bool notificationProfileSyncDisabled = 45; + bool automaticKeyVerificationDisabled = 46; } message StoryDistributionListRecord { - bytes identifier = 1; - string name = 2; - repeated string recipientServiceIds = 3; - uint64 deletedAtTimestamp = 4; - bool allowsReplies = 5; - bool isBlockList = 6; + bytes identifier = 1; + string name = 2; + repeated string recipientServiceIds = 3; + uint64 deletedAtTimestamp = 4; + bool allowsReplies = 5; + bool isBlockList = 6; + repeated bytes recipientServiceIdsBinary = 7; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } message CallLinkRecord { @@ -311,8 +317,9 @@ message CallLinkRecord { message Recipient { message Contact { - string serviceId = 1; - string e164 = 2; + string serviceId = 1; + string e164 = 2; + bytes serviceIdBinary = 3; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } oneof identifier { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index d512960..e30f6d6 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: UnidentifiedDelivery.proto // Copyright 2018 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index ef45ba0..f35110d 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -5,8 +5,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: WebSocketResources.proto package signalpb diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 86e176a..73930ae 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v3.21.12 +// protoc-gen-go v1.36.11 +// protoc v6.33.5 // source: backuppb/Backup.proto package backuppb @@ -210,6 +210,159 @@ func (AccountData_PhoneNumberSharingMode) EnumDescriptor() ([]byte, []int) { return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 0} } +type AccountData_SentMediaQuality int32 + +const ( + AccountData_UNKNOWN_QUALITY AccountData_SentMediaQuality = 0 // Interpret as "Standard" + AccountData_STANDARD AccountData_SentMediaQuality = 1 + AccountData_HIGH AccountData_SentMediaQuality = 2 +) + +// Enum value maps for AccountData_SentMediaQuality. +var ( + AccountData_SentMediaQuality_name = map[int32]string{ + 0: "UNKNOWN_QUALITY", + 1: "STANDARD", + 2: "HIGH", + } + AccountData_SentMediaQuality_value = map[string]int32{ + "UNKNOWN_QUALITY": 0, + "STANDARD": 1, + "HIGH": 2, + } +) + +func (x AccountData_SentMediaQuality) Enum() *AccountData_SentMediaQuality { + p := new(AccountData_SentMediaQuality) + *p = x + return p +} + +func (x AccountData_SentMediaQuality) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_SentMediaQuality) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[3].Descriptor() +} + +func (AccountData_SentMediaQuality) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[3] +} + +func (x AccountData_SentMediaQuality) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_SentMediaQuality.Descriptor instead. +func (AccountData_SentMediaQuality) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 1} +} + +type AccountData_AppTheme int32 + +const ( + AccountData_UNKNOWN_APP_THEME AccountData_AppTheme = 0 // Interpret as "System" + AccountData_SYSTEM AccountData_AppTheme = 1 + AccountData_LIGHT AccountData_AppTheme = 2 + AccountData_DARK AccountData_AppTheme = 3 +) + +// Enum value maps for AccountData_AppTheme. +var ( + AccountData_AppTheme_name = map[int32]string{ + 0: "UNKNOWN_APP_THEME", + 1: "SYSTEM", + 2: "LIGHT", + 3: "DARK", + } + AccountData_AppTheme_value = map[string]int32{ + "UNKNOWN_APP_THEME": 0, + "SYSTEM": 1, + "LIGHT": 2, + "DARK": 3, + } +) + +func (x AccountData_AppTheme) Enum() *AccountData_AppTheme { + p := new(AccountData_AppTheme) + *p = x + return p +} + +func (x AccountData_AppTheme) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_AppTheme) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[4].Descriptor() +} + +func (AccountData_AppTheme) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[4] +} + +func (x AccountData_AppTheme) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_AppTheme.Descriptor instead. +func (AccountData_AppTheme) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 2} +} + +type AccountData_CallsUseLessDataSetting int32 + +const ( + AccountData_UNKNOWN_CALL_DATA_SETTING AccountData_CallsUseLessDataSetting = 0 // Interpret as "Never" + AccountData_NEVER AccountData_CallsUseLessDataSetting = 1 + AccountData_MOBILE_DATA_ONLY AccountData_CallsUseLessDataSetting = 2 + AccountData_WIFI_AND_MOBILE_DATA AccountData_CallsUseLessDataSetting = 3 +) + +// Enum value maps for AccountData_CallsUseLessDataSetting. +var ( + AccountData_CallsUseLessDataSetting_name = map[int32]string{ + 0: "UNKNOWN_CALL_DATA_SETTING", + 1: "NEVER", + 2: "MOBILE_DATA_ONLY", + 3: "WIFI_AND_MOBILE_DATA", + } + AccountData_CallsUseLessDataSetting_value = map[string]int32{ + "UNKNOWN_CALL_DATA_SETTING": 0, + "NEVER": 1, + "MOBILE_DATA_ONLY": 2, + "WIFI_AND_MOBILE_DATA": 3, + } +) + +func (x AccountData_CallsUseLessDataSetting) Enum() *AccountData_CallsUseLessDataSetting { + p := new(AccountData_CallsUseLessDataSetting) + *p = x + return p +} + +func (x AccountData_CallsUseLessDataSetting) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_CallsUseLessDataSetting) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[5].Descriptor() +} + +func (AccountData_CallsUseLessDataSetting) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[5] +} + +func (x AccountData_CallsUseLessDataSetting) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_CallsUseLessDataSetting.Descriptor instead. +func (AccountData_CallsUseLessDataSetting) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 3} +} + type AccountData_UsernameLink_Color int32 const ( @@ -261,11 +414,11 @@ func (x AccountData_UsernameLink_Color) String() string { } func (AccountData_UsernameLink_Color) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[3].Descriptor() + return file_backuppb_Backup_proto_enumTypes[6].Descriptor() } func (AccountData_UsernameLink_Color) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[3] + return &file_backuppb_Backup_proto_enumTypes[6] } func (x AccountData_UsernameLink_Color) Number() protoreflect.EnumNumber { @@ -277,6 +430,107 @@ func (AccountData_UsernameLink_Color) EnumDescriptor() ([]byte, []int) { return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 0, 0} } +type AccountData_AutoDownloadSettings_AutoDownloadOption int32 + +const ( + AccountData_AutoDownloadSettings_UNKNOWN AccountData_AutoDownloadSettings_AutoDownloadOption = 0 // Interpret as "Never" + AccountData_AutoDownloadSettings_NEVER AccountData_AutoDownloadSettings_AutoDownloadOption = 1 + AccountData_AutoDownloadSettings_WIFI AccountData_AutoDownloadSettings_AutoDownloadOption = 2 + AccountData_AutoDownloadSettings_WIFI_AND_CELLULAR AccountData_AutoDownloadSettings_AutoDownloadOption = 3 +) + +// Enum value maps for AccountData_AutoDownloadSettings_AutoDownloadOption. +var ( + AccountData_AutoDownloadSettings_AutoDownloadOption_name = map[int32]string{ + 0: "UNKNOWN", + 1: "NEVER", + 2: "WIFI", + 3: "WIFI_AND_CELLULAR", + } + AccountData_AutoDownloadSettings_AutoDownloadOption_value = map[string]int32{ + "UNKNOWN": 0, + "NEVER": 1, + "WIFI": 2, + "WIFI_AND_CELLULAR": 3, + } +) + +func (x AccountData_AutoDownloadSettings_AutoDownloadOption) Enum() *AccountData_AutoDownloadSettings_AutoDownloadOption { + p := new(AccountData_AutoDownloadSettings_AutoDownloadOption) + *p = x + return p +} + +func (x AccountData_AutoDownloadSettings_AutoDownloadOption) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_AutoDownloadSettings_AutoDownloadOption) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[7].Descriptor() +} + +func (AccountData_AutoDownloadSettings_AutoDownloadOption) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[7] +} + +func (x AccountData_AutoDownloadSettings_AutoDownloadOption) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_AutoDownloadSettings_AutoDownloadOption.Descriptor instead. +func (AccountData_AutoDownloadSettings_AutoDownloadOption) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 1, 0} +} + +type AccountData_AndroidSpecificSettings_NavigationBarSize int32 + +const ( + AccountData_AndroidSpecificSettings_UNKNOWN_BAR_SIZE AccountData_AndroidSpecificSettings_NavigationBarSize = 0 // Intepret as "Normal" + AccountData_AndroidSpecificSettings_NORMAL AccountData_AndroidSpecificSettings_NavigationBarSize = 1 + AccountData_AndroidSpecificSettings_COMPACT AccountData_AndroidSpecificSettings_NavigationBarSize = 2 +) + +// Enum value maps for AccountData_AndroidSpecificSettings_NavigationBarSize. +var ( + AccountData_AndroidSpecificSettings_NavigationBarSize_name = map[int32]string{ + 0: "UNKNOWN_BAR_SIZE", + 1: "NORMAL", + 2: "COMPACT", + } + AccountData_AndroidSpecificSettings_NavigationBarSize_value = map[string]int32{ + "UNKNOWN_BAR_SIZE": 0, + "NORMAL": 1, + "COMPACT": 2, + } +) + +func (x AccountData_AndroidSpecificSettings_NavigationBarSize) Enum() *AccountData_AndroidSpecificSettings_NavigationBarSize { + p := new(AccountData_AndroidSpecificSettings_NavigationBarSize) + *p = x + return p +} + +func (x AccountData_AndroidSpecificSettings_NavigationBarSize) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccountData_AndroidSpecificSettings_NavigationBarSize) Descriptor() protoreflect.EnumDescriptor { + return file_backuppb_Backup_proto_enumTypes[8].Descriptor() +} + +func (AccountData_AndroidSpecificSettings_NavigationBarSize) Type() protoreflect.EnumType { + return &file_backuppb_Backup_proto_enumTypes[8] +} + +func (x AccountData_AndroidSpecificSettings_NavigationBarSize) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccountData_AndroidSpecificSettings_NavigationBarSize.Descriptor instead. +func (AccountData_AndroidSpecificSettings_NavigationBarSize) EnumDescriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 5, 0} +} + type Contact_IdentityState int32 const ( @@ -310,11 +564,11 @@ func (x Contact_IdentityState) String() string { } func (Contact_IdentityState) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[4].Descriptor() + return file_backuppb_Backup_proto_enumTypes[9].Descriptor() } func (Contact_IdentityState) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[4] + return &file_backuppb_Backup_proto_enumTypes[9] } func (x Contact_IdentityState) Number() protoreflect.EnumNumber { @@ -359,11 +613,11 @@ func (x Contact_Visibility) String() string { } func (Contact_Visibility) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[5].Descriptor() + return file_backuppb_Backup_proto_enumTypes[10].Descriptor() } func (Contact_Visibility) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[5] + return &file_backuppb_Backup_proto_enumTypes[10] } func (x Contact_Visibility) Number() protoreflect.EnumNumber { @@ -408,11 +662,11 @@ func (x Group_StorySendMode) String() string { } func (Group_StorySendMode) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[6].Descriptor() + return file_backuppb_Backup_proto_enumTypes[11].Descriptor() } func (Group_StorySendMode) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[6] + return &file_backuppb_Backup_proto_enumTypes[11] } func (x Group_StorySendMode) Number() protoreflect.EnumNumber { @@ -457,11 +711,11 @@ func (x Group_Member_Role) String() string { } func (Group_Member_Role) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[7].Descriptor() + return file_backuppb_Backup_proto_enumTypes[12].Descriptor() } func (Group_Member_Role) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[7] + return &file_backuppb_Backup_proto_enumTypes[12] } func (x Group_Member_Role) Number() protoreflect.EnumNumber { @@ -512,11 +766,11 @@ func (x Group_AccessControl_AccessRequired) String() string { } func (Group_AccessControl_AccessRequired) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[8].Descriptor() + return file_backuppb_Backup_proto_enumTypes[13].Descriptor() } func (Group_AccessControl_AccessRequired) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[8] + return &file_backuppb_Backup_proto_enumTypes[13] } func (x Group_AccessControl_AccessRequired) Number() protoreflect.EnumNumber { @@ -561,11 +815,11 @@ func (x CallLink_Restrictions) String() string { } func (CallLink_Restrictions) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[9].Descriptor() + return file_backuppb_Backup_proto_enumTypes[14].Descriptor() } func (CallLink_Restrictions) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[9] + return &file_backuppb_Backup_proto_enumTypes[14] } func (x CallLink_Restrictions) Number() protoreflect.EnumNumber { @@ -607,11 +861,11 @@ func (x AdHocCall_State) String() string { } func (AdHocCall_State) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[10].Descriptor() + return file_backuppb_Backup_proto_enumTypes[15].Descriptor() } func (AdHocCall_State) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[10] + return &file_backuppb_Backup_proto_enumTypes[15] } func (x AdHocCall_State) Number() protoreflect.EnumNumber { @@ -659,11 +913,11 @@ func (x DistributionList_PrivacyMode) String() string { } func (DistributionList_PrivacyMode) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[11].Descriptor() + return file_backuppb_Backup_proto_enumTypes[16].Descriptor() } func (DistributionList_PrivacyMode) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[11] + return &file_backuppb_Backup_proto_enumTypes[16] } func (x DistributionList_PrivacyMode) Number() protoreflect.EnumNumber { @@ -708,11 +962,11 @@ func (x SendStatus_Failed_FailureReason) String() string { } func (SendStatus_Failed_FailureReason) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[12].Descriptor() + return file_backuppb_Backup_proto_enumTypes[17].Descriptor() } func (SendStatus_Failed_FailureReason) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[12] + return &file_backuppb_Backup_proto_enumTypes[17] } func (x SendStatus_Failed_FailureReason) Number() protoreflect.EnumNumber { @@ -757,11 +1011,11 @@ func (x PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) } func (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[13].Descriptor() + return file_backuppb_Backup_proto_enumTypes[18].Descriptor() } func (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[13] + return &file_backuppb_Backup_proto_enumTypes[18] } func (x PaymentNotification_TransactionDetails_FailedTransaction_FailureReason) Number() protoreflect.EnumNumber { @@ -806,11 +1060,11 @@ func (x PaymentNotification_TransactionDetails_Transaction_Status) String() stri } func (PaymentNotification_TransactionDetails_Transaction_Status) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[14].Descriptor() + return file_backuppb_Backup_proto_enumTypes[19].Descriptor() } func (PaymentNotification_TransactionDetails_Transaction_Status) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[14] + return &file_backuppb_Backup_proto_enumTypes[19] } func (x PaymentNotification_TransactionDetails_Transaction_Status) Number() protoreflect.EnumNumber { @@ -858,11 +1112,11 @@ func (x GiftBadge_State) String() string { } func (GiftBadge_State) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[15].Descriptor() + return file_backuppb_Backup_proto_enumTypes[20].Descriptor() } func (GiftBadge_State) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[15] + return &file_backuppb_Backup_proto_enumTypes[20] } func (x GiftBadge_State) Number() protoreflect.EnumNumber { @@ -913,11 +1167,11 @@ func (x ContactAttachment_Phone_Type) String() string { } func (ContactAttachment_Phone_Type) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[16].Descriptor() + return file_backuppb_Backup_proto_enumTypes[21].Descriptor() } func (ContactAttachment_Phone_Type) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[16] + return &file_backuppb_Backup_proto_enumTypes[21] } func (x ContactAttachment_Phone_Type) Number() protoreflect.EnumNumber { @@ -968,11 +1222,11 @@ func (x ContactAttachment_Email_Type) String() string { } func (ContactAttachment_Email_Type) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[17].Descriptor() + return file_backuppb_Backup_proto_enumTypes[22].Descriptor() } func (ContactAttachment_Email_Type) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[17] + return &file_backuppb_Backup_proto_enumTypes[22] } func (x ContactAttachment_Email_Type) Number() protoreflect.EnumNumber { @@ -1020,11 +1274,11 @@ func (x ContactAttachment_PostalAddress_Type) String() string { } func (ContactAttachment_PostalAddress_Type) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[18].Descriptor() + return file_backuppb_Backup_proto_enumTypes[23].Descriptor() } func (ContactAttachment_PostalAddress_Type) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[18] + return &file_backuppb_Backup_proto_enumTypes[23] } func (x ContactAttachment_PostalAddress_Type) Number() protoreflect.EnumNumber { @@ -1075,11 +1329,11 @@ func (x MessageAttachment_Flag) String() string { } func (MessageAttachment_Flag) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[19].Descriptor() + return file_backuppb_Backup_proto_enumTypes[24].Descriptor() } func (MessageAttachment_Flag) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[19] + return &file_backuppb_Backup_proto_enumTypes[24] } func (x MessageAttachment_Flag) Number() protoreflect.EnumNumber { @@ -1130,11 +1384,11 @@ func (x Quote_Type) String() string { } func (Quote_Type) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[20].Descriptor() + return file_backuppb_Backup_proto_enumTypes[25].Descriptor() } func (Quote_Type) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[20] + return &file_backuppb_Backup_proto_enumTypes[25] } func (x Quote_Type) Number() protoreflect.EnumNumber { @@ -1188,11 +1442,11 @@ func (x BodyRange_Style) String() string { } func (BodyRange_Style) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[21].Descriptor() + return file_backuppb_Backup_proto_enumTypes[26].Descriptor() } func (BodyRange_Style) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[21] + return &file_backuppb_Backup_proto_enumTypes[26] } func (x BodyRange_Style) Number() protoreflect.EnumNumber { @@ -1237,11 +1491,11 @@ func (x IndividualCall_Type) String() string { } func (IndividualCall_Type) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[22].Descriptor() + return file_backuppb_Backup_proto_enumTypes[27].Descriptor() } func (IndividualCall_Type) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[22] + return &file_backuppb_Backup_proto_enumTypes[27] } func (x IndividualCall_Type) Number() protoreflect.EnumNumber { @@ -1286,11 +1540,11 @@ func (x IndividualCall_Direction) String() string { } func (IndividualCall_Direction) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[23].Descriptor() + return file_backuppb_Backup_proto_enumTypes[28].Descriptor() } func (IndividualCall_Direction) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[23] + return &file_backuppb_Backup_proto_enumTypes[28] } func (x IndividualCall_Direction) Number() protoreflect.EnumNumber { @@ -1345,11 +1599,11 @@ func (x IndividualCall_State) String() string { } func (IndividualCall_State) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[24].Descriptor() + return file_backuppb_Backup_proto_enumTypes[29].Descriptor() } func (IndividualCall_State) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[24] + return &file_backuppb_Backup_proto_enumTypes[29] } func (x IndividualCall_State) Number() protoreflect.EnumNumber { @@ -1421,11 +1675,11 @@ func (x GroupCall_State) String() string { } func (GroupCall_State) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[25].Descriptor() + return file_backuppb_Backup_proto_enumTypes[30].Descriptor() } func (GroupCall_State) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[25] + return &file_backuppb_Backup_proto_enumTypes[30] } func (x GroupCall_State) Number() protoreflect.EnumNumber { @@ -1512,11 +1766,11 @@ func (x SimpleChatUpdate_Type) String() string { } func (SimpleChatUpdate_Type) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[26].Descriptor() + return file_backuppb_Backup_proto_enumTypes[31].Descriptor() } func (SimpleChatUpdate_Type) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[26] + return &file_backuppb_Backup_proto_enumTypes[31] } func (x SimpleChatUpdate_Type) Number() protoreflect.EnumNumber { @@ -1618,11 +1872,11 @@ func (x ChatStyle_WallpaperPreset) String() string { } func (ChatStyle_WallpaperPreset) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[27].Descriptor() + return file_backuppb_Backup_proto_enumTypes[32].Descriptor() } func (ChatStyle_WallpaperPreset) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[27] + return &file_backuppb_Backup_proto_enumTypes[32] } func (x ChatStyle_WallpaperPreset) Number() protoreflect.EnumNumber { @@ -1631,7 +1885,7 @@ func (x ChatStyle_WallpaperPreset) Number() protoreflect.EnumNumber { // Deprecated: Use ChatStyle_WallpaperPreset.Descriptor instead. func (ChatStyle_WallpaperPreset) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 0} } type ChatStyle_BubbleColorPreset int32 @@ -1727,11 +1981,11 @@ func (x ChatStyle_BubbleColorPreset) String() string { } func (ChatStyle_BubbleColorPreset) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[28].Descriptor() + return file_backuppb_Backup_proto_enumTypes[33].Descriptor() } func (ChatStyle_BubbleColorPreset) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[28] + return &file_backuppb_Backup_proto_enumTypes[33] } func (x ChatStyle_BubbleColorPreset) Number() protoreflect.EnumNumber { @@ -1740,7 +1994,7 @@ func (x ChatStyle_BubbleColorPreset) Number() protoreflect.EnumNumber { // Deprecated: Use ChatStyle_BubbleColorPreset.Descriptor instead. func (ChatStyle_BubbleColorPreset) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 1} } type NotificationProfile_DayOfWeek int32 @@ -1791,11 +2045,11 @@ func (x NotificationProfile_DayOfWeek) String() string { } func (NotificationProfile_DayOfWeek) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[29].Descriptor() + return file_backuppb_Backup_proto_enumTypes[34].Descriptor() } func (NotificationProfile_DayOfWeek) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[29] + return &file_backuppb_Backup_proto_enumTypes[34] } func (x NotificationProfile_DayOfWeek) Number() protoreflect.EnumNumber { @@ -1804,7 +2058,7 @@ func (x NotificationProfile_DayOfWeek) Number() protoreflect.EnumNumber { // Deprecated: Use NotificationProfile_DayOfWeek.Descriptor instead. func (NotificationProfile_DayOfWeek) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{81, 0} } // Represents the default "All chats" folder record vs all other custom folders @@ -1841,11 +2095,11 @@ func (x ChatFolder_FolderType) String() string { } func (ChatFolder_FolderType) Descriptor() protoreflect.EnumDescriptor { - return file_backuppb_Backup_proto_enumTypes[30].Descriptor() + return file_backuppb_Backup_proto_enumTypes[35].Descriptor() } func (ChatFolder_FolderType) Type() protoreflect.EnumType { - return &file_backuppb_Backup_proto_enumTypes[30] + return &file_backuppb_Backup_proto_enumTypes[35] } func (x ChatFolder_FolderType) Number() protoreflect.EnumNumber { @@ -1854,7 +2108,7 @@ func (x ChatFolder_FolderType) Number() protoreflect.EnumNumber { // Deprecated: Use ChatFolder_FolderType.Descriptor instead. func (ChatFolder_FolderType) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{81, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{82, 0} } type BackupInfo struct { @@ -2138,19 +2392,23 @@ func (*Frame_NotificationProfile) isFrame_Item() {} func (*Frame_ChatFolder) isFrame_Item() {} type AccountData struct { - state protoimpl.MessageState `protogen:"open.v1"` - ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` - Username *string `protobuf:"bytes,2,opt,name=username,proto3,oneof" json:"username,omitempty"` - UsernameLink *AccountData_UsernameLink `protobuf:"bytes,3,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` - GivenName string `protobuf:"bytes,4,opt,name=givenName,proto3" json:"givenName,omitempty"` - FamilyName string `protobuf:"bytes,5,opt,name=familyName,proto3" json:"familyName,omitempty"` - AvatarUrlPath string `protobuf:"bytes,6,opt,name=avatarUrlPath,proto3" json:"avatarUrlPath,omitempty"` - DonationSubscriberData *AccountData_SubscriberData `protobuf:"bytes,7,opt,name=donationSubscriberData,proto3" json:"donationSubscriberData,omitempty"` - AccountSettings *AccountData_AccountSettings `protobuf:"bytes,9,opt,name=accountSettings,proto3" json:"accountSettings,omitempty"` - BackupsSubscriberData *AccountData_IAPSubscriberData `protobuf:"bytes,10,opt,name=backupsSubscriberData,proto3" json:"backupsSubscriberData,omitempty"` - SvrPin string `protobuf:"bytes,11,opt,name=svrPin,proto3" json:"svrPin,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + ProfileKey []byte `protobuf:"bytes,1,opt,name=profileKey,proto3" json:"profileKey,omitempty"` + Username *string `protobuf:"bytes,2,opt,name=username,proto3,oneof" json:"username,omitempty"` + UsernameLink *AccountData_UsernameLink `protobuf:"bytes,3,opt,name=usernameLink,proto3" json:"usernameLink,omitempty"` + GivenName string `protobuf:"bytes,4,opt,name=givenName,proto3" json:"givenName,omitempty"` + FamilyName string `protobuf:"bytes,5,opt,name=familyName,proto3" json:"familyName,omitempty"` + AvatarUrlPath string `protobuf:"bytes,6,opt,name=avatarUrlPath,proto3" json:"avatarUrlPath,omitempty"` + DonationSubscriberData *AccountData_SubscriberData `protobuf:"bytes,7,opt,name=donationSubscriberData,proto3" json:"donationSubscriberData,omitempty"` + AccountSettings *AccountData_AccountSettings `protobuf:"bytes,9,opt,name=accountSettings,proto3" json:"accountSettings,omitempty"` + BackupsSubscriberData *AccountData_IAPSubscriberData `protobuf:"bytes,10,opt,name=backupsSubscriberData,proto3" json:"backupsSubscriberData,omitempty"` + SvrPin string `protobuf:"bytes,11,opt,name=svrPin,proto3" json:"svrPin,omitempty"` + AndroidSpecificSettings *AccountData_AndroidSpecificSettings `protobuf:"bytes,12,opt,name=androidSpecificSettings,proto3" json:"androidSpecificSettings,omitempty"` + BioText string `protobuf:"bytes,13,opt,name=bioText,proto3" json:"bioText,omitempty"` + BioEmoji string `protobuf:"bytes,14,opt,name=bioEmoji,proto3" json:"bioEmoji,omitempty"` + KeyTransparencyData []byte `protobuf:"bytes,15,opt,name=keyTransparencyData,proto3,oneof" json:"keyTransparencyData,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountData) Reset() { @@ -2253,6 +2511,34 @@ func (x *AccountData) GetSvrPin() string { return "" } +func (x *AccountData) GetAndroidSpecificSettings() *AccountData_AndroidSpecificSettings { + if x != nil { + return x.AndroidSpecificSettings + } + return nil +} + +func (x *AccountData) GetBioText() string { + if x != nil { + return x.BioText + } + return "" +} + +func (x *AccountData) GetBioEmoji() string { + if x != nil { + return x.BioEmoji + } + return "" +} + +func (x *AccountData) GetKeyTransparencyData() []byte { + if x != nil { + return x.KeyTransparencyData + } + return nil +} + type Recipient struct { state protoimpl.MessageState `protogen:"open.v1"` Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // generated id for reference only within this file @@ -2423,22 +2709,23 @@ type Contact struct { // // *Contact_Registered_ // *Contact_NotRegistered_ - Registration isContact_Registration `protobuf_oneof:"registration"` - ProfileKey []byte `protobuf:"bytes,9,opt,name=profileKey,proto3,oneof" json:"profileKey,omitempty"` - ProfileSharing bool `protobuf:"varint,10,opt,name=profileSharing,proto3" json:"profileSharing,omitempty"` - ProfileGivenName *string `protobuf:"bytes,11,opt,name=profileGivenName,proto3,oneof" json:"profileGivenName,omitempty"` - ProfileFamilyName *string `protobuf:"bytes,12,opt,name=profileFamilyName,proto3,oneof" json:"profileFamilyName,omitempty"` - HideStory bool `protobuf:"varint,13,opt,name=hideStory,proto3" json:"hideStory,omitempty"` - IdentityKey []byte `protobuf:"bytes,14,opt,name=identityKey,proto3,oneof" json:"identityKey,omitempty"` - IdentityState Contact_IdentityState `protobuf:"varint,15,opt,name=identityState,proto3,enum=signal.backup.Contact_IdentityState" json:"identityState,omitempty"` - Nickname *Contact_Name `protobuf:"bytes,16,opt,name=nickname,proto3" json:"nickname,omitempty"` // absent iff both `given` and `family` are empty - Note string `protobuf:"bytes,17,opt,name=note,proto3" json:"note,omitempty"` - SystemGivenName string `protobuf:"bytes,18,opt,name=systemGivenName,proto3" json:"systemGivenName,omitempty"` - SystemFamilyName string `protobuf:"bytes,19,opt,name=systemFamilyName,proto3" json:"systemFamilyName,omitempty"` - SystemNickname string `protobuf:"bytes,20,opt,name=systemNickname,proto3" json:"systemNickname,omitempty"` - AvatarColor *AvatarColor `protobuf:"varint,21,opt,name=avatarColor,proto3,enum=signal.backup.AvatarColor,oneof" json:"avatarColor,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Registration isContact_Registration `protobuf_oneof:"registration"` + ProfileKey []byte `protobuf:"bytes,9,opt,name=profileKey,proto3,oneof" json:"profileKey,omitempty"` + ProfileSharing bool `protobuf:"varint,10,opt,name=profileSharing,proto3" json:"profileSharing,omitempty"` + ProfileGivenName *string `protobuf:"bytes,11,opt,name=profileGivenName,proto3,oneof" json:"profileGivenName,omitempty"` + ProfileFamilyName *string `protobuf:"bytes,12,opt,name=profileFamilyName,proto3,oneof" json:"profileFamilyName,omitempty"` + HideStory bool `protobuf:"varint,13,opt,name=hideStory,proto3" json:"hideStory,omitempty"` + IdentityKey []byte `protobuf:"bytes,14,opt,name=identityKey,proto3,oneof" json:"identityKey,omitempty"` + IdentityState Contact_IdentityState `protobuf:"varint,15,opt,name=identityState,proto3,enum=signal.backup.Contact_IdentityState" json:"identityState,omitempty"` + Nickname *Contact_Name `protobuf:"bytes,16,opt,name=nickname,proto3" json:"nickname,omitempty"` // absent iff both `given` and `family` are empty + Note string `protobuf:"bytes,17,opt,name=note,proto3" json:"note,omitempty"` + SystemGivenName string `protobuf:"bytes,18,opt,name=systemGivenName,proto3" json:"systemGivenName,omitempty"` + SystemFamilyName string `protobuf:"bytes,19,opt,name=systemFamilyName,proto3" json:"systemFamilyName,omitempty"` + SystemNickname string `protobuf:"bytes,20,opt,name=systemNickname,proto3" json:"systemNickname,omitempty"` + AvatarColor *AvatarColor `protobuf:"varint,21,opt,name=avatarColor,proto3,enum=signal.backup.AvatarColor,oneof" json:"avatarColor,omitempty"` + KeyTransparencyData []byte `protobuf:"bytes,22,opt,name=keyTransparencyData,proto3,oneof" json:"keyTransparencyData,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Contact) Reset() { @@ -2629,6 +2916,13 @@ func (x *Contact) GetAvatarColor() AvatarColor { return AvatarColor_A100 } +func (x *Contact) GetKeyTransparencyData() []byte { + if x != nil { + return x.KeyTransparencyData + } + return nil +} + type isContact_Registration interface { isContact_Registration() } @@ -3286,7 +3580,8 @@ type ChatItem struct { // *ChatItem_ViewOnceMessage // *ChatItem_DirectStoryReplyMessage // *ChatItem_Poll - Item isChatItem_Item `protobuf_oneof:"item"` + Item isChatItem_Item `protobuf_oneof:"item"` + PinDetails *ChatItem_PinDetails `protobuf:"bytes,21,opt,name=pinDetails,proto3" json:"pinDetails,omitempty"` // only set if message is pinned unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3501,6 +3796,13 @@ func (x *ChatItem) GetPoll() *Poll { return nil } +func (x *ChatItem) GetPinDetails() *ChatItem_PinDetails { + if x != nil { + return x.PinDetails + } + return nil +} + type isChatItem_DirectionalDetails interface { isChatItem_DirectionalDetails() } @@ -4983,6 +5285,7 @@ type Poll struct { AllowMultiple bool `protobuf:"varint,2,opt,name=allowMultiple,proto3" json:"allowMultiple,omitempty"` Options []*Poll_PollOption `protobuf:"bytes,3,rep,name=options,proto3" json:"options,omitempty"` // At least two HasEnded bool `protobuf:"varint,4,opt,name=hasEnded,proto3" json:"hasEnded,omitempty"` + Reactions []*Reaction `protobuf:"bytes,5,rep,name=reactions,proto3" json:"reactions,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -5045,6 +5348,13 @@ func (x *Poll) GetHasEnded() bool { return false } +func (x *Poll) GetReactions() []*Reaction { + if x != nil { + return x.Reactions + } + return nil +} + type ChatUpdateMessage struct { state protoimpl.MessageState `protogen:"open.v1"` // If unset, importers should ignore the update message without throwing an error. @@ -5061,6 +5371,7 @@ type ChatUpdateMessage struct { // *ChatUpdateMessage_GroupCall // *ChatUpdateMessage_LearnedProfileChange // *ChatUpdateMessage_PollTerminate + // *ChatUpdateMessage_PinMessage Update isChatUpdateMessage_Update `protobuf_oneof:"update"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -5193,6 +5504,15 @@ func (x *ChatUpdateMessage) GetPollTerminate() *PollTerminateUpdate { return nil } +func (x *ChatUpdateMessage) GetPinMessage() *PinMessageUpdate { + if x != nil { + if x, ok := x.Update.(*ChatUpdateMessage_PinMessage); ok { + return x.PinMessage + } + } + return nil +} + type isChatUpdateMessage_Update interface { isChatUpdateMessage_Update() } @@ -5237,6 +5557,10 @@ type ChatUpdateMessage_PollTerminate struct { PollTerminate *PollTerminateUpdate `protobuf:"bytes,10,opt,name=pollTerminate,proto3,oneof"` } +type ChatUpdateMessage_PinMessage struct { + PinMessage *PinMessageUpdate `protobuf:"bytes,11,opt,name=pinMessage,proto3,oneof"` +} + func (*ChatUpdateMessage_SimpleUpdate) isChatUpdateMessage_Update() {} func (*ChatUpdateMessage_GroupChange) isChatUpdateMessage_Update() {} @@ -5257,6 +5581,8 @@ func (*ChatUpdateMessage_LearnedProfileChange) isChatUpdateMessage_Update() {} func (*ChatUpdateMessage_PollTerminate) isChatUpdateMessage_Update() {} +func (*ChatUpdateMessage_PinMessage) isChatUpdateMessage_Update() {} + type IndividualCall struct { state protoimpl.MessageState `protogen:"open.v1"` CallId *uint64 `protobuf:"varint,1,opt,name=callId,proto3,oneof" json:"callId,omitempty"` @@ -7532,6 +7858,58 @@ func (x *PollTerminateUpdate) GetQuestion() string { return "" } +type PinMessageUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetSentTimestamp uint64 `protobuf:"varint,1,opt,name=targetSentTimestamp,proto3" json:"targetSentTimestamp,omitempty"` + AuthorId uint64 `protobuf:"varint,2,opt,name=authorId,proto3" json:"authorId,omitempty"` // recipient id + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PinMessageUpdate) Reset() { + *x = PinMessageUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PinMessageUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PinMessageUpdate) ProtoMessage() {} + +func (x *PinMessageUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[78] + 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 PinMessageUpdate.ProtoReflect.Descriptor instead. +func (*PinMessageUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} +} + +func (x *PinMessageUpdate) GetTargetSentTimestamp() uint64 { + if x != nil { + return x.TargetSentTimestamp + } + return 0 +} + +func (x *PinMessageUpdate) GetAuthorId() uint64 { + if x != nil { + return x.AuthorId + } + return 0 +} + type StickerPack struct { state protoimpl.MessageState `protogen:"open.v1"` PackId []byte `protobuf:"bytes,1,opt,name=packId,proto3" json:"packId,omitempty"` @@ -7542,7 +7920,7 @@ type StickerPack struct { func (x *StickerPack) Reset() { *x = StickerPack{} - mi := &file_backuppb_Backup_proto_msgTypes[78] + mi := &file_backuppb_Backup_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7554,7 +7932,7 @@ func (x *StickerPack) String() string { func (*StickerPack) ProtoMessage() {} func (x *StickerPack) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[78] + mi := &file_backuppb_Backup_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7567,7 +7945,7 @@ func (x *StickerPack) ProtoReflect() protoreflect.Message { // Deprecated: Use StickerPack.ProtoReflect.Descriptor instead. func (*StickerPack) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} } func (x *StickerPack) GetPackId() []byte { @@ -7608,7 +7986,7 @@ type ChatStyle struct { func (x *ChatStyle) Reset() { *x = ChatStyle{} - mi := &file_backuppb_Backup_proto_msgTypes[79] + mi := &file_backuppb_Backup_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7620,7 +7998,7 @@ func (x *ChatStyle) String() string { func (*ChatStyle) ProtoMessage() {} func (x *ChatStyle) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[79] + mi := &file_backuppb_Backup_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7633,7 +8011,7 @@ func (x *ChatStyle) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle.ProtoReflect.Descriptor instead. func (*ChatStyle) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80} } func (x *ChatStyle) GetWallpaper() isChatStyle_Wallpaper { @@ -7765,7 +8143,7 @@ type NotificationProfile struct { func (x *NotificationProfile) Reset() { *x = NotificationProfile{} - mi := &file_backuppb_Backup_proto_msgTypes[80] + mi := &file_backuppb_Backup_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7777,7 +8155,7 @@ func (x *NotificationProfile) String() string { func (*NotificationProfile) ProtoMessage() {} func (x *NotificationProfile) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[80] + mi := &file_backuppb_Backup_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7790,7 +8168,7 @@ func (x *NotificationProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use NotificationProfile.ProtoReflect.Descriptor instead. func (*NotificationProfile) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{81} } func (x *NotificationProfile) GetName() string { @@ -7896,7 +8274,7 @@ type ChatFolder struct { func (x *ChatFolder) Reset() { *x = ChatFolder{} - mi := &file_backuppb_Backup_proto_msgTypes[81] + mi := &file_backuppb_Backup_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7908,7 +8286,7 @@ func (x *ChatFolder) String() string { func (*ChatFolder) ProtoMessage() {} func (x *ChatFolder) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[81] + mi := &file_backuppb_Backup_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7921,7 +8299,7 @@ func (x *ChatFolder) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatFolder.ProtoReflect.Descriptor instead. func (*ChatFolder) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{81} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{82} } func (x *ChatFolder) GetName() string { @@ -7998,7 +8376,7 @@ type AccountData_UsernameLink struct { func (x *AccountData_UsernameLink) Reset() { *x = AccountData_UsernameLink{} - mi := &file_backuppb_Backup_proto_msgTypes[82] + mi := &file_backuppb_Backup_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8010,7 +8388,7 @@ func (x *AccountData_UsernameLink) String() string { func (*AccountData_UsernameLink) ProtoMessage() {} func (x *AccountData_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[82] + mi := &file_backuppb_Backup_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8047,6 +8425,74 @@ func (x *AccountData_UsernameLink) GetColor() AccountData_UsernameLink_Color { return AccountData_UsernameLink_UNKNOWN } +type AccountData_AutoDownloadSettings struct { + state protoimpl.MessageState `protogen:"open.v1"` + Images AccountData_AutoDownloadSettings_AutoDownloadOption `protobuf:"varint,1,opt,name=images,proto3,enum=signal.backup.AccountData_AutoDownloadSettings_AutoDownloadOption" json:"images,omitempty"` + Audio AccountData_AutoDownloadSettings_AutoDownloadOption `protobuf:"varint,2,opt,name=audio,proto3,enum=signal.backup.AccountData_AutoDownloadSettings_AutoDownloadOption" json:"audio,omitempty"` + Video AccountData_AutoDownloadSettings_AutoDownloadOption `protobuf:"varint,3,opt,name=video,proto3,enum=signal.backup.AccountData_AutoDownloadSettings_AutoDownloadOption" json:"video,omitempty"` + Documents AccountData_AutoDownloadSettings_AutoDownloadOption `protobuf:"varint,4,opt,name=documents,proto3,enum=signal.backup.AccountData_AutoDownloadSettings_AutoDownloadOption" json:"documents,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData_AutoDownloadSettings) Reset() { + *x = AccountData_AutoDownloadSettings{} + mi := &file_backuppb_Backup_proto_msgTypes[84] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData_AutoDownloadSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData_AutoDownloadSettings) ProtoMessage() {} + +func (x *AccountData_AutoDownloadSettings) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[84] + 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 AccountData_AutoDownloadSettings.ProtoReflect.Descriptor instead. +func (*AccountData_AutoDownloadSettings) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *AccountData_AutoDownloadSettings) GetImages() AccountData_AutoDownloadSettings_AutoDownloadOption { + if x != nil { + return x.Images + } + return AccountData_AutoDownloadSettings_UNKNOWN +} + +func (x *AccountData_AutoDownloadSettings) GetAudio() AccountData_AutoDownloadSettings_AutoDownloadOption { + if x != nil { + return x.Audio + } + return AccountData_AutoDownloadSettings_UNKNOWN +} + +func (x *AccountData_AutoDownloadSettings) GetVideo() AccountData_AutoDownloadSettings_AutoDownloadOption { + if x != nil { + return x.Video + } + return AccountData_AutoDownloadSettings_UNKNOWN +} + +func (x *AccountData_AutoDownloadSettings) GetDocuments() AccountData_AutoDownloadSettings_AutoDownloadOption { + if x != nil { + return x.Documents + } + return AccountData_AutoDownloadSettings_UNKNOWN +} + type AccountData_AccountSettings struct { state protoimpl.MessageState `protogen:"open.v1"` ReadReceipts bool `protobuf:"varint,1,opt,name=readReceipts,proto3" json:"readReceipts,omitempty"` @@ -8070,14 +8516,22 @@ type AccountData_AccountSettings struct { CustomChatColors []*ChatStyle_CustomChatColor `protobuf:"bytes,19,rep,name=customChatColors,proto3" json:"customChatColors,omitempty"` OptimizeOnDeviceStorage bool `protobuf:"varint,20,opt,name=optimizeOnDeviceStorage,proto3" json:"optimizeOnDeviceStorage,omitempty"` // See zkgroup for integer particular values. Unset if backups are not enabled. - BackupTier *uint64 `protobuf:"varint,21,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + BackupTier *uint64 `protobuf:"varint,21,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` + DefaultSentMediaQuality AccountData_SentMediaQuality `protobuf:"varint,23,opt,name=defaultSentMediaQuality,proto3,enum=signal.backup.AccountData_SentMediaQuality" json:"defaultSentMediaQuality,omitempty"` + AutoDownloadSettings *AccountData_AutoDownloadSettings `protobuf:"bytes,24,opt,name=autoDownloadSettings,proto3" json:"autoDownloadSettings,omitempty"` + ScreenLockTimeoutMinutes *uint32 `protobuf:"varint,26,opt,name=screenLockTimeoutMinutes,proto3,oneof" json:"screenLockTimeoutMinutes,omitempty"` // If unset, consider screen lock to be disabled. + PinReminders *bool `protobuf:"varint,27,opt,name=pinReminders,proto3,oneof" json:"pinReminders,omitempty"` // If unset, consider pin reminders to be enabled. + AppTheme AccountData_AppTheme `protobuf:"varint,28,opt,name=appTheme,proto3,enum=signal.backup.AccountData_AppTheme" json:"appTheme,omitempty"` // If unset, treat the same as "Unknown" case + CallsUseLessDataSetting AccountData_CallsUseLessDataSetting `protobuf:"varint,29,opt,name=callsUseLessDataSetting,proto3,enum=signal.backup.AccountData_CallsUseLessDataSetting" json:"callsUseLessDataSetting,omitempty"` // If unset, treat the same as "Unknown" case + AllowSealedSenderFromAnyone bool `protobuf:"varint,30,opt,name=allowSealedSenderFromAnyone,proto3" json:"allowSealedSenderFromAnyone,omitempty"` + AllowAutomaticKeyVerification bool `protobuf:"varint,31,opt,name=allowAutomaticKeyVerification,proto3" json:"allowAutomaticKeyVerification,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountData_AccountSettings) Reset() { *x = AccountData_AccountSettings{} - mi := &file_backuppb_Backup_proto_msgTypes[83] + mi := &file_backuppb_Backup_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8089,7 +8543,7 @@ func (x *AccountData_AccountSettings) String() string { func (*AccountData_AccountSettings) ProtoMessage() {} func (x *AccountData_AccountSettings) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[83] + mi := &file_backuppb_Backup_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8102,7 +8556,7 @@ func (x *AccountData_AccountSettings) ProtoReflect() protoreflect.Message { // Deprecated: Use AccountData_AccountSettings.ProtoReflect.Descriptor instead. func (*AccountData_AccountSettings) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 2} } func (x *AccountData_AccountSettings) GetReadReceipts() bool { @@ -8252,6 +8706,62 @@ func (x *AccountData_AccountSettings) GetBackupTier() uint64 { return 0 } +func (x *AccountData_AccountSettings) GetDefaultSentMediaQuality() AccountData_SentMediaQuality { + if x != nil { + return x.DefaultSentMediaQuality + } + return AccountData_UNKNOWN_QUALITY +} + +func (x *AccountData_AccountSettings) GetAutoDownloadSettings() *AccountData_AutoDownloadSettings { + if x != nil { + return x.AutoDownloadSettings + } + return nil +} + +func (x *AccountData_AccountSettings) GetScreenLockTimeoutMinutes() uint32 { + if x != nil && x.ScreenLockTimeoutMinutes != nil { + return *x.ScreenLockTimeoutMinutes + } + return 0 +} + +func (x *AccountData_AccountSettings) GetPinReminders() bool { + if x != nil && x.PinReminders != nil { + return *x.PinReminders + } + return false +} + +func (x *AccountData_AccountSettings) GetAppTheme() AccountData_AppTheme { + if x != nil { + return x.AppTheme + } + return AccountData_UNKNOWN_APP_THEME +} + +func (x *AccountData_AccountSettings) GetCallsUseLessDataSetting() AccountData_CallsUseLessDataSetting { + if x != nil { + return x.CallsUseLessDataSetting + } + return AccountData_UNKNOWN_CALL_DATA_SETTING +} + +func (x *AccountData_AccountSettings) GetAllowSealedSenderFromAnyone() bool { + if x != nil { + return x.AllowSealedSenderFromAnyone + } + return false +} + +func (x *AccountData_AccountSettings) GetAllowAutomaticKeyVerification() bool { + if x != nil { + return x.AllowAutomaticKeyVerification + } + return false +} + type AccountData_SubscriberData struct { state protoimpl.MessageState `protogen:"open.v1"` SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` @@ -8263,7 +8773,7 @@ type AccountData_SubscriberData struct { func (x *AccountData_SubscriberData) Reset() { *x = AccountData_SubscriberData{} - mi := &file_backuppb_Backup_proto_msgTypes[84] + mi := &file_backuppb_Backup_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8275,7 +8785,7 @@ func (x *AccountData_SubscriberData) String() string { func (*AccountData_SubscriberData) ProtoMessage() {} func (x *AccountData_SubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[84] + mi := &file_backuppb_Backup_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8288,7 +8798,7 @@ func (x *AccountData_SubscriberData) ProtoReflect() protoreflect.Message { // Deprecated: Use AccountData_SubscriberData.ProtoReflect.Descriptor instead. func (*AccountData_SubscriberData) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 2} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 3} } func (x *AccountData_SubscriberData) GetSubscriberId() []byte { @@ -8328,7 +8838,7 @@ type AccountData_IAPSubscriberData struct { func (x *AccountData_IAPSubscriberData) Reset() { *x = AccountData_IAPSubscriberData{} - mi := &file_backuppb_Backup_proto_msgTypes[85] + mi := &file_backuppb_Backup_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8340,7 +8850,7 @@ func (x *AccountData_IAPSubscriberData) String() string { func (*AccountData_IAPSubscriberData) ProtoMessage() {} func (x *AccountData_IAPSubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[85] + mi := &file_backuppb_Backup_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8353,7 +8863,7 @@ func (x *AccountData_IAPSubscriberData) ProtoReflect() protoreflect.Message { // Deprecated: Use AccountData_IAPSubscriberData.ProtoReflect.Descriptor instead. func (*AccountData_IAPSubscriberData) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 3} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 4} } func (x *AccountData_IAPSubscriberData) GetSubscriberId() []byte { @@ -8408,6 +8918,66 @@ func (*AccountData_IAPSubscriberData_PurchaseToken) isAccountData_IAPSubscriberD func (*AccountData_IAPSubscriberData_OriginalTransactionId) isAccountData_IAPSubscriberData_IapSubscriptionId() { } +type AccountData_AndroidSpecificSettings struct { + state protoimpl.MessageState `protogen:"open.v1"` + UseSystemEmoji bool `protobuf:"varint,1,opt,name=useSystemEmoji,proto3" json:"useSystemEmoji,omitempty"` + ScreenshotSecurity bool `protobuf:"varint,2,opt,name=screenshotSecurity,proto3" json:"screenshotSecurity,omitempty"` + NavigationBarSize AccountData_AndroidSpecificSettings_NavigationBarSize `protobuf:"varint,3,opt,name=navigationBarSize,proto3,enum=signal.backup.AccountData_AndroidSpecificSettings_NavigationBarSize" json:"navigationBarSize,omitempty"` // If unset, treat the same as "Unknown" case + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AccountData_AndroidSpecificSettings) Reset() { + *x = AccountData_AndroidSpecificSettings{} + mi := &file_backuppb_Backup_proto_msgTypes[88] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AccountData_AndroidSpecificSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccountData_AndroidSpecificSettings) ProtoMessage() {} + +func (x *AccountData_AndroidSpecificSettings) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[88] + 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 AccountData_AndroidSpecificSettings.ProtoReflect.Descriptor instead. +func (*AccountData_AndroidSpecificSettings) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{2, 5} +} + +func (x *AccountData_AndroidSpecificSettings) GetUseSystemEmoji() bool { + if x != nil { + return x.UseSystemEmoji + } + return false +} + +func (x *AccountData_AndroidSpecificSettings) GetScreenshotSecurity() bool { + if x != nil { + return x.ScreenshotSecurity + } + return false +} + +func (x *AccountData_AndroidSpecificSettings) GetNavigationBarSize() AccountData_AndroidSpecificSettings_NavigationBarSize { + if x != nil { + return x.NavigationBarSize + } + return AccountData_AndroidSpecificSettings_UNKNOWN_BAR_SIZE +} + type Contact_Registered struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -8416,7 +8986,7 @@ type Contact_Registered struct { func (x *Contact_Registered) Reset() { *x = Contact_Registered{} - mi := &file_backuppb_Backup_proto_msgTypes[86] + mi := &file_backuppb_Backup_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8428,7 +8998,7 @@ func (x *Contact_Registered) String() string { func (*Contact_Registered) ProtoMessage() {} func (x *Contact_Registered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[86] + mi := &file_backuppb_Backup_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8453,7 +9023,7 @@ type Contact_NotRegistered struct { func (x *Contact_NotRegistered) Reset() { *x = Contact_NotRegistered{} - mi := &file_backuppb_Backup_proto_msgTypes[87] + mi := &file_backuppb_Backup_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8465,7 +9035,7 @@ func (x *Contact_NotRegistered) String() string { func (*Contact_NotRegistered) ProtoMessage() {} func (x *Contact_NotRegistered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[87] + mi := &file_backuppb_Backup_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8498,7 +9068,7 @@ type Contact_Name struct { func (x *Contact_Name) Reset() { *x = Contact_Name{} - mi := &file_backuppb_Backup_proto_msgTypes[88] + mi := &file_backuppb_Backup_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8510,7 +9080,7 @@ func (x *Contact_Name) String() string { func (*Contact_Name) ProtoMessage() {} func (x *Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[88] + mi := &file_backuppb_Backup_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8565,7 +9135,7 @@ type Group_GroupSnapshot struct { func (x *Group_GroupSnapshot) Reset() { *x = Group_GroupSnapshot{} - mi := &file_backuppb_Backup_proto_msgTypes[89] + mi := &file_backuppb_Backup_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8577,7 +9147,7 @@ func (x *Group_GroupSnapshot) String() string { func (*Group_GroupSnapshot) ProtoMessage() {} func (x *Group_GroupSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[89] + mi := &file_backuppb_Backup_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8694,7 +9264,7 @@ type Group_GroupAttributeBlob struct { func (x *Group_GroupAttributeBlob) Reset() { *x = Group_GroupAttributeBlob{} - mi := &file_backuppb_Backup_proto_msgTypes[90] + mi := &file_backuppb_Backup_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8706,7 +9276,7 @@ func (x *Group_GroupAttributeBlob) String() string { func (*Group_GroupAttributeBlob) ProtoMessage() {} func (x *Group_GroupAttributeBlob) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[90] + mi := &file_backuppb_Backup_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8804,7 +9374,7 @@ type Group_Member struct { func (x *Group_Member) Reset() { *x = Group_Member{} - mi := &file_backuppb_Backup_proto_msgTypes[91] + mi := &file_backuppb_Backup_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8816,7 +9386,7 @@ func (x *Group_Member) String() string { func (*Group_Member) ProtoMessage() {} func (x *Group_Member) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[91] + mi := &file_backuppb_Backup_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8864,7 +9434,7 @@ type Group_MemberPendingProfileKey struct { func (x *Group_MemberPendingProfileKey) Reset() { *x = Group_MemberPendingProfileKey{} - mi := &file_backuppb_Backup_proto_msgTypes[92] + mi := &file_backuppb_Backup_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8876,7 +9446,7 @@ func (x *Group_MemberPendingProfileKey) String() string { func (*Group_MemberPendingProfileKey) ProtoMessage() {} func (x *Group_MemberPendingProfileKey) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[92] + mi := &file_backuppb_Backup_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8923,7 +9493,7 @@ type Group_MemberPendingAdminApproval struct { func (x *Group_MemberPendingAdminApproval) Reset() { *x = Group_MemberPendingAdminApproval{} - mi := &file_backuppb_Backup_proto_msgTypes[93] + mi := &file_backuppb_Backup_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8935,7 +9505,7 @@ func (x *Group_MemberPendingAdminApproval) String() string { func (*Group_MemberPendingAdminApproval) ProtoMessage() {} func (x *Group_MemberPendingAdminApproval) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[93] + mi := &file_backuppb_Backup_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8975,7 +9545,7 @@ type Group_MemberBanned struct { func (x *Group_MemberBanned) Reset() { *x = Group_MemberBanned{} - mi := &file_backuppb_Backup_proto_msgTypes[94] + mi := &file_backuppb_Backup_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8987,7 +9557,7 @@ func (x *Group_MemberBanned) String() string { func (*Group_MemberBanned) ProtoMessage() {} func (x *Group_MemberBanned) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[94] + mi := &file_backuppb_Backup_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9028,7 +9598,7 @@ type Group_AccessControl struct { func (x *Group_AccessControl) Reset() { *x = Group_AccessControl{} - mi := &file_backuppb_Backup_proto_msgTypes[95] + mi := &file_backuppb_Backup_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9040,7 +9610,7 @@ func (x *Group_AccessControl) String() string { func (*Group_AccessControl) ProtoMessage() {} func (x *Group_AccessControl) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[95] + mi := &file_backuppb_Backup_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9089,7 +9659,7 @@ type ChatItem_IncomingMessageDetails struct { func (x *ChatItem_IncomingMessageDetails) Reset() { *x = ChatItem_IncomingMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[96] + mi := &file_backuppb_Backup_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9101,7 +9671,7 @@ func (x *ChatItem_IncomingMessageDetails) String() string { func (*ChatItem_IncomingMessageDetails) ProtoMessage() {} func (x *ChatItem_IncomingMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[96] + mi := &file_backuppb_Backup_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9155,7 +9725,7 @@ type ChatItem_OutgoingMessageDetails struct { func (x *ChatItem_OutgoingMessageDetails) Reset() { *x = ChatItem_OutgoingMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[97] + mi := &file_backuppb_Backup_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9167,7 +9737,7 @@ func (x *ChatItem_OutgoingMessageDetails) String() string { func (*ChatItem_OutgoingMessageDetails) ProtoMessage() {} func (x *ChatItem_OutgoingMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[97] + mi := &file_backuppb_Backup_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9205,7 +9775,7 @@ type ChatItem_DirectionlessMessageDetails struct { func (x *ChatItem_DirectionlessMessageDetails) Reset() { *x = ChatItem_DirectionlessMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[98] + mi := &file_backuppb_Backup_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9217,7 +9787,7 @@ func (x *ChatItem_DirectionlessMessageDetails) String() string { func (*ChatItem_DirectionlessMessageDetails) ProtoMessage() {} func (x *ChatItem_DirectionlessMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[98] + mi := &file_backuppb_Backup_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9233,6 +9803,96 @@ func (*ChatItem_DirectionlessMessageDetails) Descriptor() ([]byte, []int) { return file_backuppb_Backup_proto_rawDescGZIP(), []int{13, 2} } +type ChatItem_PinDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + PinnedAtTimestamp uint64 `protobuf:"varint,1,opt,name=pinnedAtTimestamp,proto3" json:"pinnedAtTimestamp,omitempty"` + // Types that are valid to be assigned to PinExpiry: + // + // *ChatItem_PinDetails_PinExpiresAtTimestamp + // *ChatItem_PinDetails_PinNeverExpires + PinExpiry isChatItem_PinDetails_PinExpiry `protobuf_oneof:"pinExpiry"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ChatItem_PinDetails) Reset() { + *x = ChatItem_PinDetails{} + mi := &file_backuppb_Backup_proto_msgTypes[102] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ChatItem_PinDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChatItem_PinDetails) ProtoMessage() {} + +func (x *ChatItem_PinDetails) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[102] + 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 ChatItem_PinDetails.ProtoReflect.Descriptor instead. +func (*ChatItem_PinDetails) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{13, 3} +} + +func (x *ChatItem_PinDetails) GetPinnedAtTimestamp() uint64 { + if x != nil { + return x.PinnedAtTimestamp + } + return 0 +} + +func (x *ChatItem_PinDetails) GetPinExpiry() isChatItem_PinDetails_PinExpiry { + if x != nil { + return x.PinExpiry + } + return nil +} + +func (x *ChatItem_PinDetails) GetPinExpiresAtTimestamp() uint64 { + if x != nil { + if x, ok := x.PinExpiry.(*ChatItem_PinDetails_PinExpiresAtTimestamp); ok { + return x.PinExpiresAtTimestamp + } + } + return 0 +} + +func (x *ChatItem_PinDetails) GetPinNeverExpires() bool { + if x != nil { + if x, ok := x.PinExpiry.(*ChatItem_PinDetails_PinNeverExpires); ok { + return x.PinNeverExpires + } + } + return false +} + +type isChatItem_PinDetails_PinExpiry interface { + isChatItem_PinDetails_PinExpiry() +} + +type ChatItem_PinDetails_PinExpiresAtTimestamp struct { + PinExpiresAtTimestamp uint64 `protobuf:"varint,2,opt,name=pinExpiresAtTimestamp,proto3,oneof"` // timestamp when the pin should expire +} + +type ChatItem_PinDetails_PinNeverExpires struct { + PinNeverExpires bool `protobuf:"varint,3,opt,name=pinNeverExpires,proto3,oneof"` +} + +func (*ChatItem_PinDetails_PinExpiresAtTimestamp) isChatItem_PinDetails_PinExpiry() {} + +func (*ChatItem_PinDetails_PinNeverExpires) isChatItem_PinDetails_PinExpiry() {} + type SendStatus_Pending struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -9241,7 +9901,7 @@ type SendStatus_Pending struct { func (x *SendStatus_Pending) Reset() { *x = SendStatus_Pending{} - mi := &file_backuppb_Backup_proto_msgTypes[99] + mi := &file_backuppb_Backup_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9253,7 +9913,7 @@ func (x *SendStatus_Pending) String() string { func (*SendStatus_Pending) ProtoMessage() {} func (x *SendStatus_Pending) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[99] + mi := &file_backuppb_Backup_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9278,7 +9938,7 @@ type SendStatus_Sent struct { func (x *SendStatus_Sent) Reset() { *x = SendStatus_Sent{} - mi := &file_backuppb_Backup_proto_msgTypes[100] + mi := &file_backuppb_Backup_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9290,7 +9950,7 @@ func (x *SendStatus_Sent) String() string { func (*SendStatus_Sent) ProtoMessage() {} func (x *SendStatus_Sent) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[100] + mi := &file_backuppb_Backup_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9322,7 +9982,7 @@ type SendStatus_Delivered struct { func (x *SendStatus_Delivered) Reset() { *x = SendStatus_Delivered{} - mi := &file_backuppb_Backup_proto_msgTypes[101] + mi := &file_backuppb_Backup_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9334,7 +9994,7 @@ func (x *SendStatus_Delivered) String() string { func (*SendStatus_Delivered) ProtoMessage() {} func (x *SendStatus_Delivered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[101] + mi := &file_backuppb_Backup_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9366,7 +10026,7 @@ type SendStatus_Read struct { func (x *SendStatus_Read) Reset() { *x = SendStatus_Read{} - mi := &file_backuppb_Backup_proto_msgTypes[102] + mi := &file_backuppb_Backup_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9378,7 +10038,7 @@ func (x *SendStatus_Read) String() string { func (*SendStatus_Read) ProtoMessage() {} func (x *SendStatus_Read) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[102] + mi := &file_backuppb_Backup_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9410,7 +10070,7 @@ type SendStatus_Viewed struct { func (x *SendStatus_Viewed) Reset() { *x = SendStatus_Viewed{} - mi := &file_backuppb_Backup_proto_msgTypes[103] + mi := &file_backuppb_Backup_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9422,7 +10082,7 @@ func (x *SendStatus_Viewed) String() string { func (*SendStatus_Viewed) ProtoMessage() {} func (x *SendStatus_Viewed) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[103] + mi := &file_backuppb_Backup_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9454,7 +10114,7 @@ type SendStatus_Skipped struct { func (x *SendStatus_Skipped) Reset() { *x = SendStatus_Skipped{} - mi := &file_backuppb_Backup_proto_msgTypes[104] + mi := &file_backuppb_Backup_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9466,7 +10126,7 @@ func (x *SendStatus_Skipped) String() string { func (*SendStatus_Skipped) ProtoMessage() {} func (x *SendStatus_Skipped) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[104] + mi := &file_backuppb_Backup_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9491,7 +10151,7 @@ type SendStatus_Failed struct { func (x *SendStatus_Failed) Reset() { *x = SendStatus_Failed{} - mi := &file_backuppb_Backup_proto_msgTypes[105] + mi := &file_backuppb_Backup_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9503,7 +10163,7 @@ func (x *SendStatus_Failed) String() string { func (*SendStatus_Failed) ProtoMessage() {} func (x *SendStatus_Failed) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[105] + mi := &file_backuppb_Backup_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9536,7 +10196,7 @@ type DirectStoryReplyMessage_TextReply struct { func (x *DirectStoryReplyMessage_TextReply) Reset() { *x = DirectStoryReplyMessage_TextReply{} - mi := &file_backuppb_Backup_proto_msgTypes[106] + mi := &file_backuppb_Backup_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9548,7 +10208,7 @@ func (x *DirectStoryReplyMessage_TextReply) String() string { func (*DirectStoryReplyMessage_TextReply) ProtoMessage() {} func (x *DirectStoryReplyMessage_TextReply) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[106] + mi := &file_backuppb_Backup_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9593,7 +10253,7 @@ type PaymentNotification_TransactionDetails struct { func (x *PaymentNotification_TransactionDetails) Reset() { *x = PaymentNotification_TransactionDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[107] + mi := &file_backuppb_Backup_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9605,7 +10265,7 @@ func (x *PaymentNotification_TransactionDetails) String() string { func (*PaymentNotification_TransactionDetails) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[107] + mi := &file_backuppb_Backup_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9674,7 +10334,7 @@ type PaymentNotification_TransactionDetails_MobileCoinTxoIdentification struct { func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Reset() { *x = PaymentNotification_TransactionDetails_MobileCoinTxoIdentification{} - mi := &file_backuppb_Backup_proto_msgTypes[108] + mi := &file_backuppb_Backup_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9686,7 +10346,7 @@ func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Str func (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[108] + mi := &file_backuppb_Backup_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9725,7 +10385,7 @@ type PaymentNotification_TransactionDetails_FailedTransaction struct { func (x *PaymentNotification_TransactionDetails_FailedTransaction) Reset() { *x = PaymentNotification_TransactionDetails_FailedTransaction{} - mi := &file_backuppb_Backup_proto_msgTypes[109] + mi := &file_backuppb_Backup_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9737,7 +10397,7 @@ func (x *PaymentNotification_TransactionDetails_FailedTransaction) String() stri func (*PaymentNotification_TransactionDetails_FailedTransaction) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_FailedTransaction) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[109] + mi := &file_backuppb_Backup_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9778,7 +10438,7 @@ type PaymentNotification_TransactionDetails_Transaction struct { func (x *PaymentNotification_TransactionDetails_Transaction) Reset() { *x = PaymentNotification_TransactionDetails_Transaction{} - mi := &file_backuppb_Backup_proto_msgTypes[110] + mi := &file_backuppb_Backup_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9790,7 +10450,7 @@ func (x *PaymentNotification_TransactionDetails_Transaction) String() string { func (*PaymentNotification_TransactionDetails_Transaction) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_Transaction) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[110] + mi := &file_backuppb_Backup_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9869,7 +10529,7 @@ type ContactAttachment_Name struct { func (x *ContactAttachment_Name) Reset() { *x = ContactAttachment_Name{} - mi := &file_backuppb_Backup_proto_msgTypes[111] + mi := &file_backuppb_Backup_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9881,7 +10541,7 @@ func (x *ContactAttachment_Name) String() string { func (*ContactAttachment_Name) ProtoMessage() {} func (x *ContactAttachment_Name) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[111] + mi := &file_backuppb_Backup_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9950,7 +10610,7 @@ type ContactAttachment_Phone struct { func (x *ContactAttachment_Phone) Reset() { *x = ContactAttachment_Phone{} - mi := &file_backuppb_Backup_proto_msgTypes[112] + mi := &file_backuppb_Backup_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9962,7 +10622,7 @@ func (x *ContactAttachment_Phone) String() string { func (*ContactAttachment_Phone) ProtoMessage() {} func (x *ContactAttachment_Phone) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[112] + mi := &file_backuppb_Backup_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10010,7 +10670,7 @@ type ContactAttachment_Email struct { func (x *ContactAttachment_Email) Reset() { *x = ContactAttachment_Email{} - mi := &file_backuppb_Backup_proto_msgTypes[113] + mi := &file_backuppb_Backup_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10022,7 +10682,7 @@ func (x *ContactAttachment_Email) String() string { func (*ContactAttachment_Email) ProtoMessage() {} func (x *ContactAttachment_Email) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[113] + mi := &file_backuppb_Backup_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10076,7 +10736,7 @@ type ContactAttachment_PostalAddress struct { func (x *ContactAttachment_PostalAddress) Reset() { *x = ContactAttachment_PostalAddress{} - mi := &file_backuppb_Backup_proto_msgTypes[114] + mi := &file_backuppb_Backup_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10088,7 +10748,7 @@ func (x *ContactAttachment_PostalAddress) String() string { func (*ContactAttachment_PostalAddress) ProtoMessage() {} func (x *ContactAttachment_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[114] + mi := &file_backuppb_Backup_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10203,7 +10863,7 @@ type FilePointer_LocatorInfo struct { func (x *FilePointer_LocatorInfo) Reset() { *x = FilePointer_LocatorInfo{} - mi := &file_backuppb_Backup_proto_msgTypes[115] + mi := &file_backuppb_Backup_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10215,7 +10875,7 @@ func (x *FilePointer_LocatorInfo) String() string { func (*FilePointer_LocatorInfo) ProtoMessage() {} func (x *FilePointer_LocatorInfo) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[115] + mi := &file_backuppb_Backup_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10335,7 +10995,7 @@ type Quote_QuotedAttachment struct { func (x *Quote_QuotedAttachment) Reset() { *x = Quote_QuotedAttachment{} - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10347,7 +11007,7 @@ func (x *Quote_QuotedAttachment) String() string { func (*Quote_QuotedAttachment) ProtoMessage() {} func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10394,7 +11054,7 @@ type Poll_PollOption struct { func (x *Poll_PollOption) Reset() { *x = Poll_PollOption{} - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10406,7 +11066,7 @@ func (x *Poll_PollOption) String() string { func (*Poll_PollOption) ProtoMessage() {} func (x *Poll_PollOption) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10446,7 +11106,7 @@ type Poll_PollOption_PollVote struct { func (x *Poll_PollOption_PollVote) Reset() { *x = Poll_PollOption_PollVote{} - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10458,7 +11118,7 @@ func (x *Poll_PollOption_PollVote) String() string { func (*Poll_PollOption_PollVote) ProtoMessage() {} func (x *Poll_PollOption_PollVote) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10535,7 +11195,7 @@ type GroupChangeChatUpdate_Update struct { func (x *GroupChangeChatUpdate_Update) Reset() { *x = GroupChangeChatUpdate_Update{} - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10547,7 +11207,7 @@ func (x *GroupChangeChatUpdate_Update) String() string { func (*GroupChangeChatUpdate_Update) ProtoMessage() {} func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11121,7 +11781,7 @@ type GroupInvitationRevokedUpdate_Invitee struct { func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { *x = GroupInvitationRevokedUpdate_Invitee{} - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11133,7 +11793,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) String() string { func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11181,7 +11841,7 @@ type ChatStyle_Gradient struct { func (x *ChatStyle_Gradient) Reset() { *x = ChatStyle_Gradient{} - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11193,7 +11853,7 @@ func (x *ChatStyle_Gradient) String() string { func (*ChatStyle_Gradient) ProtoMessage() {} func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11206,7 +11866,7 @@ func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_Gradient.ProtoReflect.Descriptor instead. func (*ChatStyle_Gradient) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 0} } func (x *ChatStyle_Gradient) GetAngle() uint32 { @@ -11246,7 +11906,7 @@ type ChatStyle_CustomChatColor struct { func (x *ChatStyle_CustomChatColor) Reset() { *x = ChatStyle_CustomChatColor{} - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11258,7 +11918,7 @@ func (x *ChatStyle_CustomChatColor) String() string { func (*ChatStyle_CustomChatColor) ProtoMessage() {} func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11271,7 +11931,7 @@ func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_CustomChatColor.ProtoReflect.Descriptor instead. func (*ChatStyle_CustomChatColor) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 1} } func (x *ChatStyle_CustomChatColor) GetId() uint64 { @@ -11330,7 +11990,7 @@ type ChatStyle_AutomaticBubbleColor struct { func (x *ChatStyle_AutomaticBubbleColor) Reset() { *x = ChatStyle_AutomaticBubbleColor{} - mi := &file_backuppb_Backup_proto_msgTypes[123] + mi := &file_backuppb_Backup_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11342,7 +12002,7 @@ func (x *ChatStyle_AutomaticBubbleColor) String() string { func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[123] + mi := &file_backuppb_Backup_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11355,7 +12015,7 @@ func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_AutomaticBubbleColor.ProtoReflect.Descriptor instead. func (*ChatStyle_AutomaticBubbleColor) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79, 2} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 2} } var File_backuppb_Backup_proto protoreflect.FileDescriptor @@ -11382,7 +12042,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "chatFolder\x18\b \x01(\v2\x19.signal.backup.ChatFolderH\x00R\n" + "chatFolderB\x06\n" + - "\x04item\"\xdf\x13\n" + + "\x04item\"\xf9\"\n" + "\vAccountData\x12\x1e\n" + "\n" + "profileKey\x18\x01 \x01(\fR\n" + @@ -11398,7 +12058,11 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x0faccountSettings\x18\t \x01(\v2*.signal.backup.AccountData.AccountSettingsR\x0faccountSettings\x12b\n" + "\x15backupsSubscriberData\x18\n" + " \x01(\v2,.signal.backup.AccountData.IAPSubscriberDataR\x15backupsSubscriberData\x12\x16\n" + - "\x06svrPin\x18\v \x01(\tR\x06svrPin\x1a\xf6\x01\n" + + "\x06svrPin\x18\v \x01(\tR\x06svrPin\x12l\n" + + "\x17androidSpecificSettings\x18\f \x01(\v22.signal.backup.AccountData.AndroidSpecificSettingsR\x17androidSpecificSettings\x12\x18\n" + + "\abioText\x18\r \x01(\tR\abioText\x12\x1a\n" + + "\bbioEmoji\x18\x0e \x01(\tR\bbioEmoji\x125\n" + + "\x13keyTransparencyData\x18\x0f \x01(\fH\x01R\x13keyTransparencyData\x88\x01\x01\x1a\xf6\x01\n" + "\fUsernameLink\x12\x18\n" + "\aentropy\x18\x01 \x01(\fR\aentropy\x12\x1a\n" + "\bserverId\x18\x02 \x01(\fR\bserverId\x12C\n" + @@ -11414,8 +12078,17 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x06ORANGE\x10\x06\x12\b\n" + "\x04PINK\x10\a\x12\n" + "\n" + - "\x06PURPLE\x10\b\x1a\xa2\n" + - "\n" + + "\x06PURPLE\x10\b\x1a\xd7\x03\n" + + "\x14AutoDownloadSettings\x12Z\n" + + "\x06images\x18\x01 \x01(\x0e2B.signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOptionR\x06images\x12X\n" + + "\x05audio\x18\x02 \x01(\x0e2B.signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOptionR\x05audio\x12X\n" + + "\x05video\x18\x03 \x01(\x0e2B.signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOptionR\x05video\x12`\n" + + "\tdocuments\x18\x04 \x01(\x0e2B.signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOptionR\tdocuments\"M\n" + + "\x12AutoDownloadOption\x12\v\n" + + "\aUNKNOWN\x10\x00\x12\t\n" + + "\x05NEVER\x10\x01\x12\b\n" + + "\x04WIFI\x10\x02\x12\x15\n" + + "\x11WIFI_AND_CELLULAR\x10\x03\x1a\xc9\x0f\n" + "\x0fAccountSettings\x12\"\n" + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x126\n" + "\x16sealedSenderIndicators\x18\x02 \x01(\bR\x16sealedSenderIndicators\x12*\n" + @@ -11440,9 +12113,19 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x17optimizeOnDeviceStorage\x18\x14 \x01(\bR\x17optimizeOnDeviceStorage\x12#\n" + "\n" + "backupTier\x18\x15 \x01(\x04H\x01R\n" + - "backupTier\x88\x01\x01B\x1b\n" + + "backupTier\x88\x01\x01\x12e\n" + + "\x17defaultSentMediaQuality\x18\x17 \x01(\x0e2+.signal.backup.AccountData.SentMediaQualityR\x17defaultSentMediaQuality\x12c\n" + + "\x14autoDownloadSettings\x18\x18 \x01(\v2/.signal.backup.AccountData.AutoDownloadSettingsR\x14autoDownloadSettings\x12?\n" + + "\x18screenLockTimeoutMinutes\x18\x1a \x01(\rH\x02R\x18screenLockTimeoutMinutes\x88\x01\x01\x12'\n" + + "\fpinReminders\x18\x1b \x01(\bH\x03R\fpinReminders\x88\x01\x01\x12?\n" + + "\bappTheme\x18\x1c \x01(\x0e2#.signal.backup.AccountData.AppThemeR\bappTheme\x12l\n" + + "\x17callsUseLessDataSetting\x18\x1d \x01(\x0e22.signal.backup.AccountData.CallsUseLessDataSettingR\x17callsUseLessDataSetting\x12@\n" + + "\x1ballowSealedSenderFromAnyone\x18\x1e \x01(\bR\x1ballowSealedSenderFromAnyone\x12D\n" + + "\x1dallowAutomaticKeyVerification\x18\x1f \x01(\bR\x1dallowAutomaticKeyVerificationB\x1b\n" + "\x19_storyViewReceiptsEnabledB\r\n" + - "\v_backupTier\x1a\x86\x01\n" + + "\v_backupTierB\x1b\n" + + "\x19_screenLockTimeoutMinutesB\x0f\n" + + "\r_pinRemindersJ\x04\b\x16\x10\x17J\x04\b\x19\x10\x1a\x1a\x86\x01\n" + "\x0eSubscriberData\x12\"\n" + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12\"\n" + "\fcurrencyCode\x18\x02 \x01(\tR\fcurrencyCode\x12,\n" + @@ -11451,13 +12134,38 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\fsubscriberId\x18\x01 \x01(\fR\fsubscriberId\x12&\n" + "\rpurchaseToken\x18\x02 \x01(\tH\x00R\rpurchaseToken\x126\n" + "\x15originalTransactionId\x18\x03 \x01(\x04H\x00R\x15originalTransactionIdB\x13\n" + - "\x11iapSubscriptionId\"@\n" + + "\x11iapSubscriptionId\x1a\xa9\x02\n" + + "\x17AndroidSpecificSettings\x12&\n" + + "\x0euseSystemEmoji\x18\x01 \x01(\bR\x0euseSystemEmoji\x12.\n" + + "\x12screenshotSecurity\x18\x02 \x01(\bR\x12screenshotSecurity\x12r\n" + + "\x11navigationBarSize\x18\x03 \x01(\x0e2D.signal.backup.AccountData.AndroidSpecificSettings.NavigationBarSizeR\x11navigationBarSize\"B\n" + + "\x11NavigationBarSize\x12\x14\n" + + "\x10UNKNOWN_BAR_SIZE\x10\x00\x12\n" + + "\n" + + "\x06NORMAL\x10\x01\x12\v\n" + + "\aCOMPACT\x10\x02\"@\n" + "\x16PhoneNumberSharingMode\x12\v\n" + "\aUNKNOWN\x10\x00\x12\r\n" + "\tEVERYBODY\x10\x01\x12\n" + "\n" + - "\x06NOBODY\x10\x02B\v\n" + - "\t_usernameJ\x04\b\b\x10\t\"\x84\x03\n" + + "\x06NOBODY\x10\x02\"?\n" + + "\x10SentMediaQuality\x12\x13\n" + + "\x0fUNKNOWN_QUALITY\x10\x00\x12\f\n" + + "\bSTANDARD\x10\x01\x12\b\n" + + "\x04HIGH\x10\x02\"B\n" + + "\bAppTheme\x12\x15\n" + + "\x11UNKNOWN_APP_THEME\x10\x00\x12\n" + + "\n" + + "\x06SYSTEM\x10\x01\x12\t\n" + + "\x05LIGHT\x10\x02\x12\b\n" + + "\x04DARK\x10\x03\"s\n" + + "\x17CallsUseLessDataSetting\x12\x1d\n" + + "\x19UNKNOWN_CALL_DATA_SETTING\x10\x00\x12\t\n" + + "\x05NEVER\x10\x01\x12\x14\n" + + "\x10MOBILE_DATA_ONLY\x10\x02\x12\x18\n" + + "\x14WIFI_AND_MOBILE_DATA\x10\x03B\v\n" + + "\t_usernameB\x16\n" + + "\x14_keyTransparencyDataJ\x04\b\b\x10\t\"\x84\x03\n" + "\tRecipient\x12\x0e\n" + "\x02id\x18\x01 \x01(\x04R\x02id\x122\n" + "\acontact\x18\x02 \x01(\v2\x16.signal.backup.ContactH\x00R\acontact\x12,\n" + @@ -11466,8 +12174,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x04self\x18\x05 \x01(\v2\x13.signal.backup.SelfH\x00R\x04self\x12A\n" + "\freleaseNotes\x18\x06 \x01(\v2\x1b.signal.backup.ReleaseNotesH\x00R\freleaseNotes\x125\n" + "\bcallLink\x18\a \x01(\v2\x17.signal.backup.CallLinkH\x00R\bcallLinkB\r\n" + - "\vdestination\"\xcb\n" + - "\n" + + "\vdestination\"\x9a\v\n" + "\aContact\x12\x15\n" + "\x03aci\x18\x01 \x01(\fH\x01R\x03aci\x88\x01\x01\x12\x15\n" + "\x03pni\x18\x02 \x01(\fH\x02R\x03pni\x88\x01\x01\x12\x1f\n" + @@ -11496,7 +12203,9 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x0fsystemGivenName\x18\x12 \x01(\tR\x0fsystemGivenName\x12*\n" + "\x10systemFamilyName\x18\x13 \x01(\tR\x10systemFamilyName\x12&\n" + "\x0esystemNickname\x18\x14 \x01(\tR\x0esystemNickname\x12A\n" + - "\vavatarColor\x18\x15 \x01(\x0e2\x1a.signal.backup.AvatarColorH\tR\vavatarColor\x88\x01\x01\x1a\f\n" + + "\vavatarColor\x18\x15 \x01(\x0e2\x1a.signal.backup.AvatarColorH\tR\vavatarColor\x88\x01\x01\x125\n" + + "\x13keyTransparencyData\x18\x16 \x01(\fH\n" + + "R\x13keyTransparencyData\x88\x01\x01\x1a\f\n" + "\n" + "Registered\x1aE\n" + "\rNotRegistered\x124\n" + @@ -11524,7 +12233,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x11_profileGivenNameB\x14\n" + "\x12_profileFamilyNameB\x0e\n" + "\f_identityKeyB\x0e\n" + - "\f_avatarColor\"\x8f\x12\n" + + "\f_avatarColorB\x16\n" + + "\x14_keyTransparencyData\"\x8f\x12\n" + "\x05Group\x12\x1c\n" + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12 \n" + "\vwhitelisted\x18\x02 \x01(\bR\vwhitelisted\x12\x1c\n" + @@ -11644,7 +12354,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tONLY_WITH\x10\x01\x12\x0e\n" + "\n" + "ALL_EXCEPT\x10\x02\x12\a\n" + - "\x03ALL\x10\x03\"\xf3\f\n" + + "\x03ALL\x10\x03\"\xe5\x0e\n" + "\bChatItem\x12\x16\n" + "\x06chatId\x18\x01 \x01(\x04R\x06chatId\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12\x1a\n" + @@ -11666,7 +12376,10 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tgiftBadge\x18\x11 \x01(\v2\x18.signal.backup.GiftBadgeH\x01R\tgiftBadge\x12J\n" + "\x0fviewOnceMessage\x18\x12 \x01(\v2\x1e.signal.backup.ViewOnceMessageH\x01R\x0fviewOnceMessage\x12b\n" + "\x17directStoryReplyMessage\x18\x13 \x01(\v2&.signal.backup.DirectStoryReplyMessageH\x01R\x17directStoryReplyMessage\x12)\n" + - "\x04poll\x18\x14 \x01(\v2\x13.signal.backup.PollH\x01R\x04poll\x1a\xb4\x01\n" + + "\x04poll\x18\x14 \x01(\v2\x13.signal.backup.PollH\x01R\x04poll\x12B\n" + + "\n" + + "pinDetails\x18\x15 \x01(\v2\".signal.backup.ChatItem.PinDetailsR\n" + + "pinDetails\x1a\xb4\x01\n" + "\x16IncomingMessageDetails\x12\"\n" + "\fdateReceived\x18\x01 \x01(\x04R\fdateReceived\x12+\n" + "\x0edateServerSent\x18\x02 \x01(\x04H\x00R\x0edateServerSent\x88\x01\x01\x12\x12\n" + @@ -11678,7 +12391,13 @@ const file_backuppb_Backup_proto_rawDesc = "" + "sendStatus\x18\x01 \x03(\v2\x19.signal.backup.SendStatusR\n" + "sendStatus\x12\"\n" + "\fdateReceived\x18\x02 \x01(\x04R\fdateReceived\x1a\x1d\n" + - "\x1bDirectionlessMessageDetailsB\x14\n" + + "\x1bDirectionlessMessageDetails\x1a\xab\x01\n" + + "\n" + + "PinDetails\x12,\n" + + "\x11pinnedAtTimestamp\x18\x01 \x01(\x04R\x11pinnedAtTimestamp\x126\n" + + "\x15pinExpiresAtTimestamp\x18\x02 \x01(\x04H\x00R\x15pinExpiresAtTimestamp\x12*\n" + + "\x0fpinNeverExpires\x18\x03 \x01(\bH\x00R\x0fpinNeverExpiresB\v\n" + + "\tpinExpiryB\x14\n" + "\x12directionalDetailsB\x06\n" + "\x04itemB\x12\n" + "\x10_expireStartDateB\x0e\n" + @@ -11974,19 +12693,20 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x05emoji\x18\x01 \x01(\tR\x05emoji\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12$\n" + "\rsentTimestamp\x18\x03 \x01(\x04R\rsentTimestamp\x12\x1c\n" + - "\tsortOrder\x18\x04 \x01(\x04R\tsortOrder\"\xc8\x02\n" + + "\tsortOrder\x18\x04 \x01(\x04R\tsortOrder\"\xff\x02\n" + "\x04Poll\x12\x1a\n" + "\bquestion\x18\x01 \x01(\tR\bquestion\x12$\n" + "\rallowMultiple\x18\x02 \x01(\bR\rallowMultiple\x128\n" + "\aoptions\x18\x03 \x03(\v2\x1e.signal.backup.Poll.PollOptionR\aoptions\x12\x1a\n" + - "\bhasEnded\x18\x04 \x01(\bR\bhasEnded\x1a\xa7\x01\n" + + "\bhasEnded\x18\x04 \x01(\bR\bhasEnded\x125\n" + + "\treactions\x18\x05 \x03(\v2\x17.signal.backup.ReactionR\treactions\x1a\xa7\x01\n" + "\n" + "PollOption\x12\x16\n" + "\x06option\x18\x01 \x01(\tR\x06option\x12=\n" + "\x05votes\x18\x02 \x03(\v2'.signal.backup.Poll.PollOption.PollVoteR\x05votes\x1aB\n" + "\bPollVote\x12\x18\n" + "\avoterId\x18\x01 \x01(\x04R\avoterId\x12\x1c\n" + - "\tvoteCount\x18\x02 \x01(\rR\tvoteCount\"\xb4\x06\n" + + "\tvoteCount\x18\x02 \x01(\rR\tvoteCount\"\xf7\x06\n" + "\x11ChatUpdateMessage\x12E\n" + "\fsimpleUpdate\x18\x01 \x01(\v2\x1f.signal.backup.SimpleChatUpdateH\x00R\fsimpleUpdate\x12H\n" + "\vgroupChange\x18\x02 \x01(\v2$.signal.backup.GroupChangeChatUpdateH\x00R\vgroupChange\x12`\n" + @@ -11998,7 +12718,10 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tgroupCall\x18\b \x01(\v2\x18.signal.backup.GroupCallH\x00R\tgroupCall\x12]\n" + "\x14learnedProfileChange\x18\t \x01(\v2'.signal.backup.LearnedProfileChatUpdateH\x00R\x14learnedProfileChange\x12J\n" + "\rpollTerminate\x18\n" + - " \x01(\v2\".signal.backup.PollTerminateUpdateH\x00R\rpollTerminateB\b\n" + + " \x01(\v2\".signal.backup.PollTerminateUpdateH\x00R\rpollTerminate\x12A\n" + + "\n" + + "pinMessage\x18\v \x01(\v2\x1f.signal.backup.PinMessageUpdateH\x00R\n" + + "pinMessageB\b\n" + "\x06update\"\x9d\x04\n" + "\x0eIndividualCall\x12\x1b\n" + "\x06callId\x18\x01 \x01(\x04H\x00R\x06callId\x88\x01\x01\x126\n" + @@ -12306,7 +13029,10 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\v_updaterAci\"c\n" + "\x13PollTerminateUpdate\x120\n" + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x12\x1a\n" + - "\bquestion\x18\x02 \x01(\tR\bquestion\"?\n" + + "\bquestion\x18\x02 \x01(\tR\bquestion\"`\n" + + "\x10PinMessageUpdate\x120\n" + + "\x13targetSentTimestamp\x18\x01 \x01(\x04R\x13targetSentTimestamp\x12\x1a\n" + + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\"?\n" + "\vStickerPack\x12\x16\n" + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + "\apackKey\x18\x02 \x01(\fR\apackKey\"\x80\r\n" + @@ -12465,348 +13191,370 @@ func file_backuppb_Backup_proto_rawDescGZIP() []byte { return file_backuppb_Backup_proto_rawDescData } -var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 31) -var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 124) +var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 36) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 128) var file_backuppb_Backup_proto_goTypes = []any{ - (AvatarColor)(0), // 0: signal.backup.AvatarColor - (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel - (AccountData_PhoneNumberSharingMode)(0), // 2: signal.backup.AccountData.PhoneNumberSharingMode - (AccountData_UsernameLink_Color)(0), // 3: signal.backup.AccountData.UsernameLink.Color - (Contact_IdentityState)(0), // 4: signal.backup.Contact.IdentityState - (Contact_Visibility)(0), // 5: signal.backup.Contact.Visibility - (Group_StorySendMode)(0), // 6: signal.backup.Group.StorySendMode - (Group_Member_Role)(0), // 7: signal.backup.Group.Member.Role - (Group_AccessControl_AccessRequired)(0), // 8: signal.backup.Group.AccessControl.AccessRequired - (CallLink_Restrictions)(0), // 9: signal.backup.CallLink.Restrictions - (AdHocCall_State)(0), // 10: signal.backup.AdHocCall.State - (DistributionList_PrivacyMode)(0), // 11: signal.backup.DistributionList.PrivacyMode - (SendStatus_Failed_FailureReason)(0), // 12: signal.backup.SendStatus.Failed.FailureReason - (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason)(0), // 13: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - (PaymentNotification_TransactionDetails_Transaction_Status)(0), // 14: signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - (GiftBadge_State)(0), // 15: signal.backup.GiftBadge.State - (ContactAttachment_Phone_Type)(0), // 16: signal.backup.ContactAttachment.Phone.Type - (ContactAttachment_Email_Type)(0), // 17: signal.backup.ContactAttachment.Email.Type - (ContactAttachment_PostalAddress_Type)(0), // 18: signal.backup.ContactAttachment.PostalAddress.Type - (MessageAttachment_Flag)(0), // 19: signal.backup.MessageAttachment.Flag - (Quote_Type)(0), // 20: signal.backup.Quote.Type - (BodyRange_Style)(0), // 21: signal.backup.BodyRange.Style - (IndividualCall_Type)(0), // 22: signal.backup.IndividualCall.Type - (IndividualCall_Direction)(0), // 23: signal.backup.IndividualCall.Direction - (IndividualCall_State)(0), // 24: signal.backup.IndividualCall.State - (GroupCall_State)(0), // 25: signal.backup.GroupCall.State - (SimpleChatUpdate_Type)(0), // 26: signal.backup.SimpleChatUpdate.Type - (ChatStyle_WallpaperPreset)(0), // 27: signal.backup.ChatStyle.WallpaperPreset - (ChatStyle_BubbleColorPreset)(0), // 28: signal.backup.ChatStyle.BubbleColorPreset - (NotificationProfile_DayOfWeek)(0), // 29: signal.backup.NotificationProfile.DayOfWeek - (ChatFolder_FolderType)(0), // 30: signal.backup.ChatFolder.FolderType - (*BackupInfo)(nil), // 31: signal.backup.BackupInfo - (*Frame)(nil), // 32: signal.backup.Frame - (*AccountData)(nil), // 33: signal.backup.AccountData - (*Recipient)(nil), // 34: signal.backup.Recipient - (*Contact)(nil), // 35: signal.backup.Contact - (*Group)(nil), // 36: signal.backup.Group - (*Self)(nil), // 37: signal.backup.Self - (*ReleaseNotes)(nil), // 38: signal.backup.ReleaseNotes - (*Chat)(nil), // 39: signal.backup.Chat - (*CallLink)(nil), // 40: signal.backup.CallLink - (*AdHocCall)(nil), // 41: signal.backup.AdHocCall - (*DistributionListItem)(nil), // 42: signal.backup.DistributionListItem - (*DistributionList)(nil), // 43: signal.backup.DistributionList - (*ChatItem)(nil), // 44: signal.backup.ChatItem - (*SendStatus)(nil), // 45: signal.backup.SendStatus - (*Text)(nil), // 46: signal.backup.Text - (*StandardMessage)(nil), // 47: signal.backup.StandardMessage - (*ContactMessage)(nil), // 48: signal.backup.ContactMessage - (*DirectStoryReplyMessage)(nil), // 49: signal.backup.DirectStoryReplyMessage - (*PaymentNotification)(nil), // 50: signal.backup.PaymentNotification - (*GiftBadge)(nil), // 51: signal.backup.GiftBadge - (*ViewOnceMessage)(nil), // 52: signal.backup.ViewOnceMessage - (*ContactAttachment)(nil), // 53: signal.backup.ContactAttachment - (*StickerMessage)(nil), // 54: signal.backup.StickerMessage - (*RemoteDeletedMessage)(nil), // 55: signal.backup.RemoteDeletedMessage - (*Sticker)(nil), // 56: signal.backup.Sticker - (*LinkPreview)(nil), // 57: signal.backup.LinkPreview - (*MessageAttachment)(nil), // 58: signal.backup.MessageAttachment - (*FilePointer)(nil), // 59: signal.backup.FilePointer - (*Quote)(nil), // 60: signal.backup.Quote - (*BodyRange)(nil), // 61: signal.backup.BodyRange - (*Reaction)(nil), // 62: signal.backup.Reaction - (*Poll)(nil), // 63: signal.backup.Poll - (*ChatUpdateMessage)(nil), // 64: signal.backup.ChatUpdateMessage - (*IndividualCall)(nil), // 65: signal.backup.IndividualCall - (*GroupCall)(nil), // 66: signal.backup.GroupCall - (*SimpleChatUpdate)(nil), // 67: signal.backup.SimpleChatUpdate - (*ExpirationTimerChatUpdate)(nil), // 68: signal.backup.ExpirationTimerChatUpdate - (*ProfileChangeChatUpdate)(nil), // 69: signal.backup.ProfileChangeChatUpdate - (*LearnedProfileChatUpdate)(nil), // 70: signal.backup.LearnedProfileChatUpdate - (*ThreadMergeChatUpdate)(nil), // 71: signal.backup.ThreadMergeChatUpdate - (*SessionSwitchoverChatUpdate)(nil), // 72: signal.backup.SessionSwitchoverChatUpdate - (*GroupChangeChatUpdate)(nil), // 73: signal.backup.GroupChangeChatUpdate - (*GenericGroupUpdate)(nil), // 74: signal.backup.GenericGroupUpdate - (*GroupCreationUpdate)(nil), // 75: signal.backup.GroupCreationUpdate - (*GroupNameUpdate)(nil), // 76: signal.backup.GroupNameUpdate - (*GroupAvatarUpdate)(nil), // 77: signal.backup.GroupAvatarUpdate - (*GroupDescriptionUpdate)(nil), // 78: signal.backup.GroupDescriptionUpdate - (*GroupMembershipAccessLevelChangeUpdate)(nil), // 79: signal.backup.GroupMembershipAccessLevelChangeUpdate - (*GroupAttributesAccessLevelChangeUpdate)(nil), // 80: signal.backup.GroupAttributesAccessLevelChangeUpdate - (*GroupAnnouncementOnlyChangeUpdate)(nil), // 81: signal.backup.GroupAnnouncementOnlyChangeUpdate - (*GroupAdminStatusUpdate)(nil), // 82: signal.backup.GroupAdminStatusUpdate - (*GroupMemberLeftUpdate)(nil), // 83: signal.backup.GroupMemberLeftUpdate - (*GroupMemberRemovedUpdate)(nil), // 84: signal.backup.GroupMemberRemovedUpdate - (*SelfInvitedToGroupUpdate)(nil), // 85: signal.backup.SelfInvitedToGroupUpdate - (*SelfInvitedOtherUserToGroupUpdate)(nil), // 86: signal.backup.SelfInvitedOtherUserToGroupUpdate - (*GroupUnknownInviteeUpdate)(nil), // 87: signal.backup.GroupUnknownInviteeUpdate - (*GroupInvitationAcceptedUpdate)(nil), // 88: signal.backup.GroupInvitationAcceptedUpdate - (*GroupInvitationDeclinedUpdate)(nil), // 89: signal.backup.GroupInvitationDeclinedUpdate - (*GroupMemberJoinedUpdate)(nil), // 90: signal.backup.GroupMemberJoinedUpdate - (*GroupMemberAddedUpdate)(nil), // 91: signal.backup.GroupMemberAddedUpdate - (*GroupSelfInvitationRevokedUpdate)(nil), // 92: signal.backup.GroupSelfInvitationRevokedUpdate - (*GroupInvitationRevokedUpdate)(nil), // 93: signal.backup.GroupInvitationRevokedUpdate - (*GroupJoinRequestUpdate)(nil), // 94: signal.backup.GroupJoinRequestUpdate - (*GroupJoinRequestApprovalUpdate)(nil), // 95: signal.backup.GroupJoinRequestApprovalUpdate - (*GroupJoinRequestCanceledUpdate)(nil), // 96: signal.backup.GroupJoinRequestCanceledUpdate - (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 97: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - (*GroupInviteLinkResetUpdate)(nil), // 98: signal.backup.GroupInviteLinkResetUpdate - (*GroupInviteLinkEnabledUpdate)(nil), // 99: signal.backup.GroupInviteLinkEnabledUpdate - (*GroupInviteLinkAdminApprovalUpdate)(nil), // 100: signal.backup.GroupInviteLinkAdminApprovalUpdate - (*GroupInviteLinkDisabledUpdate)(nil), // 101: signal.backup.GroupInviteLinkDisabledUpdate - (*GroupMemberJoinedByLinkUpdate)(nil), // 102: signal.backup.GroupMemberJoinedByLinkUpdate - (*GroupV2MigrationUpdate)(nil), // 103: signal.backup.GroupV2MigrationUpdate - (*GroupV2MigrationSelfInvitedUpdate)(nil), // 104: signal.backup.GroupV2MigrationSelfInvitedUpdate - (*GroupV2MigrationInvitedMembersUpdate)(nil), // 105: signal.backup.GroupV2MigrationInvitedMembersUpdate - (*GroupV2MigrationDroppedMembersUpdate)(nil), // 106: signal.backup.GroupV2MigrationDroppedMembersUpdate - (*GroupExpirationTimerUpdate)(nil), // 107: signal.backup.GroupExpirationTimerUpdate - (*PollTerminateUpdate)(nil), // 108: signal.backup.PollTerminateUpdate - (*StickerPack)(nil), // 109: signal.backup.StickerPack - (*ChatStyle)(nil), // 110: signal.backup.ChatStyle - (*NotificationProfile)(nil), // 111: signal.backup.NotificationProfile - (*ChatFolder)(nil), // 112: signal.backup.ChatFolder - (*AccountData_UsernameLink)(nil), // 113: signal.backup.AccountData.UsernameLink - (*AccountData_AccountSettings)(nil), // 114: signal.backup.AccountData.AccountSettings - (*AccountData_SubscriberData)(nil), // 115: signal.backup.AccountData.SubscriberData - (*AccountData_IAPSubscriberData)(nil), // 116: signal.backup.AccountData.IAPSubscriberData - (*Contact_Registered)(nil), // 117: signal.backup.Contact.Registered - (*Contact_NotRegistered)(nil), // 118: signal.backup.Contact.NotRegistered - (*Contact_Name)(nil), // 119: signal.backup.Contact.Name - (*Group_GroupSnapshot)(nil), // 120: signal.backup.Group.GroupSnapshot - (*Group_GroupAttributeBlob)(nil), // 121: signal.backup.Group.GroupAttributeBlob - (*Group_Member)(nil), // 122: signal.backup.Group.Member - (*Group_MemberPendingProfileKey)(nil), // 123: signal.backup.Group.MemberPendingProfileKey - (*Group_MemberPendingAdminApproval)(nil), // 124: signal.backup.Group.MemberPendingAdminApproval - (*Group_MemberBanned)(nil), // 125: signal.backup.Group.MemberBanned - (*Group_AccessControl)(nil), // 126: signal.backup.Group.AccessControl - (*ChatItem_IncomingMessageDetails)(nil), // 127: signal.backup.ChatItem.IncomingMessageDetails - (*ChatItem_OutgoingMessageDetails)(nil), // 128: signal.backup.ChatItem.OutgoingMessageDetails - (*ChatItem_DirectionlessMessageDetails)(nil), // 129: signal.backup.ChatItem.DirectionlessMessageDetails - (*SendStatus_Pending)(nil), // 130: signal.backup.SendStatus.Pending - (*SendStatus_Sent)(nil), // 131: signal.backup.SendStatus.Sent - (*SendStatus_Delivered)(nil), // 132: signal.backup.SendStatus.Delivered - (*SendStatus_Read)(nil), // 133: signal.backup.SendStatus.Read - (*SendStatus_Viewed)(nil), // 134: signal.backup.SendStatus.Viewed - (*SendStatus_Skipped)(nil), // 135: signal.backup.SendStatus.Skipped - (*SendStatus_Failed)(nil), // 136: signal.backup.SendStatus.Failed - (*DirectStoryReplyMessage_TextReply)(nil), // 137: signal.backup.DirectStoryReplyMessage.TextReply - (*PaymentNotification_TransactionDetails)(nil), // 138: signal.backup.PaymentNotification.TransactionDetails - (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 139: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 140: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - (*PaymentNotification_TransactionDetails_Transaction)(nil), // 141: signal.backup.PaymentNotification.TransactionDetails.Transaction - (*ContactAttachment_Name)(nil), // 142: signal.backup.ContactAttachment.Name - (*ContactAttachment_Phone)(nil), // 143: signal.backup.ContactAttachment.Phone - (*ContactAttachment_Email)(nil), // 144: signal.backup.ContactAttachment.Email - (*ContactAttachment_PostalAddress)(nil), // 145: signal.backup.ContactAttachment.PostalAddress - (*FilePointer_LocatorInfo)(nil), // 146: signal.backup.FilePointer.LocatorInfo - (*Quote_QuotedAttachment)(nil), // 147: signal.backup.Quote.QuotedAttachment - (*Poll_PollOption)(nil), // 148: signal.backup.Poll.PollOption - (*Poll_PollOption_PollVote)(nil), // 149: signal.backup.Poll.PollOption.PollVote - (*GroupChangeChatUpdate_Update)(nil), // 150: signal.backup.GroupChangeChatUpdate.Update - (*GroupInvitationRevokedUpdate_Invitee)(nil), // 151: signal.backup.GroupInvitationRevokedUpdate.Invitee - (*ChatStyle_Gradient)(nil), // 152: signal.backup.ChatStyle.Gradient - (*ChatStyle_CustomChatColor)(nil), // 153: signal.backup.ChatStyle.CustomChatColor - (*ChatStyle_AutomaticBubbleColor)(nil), // 154: signal.backup.ChatStyle.AutomaticBubbleColor + (AvatarColor)(0), // 0: signal.backup.AvatarColor + (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel + (AccountData_PhoneNumberSharingMode)(0), // 2: signal.backup.AccountData.PhoneNumberSharingMode + (AccountData_SentMediaQuality)(0), // 3: signal.backup.AccountData.SentMediaQuality + (AccountData_AppTheme)(0), // 4: signal.backup.AccountData.AppTheme + (AccountData_CallsUseLessDataSetting)(0), // 5: signal.backup.AccountData.CallsUseLessDataSetting + (AccountData_UsernameLink_Color)(0), // 6: signal.backup.AccountData.UsernameLink.Color + (AccountData_AutoDownloadSettings_AutoDownloadOption)(0), // 7: signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + (AccountData_AndroidSpecificSettings_NavigationBarSize)(0), // 8: signal.backup.AccountData.AndroidSpecificSettings.NavigationBarSize + (Contact_IdentityState)(0), // 9: signal.backup.Contact.IdentityState + (Contact_Visibility)(0), // 10: signal.backup.Contact.Visibility + (Group_StorySendMode)(0), // 11: signal.backup.Group.StorySendMode + (Group_Member_Role)(0), // 12: signal.backup.Group.Member.Role + (Group_AccessControl_AccessRequired)(0), // 13: signal.backup.Group.AccessControl.AccessRequired + (CallLink_Restrictions)(0), // 14: signal.backup.CallLink.Restrictions + (AdHocCall_State)(0), // 15: signal.backup.AdHocCall.State + (DistributionList_PrivacyMode)(0), // 16: signal.backup.DistributionList.PrivacyMode + (SendStatus_Failed_FailureReason)(0), // 17: signal.backup.SendStatus.Failed.FailureReason + (PaymentNotification_TransactionDetails_FailedTransaction_FailureReason)(0), // 18: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + (PaymentNotification_TransactionDetails_Transaction_Status)(0), // 19: signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + (GiftBadge_State)(0), // 20: signal.backup.GiftBadge.State + (ContactAttachment_Phone_Type)(0), // 21: signal.backup.ContactAttachment.Phone.Type + (ContactAttachment_Email_Type)(0), // 22: signal.backup.ContactAttachment.Email.Type + (ContactAttachment_PostalAddress_Type)(0), // 23: signal.backup.ContactAttachment.PostalAddress.Type + (MessageAttachment_Flag)(0), // 24: signal.backup.MessageAttachment.Flag + (Quote_Type)(0), // 25: signal.backup.Quote.Type + (BodyRange_Style)(0), // 26: signal.backup.BodyRange.Style + (IndividualCall_Type)(0), // 27: signal.backup.IndividualCall.Type + (IndividualCall_Direction)(0), // 28: signal.backup.IndividualCall.Direction + (IndividualCall_State)(0), // 29: signal.backup.IndividualCall.State + (GroupCall_State)(0), // 30: signal.backup.GroupCall.State + (SimpleChatUpdate_Type)(0), // 31: signal.backup.SimpleChatUpdate.Type + (ChatStyle_WallpaperPreset)(0), // 32: signal.backup.ChatStyle.WallpaperPreset + (ChatStyle_BubbleColorPreset)(0), // 33: signal.backup.ChatStyle.BubbleColorPreset + (NotificationProfile_DayOfWeek)(0), // 34: signal.backup.NotificationProfile.DayOfWeek + (ChatFolder_FolderType)(0), // 35: signal.backup.ChatFolder.FolderType + (*BackupInfo)(nil), // 36: signal.backup.BackupInfo + (*Frame)(nil), // 37: signal.backup.Frame + (*AccountData)(nil), // 38: signal.backup.AccountData + (*Recipient)(nil), // 39: signal.backup.Recipient + (*Contact)(nil), // 40: signal.backup.Contact + (*Group)(nil), // 41: signal.backup.Group + (*Self)(nil), // 42: signal.backup.Self + (*ReleaseNotes)(nil), // 43: signal.backup.ReleaseNotes + (*Chat)(nil), // 44: signal.backup.Chat + (*CallLink)(nil), // 45: signal.backup.CallLink + (*AdHocCall)(nil), // 46: signal.backup.AdHocCall + (*DistributionListItem)(nil), // 47: signal.backup.DistributionListItem + (*DistributionList)(nil), // 48: signal.backup.DistributionList + (*ChatItem)(nil), // 49: signal.backup.ChatItem + (*SendStatus)(nil), // 50: signal.backup.SendStatus + (*Text)(nil), // 51: signal.backup.Text + (*StandardMessage)(nil), // 52: signal.backup.StandardMessage + (*ContactMessage)(nil), // 53: signal.backup.ContactMessage + (*DirectStoryReplyMessage)(nil), // 54: signal.backup.DirectStoryReplyMessage + (*PaymentNotification)(nil), // 55: signal.backup.PaymentNotification + (*GiftBadge)(nil), // 56: signal.backup.GiftBadge + (*ViewOnceMessage)(nil), // 57: signal.backup.ViewOnceMessage + (*ContactAttachment)(nil), // 58: signal.backup.ContactAttachment + (*StickerMessage)(nil), // 59: signal.backup.StickerMessage + (*RemoteDeletedMessage)(nil), // 60: signal.backup.RemoteDeletedMessage + (*Sticker)(nil), // 61: signal.backup.Sticker + (*LinkPreview)(nil), // 62: signal.backup.LinkPreview + (*MessageAttachment)(nil), // 63: signal.backup.MessageAttachment + (*FilePointer)(nil), // 64: signal.backup.FilePointer + (*Quote)(nil), // 65: signal.backup.Quote + (*BodyRange)(nil), // 66: signal.backup.BodyRange + (*Reaction)(nil), // 67: signal.backup.Reaction + (*Poll)(nil), // 68: signal.backup.Poll + (*ChatUpdateMessage)(nil), // 69: signal.backup.ChatUpdateMessage + (*IndividualCall)(nil), // 70: signal.backup.IndividualCall + (*GroupCall)(nil), // 71: signal.backup.GroupCall + (*SimpleChatUpdate)(nil), // 72: signal.backup.SimpleChatUpdate + (*ExpirationTimerChatUpdate)(nil), // 73: signal.backup.ExpirationTimerChatUpdate + (*ProfileChangeChatUpdate)(nil), // 74: signal.backup.ProfileChangeChatUpdate + (*LearnedProfileChatUpdate)(nil), // 75: signal.backup.LearnedProfileChatUpdate + (*ThreadMergeChatUpdate)(nil), // 76: signal.backup.ThreadMergeChatUpdate + (*SessionSwitchoverChatUpdate)(nil), // 77: signal.backup.SessionSwitchoverChatUpdate + (*GroupChangeChatUpdate)(nil), // 78: signal.backup.GroupChangeChatUpdate + (*GenericGroupUpdate)(nil), // 79: signal.backup.GenericGroupUpdate + (*GroupCreationUpdate)(nil), // 80: signal.backup.GroupCreationUpdate + (*GroupNameUpdate)(nil), // 81: signal.backup.GroupNameUpdate + (*GroupAvatarUpdate)(nil), // 82: signal.backup.GroupAvatarUpdate + (*GroupDescriptionUpdate)(nil), // 83: signal.backup.GroupDescriptionUpdate + (*GroupMembershipAccessLevelChangeUpdate)(nil), // 84: signal.backup.GroupMembershipAccessLevelChangeUpdate + (*GroupAttributesAccessLevelChangeUpdate)(nil), // 85: signal.backup.GroupAttributesAccessLevelChangeUpdate + (*GroupAnnouncementOnlyChangeUpdate)(nil), // 86: signal.backup.GroupAnnouncementOnlyChangeUpdate + (*GroupAdminStatusUpdate)(nil), // 87: signal.backup.GroupAdminStatusUpdate + (*GroupMemberLeftUpdate)(nil), // 88: signal.backup.GroupMemberLeftUpdate + (*GroupMemberRemovedUpdate)(nil), // 89: signal.backup.GroupMemberRemovedUpdate + (*SelfInvitedToGroupUpdate)(nil), // 90: signal.backup.SelfInvitedToGroupUpdate + (*SelfInvitedOtherUserToGroupUpdate)(nil), // 91: signal.backup.SelfInvitedOtherUserToGroupUpdate + (*GroupUnknownInviteeUpdate)(nil), // 92: signal.backup.GroupUnknownInviteeUpdate + (*GroupInvitationAcceptedUpdate)(nil), // 93: signal.backup.GroupInvitationAcceptedUpdate + (*GroupInvitationDeclinedUpdate)(nil), // 94: signal.backup.GroupInvitationDeclinedUpdate + (*GroupMemberJoinedUpdate)(nil), // 95: signal.backup.GroupMemberJoinedUpdate + (*GroupMemberAddedUpdate)(nil), // 96: signal.backup.GroupMemberAddedUpdate + (*GroupSelfInvitationRevokedUpdate)(nil), // 97: signal.backup.GroupSelfInvitationRevokedUpdate + (*GroupInvitationRevokedUpdate)(nil), // 98: signal.backup.GroupInvitationRevokedUpdate + (*GroupJoinRequestUpdate)(nil), // 99: signal.backup.GroupJoinRequestUpdate + (*GroupJoinRequestApprovalUpdate)(nil), // 100: signal.backup.GroupJoinRequestApprovalUpdate + (*GroupJoinRequestCanceledUpdate)(nil), // 101: signal.backup.GroupJoinRequestCanceledUpdate + (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 102: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + (*GroupInviteLinkResetUpdate)(nil), // 103: signal.backup.GroupInviteLinkResetUpdate + (*GroupInviteLinkEnabledUpdate)(nil), // 104: signal.backup.GroupInviteLinkEnabledUpdate + (*GroupInviteLinkAdminApprovalUpdate)(nil), // 105: signal.backup.GroupInviteLinkAdminApprovalUpdate + (*GroupInviteLinkDisabledUpdate)(nil), // 106: signal.backup.GroupInviteLinkDisabledUpdate + (*GroupMemberJoinedByLinkUpdate)(nil), // 107: signal.backup.GroupMemberJoinedByLinkUpdate + (*GroupV2MigrationUpdate)(nil), // 108: signal.backup.GroupV2MigrationUpdate + (*GroupV2MigrationSelfInvitedUpdate)(nil), // 109: signal.backup.GroupV2MigrationSelfInvitedUpdate + (*GroupV2MigrationInvitedMembersUpdate)(nil), // 110: signal.backup.GroupV2MigrationInvitedMembersUpdate + (*GroupV2MigrationDroppedMembersUpdate)(nil), // 111: signal.backup.GroupV2MigrationDroppedMembersUpdate + (*GroupExpirationTimerUpdate)(nil), // 112: signal.backup.GroupExpirationTimerUpdate + (*PollTerminateUpdate)(nil), // 113: signal.backup.PollTerminateUpdate + (*PinMessageUpdate)(nil), // 114: signal.backup.PinMessageUpdate + (*StickerPack)(nil), // 115: signal.backup.StickerPack + (*ChatStyle)(nil), // 116: signal.backup.ChatStyle + (*NotificationProfile)(nil), // 117: signal.backup.NotificationProfile + (*ChatFolder)(nil), // 118: signal.backup.ChatFolder + (*AccountData_UsernameLink)(nil), // 119: signal.backup.AccountData.UsernameLink + (*AccountData_AutoDownloadSettings)(nil), // 120: signal.backup.AccountData.AutoDownloadSettings + (*AccountData_AccountSettings)(nil), // 121: signal.backup.AccountData.AccountSettings + (*AccountData_SubscriberData)(nil), // 122: signal.backup.AccountData.SubscriberData + (*AccountData_IAPSubscriberData)(nil), // 123: signal.backup.AccountData.IAPSubscriberData + (*AccountData_AndroidSpecificSettings)(nil), // 124: signal.backup.AccountData.AndroidSpecificSettings + (*Contact_Registered)(nil), // 125: signal.backup.Contact.Registered + (*Contact_NotRegistered)(nil), // 126: signal.backup.Contact.NotRegistered + (*Contact_Name)(nil), // 127: signal.backup.Contact.Name + (*Group_GroupSnapshot)(nil), // 128: signal.backup.Group.GroupSnapshot + (*Group_GroupAttributeBlob)(nil), // 129: signal.backup.Group.GroupAttributeBlob + (*Group_Member)(nil), // 130: signal.backup.Group.Member + (*Group_MemberPendingProfileKey)(nil), // 131: signal.backup.Group.MemberPendingProfileKey + (*Group_MemberPendingAdminApproval)(nil), // 132: signal.backup.Group.MemberPendingAdminApproval + (*Group_MemberBanned)(nil), // 133: signal.backup.Group.MemberBanned + (*Group_AccessControl)(nil), // 134: signal.backup.Group.AccessControl + (*ChatItem_IncomingMessageDetails)(nil), // 135: signal.backup.ChatItem.IncomingMessageDetails + (*ChatItem_OutgoingMessageDetails)(nil), // 136: signal.backup.ChatItem.OutgoingMessageDetails + (*ChatItem_DirectionlessMessageDetails)(nil), // 137: signal.backup.ChatItem.DirectionlessMessageDetails + (*ChatItem_PinDetails)(nil), // 138: signal.backup.ChatItem.PinDetails + (*SendStatus_Pending)(nil), // 139: signal.backup.SendStatus.Pending + (*SendStatus_Sent)(nil), // 140: signal.backup.SendStatus.Sent + (*SendStatus_Delivered)(nil), // 141: signal.backup.SendStatus.Delivered + (*SendStatus_Read)(nil), // 142: signal.backup.SendStatus.Read + (*SendStatus_Viewed)(nil), // 143: signal.backup.SendStatus.Viewed + (*SendStatus_Skipped)(nil), // 144: signal.backup.SendStatus.Skipped + (*SendStatus_Failed)(nil), // 145: signal.backup.SendStatus.Failed + (*DirectStoryReplyMessage_TextReply)(nil), // 146: signal.backup.DirectStoryReplyMessage.TextReply + (*PaymentNotification_TransactionDetails)(nil), // 147: signal.backup.PaymentNotification.TransactionDetails + (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 148: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 149: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + (*PaymentNotification_TransactionDetails_Transaction)(nil), // 150: signal.backup.PaymentNotification.TransactionDetails.Transaction + (*ContactAttachment_Name)(nil), // 151: signal.backup.ContactAttachment.Name + (*ContactAttachment_Phone)(nil), // 152: signal.backup.ContactAttachment.Phone + (*ContactAttachment_Email)(nil), // 153: signal.backup.ContactAttachment.Email + (*ContactAttachment_PostalAddress)(nil), // 154: signal.backup.ContactAttachment.PostalAddress + (*FilePointer_LocatorInfo)(nil), // 155: signal.backup.FilePointer.LocatorInfo + (*Quote_QuotedAttachment)(nil), // 156: signal.backup.Quote.QuotedAttachment + (*Poll_PollOption)(nil), // 157: signal.backup.Poll.PollOption + (*Poll_PollOption_PollVote)(nil), // 158: signal.backup.Poll.PollOption.PollVote + (*GroupChangeChatUpdate_Update)(nil), // 159: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 160: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 161: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 162: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 163: signal.backup.ChatStyle.AutomaticBubbleColor } var file_backuppb_Backup_proto_depIdxs = []int32{ - 33, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData - 34, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient - 39, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat - 44, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem - 109, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack - 41, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall - 111, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile - 112, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder - 113, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink - 115, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData - 114, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings - 116, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData - 35, // 12: signal.backup.Recipient.contact:type_name -> signal.backup.Contact - 36, // 13: signal.backup.Recipient.group:type_name -> signal.backup.Group - 42, // 14: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem - 37, // 15: signal.backup.Recipient.self:type_name -> signal.backup.Self - 38, // 16: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes - 40, // 17: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink - 5, // 18: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility - 117, // 19: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered - 118, // 20: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered - 4, // 21: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState - 119, // 22: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name - 0, // 23: signal.backup.Contact.avatarColor:type_name -> signal.backup.AvatarColor - 6, // 24: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode - 120, // 25: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot - 0, // 26: signal.backup.Group.avatarColor:type_name -> signal.backup.AvatarColor - 0, // 27: signal.backup.Self.avatarColor:type_name -> signal.backup.AvatarColor - 110, // 28: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle - 9, // 29: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions - 10, // 30: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State - 43, // 31: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList - 11, // 32: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode - 44, // 33: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem - 127, // 34: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails - 128, // 35: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails - 129, // 36: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails - 47, // 37: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage - 48, // 38: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage - 54, // 39: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage - 55, // 40: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage - 64, // 41: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage - 50, // 42: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification - 51, // 43: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge - 52, // 44: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage - 49, // 45: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage - 63, // 46: signal.backup.ChatItem.poll:type_name -> signal.backup.Poll - 130, // 47: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending - 131, // 48: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent - 132, // 49: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered - 133, // 50: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read - 134, // 51: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed - 135, // 52: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped - 136, // 53: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed - 61, // 54: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange - 60, // 55: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote - 46, // 56: signal.backup.StandardMessage.text:type_name -> signal.backup.Text - 58, // 57: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment - 57, // 58: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview - 59, // 59: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer - 62, // 60: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction - 53, // 61: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment - 62, // 62: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction - 137, // 63: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply - 62, // 64: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction - 138, // 65: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails - 15, // 66: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State - 58, // 67: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment - 62, // 68: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction - 142, // 69: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name - 143, // 70: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone - 144, // 71: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email - 145, // 72: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress - 59, // 73: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer - 56, // 74: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker - 62, // 75: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction - 59, // 76: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer - 59, // 77: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer - 59, // 78: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer - 19, // 79: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag - 146, // 80: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo - 46, // 81: signal.backup.Quote.text:type_name -> signal.backup.Text - 147, // 82: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 20, // 83: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 21, // 84: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 148, // 85: signal.backup.Poll.options:type_name -> signal.backup.Poll.PollOption - 67, // 86: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 73, // 87: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 68, // 88: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 69, // 89: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 71, // 90: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 72, // 91: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 65, // 92: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 66, // 93: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 70, // 94: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 108, // 95: signal.backup.ChatUpdateMessage.pollTerminate:type_name -> signal.backup.PollTerminateUpdate - 22, // 96: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 23, // 97: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 24, // 98: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 25, // 99: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 26, // 100: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 150, // 101: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 1, // 102: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 1, // 103: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 151, // 104: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 27, // 105: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 59, // 106: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 154, // 107: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 28, // 108: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 29, // 109: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 30, // 110: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 3, // 111: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 2, // 112: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 110, // 113: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 153, // 114: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 121, // 115: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 121, // 116: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 121, // 117: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 126, // 118: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 122, // 119: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 123, // 120: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 124, // 121: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 125, // 122: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 7, // 123: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 122, // 124: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 8, // 125: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 126: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 8, // 127: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 45, // 128: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 12, // 129: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 46, // 130: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 59, // 131: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 141, // 132: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 140, // 133: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 13, // 134: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 14, // 135: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 139, // 136: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 16, // 137: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 17, // 138: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 18, // 139: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 58, // 140: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 149, // 141: signal.backup.Poll.PollOption.votes:type_name -> signal.backup.Poll.PollOption.PollVote - 74, // 142: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 75, // 143: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 76, // 144: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 77, // 145: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 78, // 146: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 79, // 147: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 80, // 148: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 81, // 149: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 82, // 150: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 83, // 151: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 84, // 152: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 85, // 153: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 86, // 154: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 87, // 155: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 88, // 156: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 89, // 157: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 90, // 158: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 91, // 159: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 92, // 160: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 93, // 161: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 94, // 162: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 95, // 163: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 96, // 164: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 98, // 165: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 99, // 166: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 100, // 167: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 101, // 168: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 102, // 169: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 103, // 170: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 104, // 171: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 105, // 172: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 106, // 173: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 97, // 174: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 107, // 175: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 152, // 176: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 177, // [177:177] is the sub-list for method output_type - 177, // [177:177] is the sub-list for method input_type - 177, // [177:177] is the sub-list for extension type_name - 177, // [177:177] is the sub-list for extension extendee - 0, // [0:177] is the sub-list for field type_name + 38, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData + 39, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient + 44, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat + 49, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem + 115, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack + 46, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall + 117, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile + 118, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder + 119, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink + 122, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData + 121, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings + 123, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData + 124, // 12: signal.backup.AccountData.androidSpecificSettings:type_name -> signal.backup.AccountData.AndroidSpecificSettings + 40, // 13: signal.backup.Recipient.contact:type_name -> signal.backup.Contact + 41, // 14: signal.backup.Recipient.group:type_name -> signal.backup.Group + 47, // 15: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem + 42, // 16: signal.backup.Recipient.self:type_name -> signal.backup.Self + 43, // 17: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes + 45, // 18: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink + 10, // 19: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility + 125, // 20: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered + 126, // 21: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered + 9, // 22: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState + 127, // 23: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name + 0, // 24: signal.backup.Contact.avatarColor:type_name -> signal.backup.AvatarColor + 11, // 25: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode + 128, // 26: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot + 0, // 27: signal.backup.Group.avatarColor:type_name -> signal.backup.AvatarColor + 0, // 28: signal.backup.Self.avatarColor:type_name -> signal.backup.AvatarColor + 116, // 29: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle + 14, // 30: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions + 15, // 31: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State + 48, // 32: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList + 16, // 33: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode + 49, // 34: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem + 135, // 35: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails + 136, // 36: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails + 137, // 37: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails + 52, // 38: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage + 53, // 39: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage + 59, // 40: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage + 60, // 41: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage + 69, // 42: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage + 55, // 43: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification + 56, // 44: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge + 57, // 45: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage + 54, // 46: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage + 68, // 47: signal.backup.ChatItem.poll:type_name -> signal.backup.Poll + 138, // 48: signal.backup.ChatItem.pinDetails:type_name -> signal.backup.ChatItem.PinDetails + 139, // 49: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending + 140, // 50: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent + 141, // 51: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered + 142, // 52: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read + 143, // 53: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed + 144, // 54: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped + 145, // 55: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed + 66, // 56: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange + 65, // 57: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote + 51, // 58: signal.backup.StandardMessage.text:type_name -> signal.backup.Text + 63, // 59: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment + 62, // 60: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview + 64, // 61: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer + 67, // 62: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction + 58, // 63: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment + 67, // 64: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction + 146, // 65: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply + 67, // 66: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction + 147, // 67: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails + 20, // 68: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State + 63, // 69: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment + 67, // 70: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction + 151, // 71: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name + 152, // 72: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone + 153, // 73: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email + 154, // 74: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress + 64, // 75: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer + 61, // 76: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker + 67, // 77: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction + 64, // 78: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer + 64, // 79: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer + 64, // 80: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer + 24, // 81: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag + 155, // 82: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo + 51, // 83: signal.backup.Quote.text:type_name -> signal.backup.Text + 156, // 84: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 25, // 85: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 26, // 86: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 157, // 87: signal.backup.Poll.options:type_name -> signal.backup.Poll.PollOption + 67, // 88: signal.backup.Poll.reactions:type_name -> signal.backup.Reaction + 72, // 89: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 78, // 90: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 73, // 91: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 74, // 92: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 76, // 93: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 77, // 94: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 70, // 95: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 71, // 96: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 75, // 97: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 113, // 98: signal.backup.ChatUpdateMessage.pollTerminate:type_name -> signal.backup.PollTerminateUpdate + 114, // 99: signal.backup.ChatUpdateMessage.pinMessage:type_name -> signal.backup.PinMessageUpdate + 27, // 100: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 28, // 101: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 29, // 102: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 30, // 103: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 31, // 104: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 159, // 105: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 106: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 107: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 160, // 108: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 32, // 109: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 64, // 110: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 163, // 111: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 33, // 112: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 34, // 113: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 35, // 114: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 6, // 115: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 7, // 116: signal.backup.AccountData.AutoDownloadSettings.images:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 7, // 117: signal.backup.AccountData.AutoDownloadSettings.audio:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 7, // 118: signal.backup.AccountData.AutoDownloadSettings.video:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 7, // 119: signal.backup.AccountData.AutoDownloadSettings.documents:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 2, // 120: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 116, // 121: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 162, // 122: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 3, // 123: signal.backup.AccountData.AccountSettings.defaultSentMediaQuality:type_name -> signal.backup.AccountData.SentMediaQuality + 120, // 124: signal.backup.AccountData.AccountSettings.autoDownloadSettings:type_name -> signal.backup.AccountData.AutoDownloadSettings + 4, // 125: signal.backup.AccountData.AccountSettings.appTheme:type_name -> signal.backup.AccountData.AppTheme + 5, // 126: signal.backup.AccountData.AccountSettings.callsUseLessDataSetting:type_name -> signal.backup.AccountData.CallsUseLessDataSetting + 8, // 127: signal.backup.AccountData.AndroidSpecificSettings.navigationBarSize:type_name -> signal.backup.AccountData.AndroidSpecificSettings.NavigationBarSize + 129, // 128: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 129, // 129: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 129, // 130: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 134, // 131: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 130, // 132: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 131, // 133: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 132, // 134: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 133, // 135: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 12, // 136: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 130, // 137: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 13, // 138: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 13, // 139: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 13, // 140: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 50, // 141: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 17, // 142: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 51, // 143: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 64, // 144: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 150, // 145: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 149, // 146: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 18, // 147: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 19, // 148: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 148, // 149: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 21, // 150: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 22, // 151: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 23, // 152: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 63, // 153: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 158, // 154: signal.backup.Poll.PollOption.votes:type_name -> signal.backup.Poll.PollOption.PollVote + 79, // 155: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 80, // 156: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 81, // 157: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 82, // 158: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 83, // 159: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 84, // 160: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 85, // 161: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 86, // 162: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 87, // 163: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 88, // 164: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 89, // 165: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 90, // 166: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 91, // 167: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 92, // 168: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 93, // 169: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 94, // 170: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 95, // 171: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 96, // 172: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 97, // 173: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 98, // 174: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 99, // 175: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 100, // 176: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 101, // 177: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 103, // 178: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 104, // 179: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 105, // 180: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 106, // 181: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 107, // 182: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 108, // 183: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 109, // 184: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 110, // 185: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 111, // 186: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 102, // 187: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 112, // 188: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 161, // 189: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 190, // [190:190] is the sub-list for method output_type + 190, // [190:190] is the sub-list for method input_type + 190, // [190:190] is the sub-list for extension type_name + 190, // [190:190] is the sub-list for extension extendee + 0, // [0:190] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -12896,6 +13644,7 @@ func file_backuppb_Backup_proto_init() { (*ChatUpdateMessage_GroupCall)(nil), (*ChatUpdateMessage_LearnedProfileChange)(nil), (*ChatUpdateMessage_PollTerminate)(nil), + (*ChatUpdateMessage_PinMessage)(nil), } file_backuppb_Backup_proto_msgTypes[34].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[35].OneofWrappers = []any{} @@ -12926,37 +13675,41 @@ func file_backuppb_Backup_proto_init() { file_backuppb_Backup_proto_msgTypes[69].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[70].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[76].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[79].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[80].OneofWrappers = []any{ (*ChatStyle_WallpaperPreset_)(nil), (*ChatStyle_WallpaperPhoto)(nil), (*ChatStyle_AutoBubbleColor)(nil), (*ChatStyle_BubbleColorPreset_)(nil), (*ChatStyle_CustomColorId)(nil), } - file_backuppb_Backup_proto_msgTypes[80].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[83].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[85].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[81].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[85].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[87].OneofWrappers = []any{ (*AccountData_IAPSubscriberData_PurchaseToken)(nil), (*AccountData_IAPSubscriberData_OriginalTransactionId)(nil), } - file_backuppb_Backup_proto_msgTypes[90].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[93].OneofWrappers = []any{ (*Group_GroupAttributeBlob_Title)(nil), (*Group_GroupAttributeBlob_Avatar)(nil), (*Group_GroupAttributeBlob_DisappearingMessagesDuration)(nil), (*Group_GroupAttributeBlob_DescriptionText)(nil), } - file_backuppb_Backup_proto_msgTypes[96].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[107].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[99].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[102].OneofWrappers = []any{ + (*ChatItem_PinDetails_PinExpiresAtTimestamp)(nil), + (*ChatItem_PinDetails_PinNeverExpires)(nil), + } + file_backuppb_Backup_proto_msgTypes[111].OneofWrappers = []any{ (*PaymentNotification_TransactionDetails_Transaction_)(nil), (*PaymentNotification_TransactionDetails_FailedTransaction_)(nil), } - file_backuppb_Backup_proto_msgTypes[110].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[115].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{ (*FilePointer_LocatorInfo_PlaintextHash)(nil), (*FilePointer_LocatorInfo_EncryptedDigest)(nil), } - file_backuppb_Backup_proto_msgTypes[116].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[123].OneofWrappers = []any{ (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), @@ -12992,8 +13745,8 @@ func file_backuppb_Backup_proto_init() { (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), } - file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[122].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[124].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[126].OneofWrappers = []any{ (*ChatStyle_CustomChatColor_Solid)(nil), (*ChatStyle_CustomChatColor_Gradient)(nil), } @@ -13002,8 +13755,8 @@ func file_backuppb_Backup_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), - NumEnums: 31, - NumMessages: 124, + NumEnums: 36, + NumMessages: 128, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 66125fc..1b70167 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -68,6 +68,40 @@ message AccountData { Color color = 3; } + enum SentMediaQuality { + UNKNOWN_QUALITY = 0; // Interpret as "Standard" + STANDARD = 1; + HIGH = 2; + } + + message AutoDownloadSettings { + enum AutoDownloadOption { + UNKNOWN = 0; // Interpret as "Never" + NEVER = 1; + WIFI = 2; + WIFI_AND_CELLULAR = 3; + } + + AutoDownloadOption images = 1; + AutoDownloadOption audio = 2; + AutoDownloadOption video = 3; + AutoDownloadOption documents = 4; + } + + enum AppTheme { + UNKNOWN_APP_THEME = 0; // Interpret as "System" + SYSTEM = 1; + LIGHT = 2; + DARK = 3; + } + + enum CallsUseLessDataSetting { + UNKNOWN_CALL_DATA_SETTING = 0; // Interpret as "Never" + NEVER = 1; + MOBILE_DATA_ONLY = 2; + WIFI_AND_MOBILE_DATA = 3; + } + message AccountSettings { bool readReceipts = 1; bool sealedSenderIndicators = 2; @@ -91,6 +125,16 @@ message AccountData { bool optimizeOnDeviceStorage = 20; // See zkgroup for integer particular values. Unset if backups are not enabled. optional uint64 backupTier = 21; + reserved /* showSealedSenderIndicators */ 22; + SentMediaQuality defaultSentMediaQuality = 23; + AutoDownloadSettings autoDownloadSettings = 24; + reserved /* wifiAutoDownloadSettings */ 25; + optional uint32 screenLockTimeoutMinutes = 26; // If unset, consider screen lock to be disabled. + optional bool pinReminders = 27; // If unset, consider pin reminders to be enabled. + AppTheme appTheme = 28; // If unset, treat the same as "Unknown" case + CallsUseLessDataSetting callsUseLessDataSetting = 29; // If unset, treat the same as "Unknown" case + bool allowSealedSenderFromAnyone = 30; + bool allowAutomaticKeyVerification = 31; } message SubscriberData { @@ -111,6 +155,18 @@ message AccountData { } } + message AndroidSpecificSettings { + enum NavigationBarSize { + UNKNOWN_BAR_SIZE = 0; // Intepret as "Normal" + NORMAL = 1; + COMPACT = 2; + } + + bool useSystemEmoji = 1; + bool screenshotSecurity = 2; + NavigationBarSize navigationBarSize = 3; // If unset, treat the same as "Unknown" case + } + bytes profileKey = 1; optional string username = 2; UsernameLink usernameLink = 3; @@ -122,6 +178,10 @@ message AccountData { AccountSettings accountSettings = 9; IAPSubscriberData backupsSubscriberData = 10; string svrPin = 11; + AndroidSpecificSettings androidSpecificSettings = 12; + string bioText = 13; + string bioEmoji = 14; + optional bytes keyTransparencyData = 15; } message Recipient { @@ -210,6 +270,7 @@ message Contact { string systemFamilyName = 19; string systemNickname = 20; optional AvatarColor avatarColor = 21; + optional bytes keyTransparencyData = 22; } message Group { @@ -402,6 +463,14 @@ message ChatItem { message DirectionlessMessageDetails { } + message PinDetails { + uint64 pinnedAtTimestamp = 1; + oneof pinExpiry { + uint64 pinExpiresAtTimestamp = 2; // timestamp when the pin should expire + bool pinNeverExpires = 3; + } + } + uint64 chatId = 1; // conversation id uint64 authorId = 2; // recipient id uint64 dateSent = 3; @@ -430,6 +499,8 @@ message ChatItem { DirectStoryReplyMessage directStoryReplyMessage = 19; // group story reply messages are not backed up Poll poll = 20; } + + PinDetails pinDetails = 21; // only set if message is pinned } message SendStatus { @@ -824,6 +895,7 @@ message Poll { bool allowMultiple = 2; repeated PollOption options = 3; // At least two bool hasEnded = 4; + repeated Reaction reactions = 5; } message ChatUpdateMessage { @@ -839,6 +911,7 @@ message ChatUpdateMessage { GroupCall groupCall = 8; LearnedProfileChatUpdate learnedProfileChange = 9; PollTerminateUpdate pollTerminate = 10; + PinMessageUpdate pinMessage = 11; } } @@ -1209,6 +1282,11 @@ message PollTerminateUpdate { string question = 2; // Between 1-100 characters } +message PinMessageUpdate { + uint64 targetSentTimestamp = 1; + uint64 authorId = 2; // recipient id +} + message StickerPack { bytes packId = 1; bytes packKey = 2; diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index d8fea17..d65567c 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,14 +1,14 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-d261f3ebf51864da067b968ee3366ed3e7369c78} -DESKTOP_GIT_REVISION=${1:-fb566c48e0fa146dfe0bea077ecdb3ff846ef80a} +ANDROID_GIT_REVISION=${1:-bc6114f6e0d3a4b1dcdc472331505f2644185264} +DESKTOP_GIT_REVISION=${1:-a9063ec0c3c1079072c1e30e0749c1ae8be5500a} update_proto() { case "$1" in Signal-Android) REPO="Signal-Android" - prefix="libsignal-service/src/main/protowire/" + prefix="lib/libsignal-service/src/main/protowire/" GIT_REVISION=$ANDROID_GIT_REVISION ;; Signal-Android-App) From 28af2ed551dcd614be32a9e81b38bd34dbf661ef Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 13 Feb 2026 16:17:43 +0200 Subject: [PATCH 658/718] signalmeow/store: add missing signalmeow_device foreign keys --- pkg/signalmeow/store/upgrades/00-latest.sql | 10 ++++-- ...7-sender-key-info-foreign-key.postgres.sql | 10 ++++++ .../27-sender-key-info-foreign-key.sqlite.sql | 32 +++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.postgres.sql create mode 100644 pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.sqlite.sql diff --git a/pkg/signalmeow/store/upgrades/00-latest.sql b/pkg/signalmeow/store/upgrades/00-latest.sql index 8f54eac..fbb44ad 100644 --- a/pkg/signalmeow/store/upgrades/00-latest.sql +++ b/pkg/signalmeow/store/upgrades/00-latest.sql @@ -1,4 +1,4 @@ --- v0 -> v26 (compatible with v13+): Latest revision +-- v0 -> v27 (compatible with v13+): Latest revision CREATE TABLE signalmeow_device ( aci_uuid TEXT PRIMARY KEY, @@ -100,7 +100,9 @@ CREATE TABLE signalmeow_outbound_sender_key_info ( distribution_id TEXT NOT NULL, shared_with jsonb NOT NULL, - PRIMARY KEY (account_id, group_id) + PRIMARY KEY (account_id, group_id), + CONSTRAINT signalmeow_outbound_sender_key_info_device_fkey + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_groups ( @@ -108,7 +110,9 @@ CREATE TABLE signalmeow_groups ( group_identifier TEXT NOT NULL, master_key TEXT NOT NULL, - PRIMARY KEY (account_id, group_identifier) + PRIMARY KEY (account_id, group_identifier), + CONSTRAINT signalmeow_groups_device_fkey + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE signalmeow_recipients ( diff --git a/pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.postgres.sql b/pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.postgres.sql new file mode 100644 index 0000000..e9c0ee5 --- /dev/null +++ b/pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.postgres.sql @@ -0,0 +1,10 @@ +-- v27 (compatible with v13+): Add missing foreign key for outbound sender key info and groups +DELETE FROM signalmeow_outbound_sender_key_info +WHERE NOT EXISTS(SELECT 1 FROM signalmeow_device WHERE aci_uuid=account_id); +ALTER TABLE signalmeow_outbound_sender_key_info ADD CONSTRAINT signalmeow_outbound_sender_key_info_device_fkey + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE; + +DELETE FROM signalmeow_groups +WHERE NOT EXISTS(SELECT 1 FROM signalmeow_device WHERE aci_uuid=account_id); +ALTER TABLE signalmeow_groups ADD CONSTRAINT signalmeow_groups_device_fkey + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.sqlite.sql b/pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.sqlite.sql new file mode 100644 index 0000000..b6017ba --- /dev/null +++ b/pkg/signalmeow/store/upgrades/27-sender-key-info-foreign-key.sqlite.sql @@ -0,0 +1,32 @@ +-- v27 (compatible with v13+): Add missing foreign key for outbound sender key info and groups + +CREATE TABLE new_signalmeow_outbound_sender_key_info ( + account_id TEXT NOT NULL, + group_id TEXT NOT NULL, + distribution_id TEXT NOT NULL, + shared_with jsonb NOT NULL, + + PRIMARY KEY (account_id, group_id), + CONSTRAINT signalmeow_outbound_sender_key_info_device_fkey + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +INSERT INTO new_signalmeow_outbound_sender_key_info +SELECT * FROM signalmeow_outbound_sender_key_info +WHERE EXISTS(SELECT 1 FROM signalmeow_device WHERE aci_uuid=account_id); +DROP TABLE signalmeow_outbound_sender_key_info; +ALTER TABLE new_signalmeow_outbound_sender_key_info RENAME TO signalmeow_outbound_sender_key_info; + +CREATE TABLE new_signalmeow_groups ( + account_id TEXT NOT NULL, + group_identifier TEXT NOT NULL, + master_key TEXT NOT NULL, + + PRIMARY KEY (account_id, group_identifier), + CONSTRAINT signalmeow_groups_device_fkey + FOREIGN KEY (account_id) REFERENCES signalmeow_device (aci_uuid) ON DELETE CASCADE ON UPDATE CASCADE +); +INSERT INTO new_signalmeow_groups +SELECT * FROM signalmeow_groups +WHERE EXISTS(SELECT 1 FROM signalmeow_device WHERE aci_uuid=account_id); +DROP TABLE signalmeow_groups; +ALTER TABLE new_signalmeow_groups RENAME TO signalmeow_groups; From 3faa0d4f3091c462b447d9cc1f16d8a27d5c643e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 15 Feb 2026 13:08:11 +0200 Subject: [PATCH 659/718] main: bump minimum Go version to 1.25 --- .github/workflows/go.yml | 8 ++++---- go.mod | 4 ++-- pkg/signalmeow/groups.go | 3 +-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 767c119..ebd9186 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,8 +11,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.24", "1.25"] - name: Lint ${{ matrix.go-version == '1.25' && '(latest)' || '(old)' }} + go-version: ["1.25", "1.26"] + name: Lint ${{ matrix.go-version == '1.26' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v6 @@ -40,8 +40,8 @@ jobs: strategy: fail-fast: false matrix: - go-version: ["1.24", "1.25"] - name: Test ${{ matrix.go-version == '1.25' && '(latest)' || '(old)' }} + go-version: ["1.25", "1.26"] + name: Test ${{ matrix.go-version == '1.26' && '(latest)' || '(old)' }} steps: - uses: actions/checkout@v6 diff --git a/go.mod b/go.mod index 728ffb7..340f05c 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module go.mau.fi/mautrix-signal -go 1.24.0 +go 1.25.0 -toolchain go1.25.6 +toolchain go1.26.0 tool go.mau.fi/util/cmd/maubuild diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index dcdfe7d..b02687b 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -226,8 +226,7 @@ func (groupChange *GroupChange) isEmpty() bool { len(groupChange.PromoteRequestingMembers) == 0 && groupChange.ModifyDescription == nil && groupChange.ModifyAnnouncementsOnly == nil && - len(groupChange.AddBannedMembers) == 0 && - len(groupChange.DeleteMembers) == 0 + len(groupChange.AddBannedMembers) == 0 } func (groupChange *GroupChange) resolveConflict(group *Group) { From 634f7c21caf96913a4b7cf93f5335d8ad25ecbb9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Feb 2026 15:02:53 +0200 Subject: [PATCH 660/718] Bump version to v26.02 --- CHANGELOG.md | 7 +++++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 20 +++++++++---------- go.sum | 40 +++++++++++++++++++------------------- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29f2299..f18590b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v26.02 + +* Bumped minimum Go version to 1.25. +* Updated libsignal to v0.87.1. +* Added automatic recovery for the session not found error from libsignal. +* Fixed sender key state not being cleared on logout properly. + # v26.01 * Updated libsignal to v0.86.12. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 5391084..064b1e0 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -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.01", + Version: "26.02", SemCalVer: true, Connector: &connector.SignalConnector{}, diff --git a/go.mod b/go.mod index 340f05c..3b6cc07 100644 --- a/go.mod +++ b/go.mod @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.5 - golang.org/x/crypto v0.47.0 - golang.org/x/exp v0.0.0-20260112195511-716be5621a96 - golang.org/x/net v0.49.0 + go.mau.fi/util v0.9.6 + golang.org/x/crypto v0.48.0 + golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a + golang.org/x/net v0.50.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.3-0.20260129174719-d2364b382275 + maunium.net/go/mautrix v0.26.3 ) require ( @@ -28,10 +28,10 @@ require ( github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/lib/pq v1.10.9 // indirect + github.com/lib/pq v1.11.2 // 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.33 // indirect + github.com/mattn/go-sqlite3 v1.14.34 // indirect github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -42,10 +42,10 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.16 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/mod v0.32.0 // indirect + golang.org/x/mod v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // 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 diff --git a/go.sum b/go.sum index 8dba58f..26c13e2 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs= +github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -35,8 +35,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= -github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0= -github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= +github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -67,27 +67,27 @@ 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.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.5 h1:7AoWPCIZJGv4jvtFEuCe3GhAbI7uF9ckIooaXvwlIR4= -go.mau.fi/util v0.9.5/go.mod h1:g1uvZ03VQhtTt2BgaRGVytS/Zj67NV0YNIECch0sQCQ= +go.mau.fi/util v0.9.6 h1:2nsvxm49KhI3wrFltr0+wSUBlnQ4CMtykuELjpIU+ts= +go.mau.fi/util v0.9.6/go.mod h1:sIJpRH7Iy5Ad1SBuxQoatxtIeErgzxCtjd/2hCMkYMI= 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.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= -golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= +golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -99,5 +99,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.26.3-0.20260129174719-d2364b382275 h1:r8BL0+HW4Dar1xV7Fc7NV/LxGH6VCvffkCUGe9ZfJg8= -maunium.net/go/mautrix v0.26.3-0.20260129174719-d2364b382275/go.mod h1:CUxSZcjPtQNxsZLRQqETAxg2hiz7bjWT+L1HCYoMMKo= +maunium.net/go/mautrix v0.26.3 h1:tWZih6Vjw0qGTWuPmg9JUrQPzViTNDPGQLVc5UXC4nk= +maunium.net/go/mautrix v0.26.3/go.mod h1:v5ZdDoCwUpNqEj5OrhEoUa3L1kEddKPaAya9TgGXN38= From 375c51e7b884f742d526c167418c71750d827398 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 23 Feb 2026 15:11:56 +0200 Subject: [PATCH 661/718] handle*,msgconv,signalmeow: add support for binary ACI fields Fixes #635 --- pkg/connector/handlematrix.go | 20 ++++++++++++-------- pkg/connector/handlesignal.go | 28 ++++++++++++++++++++++------ pkg/libsignalgo/serviceid.go | 15 +++++++++++++++ pkg/msgconv/from-matrix.go | 4 +++- pkg/msgconv/from-signal.go | 2 +- pkg/signalmeow/misc.go | 28 ++++++++++++++++++++++++++++ pkg/signalmeow/receiving.go | 8 ++++++-- pkg/signalmeow/receiving_decrypt.go | 16 +++++----------- 8 files changed, 92 insertions(+), 29 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 610dd81..8819d69 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -205,9 +205,11 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M Timestamp: proto.Uint64(ts), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.PreHandleResp.Emoji), - Remove: proto.Bool(false), - TargetAuthorAci: proto.String(targetAuthorACI.String()), + Emoji: proto.String(msg.PreHandleResp.Emoji), + Remove: proto.Bool(false), + TargetAuthorAci: proto.String(targetAuthorACI.String()), + // TODO update aci format + //TargetAuthorAciBinary: targetAuthorACI[:], TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, }, @@ -230,9 +232,11 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid Timestamp: proto.Uint64(ts), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.TargetReaction.Emoji), - Remove: proto.Bool(true), - TargetAuthorAci: proto.String(targetAuthorACI.String()), + Emoji: proto.String(msg.TargetReaction.Emoji), + Remove: proto.Bool(true), + TargetAuthorAci: proto.String(targetAuthorACI.String()), + // TODO update aci format + //TargetAuthorAciBinary: targetAuthorACI[:], TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, }, @@ -760,8 +764,8 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2 } mostRecentMessages = append(mostRecentMessages, &signalpb.AddressableMessage{ - Author: &signalpb.AddressableMessage_AuthorServiceId{ - AuthorServiceId: senderACI.String(), + Author: &signalpb.AddressableMessage_AuthorServiceIdBinary{ + AuthorServiceIdBinary: senderACI[:], }, SentTimestamp: proto.Uint64(timestamp), }) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index fb1a3ce..f248d48 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -37,6 +37,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" "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/types" @@ -292,13 +293,13 @@ func (evt *Bv2ChatEvent) GetTimestamp() time.Time { } func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { - var targetAuthorACI string + var targetAuthorACI uuid.UUID var targetSentTS uint64 switch innerEvt := evt.Event.(type) { case *signalpb.DataMessage: switch { case innerEvt.Reaction != nil: - targetAuthorACI = innerEvt.Reaction.GetTargetAuthorAci() + targetAuthorACI, _ = signalmeow.ParseStringOrBinaryUUID(innerEvt.Reaction.GetTargetAuthorAci(), innerEvt.Reaction.GetTargetAuthorAciBinary()) targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp() case innerEvt.Delete != nil: targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() @@ -310,11 +311,10 @@ func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { default: return "" } - targetAuthorUUID := evt.Info.Sender - if targetAuthorACI != "" { - targetAuthorUUID, _ = uuid.Parse(targetAuthorACI) + if targetAuthorACI == uuid.Nil { + targetAuthorACI = evt.Info.Sender } - return signalid.MakeMessageID(targetAuthorUUID, targetSentTS) + return signalid.MakeMessageID(targetAuthorACI, targetSentTS) } func (evt *Bv2ChatEvent) GetReactionEmoji() (string, networkid.EmojiID) { @@ -537,6 +537,22 @@ func (s *SignalClient) addressableMessageToID(ctx context.Context, portalKey net return "" } return signalid.MakeMessageID(serviceID.UUID, am.GetSentTimestamp()) + case *signalpb.AddressableMessage_AuthorServiceIdBinary: + serviceID, err := libsignalgo.ServiceIDFromBytes(typedAuthor.AuthorServiceIdBinary) + if err != nil { + log.Err(err). + Object("portal_key", portalKey). + Hex("author_service_id_binary", typedAuthor.AuthorServiceIdBinary). + Msg("Failed to parse delete for me message author service ID") + return "" + } else if serviceID.Type != libsignalgo.ServiceIDTypeACI { + log.Warn(). + Object("portal_key", portalKey). + Hex("author_service_id_binary", typedAuthor.AuthorServiceIdBinary). + Msg("Dropping delete for me message with unsupported service ID type") + return "" + } + return signalid.MakeMessageID(serviceID.UUID, am.GetSentTimestamp()) case *signalpb.AddressableMessage_AuthorE164: log.Warn(). Object("portal_key", portalKey). diff --git a/pkg/libsignalgo/serviceid.go b/pkg/libsignalgo/serviceid.go index ae7cea7..21d64b2 100644 --- a/pkg/libsignalgo/serviceid.go +++ b/pkg/libsignalgo/serviceid.go @@ -87,6 +87,9 @@ func (s ServiceID) IsEmpty() bool { } func (s ServiceID) Address(deviceID uint) (*Address, error) { + if s.IsEmpty() { + return nil, fmt.Errorf("cannot create address from empty ServiceID") + } return newAddress(s.String(), deviceID) } @@ -158,6 +161,18 @@ func ServiceIDFromString(val string) (ServiceID, error) { } } +func ServiceIDFromBytes(bytes []byte) (ServiceID, error) { + if len(bytes) == 16 { + return NewACIServiceID(uuid.UUID(bytes)), nil + } else if len(bytes) == 17 { + 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)) +} + func ServiceIDFromCFixedBytes(serviceID *C.SignalServiceIdFixedWidthBinaryBytes) ServiceID { var id ServiceID fixedBytes := (*ServiceIDFixedBytes)(unsafe.Pointer(serviceID)) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 67352f1..fa5deb4 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -62,7 +62,9 @@ func (mc *MessageConverter) ToSignal( dm.Quote = &signalpb.DataMessage_Quote{ Id: proto.Uint64(messageID), AuthorAci: proto.String(authorACI.String()), - Type: signalpb.DataMessage_Quote_NORMAL.Enum(), + // TODO update aci format + //AuthorAciBinary: authorACI[:], + Type: signalpb.DataMessage_Quote_NORMAL.Enum(), } if replyTo.Metadata.(*signalid.MessageMetadata).ContainsAttachments { dm.Quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index c8ac40e..dadfe3f 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -174,7 +174,7 @@ func (mc *MessageConverter) ToMatrix( } } if dm.Quote != nil { - authorACI, err := uuid.Parse(dm.Quote.GetAuthorAci()) + authorACI, err := signalmeow.ParseStringOrBinaryUUID(dm.Quote.GetAuthorAci(), dm.Quote.GetAuthorAciBinary()) if err != nil { zerolog.Ctx(ctx).Err(err).Str("author_aci", dm.Quote.GetAuthorAci()).Msg("Failed to parse quote author ACI") } else { diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 1bf88a3..467f646 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -18,7 +18,10 @@ package signalmeow import ( _ "embed" + "errors" + "fmt" + "github.com/google/uuid" "github.com/rs/zerolog" "go.mau.fi/util/exerrors" @@ -76,3 +79,28 @@ var prodServerPublicParams *libsignalgo.ServerPublicParams func init() { prodServerPublicParams = exerrors.Must(libsignalgo.DeserializeServerPublicParams(prodServerPublicParamsSlice)) } + +var ErrEmptyUUIDInput = errors.New("both input variables are empty") + +func ParseStringOrBinaryServiceID(str string, bytes []byte) (libsignalgo.ServiceID, error) { + if str != "" { + return libsignalgo.ServiceIDFromString(str) + } + if bytes != nil { + return libsignalgo.ServiceIDFromBytes(bytes) + } + return libsignalgo.EmptyServiceID, ErrEmptyUUIDInput +} + +func ParseStringOrBinaryUUID(str string, bytes []byte) (uuid.UUID, error) { + if str != "" { + return uuid.Parse(str) + } + if bytes != nil { + if len(bytes) != 16 { + return uuid.Nil, fmt.Errorf("invalid UUID length %d (expected 16)", len(bytes)) + } + return uuid.UUID(bytes), nil + } + return uuid.Nil, ErrEmptyUUIDInput +} diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index b802e06..2dd1d64 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -361,17 +361,21 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. Uint64("server_timestamp", envelope.GetServerTimestamp()). Logger() ctx = log.WithContext(ctx) - destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) + destinationServiceID, _ := ParseStringOrBinaryServiceID(envelope.GetDestinationServiceId(), envelope.GetDestinationServiceIdBinary()) + sourceServiceID, _ := ParseStringOrBinaryServiceID(envelope.GetSourceServiceId(), envelope.GetSourceServiceIdBinary()) log.Debug(). Str("destination_service_id", envelope.GetDestinationServiceId()). Str("source_service_id", envelope.GetSourceServiceId()). + Hex("destination_service_id_bytes", envelope.GetDestinationServiceIdBinary()). + Hex("source_service_id_bytes", envelope.GetSourceServiceIdBinary()). Uint32("source_device_id", envelope.GetSourceDevice()). Object("parsed_destination_service_id", destinationServiceID). + Object("parsed_source_service_id", sourceServiceID). Int32("envelope_type_id", int32(envelope.GetType())). Str("envelope_type", signalpb.Envelope_Type_name[int32(envelope.GetType())]). Msg("Received envelope") - result := cli.decryptEnvelope(ctx, envelope) + result := cli.decryptEnvelope(ctx, envelope, sourceServiceID, destinationServiceID) err = cli.handleDecryptedResult(ctx, result, envelope, destinationServiceID) if err != nil { diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 5c8da08..958f84f 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -50,13 +50,10 @@ type DecryptionResult struct { func (cli *Client) decryptEnvelope( ctx context.Context, envelope *signalpb.Envelope, + sourceServiceID, destinationServiceID libsignalgo.ServiceID, ) DecryptionResult { - log := zerolog.Ctx(ctx) - - destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) - if err != nil { - log.Err(err).Str("destination_service_id", envelope.GetDestinationServiceId()).Msg("Failed to parse destination service ID") - return DecryptionResult{Err: fmt.Errorf("failed to parse destination service ID: %w", err)} + if destinationServiceID.IsEmpty() { + return DecryptionResult{Err: fmt.Errorf("envelope missing destination service ID")} } switch *envelope.Type { @@ -68,10 +65,7 @@ func (cli *Client) decryptEnvelope( return result case signalpb.Envelope_PREKEY_BUNDLE, signalpb.Envelope_CIPHERTEXT: - sender, err := libsignalgo.NewUUIDAddressFromString( - *envelope.SourceServiceId, - uint(*envelope.SourceDevice), - ) + sender, err := sourceServiceID.Address(uint(envelope.GetSourceDevice())) if err != nil { return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} } @@ -96,7 +90,7 @@ func (cli *Client) decryptEnvelope( return *result case signalpb.Envelope_PLAINTEXT_CONTENT: - addr, err := libsignalgo.NewUUIDAddressFromString(envelope.GetSourceServiceId(), uint(envelope.GetSourceDevice())) + addr, err := sourceServiceID.Address(uint(envelope.GetSourceDevice())) if err != nil { return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} } From af5f936d3e9de27f0d4e7091e10fdb855eb28ae7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Feb 2026 13:48:39 +0200 Subject: [PATCH 662/718] signalmeow: add support for binary ACI field in sync messages --- pkg/signalmeow/receiving.go | 24 +++++++++--------------- pkg/signalmeow/sending.go | 32 ++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 2dd1d64..d3d039c 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -714,21 +714,15 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess } syncSent := msg.GetSent() if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { - destination := syncSent.DestinationServiceId - var syncDestinationServiceID libsignalgo.ServiceID - if destination != nil { - var err error - syncDestinationServiceID, err = libsignalgo.ServiceIDFromString(*destination) + syncDestinationServiceID, err := ParseStringOrBinaryServiceID(syncSent.GetDestinationServiceId(), syncSent.GetDestinationServiceIdBinary()) + if err != nil && !errors.Is(err, ErrEmptyUUIDInput) { + log.Err(err).Msg("Sync message destination parse error") + } + if syncSent.GetDestinationE164() != "" && !syncDestinationServiceID.IsEmpty() { + aci, pni := syncDestinationServiceID.ToACIAndPNI() + _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) if err != nil { - log.Err(err).Msg("Sync message destination parse error") - return - } - if syncSent.GetDestinationE164() != "" { - aci, pni := syncDestinationServiceID.ToACIAndPNI() - _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) - if err != nil { - log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") - } + log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") } } for _, unident := range syncSent.GetUnidentifiedStatus() { @@ -744,7 +738,7 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess } } - if destination == nil && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { + if syncDestinationServiceID.IsEmpty() && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { log.Warn().Msg("sync message sent destination is nil") } else if msg.Sent.Message != nil { // TODO handle expiration start ts, and maybe the sync message ts? diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 8e6b892..86bc1db 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -307,7 +307,9 @@ func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results for _, result := range results { unidentifiedStatuses = append(unidentifiedStatuses, &signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ DestinationServiceId: proto.String(result.Recipient.String()), - Unidentified: &result.Unidentified, + // TODO update aci format + //DestinationServiceIdBinary: result.Recipient.Bytes(), + Unidentified: &result.Unidentified, }) } return &signalpb.Content{ @@ -326,7 +328,9 @@ func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results for _, result := range results { unidentifiedStatuses = append(unidentifiedStatuses, &signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ DestinationServiceId: proto.String(result.Recipient.String()), - Unidentified: &result.Unidentified, + // TODO update aci format + //DestinationServiceIdBinary: result.Recipient.Bytes(), + Unidentified: &result.Unidentified, }) } return &signalpb.Content{ @@ -345,14 +349,18 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - Message: dataMessage, - DestinationE164: result.RecipientE164, - DestinationServiceId: proto.String(result.Recipient.String()), + Message: dataMessage, + DestinationE164: result.RecipientE164, + DestinationServiceId: proto.String(result.Recipient.String()), + // TODO update aci format + //DestinationServiceIdBinary: result.Recipient.Bytes(), Timestamp: dataMessage.Timestamp, ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), + DestinationServiceId: proto.String(result.Recipient.String()), + // TODO update aci format + //DestinationServiceIdBinary: result.Recipient.Bytes(), Unidentified: &result.Unidentified, DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, @@ -366,14 +374,18 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - EditMessage: editMessage, - DestinationE164: result.RecipientE164, - DestinationServiceId: proto.String(result.Recipient.String()), + EditMessage: editMessage, + DestinationE164: result.RecipientE164, + DestinationServiceId: proto.String(result.Recipient.String()), + // TODO update aci format + //DestinationServiceIdBinary: result.Recipient.Bytes(), Timestamp: editMessage.DataMessage.Timestamp, ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), + DestinationServiceId: proto.String(result.Recipient.String()), + // TODO update aci format + //DestinationServiceIdBinary: result.Recipient.Bytes(), Unidentified: &result.Unidentified, DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, From 09ba9d04b2b1f9e6d44fa93cbabc009ec8851962 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Feb 2026 14:05:11 +0200 Subject: [PATCH 663/718] signalmeow/receiving: add support for binary ACI field in unidentified send statuses --- pkg/signalmeow/receiving.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index d3d039c..3d81259 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -726,14 +726,22 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess } } for _, unident := range syncSent.GetUnidentifiedStatus() { - changed, err := cli.saveSyncPNIIdentityKey(ctx, unident.GetDestinationServiceId(), unident.GetDestinationPniIdentityKey()) + serviceID, err := ParseStringOrBinaryServiceID(unident.GetDestinationServiceId(), unident.GetDestinationServiceIdBinary()) if err != nil { log.Err(err). Str("destination_service_id", unident.GetDestinationServiceId()). + Hex("destination_service_id_bytes", unident.GetDestinationServiceIdBinary()). + Msg("Failed to parse destination service ID of unidentified send") + continue + } + changed, err := cli.saveSyncPNIIdentityKey(ctx, serviceID, unident.GetDestinationPniIdentityKey()) + if err != nil { + log.Err(err). + Stringer("destination_service_id", serviceID). Msg("Failed to save PNI identity key from sync message") } else if changed { log.Debug(). - Str("destination_service_id", unident.GetDestinationServiceId()). + Stringer("destination_service_id", serviceID). Msg("Saved new PNI identity key from sync message") } } @@ -828,20 +836,14 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess return } -func (cli *Client) saveSyncPNIIdentityKey(ctx context.Context, serviceIDString string, identityKeyBytes []byte) (bool, error) { - if identityKeyBytes == nil { +func (cli *Client) saveSyncPNIIdentityKey(ctx context.Context, serviceID libsignalgo.ServiceID, identityKeyBytes []byte) (bool, error) { + if identityKeyBytes == nil || serviceID.Type != libsignalgo.ServiceIDTypePNI { return false, nil } identityKey, err := libsignalgo.DeserializeIdentityKey(identityKeyBytes) if err != nil { return false, fmt.Errorf("failed to deserialize PNI identity key: %w", err) } - serviceID, err := libsignalgo.ServiceIDFromString(serviceIDString) - if err != nil { - return false, fmt.Errorf("failed to parse PNI service ID: %w", err) - } else if serviceID.Type != libsignalgo.ServiceIDTypePNI { - return false, nil - } changed, err := cli.Store.IdentityKeyStore.SaveIdentityKey(ctx, serviceID, identityKey) if err != nil { return false, fmt.Errorf("failed to save PNI identity key: %w", err) From ee306f5221ad9d259d94532c35b20dc372a8c82a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 27 Feb 2026 14:52:27 +0200 Subject: [PATCH 664/718] libsignal: update to v0.87.5 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index f08390b..ffaa9f0 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit f08390b0e2f67d5faf47bb9d1a3db191314db93c +Subproject commit ffaa9f0435569d6775d8be636f268f882ed67ce3 diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 8f445ad..bb1774c 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.87.1" +const Version = "v0.87.5" From 2447903e036c1e77ccf0ccf8c5d541d931d7220a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 27 Feb 2026 15:26:42 +0200 Subject: [PATCH 665/718] libsignalgo: add -lstdc++ to cflags --- pkg/libsignalgo/cflags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/libsignalgo/cflags.go b/pkg/libsignalgo/cflags.go index 12c1e0c..e1bb7d5 100644 --- a/pkg/libsignalgo/cflags.go +++ b/pkg/libsignalgo/cflags.go @@ -1,6 +1,6 @@ package libsignalgo /* -#cgo LDFLAGS: -lsignal_ffi -ldl -lm -lz +#cgo LDFLAGS: -lsignal_ffi -ldl -lm -lz -lstdc++ */ import "C" From 6a6e5d50dfe7416cf56874baa41b5d76b053295b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 27 Feb 2026 17:36:33 +0200 Subject: [PATCH 666/718] Bump version to v26.02.1 --- CHANGELOG.md | 5 +++++ cmd/mautrix-signal/main.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f18590b..7c6869c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v26.02.1 + +* Updated libsignal to v0.87.5. +* Added support for new binary service ID fields that Signal 8.0 switched to. + # v26.02 * Bumped minimum Go version to 1.25. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 064b1e0..ab7fd46 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -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.02", + Version: "26.02.1", SemCalVer: true, Connector: &connector.SignalConnector{}, From cc4b81da6c760f204df7dc57094b6d22c13b80bb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 28 Feb 2026 12:08:26 +0200 Subject: [PATCH 667/718] handlesignal: add support for binary service IDs in delete for me events Fixes #638 --- pkg/connector/handlesignal.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index f248d48..843dd10 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -499,6 +499,13 @@ func (s *SignalClient) conversationIDToPortalKey(ctx context.Context, cid *signa return networkid.PortalKey{}, false } return s.makeDMPortalKey(serviceID), true + case *signalpb.ConversationIdentifier_ThreadServiceIdBinary: + serviceID, err := libsignalgo.ServiceIDFromBytes(ident.ThreadServiceIdBinary) + if err != nil { + log.Err(err).Hex("chat_id", ident.ThreadServiceIdBinary).Msg("Failed to parse delete for me conversation ID") + return networkid.PortalKey{}, false + } + return s.makeDMPortalKey(serviceID), true case *signalpb.ConversationIdentifier_ThreadGroupId: if len(ident.ThreadGroupId) != libsignalgo.GroupIdentifierLength { log.Error(). From 0442a32f6816cead7cc91f8f8d36c5b8f2006a47 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 28 Feb 2026 12:27:46 +0200 Subject: [PATCH 668/718] handlesignal,msgconv,signalmeow: add support for remaining binary ACI fields --- pkg/connector/handlesignal.go | 2 +- pkg/msgconv/msgconv.go | 4 ++-- pkg/msgconv/signalfmt/convert.go | 15 ++++++++++++--- pkg/signalmeow/contact.go | 2 +- pkg/signalmeow/receiving.go | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 843dd10..bc0dbe3 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -480,7 +480,7 @@ func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) bool { Logger() ctx := log.WithContext(context.TODO()) receipts := convertReceipts(ctx, evt.Messages, func(ctx context.Context, msgInfo *signalpb.SyncMessage_Read) (*database.Message, error) { - aciUUID, err := uuid.Parse(msgInfo.GetSenderAci()) + aciUUID, err := signalmeow.ParseStringOrBinaryUUID(msgInfo.GetSenderAci(), msgInfo.GetSenderAciBinary()) if err != nil { return nil, err } diff --git a/pkg/msgconv/msgconv.go b/pkg/msgconv/msgconv.go index 1b8564a..e312a1f 100644 --- a/pkg/msgconv/msgconv.go +++ b/pkg/msgconv/msgconv.go @@ -78,7 +78,7 @@ func NewMessageConverter(br *bridgev2.Bridge) *MessageConverter { GetUUIDFromMXID: func(ctx context.Context, userID id.UserID) uuid.UUID { parsed, ok := br.Matrix.ParseGhostMXID(userID) if ok { - u, _ := uuid.Parse(string(parsed)) + u, _ := signalid.ParseUserID(parsed) return u } user, _ := br.GetExistingUserByMXID(ctx, userID) @@ -86,7 +86,7 @@ func NewMessageConverter(br *bridgev2.Bridge) *MessageConverter { if user != nil { preferredLogin, _, _ := getPortal(ctx).FindPreferredLogin(ctx, user, true) if preferredLogin != nil { - u, _ := uuid.Parse(string(preferredLogin.ID)) + u, _ := signalid.ParseUserLoginID(preferredLogin.ID) return u } } diff --git a/pkg/msgconv/signalfmt/convert.go b/pkg/msgconv/signalfmt/convert.go index f950a59..5a9b520 100644 --- a/pkg/msgconv/signalfmt/convert.go +++ b/pkg/msgconv/signalfmt/convert.go @@ -85,15 +85,24 @@ func Parse(ctx context.Context, message string, ranges []*signalpb.BodyRange, pa Start: int(*r.Start), Length: int(*r.Length), }.TruncateEnd(maxLength) + var mentionACI uuid.UUID switch rv := r.GetAssociatedValue().(type) { case *signalpb.BodyRange_Style_: br.Value = Style(rv.Style) case *signalpb.BodyRange_MentionAci: - parsed, err := uuid.Parse(rv.MentionAci) + var err error + mentionACI, err = uuid.Parse(rv.MentionAci) if err != nil { continue } - userInfo := params.GetUserInfo(ctx, parsed) + case *signalpb.BodyRange_MentionAciBinary: + if len(rv.MentionAciBinary) != 16 { + continue + } + mentionACI = uuid.UUID(rv.MentionAciBinary) + } + if mentionACI != uuid.Nil { + userInfo := params.GetUserInfo(ctx, mentionACI) if userInfo.MXID == "" { continue } @@ -102,7 +111,7 @@ func Parse(ctx context.Context, message string, ranges []*signalpb.BodyRange, pa // Maybe use NewUTF16String and do index replacements for the plaintext body too, // or just replace the plaintext body by parsing the generated HTML. content.Body = strings.Replace(content.Body, "\uFFFC", userInfo.Name, 1) - br.Value = Mention{UserInfo: userInfo, UUID: parsed} + br.Value = Mention{UserInfo: userInfo, UUID: mentionACI} } lrt.Add(br) } diff --git a/pkg/signalmeow/contact.go b/pkg/signalmeow/contact.go index 8407b74..f30f54f 100644 --- a/pkg/signalmeow/contact.go +++ b/pkg/signalmeow/contact.go @@ -36,7 +36,7 @@ import ( ) func (cli *Client) StoreContactDetailsAsContact(ctx context.Context, contactDetails *signalpb.ContactDetails, avatar *[]byte) (*types.Recipient, error) { - parsedUUID, err := uuid.Parse(contactDetails.GetAci()) + parsedUUID, err := ParseStringOrBinaryUUID(contactDetails.GetAci(), contactDetails.GetAciBinary()) if err != nil { return nil, err } diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 3d81259..142bc0f 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -809,7 +809,7 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess }) } if msg.MessageRequestResponse != nil { - aciUUID, _ := uuid.Parse(msg.MessageRequestResponse.GetThreadAci()) + aciUUID, _ := ParseStringOrBinaryUUID(msg.MessageRequestResponse.GetThreadAci(), msg.MessageRequestResponse.GetThreadAciBinary()) if aciUUID != uuid.Nil && msg.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT { _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aciUUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { changed = !ptr.Val(recipient.Whitelisted) || recipient.NeedsPNISignature From d9dc134b9640bd1ec432f43254e7afcfcf635287 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 28 Feb 2026 12:35:29 +0200 Subject: [PATCH 669/718] login: fix context used for background connection --- pkg/connector/login.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/connector/login.go b/pkg/connector/login.go index 5cfdae1..9116390 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -75,7 +75,7 @@ func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) { Str("action", "login"). Stringer("user_id", qr.User.MXID). Logger() - provCtx, cancel := context.WithCancel(log.WithContext(context.Background())) + provCtx, cancel := context.WithCancel(log.WithContext(qr.Main.Bridge.BackgroundCtx)) qr.cancelChan = cancel // Don't use the start context here: the channel will outlive the start request. qr.ProvChan = signalmeow.PerformProvisioning( From 7e72153efb6cb26f8bf2b3c3a434a0927fdc0717 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Mar 2026 14:25:40 +0200 Subject: [PATCH 670/718] msgconv/signalfmt: ignore unsupported body ranges --- pkg/msgconv/signalfmt/convert.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/msgconv/signalfmt/convert.go b/pkg/msgconv/signalfmt/convert.go index 5a9b520..412af36 100644 --- a/pkg/msgconv/signalfmt/convert.go +++ b/pkg/msgconv/signalfmt/convert.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/google/uuid" + "github.com/rs/zerolog" "golang.org/x/exp/maps" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -100,6 +101,9 @@ func Parse(ctx context.Context, message string, ranges []*signalpb.BodyRange, pa continue } mentionACI = uuid.UUID(rv.MentionAciBinary) + default: + zerolog.Ctx(ctx).Warn().Type("value_type", rv).Msg("Unsupported body range type") + continue } if mentionACI != uuid.Nil { userInfo := params.GetUserInfo(ctx, mentionACI) From 509dfbde0a96813d837bd7bb54140dc84ce893d6 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 2 Mar 2026 14:30:01 +0200 Subject: [PATCH 671/718] Bump version to v26.02.2 --- CHANGELOG.md | 4 ++++ cmd/mautrix-signal/main.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c6869c..dd0a2d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v26.02.2 + +* Added support for more new binary service ID fields. + # v26.02.1 * Updated libsignal to v0.87.5. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index ab7fd46..7f1d5fe 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -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.02.1", + Version: "26.02.2", SemCalVer: true, Connector: &connector.SignalConnector{}, From cb7849efd6b1918f07faf4129b58588160941b46 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 6 Mar 2026 00:12:23 +0200 Subject: [PATCH 672/718] signalmeow,msgconv/from-signal: add support for transferring attachments via disk --- go.mod | 6 +- go.sum | 12 +-- pkg/connector/directmedia.go | 16 ++-- pkg/msgconv/from-signal.go | 108 +++++++++++++++++-------- pkg/signalmeow/attachments.go | 143 ++++++++++++++++++++++++++++++++-- pkg/signalmeow/receiving.go | 3 +- 6 files changed, 229 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index 3b6cc07..6758d92 100644 --- a/go.mod +++ b/go.mod @@ -16,15 +16,15 @@ require ( github.com/tidwall/gjson v1.18.0 go.mau.fi/util v0.9.6 golang.org/x/crypto v0.48.0 - golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a + golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa golang.org/x/net v0.50.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.3 + maunium.net/go/mautrix v0.26.4-0.20260305215735-7836f35a1a74 ) require ( - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.2.0 // indirect github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect diff --git a/go.sum b/go.sum index 26c13e2..78bfb4e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +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/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= @@ -73,8 +73,8 @@ 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.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= @@ -99,5 +99,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.26.3 h1:tWZih6Vjw0qGTWuPmg9JUrQPzViTNDPGQLVc5UXC4nk= -maunium.net/go/mautrix v0.26.3/go.mod h1:v5ZdDoCwUpNqEj5OrhEoUa3L1kEddKPaAya9TgGXN38= +maunium.net/go/mautrix v0.26.4-0.20260305215735-7836f35a1a74 h1:kHlana4CKRoAzPGbagU82y+uN4k5Tvfwt1nyj3cJHEw= +maunium.net/go/mautrix v0.26.4-0.20260305215735-7836f35a1a74/go.mod h1:lJvXCZya2dGT2KW7LUO7Ucna7Ohs6hl2+7v8Ji6R3iM= diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go index 6f31e15..0877d66 100644 --- a/pkg/connector/directmedia.go +++ b/pkg/connector/directmedia.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "fmt" "io" + "os" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" @@ -41,18 +42,15 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI Uint32("size", info.Size). Msg("Direct downloading attachment") - return &mediaproxy.GetMediaResponseCallback{ - Callback: func(w io.Writer) (int64, error) { - data, err := signalmeow.DownloadAttachment( - ctx, info.CDNID, info.CDNKey, info.CDNNumber, info.Key, info.Digest, info.PlaintextDigest, info.Size, + return &mediaproxy.GetMediaResponseFile{ + Callback: func(w *os.File) (*mediaproxy.FileMeta, error) { + _, err := signalmeow.DownloadAttachment( + ctx, info.CDNID, info.CDNKey, info.CDNNumber, info.Key, info.Digest, info.PlaintextDigest, info.Size, w, ) if err != nil { - log.Err(err).Msg("Direct download failed") - return 0, err + return nil, err } - - _, err = w.Write(data) - return int64(info.Size), err + return &mediaproxy.FileMeta{}, nil }, }, nil case *signalid.DirectMediaGroupAvatar: diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index dadfe3f..4119cc5 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -22,7 +22,9 @@ import ( "encoding/base64" "errors" "fmt" + "io" "net/http" + "os" "strconv" "strings" "time" @@ -76,6 +78,7 @@ func CanConvertSignal(dm *signalpb.DataMessage) bool { } const ViewOnceDisappearTimer = 5 * time.Minute +const matrixTextMaxLength = 30000 // approximate value to avoid hitting 64 KiB PDU size limit with HTML duplication func (mc *MessageConverter) ToMatrix( ctx context.Context, @@ -123,7 +126,7 @@ func (mc *MessageConverter) ToMatrix( return cm } for i, att := range dm.GetAttachments() { - if att.GetContentType() != "text/x-signal-plain" { + if att.GetContentType() != "text/x-signal-plain" || att.GetSize() > matrixTextMaxLength { cm.Parts = append(cm.Parts, mc.convertAttachmentToMatrix(ctx, i, att, attMap)) } else { longBody, err := mc.downloadSignalLongText(ctx, att, attMap) @@ -337,7 +340,7 @@ func (mc *MessageConverter) convertContactToVCard(ctx context.Context, contact * card.Add(vcard.FieldTelephone, &field) } if contact.GetAvatar().GetAvatar() != nil { - avatarData, err := mc.downloadAttachment(ctx, contact.GetAvatar().GetAvatar(), attMap) + avatarData, err := mc.downloadAttachment(ctx, contact.GetAvatar().GetAvatar(), attMap, nil) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to download contact avatar") } else { @@ -480,7 +483,7 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker } func (mc *MessageConverter) downloadSignalLongText(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*string, error) { - data, err := mc.downloadAttachment(ctx, att, attMap) + data, err := mc.downloadAttachment(ctx, att, attMap, nil) if err != nil { return nil, err } @@ -506,7 +509,9 @@ func checkIfAttachmentExists(att *signalpb.AttachmentPointer, attMap AttachmentM return nil } -func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) ([]byte, error) { +func (mc *MessageConverter) downloadAttachment( + ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap, into *os.File, +) ([]byte, error) { if err := checkIfAttachmentExists(att, attMap); err != nil { return nil, err } @@ -517,19 +522,19 @@ func (mc *MessageConverter) downloadAttachment(ctx context.Context, att *signalp plaintextHash = target.GetPlaintextHash() } } - return signalmeow.DownloadAttachmentWithPointer(ctx, att, plaintextHash) + return signalmeow.DownloadAttachmentWithPointer(ctx, att, plaintextHash, into) } func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalpb.AttachmentPointer, attMap AttachmentMap) (*bridgev2.ConvertedMessagePart, error) { - fileName := att.GetFileName() content := &event.MessageEventContent{ + Body: att.GetFileName(), Info: &event.FileInfo{ - Width: int(att.GetWidth()), - Height: int(att.GetHeight()), - Size: int(att.GetSize()), + MimeType: att.GetContentType(), + Width: int(att.GetWidth()), + Height: int(att.GetHeight()), + Size: int(att.GetSize()), }, } - mimeType := att.GetContentType() if err := checkIfAttachmentExists(att, attMap); err != nil { return nil, err } else if mc.DirectMedia { @@ -556,25 +561,7 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp } content.URL, err = mc.Bridge.Matrix.GenerateContentURI(ctx, mediaID) } else { - data, err := mc.downloadAttachment(ctx, att, attMap) - if err != nil { - return nil, err - } - if mimeType == "" { - mimeType = http.DetectContentType(data) - } - if att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 && ffmpeg.Supported() { - data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mimeType) - if err != nil { - return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err) - } - fileName += ".ogg" - mimeType = "audio/ogg" - content.MSC3245Voice = &event.MSC3245Voice{} - // TODO include duration here (and in info) if there's some easy way to extract it with ffmpeg - //content.MSC1767Audio = &event.MSC1767Audio{} - } - content.URL, content.File, err = getIntent(ctx).UploadMedia(ctx, getPortal(ctx).MXID, data, fileName, mimeType) + err = mc.actuallyReuploadAttachment(ctx, content, att, attMap) if err != nil { return nil, err } @@ -583,7 +570,7 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp content.Info.Blurhash = att.GetBlurHash() content.Info.AnoaBlurhash = att.GetBlurHash() } - switch strings.Split(mimeType, "/")[0] { + switch strings.Split(content.Info.MimeType, "/")[0] { case "image": content.MsgType = event.MsgImage case "video": @@ -605,10 +592,8 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp }, } } - content.Body = fileName - content.Info.MimeType = mimeType if content.Body == "" { - content.Body = strings.TrimPrefix(string(content.MsgType), "m.") + exmime.ExtensionFromMimetype(mimeType) + content.Body = strings.TrimPrefix(string(content.MsgType), "m.") + exmime.ExtensionFromMimetype(content.Info.MimeType) } return &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, @@ -617,6 +602,63 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp }, nil } +func (mc *MessageConverter) actuallyReuploadAttachment( + ctx context.Context, + content *event.MessageEventContent, + att *signalpb.AttachmentPointer, + attMap AttachmentMap, +) (err error) { + convertVoice := att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 && ffmpeg.Supported() + requireFile := convertVoice + content.URL, content.File, err = getIntent(ctx).UploadMediaStream(ctx, getPortal(ctx).MXID, int64(att.GetSize()), requireFile, func(file io.Writer) (*bridgev2.FileStreamResult, error) { + osFile, ok := file.(*os.File) + inMemData, err := mc.downloadAttachment(ctx, att, attMap, osFile) + if err != nil { + return nil, err + } else if !ok { + if content.Info.MimeType == "" { + content.Info.MimeType = http.DetectContentType(inMemData) + } + _, err = file.Write(inMemData) + return &bridgev2.FileStreamResult{ + FileName: content.Body, + MimeType: content.Info.MimeType, + }, err + } + if content.Info.MimeType == "" { + header := make([]byte, 512) + _, err = osFile.ReadAt(header, 0) + if err != nil { + return nil, fmt.Errorf("failed to read file header for MIME type detection: %w", err) + } else { + content.Info.MimeType = http.DetectContentType(header) + } + } + var replFile string + if att.GetFlags()&uint32(signalpb.AttachmentPointer_VOICE_MESSAGE) != 0 && ffmpeg.Supported() { + replFile, err = ffmpeg.ConvertPath(ctx, osFile.Name(), ".ogg", []string{}, []string{"-c:a", "libopus"}, true) + if err != nil { + return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err) + } + if content.Body == "" { + content.Body = "Voice message.ogg" + } else { + content.Body += ".ogg" + } + content.Info.MimeType = "audio/ogg" + content.MSC3245Voice = &event.MSC3245Voice{} + // TODO include duration here (and in info) if there's some easy way to extract it with ffmpeg + //content.MSC1767Audio = &event.MSC1767Audio{} + } + return &bridgev2.FileStreamResult{ + ReplacementFile: replFile, + FileName: content.Body, + MimeType: content.Info.MimeType, + }, nil + }) + return +} + func (mc *MessageConverter) convertPollCreateToMatrix(create *signalpb.DataMessage_PollCreate) *bridgev2.ConvertedMessagePart { evtType := event.EventMessage if mc.ExtEvPolls { diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 6b78c68..2c8f1ea 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -31,8 +31,10 @@ import ( "math" "mime/multipart" "net/http" + "os" "github.com/rs/zerolog" + "go.mau.fi/util/fallocate" "go.mau.fi/util/random" "google.golang.org/protobuf/proto" @@ -59,25 +61,48 @@ var ErrInvalidMACForAttachment = errors.New("invalid MAC for attachment") var ErrInvalidDigestForAttachment = errors.New("invalid digest for attachment") var ErrAttachmentNotFound = errors.New("attachment not found on server") -func DownloadAttachmentWithPointer(ctx context.Context, a *signalpb.AttachmentPointer, plaintextHash []byte) ([]byte, error) { +func DownloadAttachmentWithPointer(ctx context.Context, a *signalpb.AttachmentPointer, plaintextHash []byte, into *os.File) ([]byte, error) { digest := a.GetDigest() plaintextDigest := false if digest == nil && plaintextHash != nil { digest = plaintextHash plaintextDigest = true } - return DownloadAttachment(ctx, a.GetCdnId(), a.GetCdnKey(), a.GetCdnNumber(), a.Key, digest, plaintextDigest, a.GetSize()) + return DownloadAttachment( + ctx, a.GetCdnId(), a.GetCdnKey(), a.GetCdnNumber(), a.Key, digest, plaintextDigest, a.GetSize(), into, + ) } -func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNumber uint32, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) { +func DownloadAttachment( + ctx context.Context, + cdnID uint64, + cdnKey string, + cdnNumber uint32, + key, digest []byte, + plaintextDigest bool, + size uint32, + into *os.File, +) ([]byte, error) { resp, err := web.GetAttachment(ctx, getAttachmentPath(cdnID, cdnKey), cdnNumber) if err != nil { return nil, err } - bodyReader := resp.Body - defer bodyReader.Close() + defer func() { + _ = resp.Body.Close() + }() - body, err := io.ReadAll(bodyReader) + var body []byte + var downloadedSize int64 + if into == nil || resp.StatusCode > 400 { + body = make([]byte, resp.ContentLength) + _, err = io.ReadFull(resp.Body, body) + } else { + err = fallocate.Fallocate(into, int(resp.ContentLength)) + if err != nil { + return nil, fmt.Errorf("failed to pre-allocate file for attachment: %w", err) + } + downloadedSize, err = io.Copy(into, resp.Body) + } if err != nil { return nil, err } @@ -93,6 +118,12 @@ func DownloadAttachment(ctx context.Context, cdnID uint64, cdnKey string, cdnNum return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } + if into != nil { + if _, err = into.Seek(0, io.SeekStart); err != nil { + return nil, fmt.Errorf("failed to seek attachment file after downloading: %w", err) + } + return nil, decryptAttachmentFile(into, downloadedSize, key, digest, plaintextDigest, size) + } return decryptAttachment(body, key, digest, plaintextDigest, size) } @@ -128,6 +159,59 @@ func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint return decrypted, nil } +func decryptAttachmentFile(file *os.File, downloadedSize int64, key, digest []byte, plaintextDigest bool, size uint32) error { + if !plaintextDigest { + hasher := sha256.New() + if _, err := io.Copy(hasher, file); err != nil { + return fmt.Errorf("failed to hash attachment file: %w", err) + } else if !hmac.Equal(hasher.Sum(nil), digest) { + return ErrInvalidDigestForAttachment + } else if _, err = file.Seek(0, io.SeekStart); err != nil { + return fmt.Errorf("failed to seek attachment file after hashing: %w", err) + } + } + mac := make([]byte, MACLength) + n, err := file.ReadAt(mac, downloadedSize-MACLength) + if err != nil { + return fmt.Errorf("failed to read MAC from attachment file: %w", err) + } else if n != MACLength { + return fmt.Errorf("unexpected MAC length read from attachment file: %d", n) + } + hasher := hmac.New(sha256.New, key[MACLength:]) + _, err = io.CopyN(hasher, file, downloadedSize-MACLength) + if err != nil { + return fmt.Errorf("failed to hash attachment file for MAC verification: %w", err) + } else if !hmac.Equal(hasher.Sum(nil), mac) { + return ErrInvalidMACForAttachment + } else if _, err = file.Seek(0, io.SeekStart); err != nil { + return fmt.Errorf("failed to seek attachment file after verifying mac: %w", err) + } + + decryptedSize, err := aesDecryptFile(key[:MACLength], file, downloadedSize-MACLength) + if err != nil { + return err + } else if decryptedSize < int64(size) { + return fmt.Errorf("decrypted attachment length %d < expected %d", decryptedSize, size) + } else if _, err = file.Seek(0, io.SeekStart); err != nil { + return fmt.Errorf("failed to seek attachment file after decrypting: %w", err) + } + err = file.Truncate(int64(size)) + if err != nil { + return fmt.Errorf("failed to truncate attachment file to expected size: %w", err) + } + if plaintextDigest { + hasher = sha256.New() + if _, err = io.Copy(hasher, file); err != nil { + return fmt.Errorf("failed to hash decrypted attachment file: %w", err) + } else if !hmac.Equal(hasher.Sum(nil), digest) { + return fmt.Errorf("%w (plaintext hash)", ErrInvalidDigestForAttachment) + } else if _, err = file.Seek(0, io.SeekStart); err != nil { + return fmt.Errorf("failed to seek attachment file after hashing plaintext: %w", err) + } + } + return nil +} + type attachmentV4UploadAttributes struct { Cdn uint32 `json:"cdn"` Key string `json:"key"` @@ -371,7 +455,7 @@ func aesDecrypt(key, ciphertext []byte) ([]byte, error) { return nil, fmt.Errorf("ciphertext not multiple of AES blocksize (%d extra bytes)", len(ciphertext)%aes.BlockSize) } - iv := ciphertext[:aes.BlockSize] + iv := ciphertext[:IVLength] mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(ciphertext, ciphertext) pad := ciphertext[len(ciphertext)-1] @@ -381,6 +465,51 @@ func aesDecrypt(key, ciphertext []byte) ([]byte, error) { return ciphertext[aes.BlockSize : len(ciphertext)-int(pad)], nil } +func aesDecryptFile(key []byte, file *os.File, downloadedSize int64) (int64, error) { + block, err := aes.NewCipher(key) + if err != nil { + return 0, err + } + fileReader := io.LimitReader(file, downloadedSize) + + if downloadedSize%aes.BlockSize != 0 { + return 0, fmt.Errorf("ciphertext not multiple of AES blocksize (%d extra bytes)", downloadedSize%aes.BlockSize) + } + + iv := make([]byte, IVLength) + n, err := fileReader.Read(iv) + if err != nil { + return 0, fmt.Errorf("failed to read IV from attachment file: %w", err) + } else if n != IVLength { + return 0, fmt.Errorf("unexpected IV length read from attachment file: %d", n) + } + mode := cipher.NewCBCDecrypter(block, iv) + buf := make([]byte, 4096) + var offset int64 + var pad byte + for { + n, err = fileReader.Read(buf) + if err != nil && !errors.Is(err, io.EOF) { + return 0, fmt.Errorf("failed to read from attachment file: %w", err) + } + if n > 0 { + mode.CryptBlocks(buf[:n], buf[:n]) + if _, err = file.WriteAt(buf[:n], offset); err != nil { + return 0, fmt.Errorf("failed to write decrypted data to attachment file: %w", err) + } + offset += int64(n) + pad = buf[n-1] + } + if errors.Is(err, io.EOF) { + break + } + } + if pad > aes.BlockSize { + return 0, fmt.Errorf("pad value (%d) larger than AES blocksize (%d)", pad, aes.BlockSize) + } + return downloadedSize - int64(pad), nil +} + func appendMAC(key, body []byte) []byte { m := hmac.New(sha256.New, key) m.Write(body) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 142bc0f..45fafa5 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -759,7 +759,8 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess log.Debug().Msg("Recieved sync message contacts") blob := msg.Contacts.Blob if blob != nil { - contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil) + // TODO roundtrip via disk to save memory + contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil, nil) if err != nil { log.Err(err).Msg("Contacts Sync DownloadAttachment error") } From 37a0199f79781ea1f4ba0427383e2dcc10e64fea Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 28 Feb 2026 12:33:08 +0200 Subject: [PATCH 673/718] handlematrix,msgconv,signalmeow: switch to sending binary ID fields --- pkg/connector/handlematrix.go | 26 +++++++--------- pkg/msgconv/from-matrix.go | 8 ++--- pkg/msgconv/from-signal-backup.go | 6 +--- pkg/msgconv/signalfmt/tags.go | 4 +-- pkg/signalmeow/sending.go | 52 ++++++++++++------------------- 5 files changed, 37 insertions(+), 59 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 8819d69..0ef84f6 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -205,12 +205,10 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M Timestamp: proto.Uint64(ts), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.PreHandleResp.Emoji), - Remove: proto.Bool(false), - TargetAuthorAci: proto.String(targetAuthorACI.String()), - // TODO update aci format - //TargetAuthorAciBinary: targetAuthorACI[:], - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + Emoji: proto.String(msg.PreHandleResp.Emoji), + Remove: proto.Bool(false), + TargetAuthorAciBinary: targetAuthorACI[:], + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, }, } @@ -232,12 +230,10 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid Timestamp: proto.Uint64(ts), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.TargetReaction.Emoji), - Remove: proto.Bool(true), - TargetAuthorAci: proto.String(targetAuthorACI.String()), - // TODO update aci format - //TargetAuthorAciBinary: targetAuthorACI[:], - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), + Emoji: proto.String(msg.TargetReaction.Emoji), + Remove: proto.Bool(true), + TargetAuthorAciBinary: targetAuthorACI[:], + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, }, } @@ -722,8 +718,8 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2 var conversationID *signalpb.ConversationIdentifier if groupID == "" { conversationID = &signalpb.ConversationIdentifier{ - Identifier: &signalpb.ConversationIdentifier_ThreadServiceId{ - ThreadServiceId: userID.String(), + Identifier: &signalpb.ConversationIdentifier_ThreadServiceIdBinary{ + ThreadServiceIdBinary: userID.Bytes(), }, } } else { @@ -865,7 +861,7 @@ func (s *SignalClient) syncMessageRequestResponse( } accept.GroupId = gidBytes[:] } else if userID.Type == libsignalgo.ServiceIDTypeACI { - accept.ThreadAci = ptr.Ptr(userID.UUID.String()) + accept.ThreadAciBinary = userID.UUID[:] } else { return fmt.Errorf("invalid portal ID for message request response: %s", portal.ID) } diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index fa5deb4..89b0181 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -60,11 +60,9 @@ func (mc *MessageConverter) ToSignal( authorACI, messageID, err := signalid.ParseMessageID(replyTo.ID) if err == nil { dm.Quote = &signalpb.DataMessage_Quote{ - Id: proto.Uint64(messageID), - AuthorAci: proto.String(authorACI.String()), - // TODO update aci format - //AuthorAciBinary: authorACI[:], - Type: signalpb.DataMessage_Quote_NORMAL.Enum(), + Id: proto.Uint64(messageID), + AuthorAciBinary: authorACI[:], + Type: signalpb.DataMessage_Quote_NORMAL.Enum(), } if replyTo.Metadata.(*signalid.MessageMetadata).ContainsAttachments { dm.Quote.Attachments = make([]*signalpb.DataMessage_Quote_QuotedAttachment, 1) diff --git a/pkg/msgconv/from-signal-backup.go b/pkg/msgconv/from-signal-backup.go index 97f756c..978c6a6 100644 --- a/pkg/msgconv/from-signal-backup.go +++ b/pkg/msgconv/from-signal-backup.go @@ -248,11 +248,7 @@ func backupToSignalBodyRange(from *backuppb.BodyRange) *signalpb.BodyRange { out.Length = &from.Length switch av := from.AssociatedValue.(type) { case *backuppb.BodyRange_MentionAci: - // TODO confirm this is correct - if len(av.MentionAci) != 16 { - return nil - } - out.AssociatedValue = &signalpb.BodyRange_MentionAci{MentionAci: uuid.UUID(av.MentionAci).String()} + out.AssociatedValue = &signalpb.BodyRange_MentionAciBinary{MentionAciBinary: av.MentionAci} case *backuppb.BodyRange_Style_: out.AssociatedValue = &signalpb.BodyRange_Style_{Style: signalpb.BodyRange_Style(av.Style)} } diff --git a/pkg/msgconv/signalfmt/tags.go b/pkg/msgconv/signalfmt/tags.go index 043bb43..b273e0e 100644 --- a/pkg/msgconv/signalfmt/tags.go +++ b/pkg/msgconv/signalfmt/tags.go @@ -40,8 +40,8 @@ func (m Mention) String() string { } func (m Mention) Proto() signalpb.BodyRangeAssociatedValue { - return &signalpb.BodyRange_MentionAci{ - MentionAci: m.UUID.String(), + return &signalpb.BodyRange_MentionAciBinary{ + MentionAciBinary: m.UUID[:], } } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 86bc1db..568b4d4 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -306,10 +306,8 @@ func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} for _, result := range results { unidentifiedStatuses = append(unidentifiedStatuses, &signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ - DestinationServiceId: proto.String(result.Recipient.String()), - // TODO update aci format - //DestinationServiceIdBinary: result.Recipient.Bytes(), - Unidentified: &result.Unidentified, + DestinationServiceIdBinary: result.Recipient.Bytes(), + Unidentified: &result.Unidentified, }) } return &signalpb.Content{ @@ -327,10 +325,8 @@ func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} for _, result := range results { unidentifiedStatuses = append(unidentifiedStatuses, &signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ - DestinationServiceId: proto.String(result.Recipient.String()), - // TODO update aci format - //DestinationServiceIdBinary: result.Recipient.Bytes(), - Unidentified: &result.Unidentified, + DestinationServiceIdBinary: result.Recipient.Bytes(), + Unidentified: &result.Unidentified, }) } return &signalpb.Content{ @@ -349,20 +345,16 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - Message: dataMessage, - DestinationE164: result.RecipientE164, - DestinationServiceId: proto.String(result.Recipient.String()), - // TODO update aci format - //DestinationServiceIdBinary: result.Recipient.Bytes(), - Timestamp: dataMessage.Timestamp, - ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), + Message: dataMessage, + DestinationE164: result.RecipientE164, + DestinationServiceIdBinary: result.Recipient.Bytes(), + Timestamp: dataMessage.Timestamp, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), - // TODO update aci format - //DestinationServiceIdBinary: result.Recipient.Bytes(), - Unidentified: &result.Unidentified, - DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), + DestinationServiceIdBinary: result.Recipient.Bytes(), + Unidentified: &result.Unidentified, + DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, }, }, @@ -374,20 +366,16 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su return &signalpb.Content{ SyncMessage: &signalpb.SyncMessage{ Sent: &signalpb.SyncMessage_Sent{ - EditMessage: editMessage, - DestinationE164: result.RecipientE164, - DestinationServiceId: proto.String(result.Recipient.String()), - // TODO update aci format - //DestinationServiceIdBinary: result.Recipient.Bytes(), - Timestamp: editMessage.DataMessage.Timestamp, - ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), + EditMessage: editMessage, + DestinationE164: result.RecipientE164, + DestinationServiceIdBinary: result.Recipient.Bytes(), + Timestamp: editMessage.DataMessage.Timestamp, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ { - DestinationServiceId: proto.String(result.Recipient.String()), - // TODO update aci format - //DestinationServiceIdBinary: result.Recipient.Bytes(), - Unidentified: &result.Unidentified, - DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), + DestinationServiceIdBinary: result.Recipient.Bytes(), + Unidentified: &result.Unidentified, + DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, }, }, From 01b06408ab5d36a1fc2e69a370acfe13251ccf07 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 9 Mar 2026 11:48:10 +0200 Subject: [PATCH 674/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6758d92..a97408d 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.50.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.4-0.20260305215735-7836f35a1a74 + maunium.net/go/mautrix v0.26.4-0.20260307142642-c107c25d078e ) require ( diff --git a/go.sum b/go.sum index 78bfb4e..239a198 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.26.4-0.20260305215735-7836f35a1a74 h1:kHlana4CKRoAzPGbagU82y+uN4k5Tvfwt1nyj3cJHEw= -maunium.net/go/mautrix v0.26.4-0.20260305215735-7836f35a1a74/go.mod h1:lJvXCZya2dGT2KW7LUO7Ucna7Ohs6hl2+7v8Ji6R3iM= +maunium.net/go/mautrix v0.26.4-0.20260307142642-c107c25d078e h1:R1ebuJojcAFo14HKB6Kz2q6FWWIQPc2XRMkuRUq7BVY= +maunium.net/go/mautrix v0.26.4-0.20260307142642-c107c25d078e/go.mod h1:lJvXCZya2dGT2KW7LUO7Ucna7Ohs6hl2+7v8Ji6R3iM= From f4b6d0641ffef16e0d79a8ba17c6ec4ca29de821 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 16 Mar 2026 17:32:08 +0200 Subject: [PATCH 675/718] Bump version to v26.03 --- CHANGELOG.md | 6 ++++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 22 ++++++++++----------- go.sum | 40 +++++++++++++++++++------------------- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0a2d4..d992cab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v26.03 + +* Switched to sending binary service ID fields in outgoing messages. +* Added support for roundtripping large attachments via disk to avoid keeping + the entire file in memory during en/decryption. + # v26.02.2 * Added support for more new binary service ID fields. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index 7f1d5fe..cc1ec10 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -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.02.2", + Version: "26.03", SemCalVer: true, Connector: &connector.SignalConnector{}, diff --git a/go.mod b/go.mod index a97408d..b0be4f5 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.25.0 -toolchain go1.26.0 +toolchain go1.26.1 tool go.mau.fi/util/cmd/maubuild @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.6 - golang.org/x/crypto v0.48.0 - golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa - golang.org/x/net v0.50.0 + go.mau.fi/util v0.9.7 + golang.org/x/crypto v0.49.0 + golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 + golang.org/x/net v0.52.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.4-0.20260307142642-c107c25d078e + maunium.net/go/mautrix v0.26.4 ) require ( @@ -32,7 +32,7 @@ require ( 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.34 // indirect - github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect + github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -42,10 +42,10 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.7.16 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/mod v0.33.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.41.0 // indirect - golang.org/x/text v0.34.0 // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // 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 diff --git a/go.sum b/go.sum index 239a198..ec06d77 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= -github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -67,27 +67,27 @@ 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.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.6 h1:2nsvxm49KhI3wrFltr0+wSUBlnQ4CMtykuELjpIU+ts= -go.mau.fi/util v0.9.6/go.mod h1:sIJpRH7Iy5Ad1SBuxQoatxtIeErgzxCtjd/2hCMkYMI= +go.mau.fi/util v0.9.7 h1:AWGNbJfz1zRcQOKeOEYhKUG2fT+/26Gy6kyqcH8tnBg= +go.mau.fi/util v0.9.7/go.mod h1:5T2f3ZWZFAGgmFwg3dGw7YK6kIsb9lryDzvynoR98pE= 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.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= -golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= +golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -99,5 +99,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.26.4-0.20260307142642-c107c25d078e h1:R1ebuJojcAFo14HKB6Kz2q6FWWIQPc2XRMkuRUq7BVY= -maunium.net/go/mautrix v0.26.4-0.20260307142642-c107c25d078e/go.mod h1:lJvXCZya2dGT2KW7LUO7Ucna7Ohs6hl2+7v8Ji6R3iM= +maunium.net/go/mautrix v0.26.4 h1:enHSnkf0L2V9+VnfJfNhKSReSW6pBKS/x3Su+v+Vovs= +maunium.net/go/mautrix v0.26.4/go.mod h1:YWw8NWTszsbyFAznboicBObwHPgTSLcuTbVX2kY7U2M= From 09bb6d71608cde2e3781b827a1a20aad5f50f279 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 19 Mar 2026 17:58:19 +0200 Subject: [PATCH 676/718] libsignal: update to v0.89.1 --- pkg/libsignalgo/identitykeystore.go | 41 ++++++++++-------- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 66 +++++++++++++++++++++++++---- pkg/libsignalgo/version.go | 2 +- 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index 6a425e8..43941da 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -20,7 +20,7 @@ package libsignalgo /* #include "./libsignal-ffi.h" -extern int signal_get_identity_key_pair_callback(void *store_ctx, SignalMutPointerPrivateKey *keyp); +extern int signal_get_identity_key_pair_callback(void *store_ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *keyp); extern int signal_get_local_registration_id_callback(void *store_ctx, uint32_t *idp); extern int signal_save_identity_key_callback(void *store_ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); extern int signal_get_identity_key_callback(void *store_ctx, SignalMutPointerPublicKey *public_keyp, SignalMutPointerProtocolAddress address); @@ -49,22 +49,29 @@ type IdentityKeyStore interface { } //export signal_get_identity_key_pair_callback -func signal_get_identity_key_pair_callback(storeCtx unsafe.Pointer, keyp *C.SignalMutPointerPrivateKey) C.int { +func signal_get_identity_key_pair_callback(storeCtx unsafe.Pointer, keyp *C.SignalPairOfMutPointerPrivateKeyMutPointerPublicKey) C.int { return wrapStoreCallback(storeCtx, func(store IdentityKeyStore, ctx context.Context) error { key, err := store.GetIdentityKeyPair(ctx) if err != nil { return err } if key == nil { - keyp.raw = nil - } else { - clone, err := key.privateKey.Clone() - if err != nil { - return err - } - clone.CancelFinalizer() - keyp.raw = clone.ptr + keyp.first.raw = nil + keyp.second.raw = nil + return nil } + privClone, err := key.privateKey.Clone() + if err != nil { + return err + } + pubClone, err := key.publicKey.Clone() + if err != nil { + return err + } + privClone.CancelFinalizer() + pubClone.CancelFinalizer() + keyp.first.raw = privClone.ptr + keyp.second.raw = pubClone.ptr return err }) } @@ -151,12 +158,12 @@ func signal_destroy_identity_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct { return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{ - ctx: wrapStore(ctx, store), - get_local_identity_private_key: C.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityPrivateKey(C.signal_get_identity_key_pair_callback), - get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), - get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), - save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), - is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), - destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), + ctx: wrapStore(ctx, store), + get_local_identity_key_pair: C.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), + get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), + get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), + save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), + is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), + destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), }} } diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index ffaa9f0..a5e7667 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit ffaa9f0435569d6775d8be636f268f882ed67ce3 +Subproject commit a5e76674882a89bac1ed3f4a982120652966d21e diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index deb72cd..59409c8 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -260,6 +260,7 @@ typedef enum { SignalErrorCodeKeyTransparencyVerificationFailed = 211, SignalErrorCodeRequestUnauthorized = 220, SignalErrorCodeMismatchedDevices = 221, + SignalErrorCodeServiceIdNotFound = 222, } SignalErrorCode; enum SignalSvr2CredentialsResult { @@ -776,14 +777,19 @@ typedef struct { const SignalSessionStore *raw; } SignalConstPointerFfiSessionStoreStruct; -typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalIdentityPrivateKey)(void *ctx, SignalMutPointerPrivateKey *out); - -typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); - typedef struct { SignalPublicKey *raw; } SignalMutPointerPublicKey; +typedef struct { + SignalMutPointerPrivateKey first; + SignalMutPointerPublicKey second; +} SignalPairOfMutPointerPrivateKeyMutPointerPublicKey; + +typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out); + +typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); + typedef int (*SignalFfiBridgeIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); typedef int (*SignalFfiBridgeIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); @@ -794,7 +800,7 @@ typedef void (*SignalFfiBridgeIdentityKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeIdentityKeyStoreGetLocalIdentityPrivateKey get_local_identity_private_key; + SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; SignalFfiBridgeIdentityKeyStoreGetIdentityKey get_identity_key; SignalFfiBridgeIdentityKeyStoreSaveIdentityKey save_identity_key; @@ -993,6 +999,21 @@ typedef struct { size_t length; } SignalOwnedBufferOfServiceIdFixedWidthBinaryBytes; +typedef struct { + SignalPreKeyBundle *raw; +} SignalMutPointerPreKeyBundle; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalMutPointerPreKeyBundle *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfMutPointerPreKeyBundle; + typedef struct { SignalSenderKeyRecord *raw; } SignalMutPointerSenderKeyRecord; @@ -1190,10 +1211,6 @@ typedef struct { SignalPlaintextContent *raw; } SignalMutPointerPlaintextContent; -typedef struct { - SignalPreKeyBundle *raw; -} SignalMutPointerPreKeyBundle; - typedef struct { const SignalPreKeyBundle *raw; } SignalConstPointerPreKeyBundle; @@ -1523,6 +1540,26 @@ typedef struct { SignalCancellationId cancellation_id; } SignalCPromiseMutPointerUnauthenticatedChatConnection; +typedef struct { + SignalMutPointerPublicKey identity_key; + SignalOwnedBufferOfMutPointerPreKeyBundle pre_key_bundles; +} SignalFfiPreKeysResponse; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiPreKeysResponse *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiPreKeysResponse; + /** * A C callback used to report the results of Rust futures. * @@ -1918,6 +1955,13 @@ void signal_free_list_of_strings(SignalOwnedBufferOfCStringPtr buffer); void signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry buffer); +/** + * This frees a buffer of PreKeyBundle pointers, and _does not_ free the + * pointers within the buffer. This _only_ frees the buffer containing + * the pointers. + */ +void signal_free_outer_buffer_list_of_prekey_bundles(SignalOwnedBufferOfMutPointerPreKeyBundle buffer); + void signal_free_string(const char *buf); SignalFfiError *signal_generic_server_public_params_check_valid_contents(SignalBorrowedBuffer params_bytes); @@ -2686,6 +2730,10 @@ SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerU SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat); +SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_group_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer auth, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); + +SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_key_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const uint8_t (*auth)[16], const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); + SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index bb1774c..ccd0d51 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.87.5" +const Version = "v0.89.1" From 4842b35ab4a9a500a1cfbbc863687eb5c4236cc9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 19 Mar 2026 17:59:15 +0200 Subject: [PATCH 677/718] msgconv/from-signal: add more details to quote aci parse error log --- pkg/msgconv/from-signal.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 4119cc5..96b4f10 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -179,7 +179,10 @@ func (mc *MessageConverter) ToMatrix( if dm.Quote != nil { authorACI, err := signalmeow.ParseStringOrBinaryUUID(dm.Quote.GetAuthorAci(), dm.Quote.GetAuthorAciBinary()) if err != nil { - zerolog.Ctx(ctx).Err(err).Str("author_aci", dm.Quote.GetAuthorAci()).Msg("Failed to parse quote author ACI") + zerolog.Ctx(ctx).Err(err). + Str("author_aci", dm.Quote.GetAuthorAci()). + Hex("author_aci_binary", dm.Quote.GetAuthorAciBinary()). + Msg("Failed to parse quote author ACI") } else { cm.ReplyTo = &networkid.MessageOptionalPartID{ MessageID: signalid.MakeMessageID(authorACI, dm.Quote.GetId()), From 69f9b48e356a76c978e6f67cc49cdcd5aedf4f4e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 19 Mar 2026 20:57:46 +0200 Subject: [PATCH 678/718] signalmeow/attachments: handle unknown content length in downloads Closes #644 --- pkg/signalmeow/attachments.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index 2c8f1ea..e09dd7e 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -93,9 +93,15 @@ func DownloadAttachment( var body []byte var downloadedSize int64 - if into == nil || resp.StatusCode > 400 { - body = make([]byte, resp.ContentLength) - _, err = io.ReadFull(resp.Body, body) + if resp.StatusCode > 400 { + body, err = io.ReadAll(io.LimitReader(resp.Body, 4096)) + } else if into == nil { + if resp.ContentLength > 0 { + body = make([]byte, resp.ContentLength) + _, err = io.ReadFull(resp.Body, body) + } else { + body, err = io.ReadAll(http.MaxBytesReader(nil, resp.Body, max(int64(size), 32*1024)*2)) + } } else { err = fallocate.Fallocate(into, int(resp.ContentLength)) if err != nil { From f49b11c4cbbb46447e8aba055704ef973870ca27 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 22 Mar 2026 12:26:01 +0200 Subject: [PATCH 679/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b0be4f5..99019d5 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.52.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.4 + maunium.net/go/mautrix v0.26.5-0.20260322102453-0c955c396df7 ) require ( diff --git a/go.sum b/go.sum index ec06d77..0ec9eec 100644 --- a/go.sum +++ b/go.sum @@ -99,5 +99,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.26.4 h1:enHSnkf0L2V9+VnfJfNhKSReSW6pBKS/x3Su+v+Vovs= -maunium.net/go/mautrix v0.26.4/go.mod h1:YWw8NWTszsbyFAznboicBObwHPgTSLcuTbVX2kY7U2M= +maunium.net/go/mautrix v0.26.5-0.20260322102453-0c955c396df7 h1:KUhlBHWGgknqYC2V8di4DFNh73atDtgPlqqO5FoLmPc= +maunium.net/go/mautrix v0.26.5-0.20260322102453-0c955c396df7/go.mod h1:YWw8NWTszsbyFAznboicBObwHPgTSLcuTbVX2kY7U2M= From 73a8a77e8855419894704402d47ccd9ba338fd3a Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 24 Mar 2026 15:24:03 +0200 Subject: [PATCH 680/718] signalmeow: don't drop valid contact entries --- pkg/signalmeow/receiving.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 45fafa5..9fa4b84 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -773,7 +773,7 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess convertedContacts := make([]*types.Recipient, 0, len(contacts)) err = cli.Store.DoContactTxn(ctx, func(ctx context.Context) error { for i, signalContact := range contacts { - if signalContact.Aci == nil || *signalContact.Aci == "" { + if (signalContact.Aci == nil || *signalContact.Aci == "") && len(signalContact.AciBinary) != 16 { // TODO lookup PNI via CDSI and store that when ACI is missing? log.Info(). Any("contact", signalContact). From 40f320061c1d09691a7f15f901b814f5b58e27f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 31 Mar 2026 19:56:36 +0300 Subject: [PATCH 681/718] dependencies: update mautrix-go --- go.mod | 12 ++++++------ go.sum | 32 ++++++++++++-------------------- pkg/connector/handlematrix.go | 3 +++ 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 99019d5..c2ff042 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 github.com/mattn/go-pointer v0.0.1 - github.com/rs/zerolog v1.34.0 + github.com/rs/zerolog v1.35.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 go.mau.fi/util v0.9.7 @@ -20,18 +20,18 @@ require ( golang.org/x/net v0.52.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.5-0.20260322102453-0c955c396df7 + maunium.net/go/mautrix v0.26.5-0.20260331163037-18917f3bdc14 ) require ( filippo.io/edwards25519 v1.2.0 // indirect - github.com/coreos/go-systemd/v22 v22.6.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.11.2 // indirect + github.com/lib/pq v1.12.0 // 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.34 // indirect + github.com/mattn/go-sqlite3 v1.14.37 // indirect github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -40,7 +40,7 @@ require ( 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.7.16 // indirect + github.com/yuin/goldmark v1.8.2 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect golang.org/x/mod v0.34.0 // indirect golang.org/x/sync v0.20.0 // indirect diff --git a/go.sum b/go.sum index 0ec9eec..44ce4a1 100644 --- a/go.sum +++ b/go.sum @@ -4,15 +4,13 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= -github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= +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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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= @@ -24,23 +22,19 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs= -github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/lib/pq v1.12.0 h1:mC1zeiNamwKBecjHarAr26c/+d8V5w/u4J0I/yASbJo= +github.com/lib/pq v1.12.0/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-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.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= -github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.37 h1:3DOZp4cXis1cUIpCfXLtmlGolNLp2VEqhiB/PARNBIg= +github.com/mattn/go-sqlite3 v1.14.37/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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= @@ -48,8 +42,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= -github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI= +github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -65,8 +59,8 @@ 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.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE= -github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= +github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= +github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= go.mau.fi/util v0.9.7 h1:AWGNbJfz1zRcQOKeOEYhKUG2fT+/26Gy6kyqcH8tnBg= go.mau.fi/util v0.9.7/go.mod h1:5T2f3ZWZFAGgmFwg3dGw7YK6kIsb9lryDzvynoR98pE= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= @@ -81,9 +75,7 @@ golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= @@ -99,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.26.5-0.20260322102453-0c955c396df7 h1:KUhlBHWGgknqYC2V8di4DFNh73atDtgPlqqO5FoLmPc= -maunium.net/go/mautrix v0.26.5-0.20260322102453-0c955c396df7/go.mod h1:YWw8NWTszsbyFAznboicBObwHPgTSLcuTbVX2kY7U2M= +maunium.net/go/mautrix v0.26.5-0.20260331163037-18917f3bdc14 h1:y+4gtqKBMTtcVUiAeWJnvp88JLo/h3myQPsz1rZfNOY= +maunium.net/go/mautrix v0.26.5-0.20260331163037-18917f3bdc14/go.mod h1:RUSMBPky3jhXB7Ux+AptfkEvFlJ4ajZKCYiXI8YzxVE= diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 0ef84f6..89b7d45 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -407,6 +407,9 @@ func (s *SignalClient) HandleMatrixRoomTopic(ctx context.Context, msg *bridgev2. } func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2.MatrixMembershipChange) (*bridgev2.MatrixMembershipResult, error) { + if msg.Type.IsSelf && msg.OrigSender != nil { + return nil, nil + } var targetIntent bridgev2.MatrixAPI var targetSignalID libsignalgo.ServiceID var err error From e9da747f37d21b5ddadb88a190b508436c0b27de Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 7 Apr 2026 00:50:21 +0300 Subject: [PATCH 682/718] .github: add checklist to bug report template --- .github/ISSUE_TEMPLATE/bug.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 3703df9..c10630f 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -7,10 +7,11 @@ type: Bug --- - -It's always best to ask in the Matrix room first, especially if you aren't sure -what details are needed. Issues with insufficient detail will likely just be -ignored or closed immediately. ---> +### Checklist + + + +* [ ] This is an actual bug, not just a setup issue (see the [troubleshooting docs](https://docs.mau.fi/bridges/general/troubleshooting.html) or ask in the Matrix room for setup help). +* [ ] I am certain that sufficient information is included. Ask in the Matrix room first if not. From 426b1f82669e8ba4690006016471b52b416f9db0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 7 Apr 2026 00:50:47 +0300 Subject: [PATCH 683/718] chatinfo: fix room name in DMs --- pkg/connector/chatinfo.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 4ce1f9d..87f1f6f 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -414,7 +414,7 @@ func (s *SignalClient) GetContactList(ctx context.Context) ([]*bridgev2.ResolveI } func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *types.Recipient, backupChat *store.BackupChat) *bridgev2.CreateChatResponse { - name := "" + namePtr := bridgev2.DefaultChatName topic := PrivateChatTopic selfUser := s.makeEventSender(s.Client.Store.ACI) members := &bridgev2.ChatMemberList{ @@ -441,7 +441,7 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type var serviceID libsignalgo.ServiceID var avatar *bridgev2.Avatar if recipient.ACI == uuid.Nil { - name = s.Main.Config.FormatDisplayname(recipient) + namePtr = ptr.Ptr(s.Main.Config.FormatDisplayname(recipient)) serviceID = libsignalgo.NewPNIServiceID(recipient.PNI) } else { if backupChat == nil { @@ -453,7 +453,7 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type } members.OtherUserID = signalid.MakeUserID(recipient.ACI) if recipient.ACI == s.Client.Store.ACI { - name = NoteToSelfName + namePtr = ptr.Ptr(NoteToSelfName) avatar = &bridgev2.Avatar{ ID: networkid.AvatarID(s.Main.Config.NoteToSelfAvatar), Remove: len(s.Main.Config.NoteToSelfAvatar) == 0, @@ -474,7 +474,7 @@ func (s *SignalClient) makeCreateDMResponse(ctx context.Context, recipient *type return &bridgev2.CreateChatResponse{ PortalKey: s.makeDMPortalKey(serviceID), PortalInfo: &bridgev2.ChatInfo{ - Name: &name, + Name: namePtr, Avatar: avatar, Topic: &topic, Members: members, From 9257116792a818485859627ed1db857977d98b8f Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 9 Apr 2026 13:58:06 +0300 Subject: [PATCH 684/718] client: ensure connection is cancelled when bridge is stopped --- pkg/connector/client.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/connector/client.go b/pkg/connector/client.go index e224c17..186ab4d 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -281,7 +281,7 @@ func (s *SignalClient) Disconnect() { } func (s *SignalClient) postLoginConnect() { - ctx := s.UserLogin.Log.WithContext(context.Background()) + ctx := s.UserLogin.Log.WithContext(s.Main.Bridge.BackgroundCtx) // TODO it would be more proper to only connect after syncing, // but currently syncing will fetch group info online, so it has to be connected. s.tryConnect(ctx, 0, false) @@ -300,6 +300,13 @@ func (s *SignalClient) postLoginConnect() { } func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bool) { + if ctx.Err() != nil { + zerolog.Ctx(ctx).Debug(). + Int("retry_count", retryCount). + AnErr("ctx_err", ctx.Err()). + Msg("Context is canceled, not trying to connect") + return + } if retryCount == 0 { s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) } From e5a4f55e83749f25c153c6bea02f2c89c4fa932d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 9 Apr 2026 13:58:24 +0300 Subject: [PATCH 685/718] signalmeow/backup: return early if WaitForTransfer is cancelled --- pkg/signalmeow/backup.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/backup.go b/pkg/signalmeow/backup.go index fcbfff0..f003e19 100644 --- a/pkg/signalmeow/backup.go +++ b/pkg/signalmeow/backup.go @@ -282,7 +282,11 @@ func (cli *Client) WaitForTransfer(ctx context.Context) (*TransferArchiveMetadat } reqDuration := time.Since(reqStart) if reqDuration < reqTimeout-10*time.Second { - time.Sleep(15 * time.Second) + select { + case <-time.After(15 * time.Second): + case <-ctx.Done(): + return nil, ctx.Err() + } } } } From 9d34e0d7fac468be20b6b451092b58aad36624dd Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 9 Apr 2026 13:58:58 +0300 Subject: [PATCH 686/718] chatsync: catch missing recipients for backup chats --- pkg/connector/chatsync.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/connector/chatsync.go b/pkg/connector/chatsync.go index 5211270..7c891aa 100644 --- a/pkg/connector/chatsync.go +++ b/pkg/connector/chatsync.go @@ -69,6 +69,12 @@ func (s *SignalClient) syncChats(ctx context.Context) { if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get recipient for chat") continue + } else if recipient == nil { + zerolog.Ctx(ctx).Warn(). + Uint64("backup_chat_id", chat.Id). + Uint64("backup_recipient_id", chat.RecipientId). + Msg("No recipient found for chat") + continue } resyncEvt := &simplevent.ChatResync{ EventMeta: simplevent.EventMeta{ From 59eaa364159c4910575e635cb9d78fd59077f7ff Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 9 Apr 2026 13:59:21 +0300 Subject: [PATCH 687/718] chatsync: stop syncing if client is logged out Closes #645 --- pkg/connector/chatsync.go | 17 ++++++++++++- pkg/connector/client.go | 51 ++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/pkg/connector/chatsync.go b/pkg/connector/chatsync.go index 7c891aa..636cad7 100644 --- a/pkg/connector/chatsync.go +++ b/pkg/connector/chatsync.go @@ -32,10 +32,19 @@ import ( "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) -func (s *SignalClient) syncChats(ctx context.Context) { +func (s *SignalClient) stopChatSync() { + if cancel := s.cancelChatSync.Swap(nil); cancel != nil { + (*cancel)() + } +} + +func (s *SignalClient) syncChats(ctx context.Context, cancel context.CancelFunc) { + defer cancel() + if s.UserLogin.Metadata.(*signalid.UserLoginMetadata).ChatsSynced { return } + if s.Client.Store.EphemeralBackupKey != nil { zerolog.Ctx(ctx).Info().Msg("Fetching transfer archive before syncing chats") meta, err := s.Client.WaitForTransfer(ctx) @@ -65,6 +74,12 @@ func (s *SignalClient) syncChats(ctx context.Context) { } zerolog.Ctx(ctx).Info().Int("chat_count", len(chats)).Msg("Fetched chats to sync from database") for _, chat := range chats { + if ctx.Err() != nil { + zerolog.Ctx(ctx).Debug(). + AnErr("ctx_err", ctx.Err()). + Msg("Context cancelled while syncing chats, stopping") + return + } recipient, err := s.Client.Store.BackupStore.GetBackupRecipient(ctx, chat.RecipientId) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get recipient for chat") diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 186ab4d..17ee216 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -19,6 +19,7 @@ package connector import ( "context" "fmt" + "sync/atomic" "time" "github.com/rs/zerolog" @@ -39,6 +40,7 @@ type SignalClient struct { Ghost *bridgev2.Ghost queueEmptyWaiter *exsync.Event + cancelChatSync atomic.Pointer[context.CancelFunc] } var ( @@ -78,6 +80,7 @@ func (s *SignalClient) LogoutRemote(ctx context.Context) { if s.Client == nil { return } + s.stopChatSync() err := s.Client.Unlink(ctx) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to unlink device") @@ -176,6 +179,7 @@ func (s *SignalClient) bridgeStateLoop(statusChan <-chan signalmeow.SignalConnec } case signalmeow.SignalConnectionEventLoggedOut: + s.stopChatSync() s.UserLogin.Log.Debug().Msg("Sending BadCredentials BridgeState") if err == nil { s.UserLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateBadCredentials, Message: "You have been logged out of Signal, please reconnect"}) @@ -274,6 +278,7 @@ func (s *SignalClient) Disconnect() { if s.Client == nil { return } + s.stopChatSync() err := s.Client.StopReceiveLoops() if err != nil { s.UserLogin.Log.Err(err).Msg("Failed to stop receive loops") @@ -282,24 +287,10 @@ func (s *SignalClient) Disconnect() { func (s *SignalClient) postLoginConnect() { ctx := s.UserLogin.Log.WithContext(s.Main.Bridge.BackgroundCtx) - // TODO it would be more proper to only connect after syncing, - // but currently syncing will fetch group info online, so it has to be connected. s.tryConnect(ctx, 0, false) - if s.Client.Store.EphemeralBackupKey != nil { - go func() { - if s.Client.Store.MasterKey != nil { - s.Client.SyncStorage(ctx) - } else { - s.UserLogin.Log.Warn().Msg("No master key for storage sync before backup sync") - } - s.syncChats(ctx) - }() - } else if s.Client.Store.MasterKey != nil { - go s.Client.SyncStorage(ctx) - } } -func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bool) { +func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, noLoginSync bool) { if ctx.Err() != nil { zerolog.Ctx(ctx).Debug(). Int("retry_count", retryCount). @@ -325,11 +316,33 @@ func (s *SignalClient) tryConnect(ctx context.Context, retryCount int, doSync bo zerolog.Ctx(ctx).Info().Msg("Context canceled, exit tryConnect") return } - s.tryConnect(ctx, retryCount+1, doSync) + s.tryConnect(ctx, retryCount+1, noLoginSync) + return + } + syncCtx, cancel := context.WithCancel(ctx) + if oldCancel := s.cancelChatSync.Swap(&cancel); oldCancel != nil { + (*oldCancel)() + } + go s.bridgeStateLoop(ch) + if noLoginSync { + go s.syncChats(syncCtx, cancel) } else { - go s.bridgeStateLoop(ch) - if doSync { - go s.syncChats(ctx) + // TODO it would be more proper to only connect after syncing, + // but currently syncing will fetch group info online, so it has to be connected. + if s.Client.Store.EphemeralBackupKey != nil { + go func() { + if s.Client.Store.MasterKey != nil { + s.Client.SyncStorage(ctx) + } else { + s.UserLogin.Log.Warn().Msg("No master key for storage sync before backup sync") + } + s.syncChats(syncCtx, cancel) + }() + } else { + cancel() + if s.Client.Store.MasterKey != nil { + go s.Client.SyncStorage(ctx) + } } } } From c2f0a1bbf78848ac5379c01c2656e82028020d9b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 9 Apr 2026 13:59:37 +0300 Subject: [PATCH 688/718] handlesignal: use bridge background context instead of todo --- pkg/connector/handlesignal.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index bc0dbe3..4438cb0 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -467,7 +467,7 @@ func (s *SignalClient) handleSignalReceipt(evt *events.Receipt) bool { Stringer("sender_id", evt.Sender). Stringer("receipt_type", evt.Content.GetType()). Logger() - ctx := log.WithContext(context.TODO()) + ctx := log.WithContext(s.Main.Bridge.BackgroundCtx) receipts := convertReceipts(ctx, evt.Content.Timestamp, func(ctx context.Context, msgTS uint64) (*database.Message, error) { return s.Main.Bridge.DB.Message.GetFirstPartByID(ctx, s.UserLogin.ID, signalid.MakeMessageID(s.Client.Store.ACI, msgTS)) }) @@ -478,7 +478,7 @@ func (s *SignalClient) handleSignalReadSelf(evt *events.ReadSelf) bool { log := s.UserLogin.Log.With(). Str("action", "handle signal read self"). Logger() - ctx := log.WithContext(context.TODO()) + ctx := log.WithContext(s.Main.Bridge.BackgroundCtx) receipts := convertReceipts(ctx, evt.Messages, func(ctx context.Context, msgInfo *signalpb.SyncMessage_Read) (*database.Message, error) { aciUUID, err := signalmeow.ParseStringOrBinaryUUID(msgInfo.GetSenderAci(), msgInfo.GetSenderAciBinary()) if err != nil { @@ -688,7 +688,7 @@ func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { Stringer("aci", evt.ACI). Stringer("pni", evt.PNI). Logger() - ctx := log.WithContext(context.TODO()) + ctx := log.WithContext(s.Main.Bridge.BackgroundCtx) pniPortalKey := s.makeDMPortalKey(evt.PNI) aciPortalKey := s.makeDMPortalKey(evt.ACI) result, portal, err := s.Main.Bridge.ReIDPortal(ctx, pniPortalKey, aciPortalKey) @@ -708,7 +708,7 @@ func (s *SignalClient) handleSignalACIFound(evt *events.ACIFound) { func (s *SignalClient) handleSignalContactList(evt *events.ContactList) { log := s.UserLogin.Log.With().Str("action", "handle contact list").Logger() - ctx := log.WithContext(context.TODO()) + ctx := log.WithContext(s.Main.Bridge.BackgroundCtx) for _, contact := range evt.Contacts { if contact.ACI == uuid.Nil { continue From 53a3faa969ad6c58216a59e0e4a36aef65678d54 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 10 Apr 2026 20:46:03 +0300 Subject: [PATCH 689/718] chatinfo: fix uploading avatar when creating group --- pkg/connector/chatinfo.go | 4 ++-- pkg/connector/handlematrix.go | 2 +- pkg/signalmeow/attachments.go | 15 ++++++++++----- pkg/signalmeow/groups.go | 14 +++----------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 87f1f6f..0d48c45 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -332,7 +332,7 @@ func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCr if err != nil { return nil, fmt.Errorf("failed to download avatar: %w", err) } - group.AvatarPath, err = s.Client.UploadGroupAvatar(ctx, avatarBytes, group.GroupIdentifier) + group.AvatarPath, err = s.Client.UploadGroupAvatar(ctx, avatarBytes, group.GroupIdentifier, group.GroupMasterKey) if err != nil { return nil, fmt.Errorf("failed to upload avatar: %w", err) } @@ -362,7 +362,7 @@ func (s *SignalClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCr return nil, fmt.Errorf("failed to set portal room ID: %w", err) } } - resp, err := s.Client.CreateGroup(ctx, group, avatarBytes) + resp, err := s.Client.CreateGroup(ctx, group) if err != nil { return nil, fmt.Errorf("failed to create group: %w", err) } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 89b7d45..0f63de2 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -387,7 +387,7 @@ func (s *SignalClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2 return false, fmt.Errorf("failed to download avatar: %w", err) } avatarHash = sha256.Sum256(data) - avatarPath, err = s.Client.UploadGroupAvatar(ctx, data, groupID) + avatarPath, err = s.Client.UploadGroupAvatar(ctx, data, groupID, "") if err != nil { return false, fmt.Errorf("failed to reupload avatar: %w", err) } diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index e09dd7e..a48414e 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -369,12 +369,17 @@ func (cli *Client) uploadAttachmentTUS( return nil } -func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier) (string, error) { +func (cli *Client) UploadGroupAvatar(ctx context.Context, avatarBytes []byte, gid types.GroupIdentifier, groupMasterKey types.SerializedGroupMasterKey) (string, error) { log := zerolog.Ctx(ctx) - groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) - if err != nil { - log.Err(err).Msg("Could not get master key from group id") - return "", err + if groupMasterKey == "" { + var err error + groupMasterKey, err = cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) + if err != nil { + log.Err(err).Msg("Could not get master key from group id") + return "", err + } else if groupMasterKey == "" { + return "", fmt.Errorf("no master key found for group %s", gid) + } } groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyToBytes(groupMasterKey)) if err != nil { diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index b02687b..b9b9db5 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -1662,7 +1662,7 @@ func PrepareGroupCreation(decryptedGroup *Group) (libsignalgo.GroupMasterKey, er return masterKeyBytes, nil } -func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { +func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Group) (*Group, error) { log := zerolog.Ctx(ctx).With().Str("action", "CreateGroupOnServer").Logger() masterKeyBytes, err := PrepareGroupCreation(decryptedGroup) if err != nil { @@ -1677,14 +1677,6 @@ func (cli *Client) createGroupOnServer(ctx context.Context, decryptedGroup *Grou log.Err(err).Msg("DeriveGroupSecretParamsFromMasterKey error") return nil, err } - if len(avatarBytes) > 0 { - avatarPath, err := cli.UploadGroupAvatar(ctx, avatarBytes, decryptedGroup.GroupIdentifier) - if err != nil { - log.Err(err).Msg("Failed to upload group avatar") - return nil, err - } - decryptedGroup.AvatarPath = avatarPath - } encryptedGroup, err := cli.EncryptGroup(ctx, decryptedGroup, groupSecretParams) if err != nil { log.Err(err).Msg("Failed to encrypt group") @@ -1735,9 +1727,9 @@ func GenerateInviteLinkPassword() types.SerializedInviteLinkPassword { return InviteLinkPasswordFromBytes(random.Bytes(16)) } -func (cli *Client) CreateGroup(ctx context.Context, decryptedGroup *Group, avatarBytes []byte) (*Group, error) { +func (cli *Client) CreateGroup(ctx context.Context, decryptedGroup *Group) (*Group, error) { log := zerolog.Ctx(ctx).With().Str("action", "CreateGroup").Logger() - group, err := cli.createGroupOnServer(ctx, decryptedGroup, avatarBytes) + group, err := cli.createGroupOnServer(ctx, decryptedGroup) if err != nil { log.Err(err).Msg("Error creating group on server") return nil, err From aad72ca39bcc3d11ad5877c28d43906d2313cb7d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 11 Apr 2026 01:06:38 +0300 Subject: [PATCH 690/718] dependencies: update mautrix-go --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/connector/backfill.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index c2ff042..78ca5a0 100644 --- a/go.mod +++ b/go.mod @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.35.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.7 + go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a golang.org/x/crypto v0.49.0 golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 golang.org/x/net v0.52.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.5-0.20260331163037-18917f3bdc14 + maunium.net/go/mautrix v0.26.5-0.20260410220226-744570e6f1f5 ) require ( diff --git a/go.sum b/go.sum index 44ce4a1..57a3b8d 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.7 h1:AWGNbJfz1zRcQOKeOEYhKUG2fT+/26Gy6kyqcH8tnBg= -go.mau.fi/util v0.9.7/go.mod h1:5T2f3ZWZFAGgmFwg3dGw7YK6kIsb9lryDzvynoR98pE= +go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a h1:OQQF3rTJH10l6+dcP0OKnYbNDMBTGoIZZINNJm8QBG8= +go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a/go.mod h1:5T2f3ZWZFAGgmFwg3dGw7YK6kIsb9lryDzvynoR98pE= 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.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.26.5-0.20260331163037-18917f3bdc14 h1:y+4gtqKBMTtcVUiAeWJnvp88JLo/h3myQPsz1rZfNOY= -maunium.net/go/mautrix v0.26.5-0.20260331163037-18917f3bdc14/go.mod h1:RUSMBPky3jhXB7Ux+AptfkEvFlJ4ajZKCYiXI8YzxVE= +maunium.net/go/mautrix v0.26.5-0.20260410220226-744570e6f1f5 h1:icMEYdJZfRKWXf5AyPk/2jncA84DmfxzrjhCZ4Mm/PE= +maunium.net/go/mautrix v0.26.5-0.20260410220226-744570e6f1f5/go.mod h1:MX4DQLiBe0c7sI/wizruqdxHinSOWs42/DYsP9GH7Q4= diff --git a/pkg/connector/backfill.go b/pkg/connector/backfill.go index 3f9a611..b7b2a23 100644 --- a/pkg/connector/backfill.go +++ b/pkg/connector/backfill.go @@ -187,7 +187,7 @@ func (s *SignalClient) FetchMessages(ctx context.Context, params bridgev2.FetchM CompleteCallback: func() { // When reaching the last backwards backfill batch, delete the chat from the backup store. // If backwards backfilling isn't enabled, delete immediately after the first backfill request. - if (!params.Forward && len(items) < params.Count) || (!s.Main.Bridge.Config.Backfill.Queue.Enabled && !s.Main.Bridge.Config.Backfill.WillPaginateManually) { + if (!params.Forward && len(items) < params.Count) || !s.Main.Bridge.Config.Backfill.Queue.AnyEnabled() { err := s.Client.Store.BackupStore.DeleteBackupChat(ctx, chat.Id) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to delete chat from backup store") From 1c531e03daf1b43cf3f3dc640c9361b3d0be0eb8 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 12 Apr 2026 23:15:42 +0300 Subject: [PATCH 691/718] signalmeow/groups: catch missing group master key --- pkg/signalmeow/groups.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index b9b9db5..6dcd4ea 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -1513,11 +1513,15 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh return &changeResp, nil } +var ErrGroupMasterKeyNotFound = errors.New("group master key not found in store") + func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) (uint32, error) { log := zerolog.Ctx(ctx).With().Str("action", "UpdateGroup").Logger() groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) if err != nil { return 0, fmt.Errorf("failed to get master key for group: %w", err) + } else if groupMasterKey == "" { + return 0, ErrGroupMasterKeyNotFound } groupChange.GroupMasterKey = groupMasterKey masterKeyBytes := masterKeyToBytes(groupMasterKey) @@ -1752,7 +1756,7 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent return nil, err } if groupMasterKey == "" { - return nil, fmt.Errorf("No group master key found for group identifier %s", gid) + return nil, ErrGroupMasterKeyNotFound } masterKeyBytes := masterKeyToBytes(groupMasterKey) groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) From fdb9a61601907d5391ab8a6716e886192ac55b58 Mon Sep 17 00:00:00 2001 From: Rowan <151715+rwky@users.noreply.github.com> Date: Mon, 13 Apr 2026 14:49:01 +0100 Subject: [PATCH 692/718] docker: add missing protobuf-dev package to non-ci dockerfile (#646) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 63e7542..1acc3d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # -- Build libsignal (with Rust) -- FROM rust:1-alpine AS rust-builder -RUN apk add --no-cache git make cmake protoc musl-dev g++ clang-dev +RUN apk add --no-cache git make cmake protoc musl-dev g++ clang-dev protobuf-dev WORKDIR /build # Copy all files needed for Rust build, and no Go files From 952e7c473b28884eea56c0d60f107f0ef2ded296 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 13 Apr 2026 15:31:31 +0300 Subject: [PATCH 693/718] libsignal: update to v0.92.1 --- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 102 +++++++++++++++++++--------- pkg/libsignalgo/logging.go | 14 +++- pkg/libsignalgo/message.go | 3 +- pkg/libsignalgo/prekey.go | 3 +- pkg/libsignalgo/sealedsender.go | 13 +++- pkg/libsignalgo/session_test.go | 12 ++-- pkg/libsignalgo/setup_test.go | 2 + pkg/libsignalgo/version.go | 2 +- pkg/signalmeow/misc.go | 2 + pkg/signalmeow/receiving_decrypt.go | 5 ++ pkg/signalmeow/sending.go | 9 ++- 12 files changed, 120 insertions(+), 49 deletions(-) diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index a5e7667..b58bd7d 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit a5e76674882a89bac1ed3f4a982120652966d21e +Subproject commit b58bd7d5dfa0a391486df4210fd83bab96b9b479 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index 59409c8..fe3bf52 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -261,6 +261,7 @@ typedef enum { SignalErrorCodeRequestUnauthorized = 220, SignalErrorCodeMismatchedDevices = 221, SignalErrorCodeServiceIdNotFound = 222, + SignalErrorCodeUploadTooLarge = 223, } SignalErrorCode; enum SignalSvr2CredentialsResult { @@ -511,6 +512,46 @@ typedef struct { const SignalAuthenticatedChatConnection *raw; } SignalConstPointerAuthenticatedChatConnection; +/** + * A type alias to be used with [`OwnedBufferOf`], so that `OwnedBufferOf` and + * `OwnedBufferOf<*const c_char>` get distinct names. + */ +typedef const char *SignalCStringPtr; + +/** + * A representation of a array allocated on the Rust heap for use in C code. + */ +typedef struct { + SignalCStringPtr *base; + /** + * The number of elements in the buffer (not necessarily the number of bytes). + */ + size_t length; +} SignalOwnedBufferOfCStringPtr; + +typedef struct { + uint32_t cdn; + SignalCStringPtr key; + SignalOwnedBufferOfCStringPtr header_keys; + SignalOwnedBufferOfCStringPtr header_values; + SignalCStringPtr signed_upload_url; +} SignalFfiUploadForm; + +/** + * A C callback used to report the results of Rust futures. + * + * cbindgen will produce independent C types like `SignalCPromisei32` and + * `SignalCPromiseProtocolAddress`. + * + * This derives Copy because it behaves like a C type; nevertheless, a promise should still only be + * completed once. + */ +typedef struct { + void (*complete)(SignalFfiError *error, const SignalFfiUploadForm *result, const void *context); + const void *context; + SignalCancellationId cancellation_id; +} SignalCPromiseFfiUploadForm; + typedef SignalConnectionInfo SignalChatConnectionInfo; typedef struct { @@ -562,23 +603,6 @@ typedef struct { const SignalFfiChatListenerStruct *raw; } SignalConstPointerFfiChatListenerStruct; -/** - * A type alias to be used with [`OwnedBufferOf`], so that `OwnedBufferOf` and - * `OwnedBufferOf<*const c_char>` get distinct names. - */ -typedef const char *SignalCStringPtr; - -/** - * A representation of a array allocated on the Rust heap for use in C code. - */ -typedef struct { - SignalCStringPtr *base; - /** - * The number of elements in the buffer (not necessarily the number of bytes). - */ - size_t length; -} SignalOwnedBufferOfCStringPtr; - typedef struct { uint16_t status; const char *message; @@ -945,6 +969,11 @@ typedef struct { SignalOwnedBuffer second; } SignalPairOfc_charOwnedBufferOfc_uchar; +typedef struct { + SignalPairOfc_charOwnedBufferOfc_uchar first; + int64_t second; +} SignalPairOfPairOfc_charOwnedBufferOfc_uchari64; + typedef struct { const char *first; bool second; @@ -1075,15 +1104,18 @@ typedef struct { SignalIncrementalMac *raw; } SignalMutPointerIncrementalMac; -typedef void (*SignalLogCallback)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); +typedef int (*SignalFfiLoggerLog)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); -typedef void (*SignalLogFlushCallback)(void *ctx); +typedef int (*SignalFfiLoggerFlush)(void *ctx); + +typedef void (*SignalFfiLoggerDestroy)(void *ctx); typedef struct { void *ctx; - SignalLogCallback log; - SignalLogFlushCallback flush; -} SignalFfiLogger; + SignalFfiLoggerLog log; + SignalFfiLoggerFlush flush; + SignalFfiLoggerDestroy destroy; +} SignalFfiLoggerStruct; /** * A C callback used to report the results of Rust futures. @@ -1695,6 +1727,8 @@ SignalFfiError *signal_authenticated_chat_connection_destroy(SignalMutPointerAut SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat); +SignalFfiError *signal_authenticated_chat_connection_get_upload_form(SignalCPromiseFfiUploadForm *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, uint64_t upload_length); + SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat); SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); @@ -1865,7 +1899,7 @@ SignalFfiError *signal_create_call_link_credential_response_check_valid_contents SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); -SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); +SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); @@ -1891,7 +1925,7 @@ SignalFfiError *signal_device_transfer_generate_private_key(SignalOwnedBuffer *o SignalFfiError *signal_device_transfer_generate_private_key_with_format(SignalOwnedBuffer *out, uint8_t key_format); -SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); +SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); void signal_error_free(SignalFfiError *err); @@ -1905,7 +1939,7 @@ SignalFfiError *signal_error_get_mismatched_device_errors(SignalOwnedBufferOfFfi SignalFfiError *signal_error_get_our_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); -SignalFfiError *signal_error_get_rate_limit_challenge(SignalPairOfc_charOwnedBufferOfc_uchar *out, SignalUnwindSafeArgSignalFfiError err); +SignalFfiError *signal_error_get_rate_limit_challenge(SignalPairOfPairOfc_charOwnedBufferOfc_uchari64 *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_registration_error_not_deliverable(SignalPairOfc_charbool *out, SignalUnwindSafeArgSignalFfiError err); @@ -2080,18 +2114,16 @@ SignalFfiError *signal_incremental_mac_initialize(SignalMutPointerIncrementalMac SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); -bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); +bool signal_init_logger(SignalLogLevel max_level, SignalFfiLoggerStruct logger); SignalFfiError *signal_key_transparency_aci_search_key(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *aci); +SignalFfiError *signal_key_transparency_check(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head, bool is_self_check, bool is_e164_discoverable); + SignalFfiError *signal_key_transparency_distinguished(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head); SignalFfiError *signal_key_transparency_e164_search_key(SignalOwnedBuffer *out, const char *e164); -SignalFfiError *signal_key_transparency_monitor(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head, bool is_self_monitor); - -SignalFfiError *signal_key_transparency_search(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head); - SignalFfiError *signal_key_transparency_username_hash_search_key(SignalOwnedBuffer *out, SignalBorrowedBuffer hash); SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj); @@ -2724,16 +2756,22 @@ SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext SignalFfiError *signal_unauthenticated_chat_connection_account_exists(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *account); +SignalFfiError *signal_unauthenticated_chat_connection_backup_get_media_upload_form(SignalCPromiseFfiUploadForm *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer credential, SignalBorrowedBuffer server_keys, SignalConstPointerPrivateKey signing_key, uint64_t upload_size, int64_t rng); + +SignalFfiError *signal_unauthenticated_chat_connection_backup_get_upload_form(SignalCPromiseFfiUploadForm *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer credential, SignalBorrowedBuffer server_keys, SignalConstPointerPrivateKey signing_key, uint64_t upload_size, int64_t rng); + SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, SignalBorrowedBytestringArray languages); SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat); -SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_group_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer auth, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); - SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_key_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const uint8_t (*auth)[16], const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); +SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_group_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer auth, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); + +SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_unrestricted_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); + SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); diff --git a/pkg/libsignalgo/logging.go b/pkg/libsignalgo/logging.go index 9d21afa..1926c23 100644 --- a/pkg/libsignalgo/logging.go +++ b/pkg/libsignalgo/logging.go @@ -21,6 +21,7 @@ package libsignalgo extern void signal_log_callback(void *ctx, SignalLogLevel level, char *file, uint32_t line, char *message); extern void signal_log_flush_callback(void *ctx); +extern void signal_log_destroy_callback(void *ctx); */ import "C" import ( @@ -40,6 +41,11 @@ func signal_log_flush_callback(ctx unsafe.Pointer) { ffiLogger.Flush() } +//export signal_log_destroy_callback +func signal_log_destroy_callback(ctx unsafe.Pointer) { + ffiLogger.Destroy() +} + type LogLevel int const ( @@ -53,12 +59,14 @@ const ( type Logger interface { Log(level LogLevel, file string, line uint, message string) Flush() + Destroy() } func InitLogger(level LogLevel, logger Logger) { ffiLogger = logger - C.signal_init_logger(C.SignalLogLevel(level), C.SignalFfiLogger{ - log: C.SignalLogCallback(C.signal_log_callback), - flush: C.SignalLogFlushCallback(C.signal_log_flush_callback), + C.signal_init_logger(C.SignalLogLevel(level), C.SignalFfiLoggerStruct{ + log: C.SignalFfiLoggerLog(C.signal_log_callback), + flush: C.SignalFfiLoggerFlush(C.signal_log_flush_callback), + destroy: C.SignalFfiLoggerDestroy(C.signal_log_destroy_callback), }) } diff --git a/pkg/libsignalgo/message.go b/pkg/libsignalgo/message.go index f016daa..1b581c0 100644 --- a/pkg/libsignalgo/message.go +++ b/pkg/libsignalgo/message.go @@ -27,7 +27,7 @@ import ( "time" ) -func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, sessionStore SessionStore, identityKeyStore IdentityKeyStore) (*CiphertextMessage, error) { +func Encrypt(ctx context.Context, plaintext []byte, forAddress, localAddress *Address, sessionStore SessionStore, identityKeyStore IdentityKeyStore) (*CiphertextMessage, error) { var ciphertextMessage C.SignalMutPointerCiphertextMessage var now C.uint64_t = C.uint64_t(time.Now().Unix()) callbackCtx := NewCallbackContext(ctx) @@ -36,6 +36,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, session &ciphertextMessage, BytesToBuffer(plaintext), forAddress.constPtr(), + localAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityKeyStore), now, diff --git a/pkg/libsignalgo/prekey.go b/pkg/libsignalgo/prekey.go index 4d01f89..29e640e 100644 --- a/pkg/libsignalgo/prekey.go +++ b/pkg/libsignalgo/prekey.go @@ -26,7 +26,7 @@ import ( "runtime" ) -func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore, preKeyStore PreKeyStore, signedPreKeyStore SignedPreKeyStore, kyberPreKeyStore KyberPreKeyStore) ([]byte, error) { +func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddress, localAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore, preKeyStore PreKeyStore, signedPreKeyStore SignedPreKeyStore, kyberPreKeyStore KyberPreKeyStore) ([]byte, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} @@ -34,6 +34,7 @@ func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddres &decrypted, preKeyMessage.constPtr(), fromAddress.constPtr(), + localAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), callbackCtx.wrapPreKeyStore(preKeyStore), diff --git a/pkg/libsignalgo/sealedsender.go b/pkg/libsignalgo/sealedsender.go index 56ffe8b..84ff254 100644 --- a/pkg/libsignalgo/sealedsender.go +++ b/pkg/libsignalgo/sealedsender.go @@ -44,8 +44,17 @@ func NewSealedSenderAddress(e164 string, uuid uuid.UUID, deviceID uint32) *Seale } } -func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHint UnidentifiedSenderMessageContentHint, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore, groupID *GroupIdentifier) ([]byte, error) { - ciphertextMessage, err := Encrypt(ctx, message, forAddress, sessionStore, identityStore) +func SealedSenderEncryptPlaintext( + ctx context.Context, + message []byte, + contentHint UnidentifiedSenderMessageContentHint, + forAddress, localAddress *Address, + fromSenderCert *SenderCertificate, + sessionStore SessionStore, + identityStore IdentityKeyStore, + groupID *GroupIdentifier, +) ([]byte, error) { + ciphertextMessage, err := Encrypt(ctx, message, forAddress, localAddress, sessionStore, identityStore) if err != nil { return nil, err } diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index 6d0b720..4bde894 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -136,7 +136,7 @@ func TestSessionCipher(t *testing.T) { alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} - aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceStore, aliceStore) + aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceAddress, aliceStore, aliceStore) assert.NoError(t, err) aliceCiphertextMessageType, err := aliceCiphertext.MessageType() assert.NoError(t, err) @@ -147,13 +147,13 @@ func TestSessionCipher(t *testing.T) { bobCiphertext, err := libsignalgo.DeserializePreKeyMessage(aliceCiphertextSerialized) assert.NoError(t, err) - bobPlaintext, err := libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobStore, bobStore, bobStore, bobStore, bobStore) + bobPlaintext, err := libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobAddress, bobStore, bobStore, bobStore, bobStore, bobStore) assert.NoError(t, err) assert.Equal(t, alicePlaintext, bobPlaintext) bobPlaintext2 := []byte{23} - bobCiphertext2, err := libsignalgo.Encrypt(ctx, bobPlaintext2, aliceAddress, bobStore, bobStore) + bobCiphertext2, err := libsignalgo.Encrypt(ctx, bobPlaintext2, aliceAddress, bobAddress, bobStore, bobStore) assert.NoError(t, err) bobCiphertext2MessageType, err := bobCiphertext2.MessageType() assert.NoError(t, err) @@ -187,7 +187,7 @@ func TestSessionCipherWithBadStore(t *testing.T) { alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} - aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceStore, aliceStore) + aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceAddress, aliceStore, aliceStore) assert.NoError(t, err) aliceCiphertextMessageType, err := aliceCiphertext.MessageType() assert.NoError(t, err) @@ -198,7 +198,7 @@ func TestSessionCipherWithBadStore(t *testing.T) { bobCiphertext, err := libsignalgo.DeserializePreKeyMessage(aliceCiphertextSerialized) assert.NoError(t, err) t.Skip("This test is broken") // TODO fix - _, err = libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobStore, bobStore, bobStore, bobStore, bobStore) + _, err = libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobAddress, bobStore, bobStore, bobStore, bobStore, bobStore) require.Error(t, err) assert.Equal(t, "Test error", err.Error()) } @@ -241,7 +241,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) { }() for i := 0; i < 100; i++ { message := []byte(fmt.Sprintf("%04d vision", i)) - ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore, nil) + ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, aliceAddress, senderCert, aliceStore, aliceStore, nil) require.NoError(t, err) assert.NotNil(t, ciphertext) } diff --git a/pkg/libsignalgo/setup_test.go b/pkg/libsignalgo/setup_test.go index c22149d..47d7d77 100644 --- a/pkg/libsignalgo/setup_test.go +++ b/pkg/libsignalgo/setup_test.go @@ -54,6 +54,8 @@ func (FFILogger) Log(level libsignalgo.LogLevel, file string, line uint, message func (FFILogger) Flush() {} +func (FFILogger) Destroy() {} + var loggingSetup = false func setupLogging() { diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index ccd0d51..bd14084 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.89.1" +const Version = "v0.92.1" diff --git a/pkg/signalmeow/misc.go b/pkg/signalmeow/misc.go index 467f646..70d3ba5 100644 --- a/pkg/signalmeow/misc.go +++ b/pkg/signalmeow/misc.go @@ -69,6 +69,8 @@ func (l FFILogger) Log(level libsignalgo.LogLevel, file string, line uint, messa func (FFILogger) Flush() {} +func (FFILogger) Destroy() {} + // Ensure FFILogger implements the Logger interface var _ libsignalgo.Logger = FFILogger{} diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 958f84f..24b76ff 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -188,12 +188,17 @@ func (cli *Client) prekeyDecrypt( if is == nil { return nil, fmt.Errorf("no identity store found for %s", destination) } + destinationAddress, err := destination.Address(uint(cli.Store.DeviceID)) + if err != nil { + return nil, fmt.Errorf("failed to get own/destination address: %w", err) + } plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, encryptedContent, serverTimestamp, func(ctx context.Context) ([]byte, error) { return libsignalgo.DecryptPreKey( ctx, preKeyMessage, sender, + destinationAddress, ss, is, pks, diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 568b4d4..94f1dcf 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -171,6 +171,10 @@ func (cli *Client) buildMessagesToSend( } else if len(sessions) == 0 { return nil, fmt.Errorf("no sessions found for recipient %s", recipient.String()) } + localAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)) + if err != nil { + return nil, fmt.Errorf("failed to get own address: %w", err) + } messages := make([]MyMessage, 0, len(sessions)) for _, tuple := range sessions { @@ -193,7 +197,7 @@ func (cli *Client) buildMessagesToSend( includeE164 := groupID == nil && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY envelopeType, encryptedPayload, err := cli.buildMessageToSend( - ctx, tuple.Address, paddedMessage, getContentHint(content), ctmOverride, groupID, includeE164, unauthenticated, + ctx, tuple.Address, localAddress, paddedMessage, getContentHint(content), ctmOverride, groupID, includeE164, unauthenticated, ) if err != nil { return nil, err @@ -232,7 +236,7 @@ func ctmTypeToEnvelopeType(ctmType libsignalgo.CiphertextMessageType) signalpb.E func (cli *Client) buildMessageToSend( ctx context.Context, - recipientAddress *libsignalgo.Address, + recipientAddress, localAddress *libsignalgo.Address, paddedMessage []byte, contentHint libsignalgo.UnidentifiedSenderMessageContentHint, ciphertextMessage *libsignalgo.CiphertextMessage, @@ -244,6 +248,7 @@ func (cli *Client) buildMessageToSend( ctx, paddedMessage, recipientAddress, + localAddress, cli.Store.ACISessionStore, cli.Store.ACIIdentityStore, ) From 38f2ba9430c23bee7ded9a9a36f11e6eb540d4f3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 13 Apr 2026 15:31:43 +0300 Subject: [PATCH 694/718] signalmeow/groups: use shared error type for unknown group master key --- pkg/signalmeow/groups.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index 6dcd4ea..147d63d 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -619,7 +619,7 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier return nil, fmt.Errorf("failed to get group master key: %w", err) } if groupMasterKey == "" { - return nil, fmt.Errorf("No group master key found for group identifier %s", gid) + return nil, fmt.Errorf("%w for %s", ErrGroupMasterKeyNotFound, gid) } return cli.fetchGroupWithMasterKey(ctx, groupMasterKey) } From 2297e6b48bfe727aaaf49ceb4fdb9efe7a9d5fae Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 13 Apr 2026 16:32:10 +0300 Subject: [PATCH 695/718] signalmeow: update protobufs Content and SyncMessage switched to use oneofs, which is why a lot of code changed --- pkg/connector/handlematrix.go | 89 +- pkg/signalmeow/protobuf/Groups.pb.go | 271 +++- pkg/signalmeow/protobuf/Groups.proto | 14 +- pkg/signalmeow/protobuf/Provisioning.pb.go | 15 +- pkg/signalmeow/protobuf/Provisioning.proto | 2 +- pkg/signalmeow/protobuf/SignalService.pb.go | 1410 ++++++++++------ pkg/signalmeow/protobuf/SignalService.proto | 166 +- pkg/signalmeow/protobuf/StorageService.pb.go | 28 +- pkg/signalmeow/protobuf/StorageService.proto | 3 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 1418 ++++++++++------- pkg/signalmeow/protobuf/backuppb/Backup.proto | 25 +- pkg/signalmeow/protobuf/update-protos.sh | 15 +- pkg/signalmeow/provisioning.go | 12 +- pkg/signalmeow/receiving.go | 293 ++-- pkg/signalmeow/receiving_decrypt.go | 17 +- pkg/signalmeow/retry.go | 12 +- pkg/signalmeow/sending.go | 279 ++-- 17 files changed, 2475 insertions(+), 1594 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 0f63de2..7bcb214 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -137,7 +137,7 @@ func (s *SignalClient) doSendMessage( } msgID := signalid.MakeMessageID(s.Client.Store.ACI, ts) msg.AddPendingToIgnore(networkid.TransactionID(msgID)) - err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) + err := s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(converted)) if err != nil { return nil, bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } @@ -173,10 +173,10 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri } ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) converted.Timestamp = &ts - err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ + err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapEditMessage(&signalpb.EditMessage{ TargetSentTimestamp: proto.Uint64(targetSentTimestamp), DataMessage: converted, - }}) + })) if err != nil { return bridgev2.WrapErrorInStatus(err).WithSendNotice(true) } @@ -200,19 +200,16 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M return nil, fmt.Errorf("failed to parse target message ID: %w", err) } ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) - wrappedContent := &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(ts), - RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), - Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.PreHandleResp.Emoji), - Remove: proto.Bool(false), - TargetAuthorAciBinary: targetAuthorACI[:], - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - }, + err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(&signalpb.DataMessage{ + Timestamp: proto.Uint64(ts), + RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), + Reaction: &signalpb.DataMessage_Reaction{ + Emoji: proto.String(msg.PreHandleResp.Emoji), + Remove: proto.Bool(false), + TargetAuthorAciBinary: targetAuthorACI[:], + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, - } - err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + })) if err != nil { return nil, err } @@ -225,19 +222,16 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid return fmt.Errorf("failed to parse target message ID: %w", err) } ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) - wrappedContent := &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(ts), - RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), - Reaction: &signalpb.DataMessage_Reaction{ - Emoji: proto.String(msg.TargetReaction.Emoji), - Remove: proto.Bool(true), - TargetAuthorAciBinary: targetAuthorACI[:], - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - }, + err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(&signalpb.DataMessage{ + Timestamp: proto.Uint64(ts), + RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), + Reaction: &signalpb.DataMessage_Reaction{ + Emoji: proto.String(msg.TargetReaction.Emoji), + Remove: proto.Bool(true), + TargetAuthorAciBinary: targetAuthorACI[:], + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, - } - err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + })) if err != nil { return err } @@ -252,15 +246,12 @@ func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridg return fmt.Errorf("cannot delete other people's messages") } ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) - wrappedContent := &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: proto.Uint64(ts), - Delete: &signalpb.DataMessage_Delete{ - TargetSentTimestamp: proto.Uint64(targetSentTimestamp), - }, + err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(&signalpb.DataMessage{ + Timestamp: proto.Uint64(ts), + Delete: &signalpb.DataMessage_Delete{ + TargetSentTimestamp: proto.Uint64(targetSentTimestamp), }, - } - err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent) + })) if err != nil { return err } @@ -688,13 +679,11 @@ func (s *SignalClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *b }) } else { ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) - res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ - Timestamp: ptr.Ptr(ts), - Flags: ptr.Ptr(uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE)), - ExpireTimer: ptr.Ptr(uint32(msg.Content.Timer.Seconds())), - }, - }) + res := s.Client.SendMessage(ctx, userID, signalmeow.WrapDataMessage(&signalpb.DataMessage{ + Timestamp: ptr.Ptr(ts), + Flags: ptr.Ptr(uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE)), + ExpireTimer: ptr.Ptr(uint32(msg.Content.Timer.Seconds())), + })) if !res.WasSuccessful { return false, res.Error } @@ -773,8 +762,8 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2 recipientID := s.Client.Store.ACIServiceID() // Send DeleteForMe sync message to self - result := s.Client.SendMessage(ctx, recipientID, &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ + result := s.Client.SendMessage(ctx, recipientID, signalmeow.WrapSyncMessage(&signalpb.SyncMessage{ + Content: &signalpb.SyncMessage_DeleteForMe_{ DeleteForMe: &signalpb.SyncMessage_DeleteForMe{ ConversationDeletes: []*signalpb.SyncMessage_DeleteForMe_ConversationDelete{{ Conversation: conversationID, @@ -783,7 +772,7 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2 }}, }, }, - }) + })) zerolog.Ctx(ctx).Debug(). Str("portal_id", string(msg.Portal.ID)). @@ -868,11 +857,11 @@ func (s *SignalClient) syncMessageRequestResponse( } else { return fmt.Errorf("invalid portal ID for message request response: %s", portal.ID) } - res := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(s.Client.Store.ACI), &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ + res := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(s.Client.Store.ACI), signalmeow.WrapSyncMessage(&signalpb.SyncMessage{ + Content: &signalpb.SyncMessage_MessageRequestResponse_{ MessageRequestResponse: accept, }, - }) + })) if !res.WasSuccessful { return res.Error } @@ -905,13 +894,13 @@ func (s *SignalClient) HandleMatrixAcceptMessageRequest(ctx context.Context, msg } } res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ - DataMessage: &signalpb.DataMessage{ + Content: &signalpb.Content_DataMessage{DataMessage: &signalpb.DataMessage{ Flags: proto.Uint32(uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE)), ProfileKey: profileKey.Slice(), Timestamp: proto.Uint64(getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)), RequiredProtocolVersion: proto.Uint32(0), - }, + }}, PniSignatureMessage: pniSig, }) if !res.WasSuccessful { diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index c7717ff..0c2b81b 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -498,6 +498,7 @@ type AccessControl struct { Attributes AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=signal.AccessControl_AccessRequired" json:"attributes,omitempty"` Members AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=signal.AccessControl_AccessRequired" json:"members,omitempty"` AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=signal.AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` + MemberLabel AccessControl_AccessRequired `protobuf:"varint,4,opt,name=memberLabel,proto3,enum=signal.AccessControl_AccessRequired" json:"memberLabel,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -553,6 +554,13 @@ func (x *AccessControl) GetAddFromInviteLink() AccessControl_AccessRequired { return AccessControl_UNKNOWN } +func (x *AccessControl) GetMemberLabel() AccessControl_AccessRequired { + if x != nil { + return x.MemberLabel + } + return AccessControl_UNKNOWN +} + type Group struct { state protoimpl.MessageState `protogen:"open.v1"` PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` @@ -569,7 +577,8 @@ type Group struct { MembersPendingAdminApproval []*MemberPendingAdminApproval `protobuf:"bytes,9,rep,name=membersPendingAdminApproval,proto3" json:"membersPendingAdminApproval,omitempty"` InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"` - MembersBanned []*MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"` // next: 14 + MembersBanned []*MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"` + Terminated bool `protobuf:"varint,14,opt,name=terminated,proto3" json:"terminated,omitempty"` // next: 15 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -695,6 +704,13 @@ func (x *Group) GetMembersBanned() []*MemberBanned { return nil } +func (x *Group) GetTerminated() bool { + if x != nil { + return x.Terminated + } + return false +} + type GroupAttributeBlob struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Content: @@ -1317,6 +1333,8 @@ type GroupChange_Actions struct { DeleteMembersBanned []*GroupChange_Actions_DeleteMemberBannedAction `protobuf:"bytes,23,rep,name=delete_members_banned,json=deleteMembersBanned,proto3" json:"delete_members_banned,omitempty"` // change epoch = 4 PromoteMembersPendingPniAciProfileKey []*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction `protobuf:"bytes,24,rep,name=promote_members_pending_pni_aci_profile_key,json=promoteMembersPendingPniAciProfileKey,proto3" json:"promote_members_pending_pni_aci_profile_key,omitempty"` // change epoch = 5 ModifyMemberLabels []*GroupChange_Actions_ModifyMemberLabelAction `protobuf:"bytes,26,rep,name=modifyMemberLabels,proto3" json:"modifyMemberLabels,omitempty"` // change epoch = 6; + ModifyMemberLabelAccess *GroupChange_Actions_ModifyMemberLabelAccessControlAction `protobuf:"bytes,27,opt,name=modifyMemberLabelAccess,proto3" json:"modifyMemberLabelAccess,omitempty"` // change epoch = 6 + TerminateGroup *GroupChange_Actions_TerminateGroupAction `protobuf:"bytes,28,opt,name=terminate_group,json=terminateGroup,proto3" json:"terminate_group,omitempty"` // change epoch = 7 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1533,6 +1551,20 @@ func (x *GroupChange_Actions) GetModifyMemberLabels() []*GroupChange_Actions_Mod return nil } +func (x *GroupChange_Actions) GetModifyMemberLabelAccess() *GroupChange_Actions_ModifyMemberLabelAccessControlAction { + if x != nil { + return x.ModifyMemberLabelAccess + } + return nil +} + +func (x *GroupChange_Actions) GetTerminateGroup() *GroupChange_Actions_TerminateGroupAction { + if x != nil { + return x.TerminateGroup + } + return nil +} + type GroupChange_Actions_AddMemberAction struct { state protoimpl.MessageState `protogen:"open.v1"` Added *Member `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` @@ -2553,6 +2585,50 @@ func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) GetAddF return AccessControl_UNKNOWN } +type GroupChange_Actions_ModifyMemberLabelAccessControlAction struct { + state protoimpl.MessageState `protogen:"open.v1"` + MemberLabelAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=memberLabelAccess,proto3,enum=signal.AccessControl_AccessRequired" json:"memberLabelAccess,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) Reset() { + *x = GroupChange_Actions_ModifyMemberLabelAccessControlAction{} + mi := &file_Groups_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChange_Actions_ModifyMemberLabelAccessControlAction) ProtoMessage() {} + +func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupChange_Actions_ModifyMemberLabelAccessControlAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_ModifyMemberLabelAccessControlAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 21} +} + +func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) GetMemberLabelAccess() AccessControl_AccessRequired { + if x != nil { + return x.MemberLabelAccess + } + return AccessControl_UNKNOWN +} + type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { state protoimpl.MessageState `protogen:"open.v1"` InviteLinkPassword []byte `protobuf:"bytes,1,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` @@ -2562,7 +2638,7 @@ type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() { *x = GroupChange_Actions_ModifyInviteLinkPasswordAction{} - mi := &file_Groups_proto_msgTypes[38] + mi := &file_Groups_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2574,7 +2650,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) String() string { func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[38] + mi := &file_Groups_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2587,7 +2663,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() prot // Deprecated: Use GroupChange_Actions_ModifyInviteLinkPasswordAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{10, 0, 21} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 22} } func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) GetInviteLinkPassword() []byte { @@ -2606,7 +2682,7 @@ type GroupChange_Actions_ModifyAnnouncementsOnlyAction struct { func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() { *x = GroupChange_Actions_ModifyAnnouncementsOnlyAction{} - mi := &file_Groups_proto_msgTypes[39] + mi := &file_Groups_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2618,7 +2694,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) String() string { func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoMessage() {} func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[39] + mi := &file_Groups_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2631,7 +2707,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() proto // Deprecated: Use GroupChange_Actions_ModifyAnnouncementsOnlyAction.ProtoReflect.Descriptor instead. func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) Descriptor() ([]byte, []int) { - return file_Groups_proto_rawDescGZIP(), []int{10, 0, 22} + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 23} } func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly() bool { @@ -2641,6 +2717,42 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly return false } +type GroupChange_Actions_TerminateGroupAction struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupChange_Actions_TerminateGroupAction) Reset() { + *x = GroupChange_Actions_TerminateGroupAction{} + mi := &file_Groups_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupChange_Actions_TerminateGroupAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupChange_Actions_TerminateGroupAction) ProtoMessage() {} + +func (x *GroupChange_Actions_TerminateGroupAction) ProtoReflect() protoreflect.Message { + mi := &file_Groups_proto_msgTypes[41] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GroupChange_Actions_TerminateGroupAction.ProtoReflect.Descriptor instead. +func (*GroupChange_Actions_TerminateGroupAction) Descriptor() ([]byte, []int) { + return file_Groups_proto_rawDescGZIP(), []int{10, 0, 24} +} + type GroupChanges_GroupChangeState struct { state protoimpl.MessageState `protogen:"open.v1"` GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` @@ -2651,7 +2763,7 @@ type GroupChanges_GroupChangeState struct { func (x *GroupChanges_GroupChangeState) Reset() { *x = GroupChanges_GroupChangeState{} - mi := &file_Groups_proto_msgTypes[40] + mi := &file_Groups_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2663,7 +2775,7 @@ func (x *GroupChanges_GroupChangeState) String() string { func (*GroupChanges_GroupChangeState) ProtoMessage() {} func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { - mi := &file_Groups_proto_msgTypes[40] + mi := &file_Groups_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2737,20 +2849,21 @@ const file_Groups_proto_rawDesc = "" + "\ttimestamp\x18\x04 \x01(\x04R\ttimestamp\"D\n" + "\fMemberBanned\x12\x16\n" + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + - "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\xc3\x02\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\x8b\x03\n" + "\rAccessControl\x12D\n" + "\n" + "attributes\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\n" + "attributes\x12>\n" + "\amembers\x18\x02 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\amembers\x12R\n" + - "\x11addFromInviteLink\x18\x03 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + + "\x11addFromInviteLink\x18\x03 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\x12F\n" + + "\vmemberLabel\x18\x04 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\vmemberLabel\"X\n" + "\x0eAccessRequired\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ANY\x10\x01\x12\n" + "\n" + "\x06MEMBER\x10\x02\x12\x11\n" + "\rADMINISTRATOR\x10\x03\x12\x11\n" + - "\rUNSATISFIABLE\x10\x04\"\x99\x05\n" + + "\rUNSATISFIABLE\x10\x04\"\xb9\x05\n" + "\x05Group\x12\x1c\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + "\x05title\x18\x02 \x01(\fR\x05title\x12 \n" + @@ -2765,7 +2878,10 @@ const file_Groups_proto_rawDesc = "" + "\x12inviteLinkPassword\x18\n" + " \x01(\fR\x12inviteLinkPassword\x12-\n" + "\x12announcements_only\x18\f \x01(\bR\x11announcementsOnly\x12;\n" + - "\x0emembers_banned\x18\r \x03(\v2\x14.signal.MemberBannedR\rmembersBanned\"\xc3\x01\n" + + "\x0emembers_banned\x18\r \x03(\v2\x14.signal.MemberBannedR\rmembersBanned\x12\x1e\n" + + "\n" + + "terminated\x18\x0e \x01(\bR\n" + + "terminated\"\xc3\x01\n" + "\x12GroupAttributeBlob\x12\x16\n" + "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + @@ -2789,11 +2905,11 @@ const file_Groups_proto_rawDesc = "" + "\vmemberCount\x18\x04 \x01(\rR\vmemberCount\x12R\n" + "\x11addFromInviteLink\x18\x05 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\x12\x18\n" + "\aversion\x18\x06 \x01(\rR\aversion\x122\n" + - "\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\"\xbb'\n" + + "\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\"\xa6*\n" + "\vGroupChange\x12\x18\n" + "\aactions\x18\x01 \x01(\fR\aactions\x12(\n" + "\x0fserverSignature\x18\x02 \x01(\fR\x0fserverSignature\x12 \n" + - "\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xc5&\n" + + "\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xb0)\n" + "\aActions\x12\"\n" + "\fsourceUserId\x18\x01 \x01(\fR\fsourceUserId\x12\x19\n" + "\bgroup_id\x18\x19 \x01(\fR\agroupId\x12\x18\n" + @@ -2823,7 +2939,9 @@ const file_Groups_proto_rawDesc = "" + "\x12add_members_banned\x18\x16 \x03(\v21.signal.GroupChange.Actions.AddMemberBannedActionR\x10addMembersBanned\x12h\n" + "\x15delete_members_banned\x18\x17 \x03(\v24.signal.GroupChange.Actions.DeleteMemberBannedActionR\x13deleteMembersBanned\x12\xa2\x01\n" + "+promote_members_pending_pni_aci_profile_key\x18\x18 \x03(\v2F.signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyActionR%promoteMembersPendingPniAciProfileKey\x12c\n" + - "\x12modifyMemberLabels\x18\x1a \x03(\v23.signal.GroupChange.Actions.ModifyMemberLabelActionR\x12modifyMemberLabels\x1ag\n" + + "\x12modifyMemberLabels\x18\x1a \x03(\v23.signal.GroupChange.Actions.ModifyMemberLabelActionR\x12modifyMemberLabels\x12z\n" + + "\x17modifyMemberLabelAccess\x18\x1b \x01(\v2@.signal.GroupChange.Actions.ModifyMemberLabelAccessControlActionR\x17modifyMemberLabelAccess\x12Y\n" + + "\x0fterminate_group\x18\x1c \x01(\v20.signal.GroupChange.Actions.TerminateGroupActionR\x0eterminateGroup\x1ag\n" + "\x0fAddMemberAction\x12$\n" + "\x05added\x18\x01 \x01(\v2\x0e.signal.MemberR\x05added\x12.\n" + "\x12joinFromInviteLink\x18\x02 \x01(\bR\x12joinFromInviteLink\x1a:\n" + @@ -2882,11 +3000,14 @@ const file_Groups_proto_rawDesc = "" + " ModifyMembersAccessControlAction\x12J\n" + "\rmembersAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\rmembersAccess\x1a\x8c\x01\n" + "*ModifyAddFromInviteLinkAccessControlAction\x12^\n" + - "\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1aP\n" + + "\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1az\n" + + "$ModifyMemberLabelAccessControlAction\x12R\n" + + "\x11memberLabelAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11memberLabelAccess\x1aP\n" + "\x1eModifyInviteLinkPasswordAction\x12.\n" + "\x12inviteLinkPassword\x18\x01 \x01(\fR\x12inviteLinkPassword\x1aN\n" + "\x1dModifyAnnouncementsOnlyAction\x12-\n" + - "\x12announcements_only\x18\x01 \x01(\bR\x11announcementsOnly\"/\n" + + "\x12announcements_only\x18\x01 \x01(\bR\x11announcementsOnly\x1a\x16\n" + + "\x14TerminateGroupAction\"/\n" + "\x17ExternalGroupCredential\x12\x14\n" + "\x05token\x18\x01 \x01(\tR\x05token\"}\n" + "\rGroupResponse\x12#\n" + @@ -2918,7 +3039,7 @@ func file_Groups_proto_rawDescGZIP() []byte { } var file_Groups_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 41) +var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 43) var file_Groups_proto_goTypes = []any{ (Member_Role)(0), // 0: signal.Member.Role (AccessControl_AccessRequired)(0), // 1: signal.AccessControl.AccessRequired @@ -2960,9 +3081,11 @@ var file_Groups_proto_goTypes = []any{ (*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 37: signal.GroupChange.Actions.ModifyAttributesAccessControlAction (*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 38: signal.GroupChange.Actions.ModifyMembersAccessControlAction (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 39: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 40: signal.GroupChange.Actions.ModifyInviteLinkPasswordAction - (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 41: signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction - (*GroupChanges_GroupChangeState)(nil), // 42: signal.GroupChanges.GroupChangeState + (*GroupChange_Actions_ModifyMemberLabelAccessControlAction)(nil), // 40: signal.GroupChange.Actions.ModifyMemberLabelAccessControlAction + (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 41: signal.GroupChange.Actions.ModifyInviteLinkPasswordAction + (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 42: signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction + (*GroupChange_Actions_TerminateGroupAction)(nil), // 43: signal.GroupChange.Actions.TerminateGroupAction + (*GroupChanges_GroupChangeState)(nil), // 44: signal.GroupChanges.GroupChangeState } var file_Groups_proto_depIdxs = []int32{ 0, // 0: signal.Member.role:type_name -> signal.Member.Role @@ -2970,55 +3093,59 @@ var file_Groups_proto_depIdxs = []int32{ 1, // 2: signal.AccessControl.attributes:type_name -> signal.AccessControl.AccessRequired 1, // 3: signal.AccessControl.members:type_name -> signal.AccessControl.AccessRequired 1, // 4: signal.AccessControl.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired - 7, // 5: signal.Group.accessControl:type_name -> signal.AccessControl - 3, // 6: signal.Group.members:type_name -> signal.Member - 4, // 7: signal.Group.membersPendingProfileKey:type_name -> signal.MemberPendingProfileKey - 5, // 8: signal.Group.membersPendingAdminApproval:type_name -> signal.MemberPendingAdminApproval - 6, // 9: signal.Group.members_banned:type_name -> signal.MemberBanned - 17, // 10: signal.GroupInviteLink.contentsV1:type_name -> signal.GroupInviteLink.GroupInviteLinkContentsV1 - 1, // 11: signal.GroupJoinInfo.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired - 8, // 12: signal.GroupResponse.group:type_name -> signal.Group - 42, // 13: signal.GroupChanges.groupChanges:type_name -> signal.GroupChanges.GroupChangeState - 12, // 14: signal.GroupChangeResponse.group_change:type_name -> signal.GroupChange - 19, // 15: signal.GroupChange.Actions.addMembers:type_name -> signal.GroupChange.Actions.AddMemberAction - 20, // 16: signal.GroupChange.Actions.deleteMembers:type_name -> signal.GroupChange.Actions.DeleteMemberAction - 21, // 17: signal.GroupChange.Actions.modifyMemberRoles:type_name -> signal.GroupChange.Actions.ModifyMemberRoleAction - 23, // 18: signal.GroupChange.Actions.modifyMemberProfileKeys:type_name -> signal.GroupChange.Actions.ModifyMemberProfileKeyAction - 24, // 19: signal.GroupChange.Actions.addMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.AddMemberPendingProfileKeyAction - 25, // 20: signal.GroupChange.Actions.deleteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.DeleteMemberPendingProfileKeyAction - 26, // 21: signal.GroupChange.Actions.promoteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.PromoteMemberPendingProfileKeyAction - 33, // 22: signal.GroupChange.Actions.modifyTitle:type_name -> signal.GroupChange.Actions.ModifyTitleAction - 35, // 23: signal.GroupChange.Actions.modifyAvatar:type_name -> signal.GroupChange.Actions.ModifyAvatarAction - 36, // 24: signal.GroupChange.Actions.modifyDisappearingMessageTimer:type_name -> signal.GroupChange.Actions.ModifyDisappearingMessageTimerAction - 37, // 25: signal.GroupChange.Actions.modifyAttributesAccess:type_name -> signal.GroupChange.Actions.ModifyAttributesAccessControlAction - 38, // 26: signal.GroupChange.Actions.modifyMemberAccess:type_name -> signal.GroupChange.Actions.ModifyMembersAccessControlAction - 39, // 27: signal.GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction - 28, // 28: signal.GroupChange.Actions.addMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction - 29, // 29: signal.GroupChange.Actions.deleteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalAction - 30, // 30: signal.GroupChange.Actions.promoteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction - 40, // 31: signal.GroupChange.Actions.modifyInviteLinkPassword:type_name -> signal.GroupChange.Actions.ModifyInviteLinkPasswordAction - 34, // 32: signal.GroupChange.Actions.modifyDescription:type_name -> signal.GroupChange.Actions.ModifyDescriptionAction - 41, // 33: signal.GroupChange.Actions.modify_announcements_only:type_name -> signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction - 31, // 34: signal.GroupChange.Actions.add_members_banned:type_name -> signal.GroupChange.Actions.AddMemberBannedAction - 32, // 35: signal.GroupChange.Actions.delete_members_banned:type_name -> signal.GroupChange.Actions.DeleteMemberBannedAction - 27, // 36: signal.GroupChange.Actions.promote_members_pending_pni_aci_profile_key:type_name -> signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyAction - 22, // 37: signal.GroupChange.Actions.modifyMemberLabels:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAction - 3, // 38: signal.GroupChange.Actions.AddMemberAction.added:type_name -> signal.Member - 0, // 39: signal.GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> signal.Member.Role - 4, // 40: signal.GroupChange.Actions.AddMemberPendingProfileKeyAction.added:type_name -> signal.MemberPendingProfileKey - 5, // 41: signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction.added:type_name -> signal.MemberPendingAdminApproval - 0, // 42: signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction.role:type_name -> signal.Member.Role - 6, // 43: signal.GroupChange.Actions.AddMemberBannedAction.added:type_name -> signal.MemberBanned - 1, // 44: signal.GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> signal.AccessControl.AccessRequired - 1, // 45: signal.GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> signal.AccessControl.AccessRequired - 1, // 46: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> signal.AccessControl.AccessRequired - 12, // 47: signal.GroupChanges.GroupChangeState.groupChange:type_name -> signal.GroupChange - 8, // 48: signal.GroupChanges.GroupChangeState.groupState:type_name -> signal.Group - 49, // [49:49] is the sub-list for method output_type - 49, // [49:49] is the sub-list for method input_type - 49, // [49:49] is the sub-list for extension type_name - 49, // [49:49] is the sub-list for extension extendee - 0, // [0:49] is the sub-list for field type_name + 1, // 5: signal.AccessControl.memberLabel:type_name -> signal.AccessControl.AccessRequired + 7, // 6: signal.Group.accessControl:type_name -> signal.AccessControl + 3, // 7: signal.Group.members:type_name -> signal.Member + 4, // 8: signal.Group.membersPendingProfileKey:type_name -> signal.MemberPendingProfileKey + 5, // 9: signal.Group.membersPendingAdminApproval:type_name -> signal.MemberPendingAdminApproval + 6, // 10: signal.Group.members_banned:type_name -> signal.MemberBanned + 17, // 11: signal.GroupInviteLink.contentsV1:type_name -> signal.GroupInviteLink.GroupInviteLinkContentsV1 + 1, // 12: signal.GroupJoinInfo.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired + 8, // 13: signal.GroupResponse.group:type_name -> signal.Group + 44, // 14: signal.GroupChanges.groupChanges:type_name -> signal.GroupChanges.GroupChangeState + 12, // 15: signal.GroupChangeResponse.group_change:type_name -> signal.GroupChange + 19, // 16: signal.GroupChange.Actions.addMembers:type_name -> signal.GroupChange.Actions.AddMemberAction + 20, // 17: signal.GroupChange.Actions.deleteMembers:type_name -> signal.GroupChange.Actions.DeleteMemberAction + 21, // 18: signal.GroupChange.Actions.modifyMemberRoles:type_name -> signal.GroupChange.Actions.ModifyMemberRoleAction + 23, // 19: signal.GroupChange.Actions.modifyMemberProfileKeys:type_name -> signal.GroupChange.Actions.ModifyMemberProfileKeyAction + 24, // 20: signal.GroupChange.Actions.addMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.AddMemberPendingProfileKeyAction + 25, // 21: signal.GroupChange.Actions.deleteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.DeleteMemberPendingProfileKeyAction + 26, // 22: signal.GroupChange.Actions.promoteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.PromoteMemberPendingProfileKeyAction + 33, // 23: signal.GroupChange.Actions.modifyTitle:type_name -> signal.GroupChange.Actions.ModifyTitleAction + 35, // 24: signal.GroupChange.Actions.modifyAvatar:type_name -> signal.GroupChange.Actions.ModifyAvatarAction + 36, // 25: signal.GroupChange.Actions.modifyDisappearingMessageTimer:type_name -> signal.GroupChange.Actions.ModifyDisappearingMessageTimerAction + 37, // 26: signal.GroupChange.Actions.modifyAttributesAccess:type_name -> signal.GroupChange.Actions.ModifyAttributesAccessControlAction + 38, // 27: signal.GroupChange.Actions.modifyMemberAccess:type_name -> signal.GroupChange.Actions.ModifyMembersAccessControlAction + 39, // 28: signal.GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction + 28, // 29: signal.GroupChange.Actions.addMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction + 29, // 30: signal.GroupChange.Actions.deleteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalAction + 30, // 31: signal.GroupChange.Actions.promoteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction + 41, // 32: signal.GroupChange.Actions.modifyInviteLinkPassword:type_name -> signal.GroupChange.Actions.ModifyInviteLinkPasswordAction + 34, // 33: signal.GroupChange.Actions.modifyDescription:type_name -> signal.GroupChange.Actions.ModifyDescriptionAction + 42, // 34: signal.GroupChange.Actions.modify_announcements_only:type_name -> signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction + 31, // 35: signal.GroupChange.Actions.add_members_banned:type_name -> signal.GroupChange.Actions.AddMemberBannedAction + 32, // 36: signal.GroupChange.Actions.delete_members_banned:type_name -> signal.GroupChange.Actions.DeleteMemberBannedAction + 27, // 37: signal.GroupChange.Actions.promote_members_pending_pni_aci_profile_key:type_name -> signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyAction + 22, // 38: signal.GroupChange.Actions.modifyMemberLabels:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAction + 40, // 39: signal.GroupChange.Actions.modifyMemberLabelAccess:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAccessControlAction + 43, // 40: signal.GroupChange.Actions.terminate_group:type_name -> signal.GroupChange.Actions.TerminateGroupAction + 3, // 41: signal.GroupChange.Actions.AddMemberAction.added:type_name -> signal.Member + 0, // 42: signal.GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> signal.Member.Role + 4, // 43: signal.GroupChange.Actions.AddMemberPendingProfileKeyAction.added:type_name -> signal.MemberPendingProfileKey + 5, // 44: signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction.added:type_name -> signal.MemberPendingAdminApproval + 0, // 45: signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction.role:type_name -> signal.Member.Role + 6, // 46: signal.GroupChange.Actions.AddMemberBannedAction.added:type_name -> signal.MemberBanned + 1, // 47: signal.GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> signal.AccessControl.AccessRequired + 1, // 48: signal.GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> signal.AccessControl.AccessRequired + 1, // 49: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> signal.AccessControl.AccessRequired + 1, // 50: signal.GroupChange.Actions.ModifyMemberLabelAccessControlAction.memberLabelAccess:type_name -> signal.AccessControl.AccessRequired + 12, // 51: signal.GroupChanges.GroupChangeState.groupChange:type_name -> signal.GroupChange + 8, // 52: signal.GroupChanges.GroupChangeState.groupState:type_name -> signal.Group + 53, // [53:53] is the sub-list for method output_type + 53, // [53:53] is the sub-list for method input_type + 53, // [53:53] is the sub-list for extension type_name + 53, // [53:53] is the sub-list for extension extendee + 0, // [0:53] is the sub-list for field type_name } func init() { file_Groups_proto_init() } @@ -3041,7 +3168,7 @@ func file_Groups_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_Groups_proto_rawDesc), len(file_Groups_proto_rawDesc)), NumEnums: 2, - NumMessages: 41, + NumMessages: 43, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/Groups.proto b/pkg/signalmeow/protobuf/Groups.proto index 448846a..9843d1c 100644 --- a/pkg/signalmeow/protobuf/Groups.proto +++ b/pkg/signalmeow/protobuf/Groups.proto @@ -69,6 +69,7 @@ message AccessControl { AccessRequired attributes = 1; AccessRequired members = 2; AccessRequired addFromInviteLink = 3; + AccessRequired memberLabel = 4; } message Group { @@ -87,7 +88,8 @@ message Group { bytes inviteLinkPassword = 10; bool announcements_only = 12; repeated MemberBanned members_banned = 13; - // next: 14 + bool terminated = 14; + // next: 15 } message GroupAttributeBlob { @@ -225,6 +227,10 @@ message GroupChange { AccessControl.AccessRequired addFromInviteLinkAccess = 1; } + message ModifyMemberLabelAccessControlAction { + AccessControl.AccessRequired memberLabelAccess = 1; + } + message ModifyInviteLinkPasswordAction { bytes inviteLinkPassword = 1; } @@ -233,6 +239,8 @@ message GroupChange { bool announcements_only = 1; } + message TerminateGroupAction {} + bytes sourceUserId = 1; // clients should not provide this value; the server will provide it in the response buffer to ensure the signature is binding to a particular group // if clients set it during a request the server will respond with 400. @@ -262,7 +270,9 @@ message GroupChange { repeated DeleteMemberBannedAction delete_members_banned = 23; // change epoch = 4 repeated PromoteMemberPendingPniAciProfileKeyAction promote_members_pending_pni_aci_profile_key = 24; // change epoch = 5 repeated ModifyMemberLabelAction modifyMemberLabels = 26; // change epoch = 6; - // next: 27 + ModifyMemberLabelAccessControlAction modifyMemberLabelAccess = 27; // change epoch = 6 + TerminateGroupAction terminate_group = 28; // change epoch = 7 + // next: 29 } bytes actions = 1; diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 0231512..c925fe6 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -199,7 +199,6 @@ type ProvisionMessage struct { ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"` ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` - MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` // Deprecated, but required by linked devices EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes @@ -323,13 +322,6 @@ func (x *ProvisionMessage) GetProvisioningVersion() uint32 { return 0 } -func (x *ProvisionMessage) GetMasterKey() []byte { - if x != nil { - return x.MasterKey - } - return nil -} - func (x *ProvisionMessage) GetEphemeralBackupKey() []byte { if x != nil { return x.EphemeralBackupKey @@ -374,7 +366,7 @@ const file_Provisioning_proto_rawDesc = "" + "\aaddress\x18\x01 \x01(\tR\aaddress\"E\n" + "\x11ProvisionEnvelope\x12\x1c\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x12\n" + - "\x04body\x18\x02 \x01(\fR\x04body\"\xcc\x05\n" + + "\x04body\x18\x02 \x01(\fR\x04body\"\xb4\x05\n" + "\x10ProvisionMessage\x122\n" + "\x14aciIdentityKeyPublic\x18\x01 \x01(\fR\x14aciIdentityKeyPublic\x124\n" + "\x15aciIdentityKeyPrivate\x18\x02 \x01(\fR\x15aciIdentityKeyPrivate\x122\n" + @@ -390,13 +382,12 @@ const file_Provisioning_proto_rawDesc = "" + "profileKey\x18\x06 \x01(\fR\n" + "profileKey\x12\"\n" + "\freadReceipts\x18\a \x01(\bR\freadReceipts\x120\n" + - "\x13provisioningVersion\x18\t \x01(\rR\x13provisioningVersion\x12\x1c\n" + - "\tmasterKey\x18\r \x01(\fR\tmasterKey\x12.\n" + + "\x13provisioningVersion\x18\t \x01(\rR\x13provisioningVersion\x12.\n" + "\x12ephemeralBackupKey\x18\x0e \x01(\fR\x12ephemeralBackupKey\x12.\n" + "\x12accountEntropyPool\x18\x0f \x01(\tR\x12accountEntropyPool\x12.\n" + "\x12mediaRootBackupKey\x18\x10 \x01(\fR\x12mediaRootBackupKey\x12\x1c\n" + "\taciBinary\x18\x11 \x01(\fR\taciBinary\x12\x1c\n" + - "\tpniBinary\x18\x12 \x01(\fR\tpniBinary*G\n" + + "\tpniBinary\x18\x12 \x01(\fR\tpniBinaryJ\x04\b\r\x10\x0e*G\n" + "\x13ProvisioningVersion\x12\v\n" + "\aINITIAL\x10\x00\x12\x12\n" + "\x0eTABLET_SUPPORT\x10\x01\x12\v\n" + diff --git a/pkg/signalmeow/protobuf/Provisioning.proto b/pkg/signalmeow/protobuf/Provisioning.proto index 2fde938..b5eeaf6 100644 --- a/pkg/signalmeow/protobuf/Provisioning.proto +++ b/pkg/signalmeow/protobuf/Provisioning.proto @@ -38,7 +38,7 @@ message ProvisionMessage { optional bytes profileKey = 6; optional bool readReceipts = 7; optional uint32 provisioningVersion = 9; - optional bytes masterKey = 13; // Deprecated, but required by linked devices + reserved /*masterKey*/ 13; // Deprecated in favor of accountEntropyPool optional bytes ephemeralBackupKey = 14; // 32 bytes optional string accountEntropyPool = 15; optional bytes mediaRootBackupKey = 16; // 32-bytes diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index 5866dbb..32842bf 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -28,33 +28,71 @@ const ( type Envelope_Type int32 const ( - Envelope_UNKNOWN Envelope_Type = 0 - Envelope_CIPHERTEXT Envelope_Type = 1 // content => (version byte | SignalMessage{Content}) - Envelope_PREKEY_BUNDLE Envelope_Type = 3 // content => (version byte | PreKeySignalMessage{Content}) - Envelope_SERVER_DELIVERY_RECEIPT Envelope_Type = 5 // legacyMessage => [] AND content => [] - Envelope_UNIDENTIFIED_SENDER Envelope_Type = 6 // legacyMessage => [] AND content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) - Envelope_SENDERKEY_MESSAGE Envelope_Type = 7 // legacyMessage => [] AND content => (version byte | SenderKeyMessage) - Envelope_PLAINTEXT_CONTENT Envelope_Type = 8 // legacyMessage => [] AND content => (marker byte | Content) + Envelope_UNKNOWN Envelope_Type = 0 + // * + // A double-ratchet message represents a "normal," "unsealed-sender" message + // encrypted using the Double Ratchet within an established Signal session. + // Double-ratchet messages include sender information in the plaintext + // portion of the `Envelope`. + Envelope_DOUBLE_RATCHET Envelope_Type = 1 // content => (version byte | SignalMessage{Content}) + // * + // 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. Like double-ratchet messages, + // prekey messages contain sender information in the plaintext portion of + // the `Envelope`. + Envelope_PREKEY_MESSAGE Envelope_Type = 3 // content => (version byte | PreKeySignalMessage{Content}) + // * + // Server delivery receipts are generated by the server when + // "unsealed-sender" messages are delivered to and acknowledged by the + // destination device. Server delivery receipts identify the sender in the + // plaintext portion of the `Envelope` and have no `content`. Note that + // receipts for sealed-sender messages are generated by clients as + // `UNIDENTIFIED_SENDER` messages. + // + // Note that, with server delivery receipts, the "client timestamp" on + // the envelope refers to the timestamp of the original message (i.e. the + // message the server just delivered) and not to the time of delivery. The + // "server timestamp" refers to the time of delivery. + Envelope_SERVER_DELIVERY_RECEIPT Envelope_Type = 5 // content => [] + // * + // An unidentified sender message represents a message with no sender + // information in the plaintext portion of the `Envelope`. Unidentified + // sender messages always contain an additional `subtype` in their + // `content`. They may or may not be part of an existing Signal session + // (i.e. an unidentified sender message may have a "prekey message" + // subtype or may indicate an encryption error). + Envelope_UNIDENTIFIED_SENDER Envelope_Type = 6 // content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) + // * + // 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. + Envelope_PLAINTEXT_CONTENT Envelope_Type = 8 // content => (marker byte | Content) ) // Enum value maps for Envelope_Type. var ( Envelope_Type_name = map[int32]string{ 0: "UNKNOWN", - 1: "CIPHERTEXT", - 3: "PREKEY_BUNDLE", + 1: "DOUBLE_RATCHET", + 3: "PREKEY_MESSAGE", 5: "SERVER_DELIVERY_RECEIPT", 6: "UNIDENTIFIED_SENDER", - 7: "SENDERKEY_MESSAGE", 8: "PLAINTEXT_CONTENT", } Envelope_Type_value = map[string]int32{ "UNKNOWN": 0, - "CIPHERTEXT": 1, - "PREKEY_BUNDLE": 3, + "DOUBLE_RATCHET": 1, + "PREKEY_MESSAGE": 3, "SERVER_DELIVERY_RECEIPT": 5, "UNIDENTIFIED_SENDER": 6, - "SENDERKEY_MESSAGE": 7, "PLAINTEXT_CONTENT": 8, } ) @@ -1753,9 +1791,9 @@ type Envelope struct { state protoimpl.MessageState `protogen:"open.v1"` Type *Envelope_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.Envelope_Type" json:"type,omitempty"` SourceServiceId *string `protobuf:"bytes,11,opt,name=sourceServiceId" json:"sourceServiceId,omitempty"` - SourceDevice *uint32 `protobuf:"varint,7,opt,name=sourceDevice" json:"sourceDevice,omitempty"` + SourceDeviceId *uint32 `protobuf:"varint,7,opt,name=sourceDeviceId" json:"sourceDeviceId,omitempty"` DestinationServiceId *string `protobuf:"bytes,13,opt,name=destinationServiceId" json:"destinationServiceId,omitempty"` - Timestamp *uint64 `protobuf:"varint,5,opt,name=timestamp" json:"timestamp,omitempty"` + ClientTimestamp *uint64 `protobuf:"varint,5,opt,name=clientTimestamp" json:"clientTimestamp,omitempty"` Content []byte `protobuf:"bytes,8,opt,name=content" json:"content,omitempty"` // Contains an encrypted Content ServerGuid *string `protobuf:"bytes,9,opt,name=serverGuid" json:"serverGuid,omitempty"` ServerTimestamp *uint64 `protobuf:"varint,10,opt,name=serverTimestamp" json:"serverTimestamp,omitempty"` @@ -1821,9 +1859,9 @@ func (x *Envelope) GetSourceServiceId() string { return "" } -func (x *Envelope) GetSourceDevice() uint32 { - if x != nil && x.SourceDevice != nil { - return *x.SourceDevice +func (x *Envelope) GetSourceDeviceId() uint32 { + if x != nil && x.SourceDeviceId != nil { + return *x.SourceDeviceId } return 0 } @@ -1835,9 +1873,9 @@ func (x *Envelope) GetDestinationServiceId() string { return "" } -func (x *Envelope) GetTimestamp() uint64 { - if x != nil && x.Timestamp != nil { - return *x.Timestamp +func (x *Envelope) GetClientTimestamp() uint64 { + if x != nil && x.ClientTimestamp != nil { + return *x.ClientTimestamp } return 0 } @@ -1927,18 +1965,21 @@ func (x *Envelope) GetUpdatedPniBinary() []byte { } type Content struct { - state protoimpl.MessageState `protogen:"open.v1"` - DataMessage *DataMessage `protobuf:"bytes,1,opt,name=dataMessage" json:"dataMessage,omitempty"` - SyncMessage *SyncMessage `protobuf:"bytes,2,opt,name=syncMessage" json:"syncMessage,omitempty"` - CallMessage *CallMessage `protobuf:"bytes,3,opt,name=callMessage" json:"callMessage,omitempty"` - NullMessage *NullMessage `protobuf:"bytes,4,opt,name=nullMessage" json:"nullMessage,omitempty"` - ReceiptMessage *ReceiptMessage `protobuf:"bytes,5,opt,name=receiptMessage" json:"receiptMessage,omitempty"` - TypingMessage *TypingMessage `protobuf:"bytes,6,opt,name=typingMessage" json:"typingMessage,omitempty"` - SenderKeyDistributionMessage []byte `protobuf:"bytes,7,opt,name=senderKeyDistributionMessage" json:"senderKeyDistributionMessage,omitempty"` - DecryptionErrorMessage []byte `protobuf:"bytes,8,opt,name=decryptionErrorMessage" json:"decryptionErrorMessage,omitempty"` - StoryMessage *StoryMessage `protobuf:"bytes,9,opt,name=storyMessage" json:"storyMessage,omitempty"` - PniSignatureMessage *PniSignatureMessage `protobuf:"bytes,10,opt,name=pniSignatureMessage" json:"pniSignatureMessage,omitempty"` - EditMessage *EditMessage `protobuf:"bytes,11,opt,name=editMessage" json:"editMessage,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Content: + // + // *Content_DataMessage + // *Content_SyncMessage + // *Content_CallMessage + // *Content_NullMessage + // *Content_ReceiptMessage + // *Content_TypingMessage + // *Content_DecryptionErrorMessage + // *Content_StoryMessage + // *Content_EditMessage + Content isContent_Content `protobuf_oneof:"content"` + SenderKeyDistributionMessage []byte `protobuf:"bytes,7,opt,name=senderKeyDistributionMessage" json:"senderKeyDistributionMessage,omitempty"` + PniSignatureMessage *PniSignatureMessage `protobuf:"bytes,10,opt,name=pniSignatureMessage" json:"pniSignatureMessage,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1973,44 +2014,90 @@ func (*Content) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{1} } +func (x *Content) GetContent() isContent_Content { + if x != nil { + return x.Content + } + return nil +} + func (x *Content) GetDataMessage() *DataMessage { if x != nil { - return x.DataMessage + if x, ok := x.Content.(*Content_DataMessage); ok { + return x.DataMessage + } } return nil } func (x *Content) GetSyncMessage() *SyncMessage { if x != nil { - return x.SyncMessage + if x, ok := x.Content.(*Content_SyncMessage); ok { + return x.SyncMessage + } } return nil } func (x *Content) GetCallMessage() *CallMessage { if x != nil { - return x.CallMessage + if x, ok := x.Content.(*Content_CallMessage); ok { + return x.CallMessage + } } return nil } func (x *Content) GetNullMessage() *NullMessage { if x != nil { - return x.NullMessage + if x, ok := x.Content.(*Content_NullMessage); ok { + return x.NullMessage + } } return nil } func (x *Content) GetReceiptMessage() *ReceiptMessage { if x != nil { - return x.ReceiptMessage + if x, ok := x.Content.(*Content_ReceiptMessage); ok { + return x.ReceiptMessage + } } return nil } func (x *Content) GetTypingMessage() *TypingMessage { if x != nil { - return x.TypingMessage + if x, ok := x.Content.(*Content_TypingMessage); ok { + return x.TypingMessage + } + } + return nil +} + +func (x *Content) GetDecryptionErrorMessage() []byte { + if x != nil { + if x, ok := x.Content.(*Content_DecryptionErrorMessage); ok { + return x.DecryptionErrorMessage + } + } + return nil +} + +func (x *Content) GetStoryMessage() *StoryMessage { + if x != nil { + if x, ok := x.Content.(*Content_StoryMessage); ok { + return x.StoryMessage + } + } + return nil +} + +func (x *Content) GetEditMessage() *EditMessage { + if x != nil { + if x, ok := x.Content.(*Content_EditMessage); ok { + return x.EditMessage + } } return nil } @@ -2022,20 +2109,6 @@ func (x *Content) GetSenderKeyDistributionMessage() []byte { return nil } -func (x *Content) GetDecryptionErrorMessage() []byte { - if x != nil { - return x.DecryptionErrorMessage - } - return nil -} - -func (x *Content) GetStoryMessage() *StoryMessage { - if x != nil { - return x.StoryMessage - } - return nil -} - func (x *Content) GetPniSignatureMessage() *PniSignatureMessage { if x != nil { return x.PniSignatureMessage @@ -2043,13 +2116,64 @@ func (x *Content) GetPniSignatureMessage() *PniSignatureMessage { return nil } -func (x *Content) GetEditMessage() *EditMessage { - if x != nil { - return x.EditMessage - } - return nil +type isContent_Content interface { + isContent_Content() } +type Content_DataMessage struct { + DataMessage *DataMessage `protobuf:"bytes,1,opt,name=dataMessage,oneof"` +} + +type Content_SyncMessage struct { + SyncMessage *SyncMessage `protobuf:"bytes,2,opt,name=syncMessage,oneof"` +} + +type Content_CallMessage struct { + CallMessage *CallMessage `protobuf:"bytes,3,opt,name=callMessage,oneof"` +} + +type Content_NullMessage struct { + NullMessage *NullMessage `protobuf:"bytes,4,opt,name=nullMessage,oneof"` +} + +type Content_ReceiptMessage struct { + ReceiptMessage *ReceiptMessage `protobuf:"bytes,5,opt,name=receiptMessage,oneof"` +} + +type Content_TypingMessage struct { + TypingMessage *TypingMessage `protobuf:"bytes,6,opt,name=typingMessage,oneof"` +} + +type Content_DecryptionErrorMessage struct { + DecryptionErrorMessage []byte `protobuf:"bytes,8,opt,name=decryptionErrorMessage,oneof"` +} + +type Content_StoryMessage struct { + StoryMessage *StoryMessage `protobuf:"bytes,9,opt,name=storyMessage,oneof"` +} + +type Content_EditMessage struct { + EditMessage *EditMessage `protobuf:"bytes,11,opt,name=editMessage,oneof"` +} + +func (*Content_DataMessage) isContent_Content() {} + +func (*Content_SyncMessage) isContent_Content() {} + +func (*Content_CallMessage) isContent_Content() {} + +func (*Content_NullMessage) isContent_Content() {} + +func (*Content_ReceiptMessage) isContent_Content() {} + +func (*Content_TypingMessage) isContent_Content() {} + +func (*Content_DecryptionErrorMessage) isContent_Content() {} + +func (*Content_StoryMessage) isContent_Content() {} + +func (*Content_EditMessage) isContent_Content() {} + type CallMessage struct { state protoimpl.MessageState `protogen:"open.v1"` Offer *CallMessage_Offer `protobuf:"bytes,1,opt,name=offer" json:"offer,omitempty"` @@ -2169,7 +2293,8 @@ type DataMessage struct { PollTerminate *DataMessage_PollTerminate `protobuf:"bytes,25,opt,name=pollTerminate" json:"pollTerminate,omitempty"` PollVote *DataMessage_PollVote `protobuf:"bytes,26,opt,name=pollVote" json:"pollVote,omitempty"` PinMessage *DataMessage_PinMessage `protobuf:"bytes,27,opt,name=pinMessage" json:"pinMessage,omitempty"` - UnpinMessage *DataMessage_UnpinMessage `protobuf:"bytes,28,opt,name=unpinMessage" json:"unpinMessage,omitempty"` // NEXT ID: 29 + UnpinMessage *DataMessage_UnpinMessage `protobuf:"bytes,28,opt,name=unpinMessage" json:"unpinMessage,omitempty"` + AdminDelete *DataMessage_AdminDelete `protobuf:"bytes,29,opt,name=adminDelete" json:"adminDelete,omitempty"` // NEXT ID: 30 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2386,6 +2511,13 @@ func (x *DataMessage) GetUnpinMessage() *DataMessage_UnpinMessage { return nil } +func (x *DataMessage) GetAdminDelete() *DataMessage_AdminDelete { + if x != nil { + return x.AdminDelete + } + return nil +} + type NullMessage struct { state protoimpl.MessageState `protogen:"open.v1"` Padding []byte `protobuf:"bytes,1,opt,name=padding" json:"padding,omitempty"` @@ -2931,32 +3063,38 @@ func (x *Verified) GetDestinationAciBinary() []byte { } type SyncMessage struct { - state protoimpl.MessageState `protogen:"open.v1"` - Sent *SyncMessage_Sent `protobuf:"bytes,1,opt,name=sent" json:"sent,omitempty"` - Contacts *SyncMessage_Contacts `protobuf:"bytes,2,opt,name=contacts" json:"contacts,omitempty"` - Request *SyncMessage_Request `protobuf:"bytes,4,opt,name=request" json:"request,omitempty"` - Read []*SyncMessage_Read `protobuf:"bytes,5,rep,name=read" json:"read,omitempty"` - Blocked *SyncMessage_Blocked `protobuf:"bytes,6,opt,name=blocked" json:"blocked,omitempty"` - Verified *Verified `protobuf:"bytes,7,opt,name=verified" json:"verified,omitempty"` - Configuration *SyncMessage_Configuration `protobuf:"bytes,9,opt,name=configuration" json:"configuration,omitempty"` - Padding []byte `protobuf:"bytes,8,opt,name=padding" json:"padding,omitempty"` - StickerPackOperation []*SyncMessage_StickerPackOperation `protobuf:"bytes,10,rep,name=stickerPackOperation" json:"stickerPackOperation,omitempty"` - ViewOnceOpen *SyncMessage_ViewOnceOpen `protobuf:"bytes,11,opt,name=viewOnceOpen" json:"viewOnceOpen,omitempty"` - FetchLatest *SyncMessage_FetchLatest `protobuf:"bytes,12,opt,name=fetchLatest" json:"fetchLatest,omitempty"` - Keys *SyncMessage_Keys `protobuf:"bytes,13,opt,name=keys" json:"keys,omitempty"` - MessageRequestResponse *SyncMessage_MessageRequestResponse `protobuf:"bytes,14,opt,name=messageRequestResponse" json:"messageRequestResponse,omitempty"` - OutgoingPayment *SyncMessage_OutgoingPayment `protobuf:"bytes,15,opt,name=outgoingPayment" json:"outgoingPayment,omitempty"` - Viewed []*SyncMessage_Viewed `protobuf:"bytes,16,rep,name=viewed" json:"viewed,omitempty"` - PniChangeNumber *SyncMessage_PniChangeNumber `protobuf:"bytes,18,opt,name=pniChangeNumber" json:"pniChangeNumber,omitempty"` - CallEvent *SyncMessage_CallEvent `protobuf:"bytes,19,opt,name=callEvent" json:"callEvent,omitempty"` - CallLinkUpdate *SyncMessage_CallLinkUpdate `protobuf:"bytes,20,opt,name=callLinkUpdate" json:"callLinkUpdate,omitempty"` - CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent" json:"callLogEvent,omitempty"` - DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe" json:"deleteForMe,omitempty"` - DeviceNameChange *SyncMessage_DeviceNameChange `protobuf:"bytes,23,opt,name=deviceNameChange" json:"deviceNameChange,omitempty"` - AttachmentBackfillRequest *SyncMessage_AttachmentBackfillRequest `protobuf:"bytes,24,opt,name=attachmentBackfillRequest" json:"attachmentBackfillRequest,omitempty"` - AttachmentBackfillResponse *SyncMessage_AttachmentBackfillResponse `protobuf:"bytes,25,opt,name=attachmentBackfillResponse" json:"attachmentBackfillResponse,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Content: + // + // *SyncMessage_Sent_ + // *SyncMessage_Contacts_ + // *SyncMessage_Request_ + // *SyncMessage_Blocked_ + // *SyncMessage_Verified + // *SyncMessage_Configuration_ + // *SyncMessage_ViewOnceOpen_ + // *SyncMessage_FetchLatest_ + // *SyncMessage_Keys_ + // *SyncMessage_MessageRequestResponse_ + // *SyncMessage_OutgoingPayment_ + // *SyncMessage_PniChangeNumber_ + // *SyncMessage_CallEvent_ + // *SyncMessage_CallLinkUpdate_ + // *SyncMessage_CallLogEvent_ + // *SyncMessage_DeleteForMe_ + // *SyncMessage_DeviceNameChange_ + // *SyncMessage_AttachmentBackfillRequest_ + // *SyncMessage_AttachmentBackfillResponse_ + Content isSyncMessage_Content `protobuf_oneof:"content"` + // Protobufs don't allow `repeated` fields to be inside of `oneof` so while + // the fields below are mutually exclusive with the rest of the values above + // we have to place them outside of `oneof`. + Read []*SyncMessage_Read `protobuf:"bytes,5,rep,name=read" json:"read,omitempty"` + StickerPackOperation []*SyncMessage_StickerPackOperation `protobuf:"bytes,10,rep,name=stickerPackOperation" json:"stickerPackOperation,omitempty"` + Viewed []*SyncMessage_Viewed `protobuf:"bytes,16,rep,name=viewed" json:"viewed,omitempty"` + Padding []byte `protobuf:"bytes,8,opt,name=padding" json:"padding,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SyncMessage) Reset() { @@ -2989,23 +3127,180 @@ func (*SyncMessage) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{11} } +func (x *SyncMessage) GetContent() isSyncMessage_Content { + if x != nil { + return x.Content + } + return nil +} + func (x *SyncMessage) GetSent() *SyncMessage_Sent { if x != nil { - return x.Sent + if x, ok := x.Content.(*SyncMessage_Sent_); ok { + return x.Sent + } } return nil } func (x *SyncMessage) GetContacts() *SyncMessage_Contacts { if x != nil { - return x.Contacts + if x, ok := x.Content.(*SyncMessage_Contacts_); ok { + return x.Contacts + } } return nil } func (x *SyncMessage) GetRequest() *SyncMessage_Request { if x != nil { - return x.Request + if x, ok := x.Content.(*SyncMessage_Request_); ok { + return x.Request + } + } + return nil +} + +func (x *SyncMessage) GetBlocked() *SyncMessage_Blocked { + if x != nil { + if x, ok := x.Content.(*SyncMessage_Blocked_); ok { + return x.Blocked + } + } + return nil +} + +func (x *SyncMessage) GetVerified() *Verified { + if x != nil { + if x, ok := x.Content.(*SyncMessage_Verified); ok { + return x.Verified + } + } + return nil +} + +func (x *SyncMessage) GetConfiguration() *SyncMessage_Configuration { + if x != nil { + if x, ok := x.Content.(*SyncMessage_Configuration_); ok { + return x.Configuration + } + } + return nil +} + +func (x *SyncMessage) GetViewOnceOpen() *SyncMessage_ViewOnceOpen { + if x != nil { + if x, ok := x.Content.(*SyncMessage_ViewOnceOpen_); ok { + return x.ViewOnceOpen + } + } + return nil +} + +func (x *SyncMessage) GetFetchLatest() *SyncMessage_FetchLatest { + if x != nil { + if x, ok := x.Content.(*SyncMessage_FetchLatest_); ok { + return x.FetchLatest + } + } + return nil +} + +func (x *SyncMessage) GetKeys() *SyncMessage_Keys { + if x != nil { + if x, ok := x.Content.(*SyncMessage_Keys_); ok { + return x.Keys + } + } + return nil +} + +func (x *SyncMessage) GetMessageRequestResponse() *SyncMessage_MessageRequestResponse { + if x != nil { + if x, ok := x.Content.(*SyncMessage_MessageRequestResponse_); ok { + return x.MessageRequestResponse + } + } + return nil +} + +func (x *SyncMessage) GetOutgoingPayment() *SyncMessage_OutgoingPayment { + if x != nil { + if x, ok := x.Content.(*SyncMessage_OutgoingPayment_); ok { + return x.OutgoingPayment + } + } + return nil +} + +func (x *SyncMessage) GetPniChangeNumber() *SyncMessage_PniChangeNumber { + if x != nil { + if x, ok := x.Content.(*SyncMessage_PniChangeNumber_); ok { + return x.PniChangeNumber + } + } + return nil +} + +func (x *SyncMessage) GetCallEvent() *SyncMessage_CallEvent { + if x != nil { + if x, ok := x.Content.(*SyncMessage_CallEvent_); ok { + return x.CallEvent + } + } + return nil +} + +func (x *SyncMessage) GetCallLinkUpdate() *SyncMessage_CallLinkUpdate { + if x != nil { + if x, ok := x.Content.(*SyncMessage_CallLinkUpdate_); ok { + return x.CallLinkUpdate + } + } + return nil +} + +func (x *SyncMessage) GetCallLogEvent() *SyncMessage_CallLogEvent { + if x != nil { + if x, ok := x.Content.(*SyncMessage_CallLogEvent_); ok { + return x.CallLogEvent + } + } + return nil +} + +func (x *SyncMessage) GetDeleteForMe() *SyncMessage_DeleteForMe { + if x != nil { + if x, ok := x.Content.(*SyncMessage_DeleteForMe_); ok { + return x.DeleteForMe + } + } + return nil +} + +func (x *SyncMessage) GetDeviceNameChange() *SyncMessage_DeviceNameChange { + if x != nil { + if x, ok := x.Content.(*SyncMessage_DeviceNameChange_); ok { + return x.DeviceNameChange + } + } + return nil +} + +func (x *SyncMessage) GetAttachmentBackfillRequest() *SyncMessage_AttachmentBackfillRequest { + if x != nil { + if x, ok := x.Content.(*SyncMessage_AttachmentBackfillRequest_); ok { + return x.AttachmentBackfillRequest + } + } + return nil +} + +func (x *SyncMessage) GetAttachmentBackfillResponse() *SyncMessage_AttachmentBackfillResponse { + if x != nil { + if x, ok := x.Content.(*SyncMessage_AttachmentBackfillResponse_); ok { + return x.AttachmentBackfillResponse + } } return nil } @@ -3017,34 +3312,6 @@ func (x *SyncMessage) GetRead() []*SyncMessage_Read { return nil } -func (x *SyncMessage) GetBlocked() *SyncMessage_Blocked { - if x != nil { - return x.Blocked - } - return nil -} - -func (x *SyncMessage) GetVerified() *Verified { - if x != nil { - return x.Verified - } - return nil -} - -func (x *SyncMessage) GetConfiguration() *SyncMessage_Configuration { - if x != nil { - return x.Configuration - } - return nil -} - -func (x *SyncMessage) GetPadding() []byte { - if x != nil { - return x.Padding - } - return nil -} - func (x *SyncMessage) GetStickerPackOperation() []*SyncMessage_StickerPackOperation { if x != nil { return x.StickerPackOperation @@ -3052,41 +3319,6 @@ func (x *SyncMessage) GetStickerPackOperation() []*SyncMessage_StickerPackOperat return nil } -func (x *SyncMessage) GetViewOnceOpen() *SyncMessage_ViewOnceOpen { - if x != nil { - return x.ViewOnceOpen - } - return nil -} - -func (x *SyncMessage) GetFetchLatest() *SyncMessage_FetchLatest { - if x != nil { - return x.FetchLatest - } - return nil -} - -func (x *SyncMessage) GetKeys() *SyncMessage_Keys { - if x != nil { - return x.Keys - } - return nil -} - -func (x *SyncMessage) GetMessageRequestResponse() *SyncMessage_MessageRequestResponse { - if x != nil { - return x.MessageRequestResponse - } - return nil -} - -func (x *SyncMessage) GetOutgoingPayment() *SyncMessage_OutgoingPayment { - if x != nil { - return x.OutgoingPayment - } - return nil -} - func (x *SyncMessage) GetViewed() []*SyncMessage_Viewed { if x != nil { return x.Viewed @@ -3094,62 +3326,131 @@ func (x *SyncMessage) GetViewed() []*SyncMessage_Viewed { return nil } -func (x *SyncMessage) GetPniChangeNumber() *SyncMessage_PniChangeNumber { +func (x *SyncMessage) GetPadding() []byte { if x != nil { - return x.PniChangeNumber + return x.Padding } return nil } -func (x *SyncMessage) GetCallEvent() *SyncMessage_CallEvent { - if x != nil { - return x.CallEvent - } - return nil +type isSyncMessage_Content interface { + isSyncMessage_Content() } -func (x *SyncMessage) GetCallLinkUpdate() *SyncMessage_CallLinkUpdate { - if x != nil { - return x.CallLinkUpdate - } - return nil +type SyncMessage_Sent_ struct { + Sent *SyncMessage_Sent `protobuf:"bytes,1,opt,name=sent,oneof"` } -func (x *SyncMessage) GetCallLogEvent() *SyncMessage_CallLogEvent { - if x != nil { - return x.CallLogEvent - } - return nil +type SyncMessage_Contacts_ struct { + Contacts *SyncMessage_Contacts `protobuf:"bytes,2,opt,name=contacts,oneof"` } -func (x *SyncMessage) GetDeleteForMe() *SyncMessage_DeleteForMe { - if x != nil { - return x.DeleteForMe - } - return nil +type SyncMessage_Request_ struct { + Request *SyncMessage_Request `protobuf:"bytes,4,opt,name=request,oneof"` } -func (x *SyncMessage) GetDeviceNameChange() *SyncMessage_DeviceNameChange { - if x != nil { - return x.DeviceNameChange - } - return nil +type SyncMessage_Blocked_ struct { + Blocked *SyncMessage_Blocked `protobuf:"bytes,6,opt,name=blocked,oneof"` } -func (x *SyncMessage) GetAttachmentBackfillRequest() *SyncMessage_AttachmentBackfillRequest { - if x != nil { - return x.AttachmentBackfillRequest - } - return nil +type SyncMessage_Verified struct { + Verified *Verified `protobuf:"bytes,7,opt,name=verified,oneof"` } -func (x *SyncMessage) GetAttachmentBackfillResponse() *SyncMessage_AttachmentBackfillResponse { - if x != nil { - return x.AttachmentBackfillResponse - } - return nil +type SyncMessage_Configuration_ struct { + Configuration *SyncMessage_Configuration `protobuf:"bytes,9,opt,name=configuration,oneof"` } +type SyncMessage_ViewOnceOpen_ struct { + ViewOnceOpen *SyncMessage_ViewOnceOpen `protobuf:"bytes,11,opt,name=viewOnceOpen,oneof"` +} + +type SyncMessage_FetchLatest_ struct { + FetchLatest *SyncMessage_FetchLatest `protobuf:"bytes,12,opt,name=fetchLatest,oneof"` +} + +type SyncMessage_Keys_ struct { + Keys *SyncMessage_Keys `protobuf:"bytes,13,opt,name=keys,oneof"` +} + +type SyncMessage_MessageRequestResponse_ struct { + MessageRequestResponse *SyncMessage_MessageRequestResponse `protobuf:"bytes,14,opt,name=messageRequestResponse,oneof"` +} + +type SyncMessage_OutgoingPayment_ struct { + OutgoingPayment *SyncMessage_OutgoingPayment `protobuf:"bytes,15,opt,name=outgoingPayment,oneof"` +} + +type SyncMessage_PniChangeNumber_ struct { + PniChangeNumber *SyncMessage_PniChangeNumber `protobuf:"bytes,18,opt,name=pniChangeNumber,oneof"` +} + +type SyncMessage_CallEvent_ struct { + CallEvent *SyncMessage_CallEvent `protobuf:"bytes,19,opt,name=callEvent,oneof"` +} + +type SyncMessage_CallLinkUpdate_ struct { + CallLinkUpdate *SyncMessage_CallLinkUpdate `protobuf:"bytes,20,opt,name=callLinkUpdate,oneof"` +} + +type SyncMessage_CallLogEvent_ struct { + CallLogEvent *SyncMessage_CallLogEvent `protobuf:"bytes,21,opt,name=callLogEvent,oneof"` +} + +type SyncMessage_DeleteForMe_ struct { + DeleteForMe *SyncMessage_DeleteForMe `protobuf:"bytes,22,opt,name=deleteForMe,oneof"` +} + +type SyncMessage_DeviceNameChange_ struct { + DeviceNameChange *SyncMessage_DeviceNameChange `protobuf:"bytes,23,opt,name=deviceNameChange,oneof"` +} + +type SyncMessage_AttachmentBackfillRequest_ struct { + AttachmentBackfillRequest *SyncMessage_AttachmentBackfillRequest `protobuf:"bytes,24,opt,name=attachmentBackfillRequest,oneof"` +} + +type SyncMessage_AttachmentBackfillResponse_ struct { + AttachmentBackfillResponse *SyncMessage_AttachmentBackfillResponse `protobuf:"bytes,25,opt,name=attachmentBackfillResponse,oneof"` +} + +func (*SyncMessage_Sent_) isSyncMessage_Content() {} + +func (*SyncMessage_Contacts_) isSyncMessage_Content() {} + +func (*SyncMessage_Request_) isSyncMessage_Content() {} + +func (*SyncMessage_Blocked_) isSyncMessage_Content() {} + +func (*SyncMessage_Verified) isSyncMessage_Content() {} + +func (*SyncMessage_Configuration_) isSyncMessage_Content() {} + +func (*SyncMessage_ViewOnceOpen_) isSyncMessage_Content() {} + +func (*SyncMessage_FetchLatest_) isSyncMessage_Content() {} + +func (*SyncMessage_Keys_) isSyncMessage_Content() {} + +func (*SyncMessage_MessageRequestResponse_) isSyncMessage_Content() {} + +func (*SyncMessage_OutgoingPayment_) isSyncMessage_Content() {} + +func (*SyncMessage_PniChangeNumber_) isSyncMessage_Content() {} + +func (*SyncMessage_CallEvent_) isSyncMessage_Content() {} + +func (*SyncMessage_CallLinkUpdate_) isSyncMessage_Content() {} + +func (*SyncMessage_CallLogEvent_) isSyncMessage_Content() {} + +func (*SyncMessage_DeleteForMe_) isSyncMessage_Content() {} + +func (*SyncMessage_DeviceNameChange_) isSyncMessage_Content() {} + +func (*SyncMessage_AttachmentBackfillRequest_) isSyncMessage_Content() {} + +func (*SyncMessage_AttachmentBackfillResponse_) isSyncMessage_Content() {} + type AttachmentPointer struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to AttachmentIdentifier: @@ -5117,8 +5418,8 @@ type DataMessage_PollVote struct { state protoimpl.MessageState `protogen:"open.v1"` TargetAuthorAciBinary []byte `protobuf:"bytes,1,opt,name=targetAuthorAciBinary" json:"targetAuthorAciBinary,omitempty"` TargetSentTimestamp *uint64 `protobuf:"varint,2,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` - OptionIndexes []uint32 `protobuf:"varint,3,rep,name=optionIndexes" json:"optionIndexes,omitempty"` // must be in the range [0, options.length) from the PollCreate - VoteCount *uint32 `protobuf:"varint,4,opt,name=voteCount" json:"voteCount,omitempty"` // increment this by 1 each time you vote on a given poll + OptionIndexes []uint32 `protobuf:"varint,3,rep,name=optionIndexes" json:"optionIndexes,omitempty"` + VoteCount *uint32 `protobuf:"varint,4,opt,name=voteCount" json:"voteCount,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -5331,6 +5632,58 @@ func (x *DataMessage_UnpinMessage) GetTargetSentTimestamp() uint64 { return 0 } +type DataMessage_AdminDelete struct { + state protoimpl.MessageState `protogen:"open.v1"` + TargetAuthorAciBinary []byte `protobuf:"bytes,1,opt,name=targetAuthorAciBinary" json:"targetAuthorAciBinary,omitempty"` // 16-byte UUID + TargetSentTimestamp *uint64 `protobuf:"varint,2,opt,name=targetSentTimestamp" json:"targetSentTimestamp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DataMessage_AdminDelete) Reset() { + *x = DataMessage_AdminDelete{} + mi := &file_SignalService_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DataMessage_AdminDelete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataMessage_AdminDelete) ProtoMessage() {} + +func (x *DataMessage_AdminDelete) ProtoReflect() protoreflect.Message { + mi := &file_SignalService_proto_msgTypes[42] + 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 DataMessage_AdminDelete.ProtoReflect.Descriptor instead. +func (*DataMessage_AdminDelete) Descriptor() ([]byte, []int) { + return file_SignalService_proto_rawDescGZIP(), []int{3, 14} +} + +func (x *DataMessage_AdminDelete) GetTargetAuthorAciBinary() []byte { + if x != nil { + return x.TargetAuthorAciBinary + } + return nil +} + +func (x *DataMessage_AdminDelete) GetTargetSentTimestamp() uint64 { + if x != nil && x.TargetSentTimestamp != nil { + return *x.TargetSentTimestamp + } + return 0 +} + type DataMessage_Payment_Amount struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Amount: @@ -5343,7 +5696,7 @@ type DataMessage_Payment_Amount struct { func (x *DataMessage_Payment_Amount) Reset() { *x = DataMessage_Payment_Amount{} - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5355,7 +5708,7 @@ func (x *DataMessage_Payment_Amount) String() string { func (*DataMessage_Payment_Amount) ProtoMessage() {} func (x *DataMessage_Payment_Amount) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[42] + mi := &file_SignalService_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5411,7 +5764,7 @@ type DataMessage_Payment_Notification struct { func (x *DataMessage_Payment_Notification) Reset() { *x = DataMessage_Payment_Notification{} - mi := &file_SignalService_proto_msgTypes[43] + mi := &file_SignalService_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5423,7 +5776,7 @@ func (x *DataMessage_Payment_Notification) String() string { func (*DataMessage_Payment_Notification) ProtoMessage() {} func (x *DataMessage_Payment_Notification) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[43] + mi := &file_SignalService_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5482,7 +5835,7 @@ type DataMessage_Payment_Activation struct { func (x *DataMessage_Payment_Activation) Reset() { *x = DataMessage_Payment_Activation{} - mi := &file_SignalService_proto_msgTypes[44] + mi := &file_SignalService_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5494,7 +5847,7 @@ func (x *DataMessage_Payment_Activation) String() string { func (*DataMessage_Payment_Activation) ProtoMessage() {} func (x *DataMessage_Payment_Activation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[44] + mi := &file_SignalService_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5526,7 +5879,7 @@ type DataMessage_Payment_Amount_MobileCoin struct { func (x *DataMessage_Payment_Amount_MobileCoin) Reset() { *x = DataMessage_Payment_Amount_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[45] + mi := &file_SignalService_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5538,7 +5891,7 @@ func (x *DataMessage_Payment_Amount_MobileCoin) String() string { func (*DataMessage_Payment_Amount_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Amount_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[45] + mi := &file_SignalService_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5570,7 +5923,7 @@ type DataMessage_Payment_Notification_MobileCoin struct { func (x *DataMessage_Payment_Notification_MobileCoin) Reset() { *x = DataMessage_Payment_Notification_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[46] + mi := &file_SignalService_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5582,7 +5935,7 @@ func (x *DataMessage_Payment_Notification_MobileCoin) String() string { func (*DataMessage_Payment_Notification_MobileCoin) ProtoMessage() {} func (x *DataMessage_Payment_Notification_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[46] + mi := &file_SignalService_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5616,7 +5969,7 @@ type DataMessage_Quote_QuotedAttachment struct { func (x *DataMessage_Quote_QuotedAttachment) Reset() { *x = DataMessage_Quote_QuotedAttachment{} - mi := &file_SignalService_proto_msgTypes[47] + mi := &file_SignalService_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5628,7 +5981,7 @@ func (x *DataMessage_Quote_QuotedAttachment) String() string { func (*DataMessage_Quote_QuotedAttachment) ProtoMessage() {} func (x *DataMessage_Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[47] + mi := &file_SignalService_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5679,7 +6032,7 @@ type DataMessage_Contact_Name struct { func (x *DataMessage_Contact_Name) Reset() { *x = DataMessage_Contact_Name{} - mi := &file_SignalService_proto_msgTypes[48] + mi := &file_SignalService_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5691,7 +6044,7 @@ func (x *DataMessage_Contact_Name) String() string { func (*DataMessage_Contact_Name) ProtoMessage() {} func (x *DataMessage_Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[48] + mi := &file_SignalService_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5760,7 +6113,7 @@ type DataMessage_Contact_Phone struct { func (x *DataMessage_Contact_Phone) Reset() { *x = DataMessage_Contact_Phone{} - mi := &file_SignalService_proto_msgTypes[49] + mi := &file_SignalService_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5772,7 +6125,7 @@ func (x *DataMessage_Contact_Phone) String() string { func (*DataMessage_Contact_Phone) ProtoMessage() {} func (x *DataMessage_Contact_Phone) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[49] + mi := &file_SignalService_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5820,7 +6173,7 @@ type DataMessage_Contact_Email struct { func (x *DataMessage_Contact_Email) Reset() { *x = DataMessage_Contact_Email{} - mi := &file_SignalService_proto_msgTypes[50] + mi := &file_SignalService_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5832,7 +6185,7 @@ func (x *DataMessage_Contact_Email) String() string { func (*DataMessage_Contact_Email) ProtoMessage() {} func (x *DataMessage_Contact_Email) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[50] + mi := &file_SignalService_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5886,7 +6239,7 @@ type DataMessage_Contact_PostalAddress struct { func (x *DataMessage_Contact_PostalAddress) Reset() { *x = DataMessage_Contact_PostalAddress{} - mi := &file_SignalService_proto_msgTypes[51] + mi := &file_SignalService_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5898,7 +6251,7 @@ func (x *DataMessage_Contact_PostalAddress) String() string { func (*DataMessage_Contact_PostalAddress) ProtoMessage() {} func (x *DataMessage_Contact_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[51] + mi := &file_SignalService_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5987,7 +6340,7 @@ type DataMessage_Contact_Avatar struct { func (x *DataMessage_Contact_Avatar) Reset() { *x = DataMessage_Contact_Avatar{} - mi := &file_SignalService_proto_msgTypes[52] + mi := &file_SignalService_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5999,7 +6352,7 @@ func (x *DataMessage_Contact_Avatar) String() string { func (*DataMessage_Contact_Avatar) ProtoMessage() {} func (x *DataMessage_Contact_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[52] + mi := &file_SignalService_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6042,7 +6395,7 @@ type TextAttachment_Gradient struct { func (x *TextAttachment_Gradient) Reset() { *x = TextAttachment_Gradient{} - mi := &file_SignalService_proto_msgTypes[53] + mi := &file_SignalService_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6054,7 +6407,7 @@ func (x *TextAttachment_Gradient) String() string { func (*TextAttachment_Gradient) ProtoMessage() {} func (x *TextAttachment_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[53] + mi := &file_SignalService_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6129,7 +6482,7 @@ const ( func (x *SyncMessage_Sent) Reset() { *x = SyncMessage_Sent{} - mi := &file_SignalService_proto_msgTypes[54] + mi := &file_SignalService_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6141,7 +6494,7 @@ func (x *SyncMessage_Sent) String() string { func (*SyncMessage_Sent) ProtoMessage() {} func (x *SyncMessage_Sent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[54] + mi := &file_SignalService_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6249,7 +6602,7 @@ const ( func (x *SyncMessage_Contacts) Reset() { *x = SyncMessage_Contacts{} - mi := &file_SignalService_proto_msgTypes[55] + mi := &file_SignalService_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6261,7 +6614,7 @@ func (x *SyncMessage_Contacts) String() string { func (*SyncMessage_Contacts) ProtoMessage() {} func (x *SyncMessage_Contacts) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[55] + mi := &file_SignalService_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6303,7 +6656,7 @@ type SyncMessage_Blocked struct { func (x *SyncMessage_Blocked) Reset() { *x = SyncMessage_Blocked{} - mi := &file_SignalService_proto_msgTypes[56] + mi := &file_SignalService_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6315,7 +6668,7 @@ func (x *SyncMessage_Blocked) String() string { func (*SyncMessage_Blocked) ProtoMessage() {} func (x *SyncMessage_Blocked) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[56] + mi := &file_SignalService_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6368,7 +6721,7 @@ type SyncMessage_Request struct { func (x *SyncMessage_Request) Reset() { *x = SyncMessage_Request{} - mi := &file_SignalService_proto_msgTypes[57] + mi := &file_SignalService_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6380,7 +6733,7 @@ func (x *SyncMessage_Request) String() string { func (*SyncMessage_Request) ProtoMessage() {} func (x *SyncMessage_Request) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[57] + mi := &file_SignalService_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6414,7 +6767,7 @@ type SyncMessage_Read struct { func (x *SyncMessage_Read) Reset() { *x = SyncMessage_Read{} - mi := &file_SignalService_proto_msgTypes[58] + mi := &file_SignalService_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6426,7 +6779,7 @@ func (x *SyncMessage_Read) String() string { func (*SyncMessage_Read) ProtoMessage() {} func (x *SyncMessage_Read) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[58] + mi := &file_SignalService_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6474,7 +6827,7 @@ type SyncMessage_Viewed struct { func (x *SyncMessage_Viewed) Reset() { *x = SyncMessage_Viewed{} - mi := &file_SignalService_proto_msgTypes[59] + mi := &file_SignalService_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6486,7 +6839,7 @@ func (x *SyncMessage_Viewed) String() string { func (*SyncMessage_Viewed) ProtoMessage() {} func (x *SyncMessage_Viewed) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[59] + mi := &file_SignalService_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6528,7 +6881,6 @@ type SyncMessage_Configuration struct { ReadReceipts *bool `protobuf:"varint,1,opt,name=readReceipts" json:"readReceipts,omitempty"` UnidentifiedDeliveryIndicators *bool `protobuf:"varint,2,opt,name=unidentifiedDeliveryIndicators" json:"unidentifiedDeliveryIndicators,omitempty"` TypingIndicators *bool `protobuf:"varint,3,opt,name=typingIndicators" json:"typingIndicators,omitempty"` - ProvisioningVersion *uint32 `protobuf:"varint,5,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` LinkPreviews *bool `protobuf:"varint,6,opt,name=linkPreviews" json:"linkPreviews,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -6536,7 +6888,7 @@ type SyncMessage_Configuration struct { func (x *SyncMessage_Configuration) Reset() { *x = SyncMessage_Configuration{} - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6548,7 +6900,7 @@ func (x *SyncMessage_Configuration) String() string { func (*SyncMessage_Configuration) ProtoMessage() {} func (x *SyncMessage_Configuration) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[60] + mi := &file_SignalService_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6585,13 +6937,6 @@ func (x *SyncMessage_Configuration) GetTypingIndicators() bool { return false } -func (x *SyncMessage_Configuration) GetProvisioningVersion() uint32 { - if x != nil && x.ProvisioningVersion != nil { - return *x.ProvisioningVersion - } - return 0 -} - func (x *SyncMessage_Configuration) GetLinkPreviews() bool { if x != nil && x.LinkPreviews != nil { return *x.LinkPreviews @@ -6610,7 +6955,7 @@ type SyncMessage_StickerPackOperation struct { func (x *SyncMessage_StickerPackOperation) Reset() { *x = SyncMessage_StickerPackOperation{} - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6622,7 +6967,7 @@ func (x *SyncMessage_StickerPackOperation) String() string { func (*SyncMessage_StickerPackOperation) ProtoMessage() {} func (x *SyncMessage_StickerPackOperation) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[61] + mi := &file_SignalService_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6670,7 +7015,7 @@ type SyncMessage_ViewOnceOpen struct { func (x *SyncMessage_ViewOnceOpen) Reset() { *x = SyncMessage_ViewOnceOpen{} - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6682,7 +7027,7 @@ func (x *SyncMessage_ViewOnceOpen) String() string { func (*SyncMessage_ViewOnceOpen) ProtoMessage() {} func (x *SyncMessage_ViewOnceOpen) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[62] + mi := &file_SignalService_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6728,7 +7073,7 @@ type SyncMessage_FetchLatest struct { func (x *SyncMessage_FetchLatest) Reset() { *x = SyncMessage_FetchLatest{} - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6740,7 +7085,7 @@ func (x *SyncMessage_FetchLatest) String() string { func (*SyncMessage_FetchLatest) ProtoMessage() {} func (x *SyncMessage_FetchLatest) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[63] + mi := &file_SignalService_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6765,7 +7110,6 @@ func (x *SyncMessage_FetchLatest) GetType() SyncMessage_FetchLatest_Type { type SyncMessage_Keys struct { state protoimpl.MessageState `protogen:"open.v1"` - Master []byte `protobuf:"bytes,2,opt,name=master" json:"master,omitempty"` // deprecated: this field will be removed in a future release. AccountEntropyPool *string `protobuf:"bytes,3,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` MediaRootBackupKey []byte `protobuf:"bytes,4,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` unknownFields protoimpl.UnknownFields @@ -6774,7 +7118,7 @@ type SyncMessage_Keys struct { func (x *SyncMessage_Keys) Reset() { *x = SyncMessage_Keys{} - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6786,7 +7130,7 @@ func (x *SyncMessage_Keys) String() string { func (*SyncMessage_Keys) ProtoMessage() {} func (x *SyncMessage_Keys) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[64] + mi := &file_SignalService_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6802,13 +7146,6 @@ func (*SyncMessage_Keys) Descriptor() ([]byte, []int) { return file_SignalService_proto_rawDescGZIP(), []int{11, 10} } -func (x *SyncMessage_Keys) GetMaster() []byte { - if x != nil { - return x.Master - } - return nil -} - func (x *SyncMessage_Keys) GetAccountEntropyPool() string { if x != nil && x.AccountEntropyPool != nil { return *x.AccountEntropyPool @@ -6833,7 +7170,7 @@ type SyncMessage_PniIdentity struct { func (x *SyncMessage_PniIdentity) Reset() { *x = SyncMessage_PniIdentity{} - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6845,7 +7182,7 @@ func (x *SyncMessage_PniIdentity) String() string { func (*SyncMessage_PniIdentity) ProtoMessage() {} func (x *SyncMessage_PniIdentity) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[65] + mi := &file_SignalService_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6887,7 +7224,7 @@ type SyncMessage_MessageRequestResponse struct { func (x *SyncMessage_MessageRequestResponse) Reset() { *x = SyncMessage_MessageRequestResponse{} - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6899,7 +7236,7 @@ func (x *SyncMessage_MessageRequestResponse) String() string { func (*SyncMessage_MessageRequestResponse) ProtoMessage() {} func (x *SyncMessage_MessageRequestResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[66] + mi := &file_SignalService_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6957,7 +7294,7 @@ type SyncMessage_OutgoingPayment struct { func (x *SyncMessage_OutgoingPayment) Reset() { *x = SyncMessage_OutgoingPayment{} - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6969,7 +7306,7 @@ func (x *SyncMessage_OutgoingPayment) String() string { func (*SyncMessage_OutgoingPayment) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[67] + mi := &file_SignalService_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7039,7 +7376,7 @@ type SyncMessage_PniChangeNumber struct { func (x *SyncMessage_PniChangeNumber) Reset() { *x = SyncMessage_PniChangeNumber{} - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7051,7 +7388,7 @@ func (x *SyncMessage_PniChangeNumber) String() string { func (*SyncMessage_PniChangeNumber) ProtoMessage() {} func (x *SyncMessage_PniChangeNumber) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[68] + mi := &file_SignalService_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7121,7 +7458,7 @@ type SyncMessage_CallEvent struct { func (x *SyncMessage_CallEvent) Reset() { *x = SyncMessage_CallEvent{} - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7133,7 +7470,7 @@ func (x *SyncMessage_CallEvent) String() string { func (*SyncMessage_CallEvent) ProtoMessage() {} func (x *SyncMessage_CallEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[69] + mi := &file_SignalService_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7196,14 +7533,13 @@ type SyncMessage_CallLinkUpdate struct { RootKey []byte `protobuf:"bytes,1,opt,name=rootKey" json:"rootKey,omitempty"` AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey" json:"adminPasskey,omitempty"` Type *SyncMessage_CallLinkUpdate_Type `protobuf:"varint,3,opt,name=type,enum=signalservice.SyncMessage_CallLinkUpdate_Type" json:"type,omitempty"` // defaults to UPDATE - Epoch []byte `protobuf:"bytes,4,opt,name=epoch" json:"epoch,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SyncMessage_CallLinkUpdate) Reset() { *x = SyncMessage_CallLinkUpdate{} - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7215,7 +7551,7 @@ func (x *SyncMessage_CallLinkUpdate) String() string { func (*SyncMessage_CallLinkUpdate) ProtoMessage() {} func (x *SyncMessage_CallLinkUpdate) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[70] + mi := &file_SignalService_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7252,13 +7588,6 @@ func (x *SyncMessage_CallLinkUpdate) GetType() SyncMessage_CallLinkUpdate_Type { return SyncMessage_CallLinkUpdate_UPDATE } -func (x *SyncMessage_CallLinkUpdate) GetEpoch() []byte { - if x != nil { - return x.Epoch - } - return nil -} - type SyncMessage_CallLogEvent struct { state protoimpl.MessageState `protogen:"open.v1"` Type *SyncMessage_CallLogEvent_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.SyncMessage_CallLogEvent_Type" json:"type,omitempty"` @@ -7276,7 +7605,7 @@ type SyncMessage_CallLogEvent struct { func (x *SyncMessage_CallLogEvent) Reset() { *x = SyncMessage_CallLogEvent{} - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7288,7 +7617,7 @@ func (x *SyncMessage_CallLogEvent) String() string { func (*SyncMessage_CallLogEvent) ProtoMessage() {} func (x *SyncMessage_CallLogEvent) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[71] + mi := &file_SignalService_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7344,7 +7673,7 @@ type SyncMessage_DeleteForMe struct { func (x *SyncMessage_DeleteForMe) Reset() { *x = SyncMessage_DeleteForMe{} - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7356,7 +7685,7 @@ func (x *SyncMessage_DeleteForMe) String() string { func (*SyncMessage_DeleteForMe) ProtoMessage() {} func (x *SyncMessage_DeleteForMe) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[72] + mi := &file_SignalService_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7409,7 +7738,7 @@ type SyncMessage_DeviceNameChange struct { func (x *SyncMessage_DeviceNameChange) Reset() { *x = SyncMessage_DeviceNameChange{} - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7421,7 +7750,7 @@ func (x *SyncMessage_DeviceNameChange) String() string { func (*SyncMessage_DeviceNameChange) ProtoMessage() {} func (x *SyncMessage_DeviceNameChange) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[73] + mi := &file_SignalService_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7454,7 +7783,7 @@ type SyncMessage_AttachmentBackfillRequest struct { func (x *SyncMessage_AttachmentBackfillRequest) Reset() { *x = SyncMessage_AttachmentBackfillRequest{} - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7466,7 +7795,7 @@ func (x *SyncMessage_AttachmentBackfillRequest) String() string { func (*SyncMessage_AttachmentBackfillRequest) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillRequest) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[74] + mi := &file_SignalService_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7511,7 +7840,7 @@ type SyncMessage_AttachmentBackfillResponse struct { func (x *SyncMessage_AttachmentBackfillResponse) Reset() { *x = SyncMessage_AttachmentBackfillResponse{} - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7523,7 +7852,7 @@ func (x *SyncMessage_AttachmentBackfillResponse) String() string { func (*SyncMessage_AttachmentBackfillResponse) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[75] + mi := &file_SignalService_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7608,7 +7937,7 @@ type SyncMessage_Sent_UnidentifiedDeliveryStatus struct { func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) Reset() { *x = SyncMessage_Sent_UnidentifiedDeliveryStatus{} - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7620,7 +7949,7 @@ func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) String() string { func (*SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoMessage() {} func (x *SyncMessage_Sent_UnidentifiedDeliveryStatus) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[76] + mi := &file_SignalService_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7676,7 +8005,7 @@ type SyncMessage_Sent_StoryMessageRecipient struct { func (x *SyncMessage_Sent_StoryMessageRecipient) Reset() { *x = SyncMessage_Sent_StoryMessageRecipient{} - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7688,7 +8017,7 @@ func (x *SyncMessage_Sent_StoryMessageRecipient) String() string { func (*SyncMessage_Sent_StoryMessageRecipient) ProtoMessage() {} func (x *SyncMessage_Sent_StoryMessageRecipient) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[77] + mi := &file_SignalService_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7748,7 +8077,7 @@ type SyncMessage_OutgoingPayment_MobileCoin struct { func (x *SyncMessage_OutgoingPayment_MobileCoin) Reset() { *x = SyncMessage_OutgoingPayment_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7760,7 +8089,7 @@ func (x *SyncMessage_OutgoingPayment_MobileCoin) String() string { func (*SyncMessage_OutgoingPayment_MobileCoin) ProtoMessage() {} func (x *SyncMessage_OutgoingPayment_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[78] + mi := &file_SignalService_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7842,7 +8171,7 @@ type SyncMessage_DeleteForMe_MessageDeletes struct { func (x *SyncMessage_DeleteForMe_MessageDeletes) Reset() { *x = SyncMessage_DeleteForMe_MessageDeletes{} - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7854,7 +8183,7 @@ func (x *SyncMessage_DeleteForMe_MessageDeletes) String() string { func (*SyncMessage_DeleteForMe_MessageDeletes) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_MessageDeletes) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[79] + mi := &file_SignalService_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7900,7 +8229,7 @@ type SyncMessage_DeleteForMe_AttachmentDelete struct { func (x *SyncMessage_DeleteForMe_AttachmentDelete) Reset() { *x = SyncMessage_DeleteForMe_AttachmentDelete{} - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7912,7 +8241,7 @@ func (x *SyncMessage_DeleteForMe_AttachmentDelete) String() string { func (*SyncMessage_DeleteForMe_AttachmentDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_AttachmentDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[80] + mi := &file_SignalService_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7975,7 +8304,7 @@ type SyncMessage_DeleteForMe_ConversationDelete struct { func (x *SyncMessage_DeleteForMe_ConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_ConversationDelete{} - mi := &file_SignalService_proto_msgTypes[81] + mi := &file_SignalService_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7987,7 +8316,7 @@ func (x *SyncMessage_DeleteForMe_ConversationDelete) String() string { func (*SyncMessage_DeleteForMe_ConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_ConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[81] + mi := &file_SignalService_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8040,7 +8369,7 @@ type SyncMessage_DeleteForMe_LocalOnlyConversationDelete struct { func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) Reset() { *x = SyncMessage_DeleteForMe_LocalOnlyConversationDelete{} - mi := &file_SignalService_proto_msgTypes[82] + mi := &file_SignalService_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8052,7 +8381,7 @@ func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) String() string { func (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoMessage() {} func (x *SyncMessage_DeleteForMe_LocalOnlyConversationDelete) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[82] + mi := &file_SignalService_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8088,7 +8417,7 @@ type SyncMessage_AttachmentBackfillResponse_AttachmentData struct { func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) Reset() { *x = SyncMessage_AttachmentBackfillResponse_AttachmentData{} - mi := &file_SignalService_proto_msgTypes[83] + mi := &file_SignalService_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8100,7 +8429,7 @@ func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) String() string func (*SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse_AttachmentData) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[83] + mi := &file_SignalService_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8169,7 +8498,7 @@ type SyncMessage_AttachmentBackfillResponse_AttachmentDataList struct { func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) Reset() { *x = SyncMessage_AttachmentBackfillResponse_AttachmentDataList{} - mi := &file_SignalService_proto_msgTypes[84] + mi := &file_SignalService_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8181,7 +8510,7 @@ func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) String() str func (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoMessage() {} func (x *SyncMessage_AttachmentBackfillResponse_AttachmentDataList) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[84] + mi := &file_SignalService_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8221,7 +8550,7 @@ type ContactDetails_Avatar struct { func (x *ContactDetails_Avatar) Reset() { *x = ContactDetails_Avatar{} - mi := &file_SignalService_proto_msgTypes[85] + mi := &file_SignalService_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8233,7 +8562,7 @@ func (x *ContactDetails_Avatar) String() string { func (*ContactDetails_Avatar) ProtoMessage() {} func (x *ContactDetails_Avatar) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[85] + mi := &file_SignalService_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8273,7 +8602,7 @@ type PaymentAddress_MobileCoin struct { func (x *PaymentAddress_MobileCoin) Reset() { *x = PaymentAddress_MobileCoin{} - mi := &file_SignalService_proto_msgTypes[86] + mi := &file_SignalService_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8285,7 +8614,7 @@ func (x *PaymentAddress_MobileCoin) String() string { func (*PaymentAddress_MobileCoin) ProtoMessage() {} func (x *PaymentAddress_MobileCoin) ProtoReflect() protoreflect.Message { - mi := &file_SignalService_proto_msgTypes[86] + mi := &file_SignalService_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8319,13 +8648,13 @@ var File_SignalService_proto protoreflect.FileDescriptor const file_SignalService_proto_rawDesc = "" + "\n" + - "\x13SignalService.proto\x12\rsignalservice\"\xf5\x06\n" + + "\x13SignalService.proto\x12\rsignalservice\"\x8c\a\n" + "\bEnvelope\x120\n" + "\x04type\x18\x01 \x01(\x0e2\x1c.signalservice.Envelope.TypeR\x04type\x12(\n" + - "\x0fsourceServiceId\x18\v \x01(\tR\x0fsourceServiceId\x12\"\n" + - "\fsourceDevice\x18\a \x01(\rR\fsourceDevice\x122\n" + - "\x14destinationServiceId\x18\r \x01(\tR\x14destinationServiceId\x12\x1c\n" + - "\ttimestamp\x18\x05 \x01(\x04R\ttimestamp\x12\x18\n" + + "\x0fsourceServiceId\x18\v \x01(\tR\x0fsourceServiceId\x12&\n" + + "\x0esourceDeviceId\x18\a \x01(\rR\x0esourceDeviceId\x122\n" + + "\x14destinationServiceId\x18\r \x01(\tR\x14destinationServiceId\x12(\n" + + "\x0fclientTimestamp\x18\x05 \x01(\x04R\x0fclientTimestamp\x12\x18\n" + "\acontent\x18\b \x01(\fR\acontent\x12\x1e\n" + "\n" + "serverGuid\x18\t \x01(\tR\n" + @@ -8342,29 +8671,28 @@ const file_SignalService_proto_rawDesc = "" + "\x15sourceServiceIdBinary\x18\x13 \x01(\fR\x15sourceServiceIdBinary\x12>\n" + "\x1adestinationServiceIdBinary\x18\x14 \x01(\fR\x1adestinationServiceIdBinary\x12*\n" + "\x10serverGuidBinary\x18\x15 \x01(\fR\x10serverGuidBinary\x12*\n" + - "\x10updatedPniBinary\x18\x16 \x01(\fR\x10updatedPniBinary\"\xae\x01\n" + + "\x10updatedPniBinary\x18\x16 \x01(\fR\x10updatedPniBinary\"\xb5\x01\n" + "\x04Type\x12\v\n" + - "\aUNKNOWN\x10\x00\x12\x0e\n" + - "\n" + - "CIPHERTEXT\x10\x01\x12\x11\n" + - "\rPREKEY_BUNDLE\x10\x03\x12\x1b\n" + + "\aUNKNOWN\x10\x00\x12\x12\n" + + "\x0eDOUBLE_RATCHET\x10\x01\x12\x12\n" + + "\x0ePREKEY_MESSAGE\x10\x03\x12\x1b\n" + "\x17SERVER_DELIVERY_RECEIPT\x10\x05\x12\x17\n" + "\x13UNIDENTIFIED_SENDER\x10\x06\x12\x15\n" + - "\x11SENDERKEY_MESSAGE\x10\a\x12\x15\n" + - "\x11PLAINTEXT_CONTENT\x10\b\"\x04\b\x02\x10\x02*\fKEY_EXCHANGEJ\x04\b\x02\x10\x03J\x04\b\x03\x10\x04J\x04\b\x06\x10\aJ\x04\b\x12\x10\x13\"\xdd\x05\n" + - "\aContent\x12<\n" + - "\vdataMessage\x18\x01 \x01(\v2\x1a.signalservice.DataMessageR\vdataMessage\x12<\n" + - "\vsyncMessage\x18\x02 \x01(\v2\x1a.signalservice.SyncMessageR\vsyncMessage\x12<\n" + - "\vcallMessage\x18\x03 \x01(\v2\x1a.signalservice.CallMessageR\vcallMessage\x12<\n" + - "\vnullMessage\x18\x04 \x01(\v2\x1a.signalservice.NullMessageR\vnullMessage\x12E\n" + - "\x0ereceiptMessage\x18\x05 \x01(\v2\x1d.signalservice.ReceiptMessageR\x0ereceiptMessage\x12B\n" + - "\rtypingMessage\x18\x06 \x01(\v2\x1c.signalservice.TypingMessageR\rtypingMessage\x12B\n" + - "\x1csenderKeyDistributionMessage\x18\a \x01(\fR\x1csenderKeyDistributionMessage\x126\n" + - "\x16decryptionErrorMessage\x18\b \x01(\fR\x16decryptionErrorMessage\x12?\n" + - "\fstoryMessage\x18\t \x01(\v2\x1b.signalservice.StoryMessageR\fstoryMessage\x12T\n" + + "\x11PLAINTEXT_CONTENT\x10\b\"\x04\b\x02\x10\x02\"\x04\b\a\x10\a*\fKEY_EXCHANGE*\x11SENDERKEY_MESSAGEJ\x04\b\x02\x10\x03J\x04\b\x03\x10\x04J\x04\b\x06\x10\aJ\x04\b\x12\x10\x13\"\xfa\x05\n" + + "\aContent\x12>\n" + + "\vdataMessage\x18\x01 \x01(\v2\x1a.signalservice.DataMessageH\x00R\vdataMessage\x12>\n" + + "\vsyncMessage\x18\x02 \x01(\v2\x1a.signalservice.SyncMessageH\x00R\vsyncMessage\x12>\n" + + "\vcallMessage\x18\x03 \x01(\v2\x1a.signalservice.CallMessageH\x00R\vcallMessage\x12>\n" + + "\vnullMessage\x18\x04 \x01(\v2\x1a.signalservice.NullMessageH\x00R\vnullMessage\x12G\n" + + "\x0ereceiptMessage\x18\x05 \x01(\v2\x1d.signalservice.ReceiptMessageH\x00R\x0ereceiptMessage\x12D\n" + + "\rtypingMessage\x18\x06 \x01(\v2\x1c.signalservice.TypingMessageH\x00R\rtypingMessage\x128\n" + + "\x16decryptionErrorMessage\x18\b \x01(\fH\x00R\x16decryptionErrorMessage\x12A\n" + + "\fstoryMessage\x18\t \x01(\v2\x1b.signalservice.StoryMessageH\x00R\fstoryMessage\x12>\n" + + "\veditMessage\x18\v \x01(\v2\x1a.signalservice.EditMessageH\x00R\veditMessage\x12B\n" + + "\x1csenderKeyDistributionMessage\x18\a \x01(\fR\x1csenderKeyDistributionMessage\x12T\n" + "\x13pniSignatureMessage\x18\n" + - " \x01(\v2\".signalservice.PniSignatureMessageR\x13pniSignatureMessage\x12<\n" + - "\veditMessage\x18\v \x01(\v2\x1a.signalservice.EditMessageR\veditMessage\"\xf2\b\n" + + " \x01(\v2\".signalservice.PniSignatureMessageR\x13pniSignatureMessageB\t\n" + + "\acontent\"\xf2\b\n" + "\vCallMessage\x126\n" + "\x05offer\x18\x01 \x01(\v2 .signalservice.CallMessage.OfferR\x05offer\x129\n" + "\x06answer\x18\x02 \x01(\v2!.signalservice.CallMessage.AnswerR\x06answer\x12B\n" + @@ -8404,7 +8732,7 @@ const file_SignalService_proto_rawDesc = "" + "\aurgency\x18\x02 \x01(\x0e2).signalservice.CallMessage.Opaque.UrgencyR\aurgency\"0\n" + "\aUrgency\x12\r\n" + "\tDROPPABLE\x10\x00\x12\x16\n" + - "\x12HANDLE_IMMEDIATELY\x10\x01J\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"\xca,\n" + + "\x12HANDLE_IMMEDIATELY\x10\x01J\x04\b\x04\x10\x05J\x04\b\x06\x10\aJ\x04\b\b\x10\t\"\x8b.\n" + "\vDataMessage\x12\x12\n" + "\x04body\x18\x01 \x01(\tR\x04body\x12B\n" + "\vattachments\x18\x02 \x03(\v2 .signalservice.AttachmentPointerR\vattachments\x127\n" + @@ -8442,7 +8770,8 @@ const file_SignalService_proto_rawDesc = "" + "\n" + "pinMessage\x18\x1b \x01(\v2%.signalservice.DataMessage.PinMessageR\n" + "pinMessage\x12K\n" + - "\funpinMessage\x18\x1c \x01(\v2'.signalservice.DataMessage.UnpinMessageR\funpinMessage\x1a\x9a\x05\n" + + "\funpinMessage\x18\x1c \x01(\v2'.signalservice.DataMessage.UnpinMessageR\funpinMessage\x12H\n" + + "\vadminDelete\x18\x1d \x01(\v2&.signalservice.DataMessage.AdminDeleteR\vadminDelete\x1a\x9a\x05\n" + "\aPayment\x12U\n" + "\fnotification\x18\x01 \x01(\v2/.signalservice.DataMessage.Payment.NotificationH\x00R\fnotification\x12O\n" + "\n" + @@ -8594,6 +8923,9 @@ const file_SignalService_proto_rawDesc = "" + "\vpinDuration\x1av\n" + "\fUnpinMessage\x124\n" + "\x15targetAuthorAciBinary\x18\x01 \x01(\fR\x15targetAuthorAciBinary\x120\n" + + "\x13targetSentTimestamp\x18\x02 \x01(\x04R\x13targetSentTimestamp\x1au\n" + + "\vAdminDelete\x124\n" + + "\x15targetAuthorAciBinary\x18\x01 \x01(\fR\x15targetAuthorAciBinary\x120\n" + "\x13targetSentTimestamp\x18\x02 \x01(\x04R\x13targetSentTimestamp\"Z\n" + "\x05Flags\x12\x0f\n" + "\vEND_SESSION\x10\x01\x12\x1b\n" + @@ -8683,32 +9015,32 @@ const file_SignalService_proto_rawDesc = "" + "\aDEFAULT\x10\x00\x12\f\n" + "\bVERIFIED\x10\x01\x12\x0e\n" + "\n" + - "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\x8fG\n" + - "\vSyncMessage\x123\n" + - "\x04sent\x18\x01 \x01(\v2\x1f.signalservice.SyncMessage.SentR\x04sent\x12?\n" + - "\bcontacts\x18\x02 \x01(\v2#.signalservice.SyncMessage.ContactsR\bcontacts\x12<\n" + - "\arequest\x18\x04 \x01(\v2\".signalservice.SyncMessage.RequestR\arequest\x123\n" + - "\x04read\x18\x05 \x03(\v2\x1f.signalservice.SyncMessage.ReadR\x04read\x12<\n" + - "\ablocked\x18\x06 \x01(\v2\".signalservice.SyncMessage.BlockedR\ablocked\x123\n" + - "\bverified\x18\a \x01(\v2\x17.signalservice.VerifiedR\bverified\x12N\n" + - "\rconfiguration\x18\t \x01(\v2(.signalservice.SyncMessage.ConfigurationR\rconfiguration\x12\x18\n" + - "\apadding\x18\b \x01(\fR\apadding\x12c\n" + + "UNVERIFIED\x10\x02J\x04\b\x01\x10\x02\"\xf1F\n" + + "\vSyncMessage\x125\n" + + "\x04sent\x18\x01 \x01(\v2\x1f.signalservice.SyncMessage.SentH\x00R\x04sent\x12A\n" + + "\bcontacts\x18\x02 \x01(\v2#.signalservice.SyncMessage.ContactsH\x00R\bcontacts\x12>\n" + + "\arequest\x18\x04 \x01(\v2\".signalservice.SyncMessage.RequestH\x00R\arequest\x12>\n" + + "\ablocked\x18\x06 \x01(\v2\".signalservice.SyncMessage.BlockedH\x00R\ablocked\x125\n" + + "\bverified\x18\a \x01(\v2\x17.signalservice.VerifiedH\x00R\bverified\x12P\n" + + "\rconfiguration\x18\t \x01(\v2(.signalservice.SyncMessage.ConfigurationH\x00R\rconfiguration\x12M\n" + + "\fviewOnceOpen\x18\v \x01(\v2'.signalservice.SyncMessage.ViewOnceOpenH\x00R\fviewOnceOpen\x12J\n" + + "\vfetchLatest\x18\f \x01(\v2&.signalservice.SyncMessage.FetchLatestH\x00R\vfetchLatest\x125\n" + + "\x04keys\x18\r \x01(\v2\x1f.signalservice.SyncMessage.KeysH\x00R\x04keys\x12k\n" + + "\x16messageRequestResponse\x18\x0e \x01(\v21.signalservice.SyncMessage.MessageRequestResponseH\x00R\x16messageRequestResponse\x12V\n" + + "\x0foutgoingPayment\x18\x0f \x01(\v2*.signalservice.SyncMessage.OutgoingPaymentH\x00R\x0foutgoingPayment\x12V\n" + + "\x0fpniChangeNumber\x18\x12 \x01(\v2*.signalservice.SyncMessage.PniChangeNumberH\x00R\x0fpniChangeNumber\x12D\n" + + "\tcallEvent\x18\x13 \x01(\v2$.signalservice.SyncMessage.CallEventH\x00R\tcallEvent\x12S\n" + + "\x0ecallLinkUpdate\x18\x14 \x01(\v2).signalservice.SyncMessage.CallLinkUpdateH\x00R\x0ecallLinkUpdate\x12M\n" + + "\fcallLogEvent\x18\x15 \x01(\v2'.signalservice.SyncMessage.CallLogEventH\x00R\fcallLogEvent\x12J\n" + + "\vdeleteForMe\x18\x16 \x01(\v2&.signalservice.SyncMessage.DeleteForMeH\x00R\vdeleteForMe\x12Y\n" + + "\x10deviceNameChange\x18\x17 \x01(\v2+.signalservice.SyncMessage.DeviceNameChangeH\x00R\x10deviceNameChange\x12t\n" + + "\x19attachmentBackfillRequest\x18\x18 \x01(\v24.signalservice.SyncMessage.AttachmentBackfillRequestH\x00R\x19attachmentBackfillRequest\x12w\n" + + "\x1aattachmentBackfillResponse\x18\x19 \x01(\v25.signalservice.SyncMessage.AttachmentBackfillResponseH\x00R\x1aattachmentBackfillResponse\x123\n" + + "\x04read\x18\x05 \x03(\v2\x1f.signalservice.SyncMessage.ReadR\x04read\x12c\n" + "\x14stickerPackOperation\x18\n" + - " \x03(\v2/.signalservice.SyncMessage.StickerPackOperationR\x14stickerPackOperation\x12K\n" + - "\fviewOnceOpen\x18\v \x01(\v2'.signalservice.SyncMessage.ViewOnceOpenR\fviewOnceOpen\x12H\n" + - "\vfetchLatest\x18\f \x01(\v2&.signalservice.SyncMessage.FetchLatestR\vfetchLatest\x123\n" + - "\x04keys\x18\r \x01(\v2\x1f.signalservice.SyncMessage.KeysR\x04keys\x12i\n" + - "\x16messageRequestResponse\x18\x0e \x01(\v21.signalservice.SyncMessage.MessageRequestResponseR\x16messageRequestResponse\x12T\n" + - "\x0foutgoingPayment\x18\x0f \x01(\v2*.signalservice.SyncMessage.OutgoingPaymentR\x0foutgoingPayment\x129\n" + - "\x06viewed\x18\x10 \x03(\v2!.signalservice.SyncMessage.ViewedR\x06viewed\x12T\n" + - "\x0fpniChangeNumber\x18\x12 \x01(\v2*.signalservice.SyncMessage.PniChangeNumberR\x0fpniChangeNumber\x12B\n" + - "\tcallEvent\x18\x13 \x01(\v2$.signalservice.SyncMessage.CallEventR\tcallEvent\x12Q\n" + - "\x0ecallLinkUpdate\x18\x14 \x01(\v2).signalservice.SyncMessage.CallLinkUpdateR\x0ecallLinkUpdate\x12K\n" + - "\fcallLogEvent\x18\x15 \x01(\v2'.signalservice.SyncMessage.CallLogEventR\fcallLogEvent\x12H\n" + - "\vdeleteForMe\x18\x16 \x01(\v2&.signalservice.SyncMessage.DeleteForMeR\vdeleteForMe\x12W\n" + - "\x10deviceNameChange\x18\x17 \x01(\v2+.signalservice.SyncMessage.DeviceNameChangeR\x10deviceNameChange\x12r\n" + - "\x19attachmentBackfillRequest\x18\x18 \x01(\v24.signalservice.SyncMessage.AttachmentBackfillRequestR\x19attachmentBackfillRequest\x12u\n" + - "\x1aattachmentBackfillResponse\x18\x19 \x01(\v25.signalservice.SyncMessage.AttachmentBackfillResponseR\x1aattachmentBackfillResponse\x1a\xbc\t\n" + + " \x03(\v2/.signalservice.SyncMessage.StickerPackOperationR\x14stickerPackOperation\x129\n" + + "\x06viewed\x18\x10 \x03(\v2!.signalservice.SyncMessage.ViewedR\x06viewed\x12\x18\n" + + "\apadding\x18\b \x01(\fR\apadding\x1a\xbc\t\n" + "\x04Sent\x12(\n" + "\x0fdestinationE164\x18\x01 \x01(\tR\x0fdestinationE164\x122\n" + "\x14destinationServiceId\x18\a \x01(\tR\x14destinationServiceId\x12\x1c\n" + @@ -8757,13 +9089,12 @@ const file_SignalService_proto_rawDesc = "" + "\x06Viewed\x12\x1c\n" + "\tsenderAci\x18\x03 \x01(\tR\tsenderAci\x12\x1c\n" + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12(\n" + - "\x0fsenderAciBinary\x18\x04 \x01(\fR\x0fsenderAciBinaryJ\x04\b\x01\x10\x02\x1a\x83\x02\n" + + "\x0fsenderAciBinary\x18\x04 \x01(\fR\x0fsenderAciBinaryJ\x04\b\x01\x10\x02\x1a\xd7\x01\n" + "\rConfiguration\x12\"\n" + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x12F\n" + "\x1eunidentifiedDeliveryIndicators\x18\x02 \x01(\bR\x1eunidentifiedDeliveryIndicators\x12*\n" + - "\x10typingIndicators\x18\x03 \x01(\bR\x10typingIndicators\x120\n" + - "\x13provisioningVersion\x18\x05 \x01(\rR\x13provisioningVersion\x12\"\n" + - "\flinkPreviews\x18\x06 \x01(\bR\flinkPreviewsJ\x04\b\x04\x10\x05\x1a\xb3\x01\n" + + "\x10typingIndicators\x18\x03 \x01(\bR\x10typingIndicators\x12\"\n" + + "\flinkPreviews\x18\x06 \x01(\bR\flinkPreviewsJ\x04\b\x04\x10\x05J\x04\b\x05\x10\x06\x1a\xb3\x01\n" + "\x14StickerPackOperation\x12\x16\n" + "\x06packId\x18\x01 \x01(\fR\x06packId\x12\x18\n" + "\apackKey\x18\x02 \x01(\fR\apackKey\x12H\n" + @@ -8782,11 +9113,10 @@ const file_SignalService_proto_rawDesc = "" + "\aUNKNOWN\x10\x00\x12\x11\n" + "\rLOCAL_PROFILE\x10\x01\x12\x14\n" + "\x10STORAGE_MANIFEST\x10\x02\x12\x17\n" + - "\x13SUBSCRIPTION_STATUS\x10\x03\x1a\x84\x01\n" + - "\x04Keys\x12\x16\n" + - "\x06master\x18\x02 \x01(\fR\x06master\x12.\n" + + "\x13SUBSCRIPTION_STATUS\x10\x03\x1ar\n" + + "\x04Keys\x12.\n" + "\x12accountEntropyPool\x18\x03 \x01(\tR\x12accountEntropyPool\x12.\n" + - "\x12mediaRootBackupKey\x18\x04 \x01(\fR\x12mediaRootBackupKeyJ\x04\b\x01\x10\x02\x1aK\n" + + "\x12mediaRootBackupKey\x18\x04 \x01(\fR\x12mediaRootBackupKeyJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03\x1aK\n" + "\vPniIdentity\x12\x1c\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x1e\n" + "\n" + @@ -8858,15 +9188,14 @@ const file_SignalService_proto_rawDesc = "" + "\fNOT_ACCEPTED\x10\x02\x12\n" + "\n" + "\x06DELETE\x10\x03\x12\f\n" + - "\bOBSERVED\x10\x04\x1a\xc2\x01\n" + + "\bOBSERVED\x10\x04\x1a\xb2\x01\n" + "\x0eCallLinkUpdate\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x12B\n" + - "\x04type\x18\x03 \x01(\x0e2..signalservice.SyncMessage.CallLinkUpdate.TypeR\x04type\x12\x14\n" + - "\x05epoch\x18\x04 \x01(\fR\x05epoch\"\x18\n" + + "\x04type\x18\x03 \x01(\x0e2..signalservice.SyncMessage.CallLinkUpdate.TypeR\x04type\"\x18\n" + "\x04Type\x12\n" + "\n" + - "\x06UPDATE\x10\x00\"\x04\b\x01\x10\x01\x1a\x94\x02\n" + + "\x06UPDATE\x10\x00\"\x04\b\x01\x10\x01J\x04\b\x04\x10\x05\x1a\x94\x02\n" + "\fCallLogEvent\x12@\n" + "\x04type\x18\x01 \x01(\x0e2,.signalservice.SyncMessage.CallLogEvent.TypeR\x04type\x12\x1c\n" + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12&\n" + @@ -8925,7 +9254,8 @@ const file_SignalService_proto_rawDesc = "" + "\blongText\x18\x02 \x01(\v2D.signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataR\blongText\"\x1e\n" + "\x05Error\x12\x15\n" + "\x11MESSAGE_NOT_FOUND\x10\x00B\x06\n" + - "\x04dataJ\x04\b\x03\x10\x04J\x04\b\x11\x10\x12\"\xe7\x04\n" + + "\x04dataB\t\n" + + "\acontentJ\x04\b\x03\x10\x04J\x04\b\x11\x10\x12\"\xe7\x04\n" + "\x11AttachmentPointer\x12\x16\n" + "\x05cdnId\x18\x01 \x01(\x06H\x00R\x05cdnId\x12\x18\n" + "\x06cdnKey\x18\x0f \x01(\tH\x00R\x06cdnKey\x12\x1e\n" + @@ -9041,7 +9371,7 @@ func file_SignalService_proto_rawDescGZIP() []byte { } var file_SignalService_proto_enumTypes = make([]protoimpl.EnumInfo, 28) -var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 87) +var file_SignalService_proto_msgTypes = make([]protoimpl.MessageInfo, 88) var file_SignalService_proto_goTypes = []any{ (Envelope_Type)(0), // 0: signalservice.Envelope.Type (CallMessage_Offer_Type)(0), // 1: signalservice.CallMessage.Offer.Type @@ -9113,51 +9443,52 @@ var file_SignalService_proto_goTypes = []any{ (*DataMessage_PollVote)(nil), // 67: signalservice.DataMessage.PollVote (*DataMessage_PinMessage)(nil), // 68: signalservice.DataMessage.PinMessage (*DataMessage_UnpinMessage)(nil), // 69: signalservice.DataMessage.UnpinMessage - (*DataMessage_Payment_Amount)(nil), // 70: signalservice.DataMessage.Payment.Amount - (*DataMessage_Payment_Notification)(nil), // 71: signalservice.DataMessage.Payment.Notification - (*DataMessage_Payment_Activation)(nil), // 72: signalservice.DataMessage.Payment.Activation - (*DataMessage_Payment_Amount_MobileCoin)(nil), // 73: signalservice.DataMessage.Payment.Amount.MobileCoin - (*DataMessage_Payment_Notification_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Notification.MobileCoin - (*DataMessage_Quote_QuotedAttachment)(nil), // 75: signalservice.DataMessage.Quote.QuotedAttachment - (*DataMessage_Contact_Name)(nil), // 76: signalservice.DataMessage.Contact.Name - (*DataMessage_Contact_Phone)(nil), // 77: signalservice.DataMessage.Contact.Phone - (*DataMessage_Contact_Email)(nil), // 78: signalservice.DataMessage.Contact.Email - (*DataMessage_Contact_PostalAddress)(nil), // 79: signalservice.DataMessage.Contact.PostalAddress - (*DataMessage_Contact_Avatar)(nil), // 80: signalservice.DataMessage.Contact.Avatar - (*TextAttachment_Gradient)(nil), // 81: signalservice.TextAttachment.Gradient - (*SyncMessage_Sent)(nil), // 82: signalservice.SyncMessage.Sent - (*SyncMessage_Contacts)(nil), // 83: signalservice.SyncMessage.Contacts - (*SyncMessage_Blocked)(nil), // 84: signalservice.SyncMessage.Blocked - (*SyncMessage_Request)(nil), // 85: signalservice.SyncMessage.Request - (*SyncMessage_Read)(nil), // 86: signalservice.SyncMessage.Read - (*SyncMessage_Viewed)(nil), // 87: signalservice.SyncMessage.Viewed - (*SyncMessage_Configuration)(nil), // 88: signalservice.SyncMessage.Configuration - (*SyncMessage_StickerPackOperation)(nil), // 89: signalservice.SyncMessage.StickerPackOperation - (*SyncMessage_ViewOnceOpen)(nil), // 90: signalservice.SyncMessage.ViewOnceOpen - (*SyncMessage_FetchLatest)(nil), // 91: signalservice.SyncMessage.FetchLatest - (*SyncMessage_Keys)(nil), // 92: signalservice.SyncMessage.Keys - (*SyncMessage_PniIdentity)(nil), // 93: signalservice.SyncMessage.PniIdentity - (*SyncMessage_MessageRequestResponse)(nil), // 94: signalservice.SyncMessage.MessageRequestResponse - (*SyncMessage_OutgoingPayment)(nil), // 95: signalservice.SyncMessage.OutgoingPayment - (*SyncMessage_PniChangeNumber)(nil), // 96: signalservice.SyncMessage.PniChangeNumber - (*SyncMessage_CallEvent)(nil), // 97: signalservice.SyncMessage.CallEvent - (*SyncMessage_CallLinkUpdate)(nil), // 98: signalservice.SyncMessage.CallLinkUpdate - (*SyncMessage_CallLogEvent)(nil), // 99: signalservice.SyncMessage.CallLogEvent - (*SyncMessage_DeleteForMe)(nil), // 100: signalservice.SyncMessage.DeleteForMe - (*SyncMessage_DeviceNameChange)(nil), // 101: signalservice.SyncMessage.DeviceNameChange - (*SyncMessage_AttachmentBackfillRequest)(nil), // 102: signalservice.SyncMessage.AttachmentBackfillRequest - (*SyncMessage_AttachmentBackfillResponse)(nil), // 103: signalservice.SyncMessage.AttachmentBackfillResponse - (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 104: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 105: signalservice.SyncMessage.Sent.StoryMessageRecipient - (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 106: signalservice.SyncMessage.OutgoingPayment.MobileCoin - (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 107: signalservice.SyncMessage.DeleteForMe.MessageDeletes - (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 108: signalservice.SyncMessage.DeleteForMe.AttachmentDelete - (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 109: signalservice.SyncMessage.DeleteForMe.ConversationDelete - (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 110: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 111: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 112: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList - (*ContactDetails_Avatar)(nil), // 113: signalservice.ContactDetails.Avatar - (*PaymentAddress_MobileCoin)(nil), // 114: signalservice.PaymentAddress.MobileCoin + (*DataMessage_AdminDelete)(nil), // 70: signalservice.DataMessage.AdminDelete + (*DataMessage_Payment_Amount)(nil), // 71: signalservice.DataMessage.Payment.Amount + (*DataMessage_Payment_Notification)(nil), // 72: signalservice.DataMessage.Payment.Notification + (*DataMessage_Payment_Activation)(nil), // 73: signalservice.DataMessage.Payment.Activation + (*DataMessage_Payment_Amount_MobileCoin)(nil), // 74: signalservice.DataMessage.Payment.Amount.MobileCoin + (*DataMessage_Payment_Notification_MobileCoin)(nil), // 75: signalservice.DataMessage.Payment.Notification.MobileCoin + (*DataMessage_Quote_QuotedAttachment)(nil), // 76: signalservice.DataMessage.Quote.QuotedAttachment + (*DataMessage_Contact_Name)(nil), // 77: signalservice.DataMessage.Contact.Name + (*DataMessage_Contact_Phone)(nil), // 78: signalservice.DataMessage.Contact.Phone + (*DataMessage_Contact_Email)(nil), // 79: signalservice.DataMessage.Contact.Email + (*DataMessage_Contact_PostalAddress)(nil), // 80: signalservice.DataMessage.Contact.PostalAddress + (*DataMessage_Contact_Avatar)(nil), // 81: signalservice.DataMessage.Contact.Avatar + (*TextAttachment_Gradient)(nil), // 82: signalservice.TextAttachment.Gradient + (*SyncMessage_Sent)(nil), // 83: signalservice.SyncMessage.Sent + (*SyncMessage_Contacts)(nil), // 84: signalservice.SyncMessage.Contacts + (*SyncMessage_Blocked)(nil), // 85: signalservice.SyncMessage.Blocked + (*SyncMessage_Request)(nil), // 86: signalservice.SyncMessage.Request + (*SyncMessage_Read)(nil), // 87: signalservice.SyncMessage.Read + (*SyncMessage_Viewed)(nil), // 88: signalservice.SyncMessage.Viewed + (*SyncMessage_Configuration)(nil), // 89: signalservice.SyncMessage.Configuration + (*SyncMessage_StickerPackOperation)(nil), // 90: signalservice.SyncMessage.StickerPackOperation + (*SyncMessage_ViewOnceOpen)(nil), // 91: signalservice.SyncMessage.ViewOnceOpen + (*SyncMessage_FetchLatest)(nil), // 92: signalservice.SyncMessage.FetchLatest + (*SyncMessage_Keys)(nil), // 93: signalservice.SyncMessage.Keys + (*SyncMessage_PniIdentity)(nil), // 94: signalservice.SyncMessage.PniIdentity + (*SyncMessage_MessageRequestResponse)(nil), // 95: signalservice.SyncMessage.MessageRequestResponse + (*SyncMessage_OutgoingPayment)(nil), // 96: signalservice.SyncMessage.OutgoingPayment + (*SyncMessage_PniChangeNumber)(nil), // 97: signalservice.SyncMessage.PniChangeNumber + (*SyncMessage_CallEvent)(nil), // 98: signalservice.SyncMessage.CallEvent + (*SyncMessage_CallLinkUpdate)(nil), // 99: signalservice.SyncMessage.CallLinkUpdate + (*SyncMessage_CallLogEvent)(nil), // 100: signalservice.SyncMessage.CallLogEvent + (*SyncMessage_DeleteForMe)(nil), // 101: signalservice.SyncMessage.DeleteForMe + (*SyncMessage_DeviceNameChange)(nil), // 102: signalservice.SyncMessage.DeviceNameChange + (*SyncMessage_AttachmentBackfillRequest)(nil), // 103: signalservice.SyncMessage.AttachmentBackfillRequest + (*SyncMessage_AttachmentBackfillResponse)(nil), // 104: signalservice.SyncMessage.AttachmentBackfillResponse + (*SyncMessage_Sent_UnidentifiedDeliveryStatus)(nil), // 105: signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + (*SyncMessage_Sent_StoryMessageRecipient)(nil), // 106: signalservice.SyncMessage.Sent.StoryMessageRecipient + (*SyncMessage_OutgoingPayment_MobileCoin)(nil), // 107: signalservice.SyncMessage.OutgoingPayment.MobileCoin + (*SyncMessage_DeleteForMe_MessageDeletes)(nil), // 108: signalservice.SyncMessage.DeleteForMe.MessageDeletes + (*SyncMessage_DeleteForMe_AttachmentDelete)(nil), // 109: signalservice.SyncMessage.DeleteForMe.AttachmentDelete + (*SyncMessage_DeleteForMe_ConversationDelete)(nil), // 110: signalservice.SyncMessage.DeleteForMe.ConversationDelete + (*SyncMessage_DeleteForMe_LocalOnlyConversationDelete)(nil), // 111: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + (*SyncMessage_AttachmentBackfillResponse_AttachmentData)(nil), // 112: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + (*SyncMessage_AttachmentBackfillResponse_AttachmentDataList)(nil), // 113: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + (*ContactDetails_Avatar)(nil), // 114: signalservice.ContactDetails.Avatar + (*PaymentAddress_MobileCoin)(nil), // 115: signalservice.PaymentAddress.MobileCoin } var file_SignalService_proto_depIdxs = []int32{ 0, // 0: signalservice.Envelope.type:type_name -> signalservice.Envelope.Type @@ -9168,8 +9499,8 @@ var file_SignalService_proto_depIdxs = []int32{ 33, // 5: signalservice.Content.receiptMessage:type_name -> signalservice.ReceiptMessage 34, // 6: signalservice.Content.typingMessage:type_name -> signalservice.TypingMessage 35, // 7: signalservice.Content.storyMessage:type_name -> signalservice.StoryMessage - 45, // 8: signalservice.Content.pniSignatureMessage:type_name -> signalservice.PniSignatureMessage - 46, // 9: signalservice.Content.editMessage:type_name -> signalservice.EditMessage + 46, // 8: signalservice.Content.editMessage:type_name -> signalservice.EditMessage + 45, // 9: signalservice.Content.pniSignatureMessage:type_name -> signalservice.PniSignatureMessage 50, // 10: signalservice.CallMessage.offer:type_name -> signalservice.CallMessage.Offer 51, // 11: signalservice.CallMessage.answer:type_name -> signalservice.CallMessage.Answer 52, // 12: signalservice.CallMessage.iceUpdate:type_name -> signalservice.CallMessage.IceUpdate @@ -9194,108 +9525,109 @@ var file_SignalService_proto_depIdxs = []int32{ 67, // 31: signalservice.DataMessage.pollVote:type_name -> signalservice.DataMessage.PollVote 68, // 32: signalservice.DataMessage.pinMessage:type_name -> signalservice.DataMessage.PinMessage 69, // 33: signalservice.DataMessage.unpinMessage:type_name -> signalservice.DataMessage.UnpinMessage - 11, // 34: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type - 12, // 35: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action - 41, // 36: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 - 40, // 37: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer - 37, // 38: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment - 47, // 39: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange - 40, // 40: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer - 13, // 41: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style - 36, // 42: signalservice.TextAttachment.preview:type_name -> signalservice.Preview - 81, // 43: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient - 14, // 44: signalservice.Verified.state:type_name -> signalservice.Verified.State - 82, // 45: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent - 83, // 46: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts - 85, // 47: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request - 86, // 48: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read - 84, // 49: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked + 70, // 34: signalservice.DataMessage.adminDelete:type_name -> signalservice.DataMessage.AdminDelete + 11, // 35: signalservice.ReceiptMessage.type:type_name -> signalservice.ReceiptMessage.Type + 12, // 36: signalservice.TypingMessage.action:type_name -> signalservice.TypingMessage.Action + 41, // 37: signalservice.StoryMessage.group:type_name -> signalservice.GroupContextV2 + 40, // 38: signalservice.StoryMessage.fileAttachment:type_name -> signalservice.AttachmentPointer + 37, // 39: signalservice.StoryMessage.textAttachment:type_name -> signalservice.TextAttachment + 47, // 40: signalservice.StoryMessage.bodyRanges:type_name -> signalservice.BodyRange + 40, // 41: signalservice.Preview.image:type_name -> signalservice.AttachmentPointer + 13, // 42: signalservice.TextAttachment.textStyle:type_name -> signalservice.TextAttachment.Style + 36, // 43: signalservice.TextAttachment.preview:type_name -> signalservice.Preview + 82, // 44: signalservice.TextAttachment.gradient:type_name -> signalservice.TextAttachment.Gradient + 14, // 45: signalservice.Verified.state:type_name -> signalservice.Verified.State + 83, // 46: signalservice.SyncMessage.sent:type_name -> signalservice.SyncMessage.Sent + 84, // 47: signalservice.SyncMessage.contacts:type_name -> signalservice.SyncMessage.Contacts + 86, // 48: signalservice.SyncMessage.request:type_name -> signalservice.SyncMessage.Request + 85, // 49: signalservice.SyncMessage.blocked:type_name -> signalservice.SyncMessage.Blocked 38, // 50: signalservice.SyncMessage.verified:type_name -> signalservice.Verified - 88, // 51: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration - 89, // 52: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation - 90, // 53: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen - 91, // 54: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest - 92, // 55: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys - 94, // 56: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse - 95, // 57: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment - 87, // 58: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed - 96, // 59: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber - 97, // 60: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent - 98, // 61: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate - 99, // 62: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent - 100, // 63: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe - 101, // 64: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange - 102, // 65: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest - 103, // 66: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse - 113, // 67: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar - 114, // 68: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin - 31, // 69: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage - 27, // 70: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style - 1, // 71: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type - 2, // 72: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type - 3, // 73: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency - 71, // 74: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification - 72, // 75: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation - 75, // 76: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment - 47, // 77: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange - 7, // 78: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type - 76, // 79: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name - 77, // 80: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone - 78, // 81: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email - 79, // 82: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress - 80, // 83: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar - 40, // 84: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer - 73, // 85: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin - 74, // 86: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin - 6, // 87: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type - 40, // 88: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer - 8, // 89: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type - 9, // 90: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type - 10, // 91: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type - 40, // 92: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer - 31, // 93: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage - 104, // 94: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus - 35, // 95: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage - 105, // 96: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient - 46, // 97: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage - 40, // 98: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer - 15, // 99: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type - 16, // 100: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type - 17, // 101: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type - 18, // 102: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type - 106, // 103: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin - 19, // 104: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type - 20, // 105: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction - 21, // 106: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event - 22, // 107: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type - 23, // 108: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type - 107, // 109: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes - 109, // 110: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete - 110, // 111: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete - 108, // 112: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete - 48, // 113: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 114: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier - 48, // 115: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 116: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier - 112, // 117: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList - 24, // 118: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error - 49, // 119: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 120: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage - 49, // 121: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 122: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage - 49, // 123: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier - 48, // 124: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage - 48, // 125: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage - 49, // 126: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier - 40, // 127: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer - 25, // 128: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status - 111, // 129: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - 111, // 130: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData - 131, // [131:131] is the sub-list for method output_type - 131, // [131:131] is the sub-list for method input_type - 131, // [131:131] is the sub-list for extension type_name - 131, // [131:131] is the sub-list for extension extendee - 0, // [0:131] is the sub-list for field type_name + 89, // 51: signalservice.SyncMessage.configuration:type_name -> signalservice.SyncMessage.Configuration + 91, // 52: signalservice.SyncMessage.viewOnceOpen:type_name -> signalservice.SyncMessage.ViewOnceOpen + 92, // 53: signalservice.SyncMessage.fetchLatest:type_name -> signalservice.SyncMessage.FetchLatest + 93, // 54: signalservice.SyncMessage.keys:type_name -> signalservice.SyncMessage.Keys + 95, // 55: signalservice.SyncMessage.messageRequestResponse:type_name -> signalservice.SyncMessage.MessageRequestResponse + 96, // 56: signalservice.SyncMessage.outgoingPayment:type_name -> signalservice.SyncMessage.OutgoingPayment + 97, // 57: signalservice.SyncMessage.pniChangeNumber:type_name -> signalservice.SyncMessage.PniChangeNumber + 98, // 58: signalservice.SyncMessage.callEvent:type_name -> signalservice.SyncMessage.CallEvent + 99, // 59: signalservice.SyncMessage.callLinkUpdate:type_name -> signalservice.SyncMessage.CallLinkUpdate + 100, // 60: signalservice.SyncMessage.callLogEvent:type_name -> signalservice.SyncMessage.CallLogEvent + 101, // 61: signalservice.SyncMessage.deleteForMe:type_name -> signalservice.SyncMessage.DeleteForMe + 102, // 62: signalservice.SyncMessage.deviceNameChange:type_name -> signalservice.SyncMessage.DeviceNameChange + 103, // 63: signalservice.SyncMessage.attachmentBackfillRequest:type_name -> signalservice.SyncMessage.AttachmentBackfillRequest + 104, // 64: signalservice.SyncMessage.attachmentBackfillResponse:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse + 87, // 65: signalservice.SyncMessage.read:type_name -> signalservice.SyncMessage.Read + 90, // 66: signalservice.SyncMessage.stickerPackOperation:type_name -> signalservice.SyncMessage.StickerPackOperation + 88, // 67: signalservice.SyncMessage.viewed:type_name -> signalservice.SyncMessage.Viewed + 114, // 68: signalservice.ContactDetails.avatar:type_name -> signalservice.ContactDetails.Avatar + 115, // 69: signalservice.PaymentAddress.mobileCoin:type_name -> signalservice.PaymentAddress.MobileCoin + 31, // 70: signalservice.EditMessage.dataMessage:type_name -> signalservice.DataMessage + 27, // 71: signalservice.BodyRange.style:type_name -> signalservice.BodyRange.Style + 1, // 72: signalservice.CallMessage.Offer.type:type_name -> signalservice.CallMessage.Offer.Type + 2, // 73: signalservice.CallMessage.Hangup.type:type_name -> signalservice.CallMessage.Hangup.Type + 3, // 74: signalservice.CallMessage.Opaque.urgency:type_name -> signalservice.CallMessage.Opaque.Urgency + 72, // 75: signalservice.DataMessage.Payment.notification:type_name -> signalservice.DataMessage.Payment.Notification + 73, // 76: signalservice.DataMessage.Payment.activation:type_name -> signalservice.DataMessage.Payment.Activation + 76, // 77: signalservice.DataMessage.Quote.attachments:type_name -> signalservice.DataMessage.Quote.QuotedAttachment + 47, // 78: signalservice.DataMessage.Quote.bodyRanges:type_name -> signalservice.BodyRange + 7, // 79: signalservice.DataMessage.Quote.type:type_name -> signalservice.DataMessage.Quote.Type + 77, // 80: signalservice.DataMessage.Contact.name:type_name -> signalservice.DataMessage.Contact.Name + 78, // 81: signalservice.DataMessage.Contact.number:type_name -> signalservice.DataMessage.Contact.Phone + 79, // 82: signalservice.DataMessage.Contact.email:type_name -> signalservice.DataMessage.Contact.Email + 80, // 83: signalservice.DataMessage.Contact.address:type_name -> signalservice.DataMessage.Contact.PostalAddress + 81, // 84: signalservice.DataMessage.Contact.avatar:type_name -> signalservice.DataMessage.Contact.Avatar + 40, // 85: signalservice.DataMessage.Sticker.data:type_name -> signalservice.AttachmentPointer + 74, // 86: signalservice.DataMessage.Payment.Amount.mobileCoin:type_name -> signalservice.DataMessage.Payment.Amount.MobileCoin + 75, // 87: signalservice.DataMessage.Payment.Notification.mobileCoin:type_name -> signalservice.DataMessage.Payment.Notification.MobileCoin + 6, // 88: signalservice.DataMessage.Payment.Activation.type:type_name -> signalservice.DataMessage.Payment.Activation.Type + 40, // 89: signalservice.DataMessage.Quote.QuotedAttachment.thumbnail:type_name -> signalservice.AttachmentPointer + 8, // 90: signalservice.DataMessage.Contact.Phone.type:type_name -> signalservice.DataMessage.Contact.Phone.Type + 9, // 91: signalservice.DataMessage.Contact.Email.type:type_name -> signalservice.DataMessage.Contact.Email.Type + 10, // 92: signalservice.DataMessage.Contact.PostalAddress.type:type_name -> signalservice.DataMessage.Contact.PostalAddress.Type + 40, // 93: signalservice.DataMessage.Contact.Avatar.avatar:type_name -> signalservice.AttachmentPointer + 31, // 94: signalservice.SyncMessage.Sent.message:type_name -> signalservice.DataMessage + 105, // 95: signalservice.SyncMessage.Sent.unidentifiedStatus:type_name -> signalservice.SyncMessage.Sent.UnidentifiedDeliveryStatus + 35, // 96: signalservice.SyncMessage.Sent.storyMessage:type_name -> signalservice.StoryMessage + 106, // 97: signalservice.SyncMessage.Sent.storyMessageRecipients:type_name -> signalservice.SyncMessage.Sent.StoryMessageRecipient + 46, // 98: signalservice.SyncMessage.Sent.editMessage:type_name -> signalservice.EditMessage + 40, // 99: signalservice.SyncMessage.Contacts.blob:type_name -> signalservice.AttachmentPointer + 15, // 100: signalservice.SyncMessage.Request.type:type_name -> signalservice.SyncMessage.Request.Type + 16, // 101: signalservice.SyncMessage.StickerPackOperation.type:type_name -> signalservice.SyncMessage.StickerPackOperation.Type + 17, // 102: signalservice.SyncMessage.FetchLatest.type:type_name -> signalservice.SyncMessage.FetchLatest.Type + 18, // 103: signalservice.SyncMessage.MessageRequestResponse.type:type_name -> signalservice.SyncMessage.MessageRequestResponse.Type + 107, // 104: signalservice.SyncMessage.OutgoingPayment.mobileCoin:type_name -> signalservice.SyncMessage.OutgoingPayment.MobileCoin + 19, // 105: signalservice.SyncMessage.CallEvent.type:type_name -> signalservice.SyncMessage.CallEvent.Type + 20, // 106: signalservice.SyncMessage.CallEvent.direction:type_name -> signalservice.SyncMessage.CallEvent.Direction + 21, // 107: signalservice.SyncMessage.CallEvent.event:type_name -> signalservice.SyncMessage.CallEvent.Event + 22, // 108: signalservice.SyncMessage.CallLinkUpdate.type:type_name -> signalservice.SyncMessage.CallLinkUpdate.Type + 23, // 109: signalservice.SyncMessage.CallLogEvent.type:type_name -> signalservice.SyncMessage.CallLogEvent.Type + 108, // 110: signalservice.SyncMessage.DeleteForMe.messageDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.MessageDeletes + 110, // 111: signalservice.SyncMessage.DeleteForMe.conversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.ConversationDelete + 111, // 112: signalservice.SyncMessage.DeleteForMe.localOnlyConversationDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete + 109, // 113: signalservice.SyncMessage.DeleteForMe.attachmentDeletes:type_name -> signalservice.SyncMessage.DeleteForMe.AttachmentDelete + 48, // 114: signalservice.SyncMessage.AttachmentBackfillRequest.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 115: signalservice.SyncMessage.AttachmentBackfillRequest.targetConversation:type_name -> signalservice.ConversationIdentifier + 48, // 116: signalservice.SyncMessage.AttachmentBackfillResponse.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 117: signalservice.SyncMessage.AttachmentBackfillResponse.targetConversation:type_name -> signalservice.ConversationIdentifier + 113, // 118: signalservice.SyncMessage.AttachmentBackfillResponse.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList + 24, // 119: signalservice.SyncMessage.AttachmentBackfillResponse.error:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.Error + 49, // 120: signalservice.SyncMessage.DeleteForMe.MessageDeletes.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 121: signalservice.SyncMessage.DeleteForMe.MessageDeletes.messages:type_name -> signalservice.AddressableMessage + 49, // 122: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 123: signalservice.SyncMessage.DeleteForMe.AttachmentDelete.targetMessage:type_name -> signalservice.AddressableMessage + 49, // 124: signalservice.SyncMessage.DeleteForMe.ConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 48, // 125: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentMessages:type_name -> signalservice.AddressableMessage + 48, // 126: signalservice.SyncMessage.DeleteForMe.ConversationDelete.mostRecentNonExpiringMessages:type_name -> signalservice.AddressableMessage + 49, // 127: signalservice.SyncMessage.DeleteForMe.LocalOnlyConversationDelete.conversation:type_name -> signalservice.ConversationIdentifier + 40, // 128: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.attachment:type_name -> signalservice.AttachmentPointer + 25, // 129: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.status:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData.Status + 112, // 130: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.attachments:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 112, // 131: signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentDataList.longText:type_name -> signalservice.SyncMessage.AttachmentBackfillResponse.AttachmentData + 132, // [132:132] is the sub-list for method output_type + 132, // [132:132] is the sub-list for method input_type + 132, // [132:132] is the sub-list for extension type_name + 132, // [132:132] is the sub-list for extension extendee + 0, // [0:132] is the sub-list for field type_name } func init() { file_SignalService_proto_init() } @@ -9303,6 +9635,17 @@ func file_SignalService_proto_init() { if File_SignalService_proto != nil { return } + file_SignalService_proto_msgTypes[1].OneofWrappers = []any{ + (*Content_DataMessage)(nil), + (*Content_SyncMessage)(nil), + (*Content_CallMessage)(nil), + (*Content_NullMessage)(nil), + (*Content_ReceiptMessage)(nil), + (*Content_TypingMessage)(nil), + (*Content_DecryptionErrorMessage)(nil), + (*Content_StoryMessage)(nil), + (*Content_EditMessage)(nil), + } file_SignalService_proto_msgTypes[7].OneofWrappers = []any{ (*StoryMessage_FileAttachment)(nil), (*StoryMessage_TextAttachment)(nil), @@ -9311,6 +9654,27 @@ func file_SignalService_proto_init() { (*TextAttachment_Gradient_)(nil), (*TextAttachment_Color)(nil), } + file_SignalService_proto_msgTypes[11].OneofWrappers = []any{ + (*SyncMessage_Sent_)(nil), + (*SyncMessage_Contacts_)(nil), + (*SyncMessage_Request_)(nil), + (*SyncMessage_Blocked_)(nil), + (*SyncMessage_Verified)(nil), + (*SyncMessage_Configuration_)(nil), + (*SyncMessage_ViewOnceOpen_)(nil), + (*SyncMessage_FetchLatest_)(nil), + (*SyncMessage_Keys_)(nil), + (*SyncMessage_MessageRequestResponse_)(nil), + (*SyncMessage_OutgoingPayment_)(nil), + (*SyncMessage_PniChangeNumber_)(nil), + (*SyncMessage_CallEvent_)(nil), + (*SyncMessage_CallLinkUpdate_)(nil), + (*SyncMessage_CallLogEvent_)(nil), + (*SyncMessage_DeleteForMe_)(nil), + (*SyncMessage_DeviceNameChange_)(nil), + (*SyncMessage_AttachmentBackfillRequest_)(nil), + (*SyncMessage_AttachmentBackfillResponse_)(nil), + } file_SignalService_proto_msgTypes[12].OneofWrappers = []any{ (*AttachmentPointer_CdnId)(nil), (*AttachmentPointer_CdnKey)(nil), @@ -9342,20 +9706,20 @@ func file_SignalService_proto_init() { (*DataMessage_PinMessage_PinDurationSeconds)(nil), (*DataMessage_PinMessage_PinDurationForever)(nil), } - file_SignalService_proto_msgTypes[42].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[43].OneofWrappers = []any{ (*DataMessage_Payment_Amount_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[43].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[44].OneofWrappers = []any{ (*DataMessage_Payment_Notification_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[67].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[68].OneofWrappers = []any{ (*SyncMessage_OutgoingPayment_MobileCoin_)(nil), } - file_SignalService_proto_msgTypes[75].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[76].OneofWrappers = []any{ (*SyncMessage_AttachmentBackfillResponse_Attachments)(nil), (*SyncMessage_AttachmentBackfillResponse_Error_)(nil), } - file_SignalService_proto_msgTypes[83].OneofWrappers = []any{ + file_SignalService_proto_msgTypes[84].OneofWrappers = []any{ (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Attachment)(nil), (*SyncMessage_AttachmentBackfillResponse_AttachmentData_Status_)(nil), } @@ -9365,7 +9729,7 @@ func file_SignalService_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_SignalService_proto_rawDesc), len(file_SignalService_proto_rawDesc)), NumEnums: 28, - NumMessages: 87, + NumMessages: 88, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/SignalService.proto b/pkg/signalmeow/protobuf/SignalService.proto index da4d44f..0089a16 100644 --- a/pkg/signalmeow/protobuf/SignalService.proto +++ b/pkg/signalmeow/protobuf/SignalService.proto @@ -13,23 +13,79 @@ option java_outer_classname = "SignalServiceProtos"; message Envelope { enum Type { UNKNOWN = 0; - CIPHERTEXT = 1; // content => (version byte | SignalMessage{Content}) + + /** + * A double-ratchet message represents a "normal," "unsealed-sender" message + * encrypted using the Double Ratchet within an established Signal session. + * Double-ratchet messages include sender information in the plaintext + * portion of the `Envelope`. + */ + DOUBLE_RATCHET = 1; // content => (version byte | SignalMessage{Content}) + reserved 2; reserved "KEY_EXCHANGE"; - PREKEY_BUNDLE = 3; // content => (version byte | PreKeySignalMessage{Content}) - SERVER_DELIVERY_RECEIPT = 5; // legacyMessage => [] AND content => [] - UNIDENTIFIED_SENDER = 6; // legacyMessage => [] AND content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) - SENDERKEY_MESSAGE = 7; // legacyMessage => [] AND content => (version byte | SenderKeyMessage) - PLAINTEXT_CONTENT = 8; // legacyMessage => [] AND content => (marker byte | Content) + + /** + * 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. Like double-ratchet messages, + * prekey messages contain sender information in the plaintext portion of + * the `Envelope`. + */ + PREKEY_MESSAGE = 3; // content => (version byte | PreKeySignalMessage{Content}) + + /** + * Server delivery receipts are generated by the server when + * "unsealed-sender" messages are delivered to and acknowledged by the + * destination device. Server delivery receipts identify the sender in the + * plaintext portion of the `Envelope` and have no `content`. Note that + * receipts for sealed-sender messages are generated by clients as + * `UNIDENTIFIED_SENDER` messages. + * + * Note that, with server delivery receipts, the "client timestamp" on + * the envelope refers to the timestamp of the original message (i.e. the + * message the server just delivered) and not to the time of delivery. The + * "server timestamp" refers to the time of delivery. + */ + SERVER_DELIVERY_RECEIPT = 5; // content => [] + + /** + * An unidentified sender message represents a message with no sender + * information in the plaintext portion of the `Envelope`. Unidentified + * sender messages always contain an additional `subtype` in their + * `content`. They may or may not be part of an existing Signal session + * (i.e. an unidentified sender message may have a "prekey message" + * subtype or may indicate an encryption error). + */ + UNIDENTIFIED_SENDER = 6; // content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) + + reserved 7; + reserved "SENDERKEY_MESSAGE"; + + /** + * A plaintext message is used solely to convey encryption error receipts + * and never contains encrypted message content. Encryption error receipts + * must be delivered in plaintext because, encryption/decryption of a prior + * message failed and there is no reason to believe that + * encryption/decryption of subsequent messages with the same key material + * would succeed. + * + * Critically, plaintext messages never have "real" message content + * generated by users. Plaintext messages include sender information. + */ + PLAINTEXT_CONTENT = 8; // content => (marker byte | Content) + + // next: 9 } optional Type type = 1; reserved 2; // formerly optional string sourceE164 = 2; optional string sourceServiceId = 11; - optional uint32 sourceDevice = 7; + optional uint32 sourceDeviceId = 7; optional string destinationServiceId = 13; reserved 3; // formerly optional string relay = 3; - optional uint64 timestamp = 5; + optional uint64 clientTimestamp = 5; reserved 6; // formerly optional bytes legacyMessage = 6; // Contains an encrypted DataMessage; this field could have been set historically for type 1 or 3 messages; no longer in use optional bytes content = 8; // Contains an encrypted Content optional string serverGuid = 9; @@ -48,17 +104,20 @@ message Envelope { } message Content { - optional DataMessage dataMessage = 1; - optional SyncMessage syncMessage = 2; - optional CallMessage callMessage = 3; - optional NullMessage nullMessage = 4; - optional ReceiptMessage receiptMessage = 5; - optional TypingMessage typingMessage = 6; + oneof content { + DataMessage dataMessage = 1; + SyncMessage syncMessage = 2; + CallMessage callMessage = 3; + NullMessage nullMessage = 4; + ReceiptMessage receiptMessage = 5; + TypingMessage typingMessage = 6; + bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8; + StoryMessage storyMessage = 9; + EditMessage editMessage = 11; + } + optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7; - optional bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8; - optional StoryMessage storyMessage = 9; optional PniSignatureMessage pniSignatureMessage = 10; - optional EditMessage editMessage = 11; } message CallMessage { @@ -331,8 +390,8 @@ message DataMessage { message PollVote { optional bytes targetAuthorAciBinary = 1; optional uint64 targetSentTimestamp = 2; - repeated uint32 optionIndexes = 3; // must be in the range [0, options.length) from the PollCreate - optional uint32 voteCount = 4; // increment this by 1 each time you vote on a given poll + repeated uint32 optionIndexes = 3; + optional uint32 voteCount = 4; } message PinMessage { @@ -349,6 +408,11 @@ message DataMessage { optional uint64 targetSentTimestamp = 2; } + message AdminDelete { + optional bytes targetAuthorAciBinary = 1; // 16-byte UUID + optional uint64 targetSentTimestamp = 2; + } + optional string body = 1; repeated AttachmentPointer attachments = 2; reserved /*groupV1*/ 3; @@ -376,7 +440,8 @@ message DataMessage { optional PollVote pollVote = 26; optional PinMessage pinMessage = 27; optional UnpinMessage unpinMessage = 28; - // NEXT ID: 29 + optional AdminDelete adminDelete = 29; + // NEXT ID: 30 } message NullMessage { @@ -435,6 +500,12 @@ message TextAttachment { } message Gradient { + // Color ordering: + // 0 degrees: bottom-to-top + // 90 degrees: left-to-right + // 180 degrees: top-to-bottom + // 270 degrees: right-to-left + optional uint32 startColor = 1; // deprecated: this field will be removed in a future release. optional uint32 endColor = 2; // deprecated: this field will be removed in a future release. optional uint32 angle = 3; // degrees @@ -547,7 +618,7 @@ message SyncMessage { optional bool unidentifiedDeliveryIndicators = 2; optional bool typingIndicators = 3; reserved /* linkPreviews */ 4; - optional uint32 provisioningVersion = 5; + reserved /* provisioningVersion */ 5; optional bool linkPreviews = 6; } @@ -582,7 +653,7 @@ message SyncMessage { message Keys { reserved /* storageService */ 1; - optional bytes master = 2; // deprecated: this field will be removed in a future release. + reserved /* master */ 2; optional string accountEntropyPool = 3; optional bytes mediaRootBackupKey = 4; } @@ -682,7 +753,7 @@ message SyncMessage { optional bytes rootKey = 1; optional bytes adminPasskey = 2; optional Type type = 3; // defaults to UPDATE - optional bytes epoch = 4; + reserved /*epoch*/ 4; } message CallLogEvent { @@ -779,31 +850,40 @@ message SyncMessage { } } - optional Sent sent = 1; - optional Contacts contacts = 2; + oneof content { + Sent sent = 1; + Contacts contacts = 2; + Request request = 4; + Blocked blocked = 6; + Verified verified = 7; + Configuration configuration = 9; + ViewOnceOpen viewOnceOpen = 11; + FetchLatest fetchLatest = 12; + Keys keys = 13; + MessageRequestResponse messageRequestResponse = 14; + OutgoingPayment outgoingPayment = 15; + PniChangeNumber pniChangeNumber = 18; + CallEvent callEvent = 19; + CallLinkUpdate callLinkUpdate = 20; + CallLogEvent callLogEvent = 21; + DeleteForMe deleteForMe = 22; + DeviceNameChange deviceNameChange = 23; + AttachmentBackfillRequest attachmentBackfillRequest = 24; + AttachmentBackfillResponse attachmentBackfillResponse = 25; + } + reserved /*groups*/ 3; - optional Request request = 4; + + // Protobufs don't allow `repeated` fields to be inside of `oneof` so while + // the fields below are mutually exclusive with the rest of the values above + // we have to place them outside of `oneof`. repeated Read read = 5; - optional Blocked blocked = 6; - optional Verified verified = 7; - optional Configuration configuration = 9; - optional bytes padding = 8; repeated StickerPackOperation stickerPackOperation = 10; - optional ViewOnceOpen viewOnceOpen = 11; - optional FetchLatest fetchLatest = 12; - optional Keys keys = 13; - optional MessageRequestResponse messageRequestResponse = 14; - optional OutgoingPayment outgoingPayment = 15; repeated Viewed viewed = 16; + reserved /*pniIdentity*/ 17; - optional PniChangeNumber pniChangeNumber = 18; - optional CallEvent callEvent = 19; - optional CallLinkUpdate callLinkUpdate = 20; - optional CallLogEvent callLogEvent = 21; - optional DeleteForMe deleteForMe = 22; - optional DeviceNameChange deviceNameChange = 23; - optional AttachmentBackfillRequest attachmentBackfillRequest = 24; - optional AttachmentBackfillResponse attachmentBackfillResponse = 25; + + optional bytes padding = 8; } message AttachmentPointer { diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 9a27146..619221f 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -1598,6 +1598,7 @@ type AccountRecord struct { NotificationProfileManualOverride *AccountRecord_NotificationProfileManualOverride `protobuf:"bytes,44,opt,name=notificationProfileManualOverride,proto3" json:"notificationProfileManualOverride,omitempty"` NotificationProfileSyncDisabled bool `protobuf:"varint,45,opt,name=notificationProfileSyncDisabled,proto3" json:"notificationProfileSyncDisabled,omitempty"` AutomaticKeyVerificationDisabled bool `protobuf:"varint,46,opt,name=automaticKeyVerificationDisabled,proto3" json:"automaticKeyVerificationDisabled,omitempty"` + HasSeenAdminDeleteEducationDialog bool `protobuf:"varint,47,opt,name=hasSeenAdminDeleteEducationDialog,proto3" json:"hasSeenAdminDeleteEducationDialog,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1905,6 +1906,13 @@ func (x *AccountRecord) GetAutomaticKeyVerificationDisabled() bool { return false } +func (x *AccountRecord) GetHasSeenAdminDeleteEducationDialog() bool { + if x != nil { + return x.HasSeenAdminDeleteEducationDialog + } + return false +} + type StoryDistributionListRecord struct { state protoimpl.MessageState `protogen:"open.v1"` Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` @@ -2002,7 +2010,6 @@ type CallLinkRecord struct { RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` - Epoch []byte `protobuf:"bytes,4,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2058,13 +2065,6 @@ func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 { return 0 } -func (x *CallLinkRecord) GetEpoch() []byte { - if x != nil { - return x.Epoch - } - return nil -} - type Recipient struct { state protoimpl.MessageState `protogen:"open.v1"` // Types that are valid to be assigned to Identifier: @@ -3216,7 +3216,7 @@ const file_StorageService_proto_rawDesc = "" + "\">\n" + "\bPayments\x12\x18\n" + "\aenabled\x18\x01 \x01(\bR\aenabled\x12\x18\n" + - "\aentropy\x18\x02 \x01(\fR\aentropy\"\xcb\x1c\n" + + "\aentropy\x18\x02 \x01(\fR\aentropy\"\x99\x1d\n" + "\rAccountRecord\x12\x1e\n" + "\n" + "profileKey\x18\x01 \x01(\fR\n" + @@ -3263,7 +3263,8 @@ const file_StorageService_proto_rawDesc = "" + "\x11backupTierHistory\x18+ \x01(\v2..signalservice.AccountRecord.BackupTierHistoryR\x11backupTierHistory\x12\x8c\x01\n" + "!notificationProfileManualOverride\x18, \x01(\v2>.signalservice.AccountRecord.NotificationProfileManualOverrideR!notificationProfileManualOverride\x12H\n" + "\x1fnotificationProfileSyncDisabled\x18- \x01(\bR\x1fnotificationProfileSyncDisabled\x12J\n" + - " automaticKeyVerificationDisabled\x18. \x01(\bR automaticKeyVerificationDisabled\x1a\xb0\x02\n" + + " automaticKeyVerificationDisabled\x18. \x01(\bR automaticKeyVerificationDisabled\x12L\n" + + "!hasSeenAdminDeleteEducationDialog\x18/ \x01(\bR!hasSeenAdminDeleteEducationDialog\x1a\xb0\x02\n" + "\x12PinnedConversation\x12S\n" + "\acontact\x18\x01 \x01(\v27.signalservice.AccountRecord.PinnedConversation.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x03 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + @@ -3329,13 +3330,11 @@ const file_StorageService_proto_rawDesc = "" + "\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" + "\visBlockList\x18\x06 \x01(\bR\visBlockList\x12<\n" + - "\x19recipientServiceIdsBinary\x18\a \x03(\fR\x19recipientServiceIdsBinary\"\xa7\x01\n" + + "\x19recipientServiceIdsBinary\x18\a \x03(\fR\x19recipientServiceIdsBinary\"\x88\x01\n" + "\x0eCallLinkRecord\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + - "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\x12\x19\n" + - "\x05epoch\x18\x04 \x01(\fH\x00R\x05epoch\x88\x01\x01B\b\n" + - "\x06_epoch\"\x90\x02\n" + + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMsJ\x04\b\x04\x10\x05\"\x90\x02\n" + "\tRecipient\x12<\n" + "\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + @@ -3531,7 +3530,6 @@ func file_StorageService_proto_init() { file_StorageService_proto_msgTypes[7].OneofWrappers = []any{} file_StorageService_proto_msgTypes[9].OneofWrappers = []any{} file_StorageService_proto_msgTypes[11].OneofWrappers = []any{} - file_StorageService_proto_msgTypes[13].OneofWrappers = []any{} file_StorageService_proto_msgTypes[14].OneofWrappers = []any{ (*Recipient_Contact_)(nil), (*Recipient_LegacyGroupId)(nil), diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index 95ec845..d22babc 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -296,6 +296,7 @@ message AccountRecord { NotificationProfileManualOverride notificationProfileManualOverride = 44; bool notificationProfileSyncDisabled = 45; bool automaticKeyVerificationDisabled = 46; + bool hasSeenAdminDeleteEducationDialog = 47; } message StoryDistributionListRecord { @@ -312,7 +313,7 @@ message CallLinkRecord { bytes rootKey = 1; bytes adminPasskey = 2; uint64 deletedAtTimestampMs = 3; - optional bytes epoch = 4; + reserved 4; // was epoch field, never used } message Recipient { diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 73930ae..326c170 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1504,7 +1504,7 @@ func (x IndividualCall_Type) Number() protoreflect.EnumNumber { // Deprecated: Use IndividualCall_Type.Descriptor instead. func (IndividualCall_Type) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 0} } type IndividualCall_Direction int32 @@ -1553,7 +1553,7 @@ func (x IndividualCall_Direction) Number() protoreflect.EnumNumber { // Deprecated: Use IndividualCall_Direction.Descriptor instead. func (IndividualCall_Direction) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 1} } type IndividualCall_State int32 @@ -1612,7 +1612,7 @@ func (x IndividualCall_State) Number() protoreflect.EnumNumber { // Deprecated: Use IndividualCall_State.Descriptor instead. func (IndividualCall_State) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{34, 2} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 2} } type GroupCall_State int32 @@ -1688,7 +1688,7 @@ func (x GroupCall_State) Number() protoreflect.EnumNumber { // Deprecated: Use GroupCall_State.Descriptor instead. func (GroupCall_State) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{35, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{36, 0} } type SimpleChatUpdate_Type int32 @@ -1779,7 +1779,7 @@ func (x SimpleChatUpdate_Type) Number() protoreflect.EnumNumber { // Deprecated: Use SimpleChatUpdate_Type.Descriptor instead. func (SimpleChatUpdate_Type) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{36, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{37, 0} } type ChatStyle_WallpaperPreset int32 @@ -1885,7 +1885,7 @@ func (x ChatStyle_WallpaperPreset) Number() protoreflect.EnumNumber { // Deprecated: Use ChatStyle_WallpaperPreset.Descriptor instead. func (ChatStyle_WallpaperPreset) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{83, 0} } type ChatStyle_BubbleColorPreset int32 @@ -1994,7 +1994,7 @@ func (x ChatStyle_BubbleColorPreset) Number() protoreflect.EnumNumber { // Deprecated: Use ChatStyle_BubbleColorPreset.Descriptor instead. func (ChatStyle_BubbleColorPreset) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{83, 1} } type NotificationProfile_DayOfWeek int32 @@ -2058,7 +2058,7 @@ func (x NotificationProfile_DayOfWeek) Number() protoreflect.EnumNumber { // Deprecated: Use NotificationProfile_DayOfWeek.Descriptor instead. func (NotificationProfile_DayOfWeek) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{81, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{84, 0} } // Represents the default "All chats" folder record vs all other custom folders @@ -2108,7 +2108,7 @@ func (x ChatFolder_FolderType) Number() protoreflect.EnumNumber { // Deprecated: Use ChatFolder_FolderType.Descriptor instead. func (ChatFolder_FolderType) EnumDescriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{82, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{85, 0} } type BackupInfo struct { @@ -3241,7 +3241,6 @@ type CallLink struct { Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Restrictions CallLink_Restrictions `protobuf:"varint,4,opt,name=restrictions,proto3,enum=signal.backup.CallLink_Restrictions" json:"restrictions,omitempty"` ExpirationMs uint64 `protobuf:"varint,5,opt,name=expirationMs,proto3" json:"expirationMs,omitempty"` - Epoch []byte `protobuf:"bytes,6,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"` // May be absent/empty for older links unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3311,13 +3310,6 @@ func (x *CallLink) GetExpirationMs() uint64 { return 0 } -func (x *CallLink) GetEpoch() []byte { - if x != nil { - return x.Epoch - } - return nil -} - type AdHocCall struct { state protoimpl.MessageState `protogen:"open.v1"` CallId uint64 `protobuf:"varint,1,opt,name=callId,proto3" json:"callId,omitempty"` @@ -3580,6 +3572,7 @@ type ChatItem struct { // *ChatItem_ViewOnceMessage // *ChatItem_DirectStoryReplyMessage // *ChatItem_Poll + // *ChatItem_AdminDeletedMessage Item isChatItem_Item `protobuf_oneof:"item"` PinDetails *ChatItem_PinDetails `protobuf:"bytes,21,opt,name=pinDetails,proto3" json:"pinDetails,omitempty"` // only set if message is pinned unknownFields protoimpl.UnknownFields @@ -3796,6 +3789,15 @@ func (x *ChatItem) GetPoll() *Poll { return nil } +func (x *ChatItem) GetAdminDeletedMessage() *AdminDeletedMessage { + if x != nil { + if x, ok := x.Item.(*ChatItem_AdminDeletedMessage); ok { + return x.AdminDeletedMessage + } + } + return nil +} + func (x *ChatItem) GetPinDetails() *ChatItem_PinDetails { if x != nil { return x.PinDetails @@ -3869,6 +3871,10 @@ type ChatItem_Poll struct { Poll *Poll `protobuf:"bytes,20,opt,name=poll,proto3,oneof"` } +type ChatItem_AdminDeletedMessage struct { + AdminDeletedMessage *AdminDeletedMessage `protobuf:"bytes,22,opt,name=adminDeletedMessage,proto3,oneof"` +} + func (*ChatItem_StandardMessage) isChatItem_Item() {} func (*ChatItem_ContactMessage) isChatItem_Item() {} @@ -3889,6 +3895,8 @@ func (*ChatItem_DirectStoryReplyMessage) isChatItem_Item() {} func (*ChatItem_Poll) isChatItem_Item() {} +func (*ChatItem_AdminDeletedMessage) isChatItem_Item() {} + type SendStatus struct { state protoimpl.MessageState `protogen:"open.v1"` RecipientId uint64 `protobuf:"varint,1,opt,name=recipientId,proto3" json:"recipientId,omitempty"` @@ -5355,6 +5363,50 @@ func (x *Poll) GetReactions() []*Reaction { return nil } +type AdminDeletedMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + AdminId uint64 `protobuf:"varint,1,opt,name=adminId,proto3" json:"adminId,omitempty"` // id of the admin that deleted the message + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdminDeletedMessage) Reset() { + *x = AdminDeletedMessage{} + mi := &file_backuppb_Backup_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdminDeletedMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdminDeletedMessage) ProtoMessage() {} + +func (x *AdminDeletedMessage) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[33] + 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 AdminDeletedMessage.ProtoReflect.Descriptor instead. +func (*AdminDeletedMessage) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{33} +} + +func (x *AdminDeletedMessage) GetAdminId() uint64 { + if x != nil { + return x.AdminId + } + return 0 +} + type ChatUpdateMessage struct { state protoimpl.MessageState `protogen:"open.v1"` // If unset, importers should ignore the update message without throwing an error. @@ -5379,7 +5431,7 @@ type ChatUpdateMessage struct { func (x *ChatUpdateMessage) Reset() { *x = ChatUpdateMessage{} - mi := &file_backuppb_Backup_proto_msgTypes[33] + mi := &file_backuppb_Backup_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5391,7 +5443,7 @@ func (x *ChatUpdateMessage) String() string { func (*ChatUpdateMessage) ProtoMessage() {} func (x *ChatUpdateMessage) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[33] + mi := &file_backuppb_Backup_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5404,7 +5456,7 @@ func (x *ChatUpdateMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatUpdateMessage.ProtoReflect.Descriptor instead. func (*ChatUpdateMessage) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{33} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{34} } func (x *ChatUpdateMessage) GetUpdate() isChatUpdateMessage_Update { @@ -5597,7 +5649,7 @@ type IndividualCall struct { func (x *IndividualCall) Reset() { *x = IndividualCall{} - mi := &file_backuppb_Backup_proto_msgTypes[34] + mi := &file_backuppb_Backup_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5609,7 +5661,7 @@ func (x *IndividualCall) String() string { func (*IndividualCall) ProtoMessage() {} func (x *IndividualCall) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[34] + mi := &file_backuppb_Backup_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5622,7 +5674,7 @@ func (x *IndividualCall) ProtoReflect() protoreflect.Message { // Deprecated: Use IndividualCall.ProtoReflect.Descriptor instead. func (*IndividualCall) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{34} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{35} } func (x *IndividualCall) GetCallId() uint64 { @@ -5682,7 +5734,7 @@ type GroupCall struct { func (x *GroupCall) Reset() { *x = GroupCall{} - mi := &file_backuppb_Backup_proto_msgTypes[35] + mi := &file_backuppb_Backup_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5694,7 +5746,7 @@ func (x *GroupCall) String() string { func (*GroupCall) ProtoMessage() {} func (x *GroupCall) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[35] + mi := &file_backuppb_Backup_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5707,7 +5759,7 @@ func (x *GroupCall) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupCall.ProtoReflect.Descriptor instead. func (*GroupCall) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{35} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{36} } func (x *GroupCall) GetCallId() uint64 { @@ -5768,7 +5820,7 @@ type SimpleChatUpdate struct { func (x *SimpleChatUpdate) Reset() { *x = SimpleChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[36] + mi := &file_backuppb_Backup_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5780,7 +5832,7 @@ func (x *SimpleChatUpdate) String() string { func (*SimpleChatUpdate) ProtoMessage() {} func (x *SimpleChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[36] + mi := &file_backuppb_Backup_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5793,7 +5845,7 @@ func (x *SimpleChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SimpleChatUpdate.ProtoReflect.Descriptor instead. func (*SimpleChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{36} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{37} } func (x *SimpleChatUpdate) GetType() SimpleChatUpdate_Type { @@ -5814,7 +5866,7 @@ type ExpirationTimerChatUpdate struct { func (x *ExpirationTimerChatUpdate) Reset() { *x = ExpirationTimerChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[37] + mi := &file_backuppb_Backup_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5826,7 +5878,7 @@ func (x *ExpirationTimerChatUpdate) String() string { func (*ExpirationTimerChatUpdate) ProtoMessage() {} func (x *ExpirationTimerChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[37] + mi := &file_backuppb_Backup_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5839,7 +5891,7 @@ func (x *ExpirationTimerChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpirationTimerChatUpdate.ProtoReflect.Descriptor instead. func (*ExpirationTimerChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{37} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{38} } func (x *ExpirationTimerChatUpdate) GetExpiresInMs() uint64 { @@ -5859,7 +5911,7 @@ type ProfileChangeChatUpdate struct { func (x *ProfileChangeChatUpdate) Reset() { *x = ProfileChangeChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[38] + mi := &file_backuppb_Backup_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5871,7 +5923,7 @@ func (x *ProfileChangeChatUpdate) String() string { func (*ProfileChangeChatUpdate) ProtoMessage() {} func (x *ProfileChangeChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[38] + mi := &file_backuppb_Backup_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5884,7 +5936,7 @@ func (x *ProfileChangeChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ProfileChangeChatUpdate.ProtoReflect.Descriptor instead. func (*ProfileChangeChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{38} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{39} } func (x *ProfileChangeChatUpdate) GetPreviousName() string { @@ -5916,7 +5968,7 @@ type LearnedProfileChatUpdate struct { func (x *LearnedProfileChatUpdate) Reset() { *x = LearnedProfileChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[39] + mi := &file_backuppb_Backup_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5928,7 +5980,7 @@ func (x *LearnedProfileChatUpdate) String() string { func (*LearnedProfileChatUpdate) ProtoMessage() {} func (x *LearnedProfileChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[39] + mi := &file_backuppb_Backup_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5941,7 +5993,7 @@ func (x *LearnedProfileChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use LearnedProfileChatUpdate.ProtoReflect.Descriptor instead. func (*LearnedProfileChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{39} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{40} } func (x *LearnedProfileChatUpdate) GetPreviousName() isLearnedProfileChatUpdate_PreviousName { @@ -5994,7 +6046,7 @@ type ThreadMergeChatUpdate struct { func (x *ThreadMergeChatUpdate) Reset() { *x = ThreadMergeChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[40] + mi := &file_backuppb_Backup_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6006,7 +6058,7 @@ func (x *ThreadMergeChatUpdate) String() string { func (*ThreadMergeChatUpdate) ProtoMessage() {} func (x *ThreadMergeChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[40] + mi := &file_backuppb_Backup_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6019,7 +6071,7 @@ func (x *ThreadMergeChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ThreadMergeChatUpdate.ProtoReflect.Descriptor instead. func (*ThreadMergeChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{40} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{41} } func (x *ThreadMergeChatUpdate) GetPreviousE164() uint64 { @@ -6038,7 +6090,7 @@ type SessionSwitchoverChatUpdate struct { func (x *SessionSwitchoverChatUpdate) Reset() { *x = SessionSwitchoverChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[41] + mi := &file_backuppb_Backup_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6050,7 +6102,7 @@ func (x *SessionSwitchoverChatUpdate) String() string { func (*SessionSwitchoverChatUpdate) ProtoMessage() {} func (x *SessionSwitchoverChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[41] + mi := &file_backuppb_Backup_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6063,7 +6115,7 @@ func (x *SessionSwitchoverChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionSwitchoverChatUpdate.ProtoReflect.Descriptor instead. func (*SessionSwitchoverChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{41} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{42} } func (x *SessionSwitchoverChatUpdate) GetE164() uint64 { @@ -6084,7 +6136,7 @@ type GroupChangeChatUpdate struct { func (x *GroupChangeChatUpdate) Reset() { *x = GroupChangeChatUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[42] + mi := &file_backuppb_Backup_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6096,7 +6148,7 @@ func (x *GroupChangeChatUpdate) String() string { func (*GroupChangeChatUpdate) ProtoMessage() {} func (x *GroupChangeChatUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[42] + mi := &file_backuppb_Backup_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6109,7 +6161,7 @@ func (x *GroupChangeChatUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChangeChatUpdate.ProtoReflect.Descriptor instead. func (*GroupChangeChatUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{42} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{43} } func (x *GroupChangeChatUpdate) GetUpdates() []*GroupChangeChatUpdate_Update { @@ -6128,7 +6180,7 @@ type GenericGroupUpdate struct { func (x *GenericGroupUpdate) Reset() { *x = GenericGroupUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[43] + mi := &file_backuppb_Backup_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6140,7 +6192,7 @@ func (x *GenericGroupUpdate) String() string { func (*GenericGroupUpdate) ProtoMessage() {} func (x *GenericGroupUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[43] + mi := &file_backuppb_Backup_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6153,7 +6205,7 @@ func (x *GenericGroupUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GenericGroupUpdate.ProtoReflect.Descriptor instead. func (*GenericGroupUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{43} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{44} } func (x *GenericGroupUpdate) GetUpdaterAci() []byte { @@ -6172,7 +6224,7 @@ type GroupCreationUpdate struct { func (x *GroupCreationUpdate) Reset() { *x = GroupCreationUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[44] + mi := &file_backuppb_Backup_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6184,7 +6236,7 @@ func (x *GroupCreationUpdate) String() string { func (*GroupCreationUpdate) ProtoMessage() {} func (x *GroupCreationUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[44] + mi := &file_backuppb_Backup_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6197,7 +6249,7 @@ func (x *GroupCreationUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupCreationUpdate.ProtoReflect.Descriptor instead. func (*GroupCreationUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{44} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{45} } func (x *GroupCreationUpdate) GetUpdaterAci() []byte { @@ -6218,7 +6270,7 @@ type GroupNameUpdate struct { func (x *GroupNameUpdate) Reset() { *x = GroupNameUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[45] + mi := &file_backuppb_Backup_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6230,7 +6282,7 @@ func (x *GroupNameUpdate) String() string { func (*GroupNameUpdate) ProtoMessage() {} func (x *GroupNameUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[45] + mi := &file_backuppb_Backup_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6243,7 +6295,7 @@ func (x *GroupNameUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupNameUpdate.ProtoReflect.Descriptor instead. func (*GroupNameUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{45} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{46} } func (x *GroupNameUpdate) GetUpdaterAci() []byte { @@ -6270,7 +6322,7 @@ type GroupAvatarUpdate struct { func (x *GroupAvatarUpdate) Reset() { *x = GroupAvatarUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[46] + mi := &file_backuppb_Backup_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6282,7 +6334,7 @@ func (x *GroupAvatarUpdate) String() string { func (*GroupAvatarUpdate) ProtoMessage() {} func (x *GroupAvatarUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[46] + mi := &file_backuppb_Backup_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6295,7 +6347,7 @@ func (x *GroupAvatarUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupAvatarUpdate.ProtoReflect.Descriptor instead. func (*GroupAvatarUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{46} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{47} } func (x *GroupAvatarUpdate) GetUpdaterAci() []byte { @@ -6323,7 +6375,7 @@ type GroupDescriptionUpdate struct { func (x *GroupDescriptionUpdate) Reset() { *x = GroupDescriptionUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[47] + mi := &file_backuppb_Backup_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6335,7 +6387,7 @@ func (x *GroupDescriptionUpdate) String() string { func (*GroupDescriptionUpdate) ProtoMessage() {} func (x *GroupDescriptionUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[47] + mi := &file_backuppb_Backup_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6348,7 +6400,7 @@ func (x *GroupDescriptionUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupDescriptionUpdate.ProtoReflect.Descriptor instead. func (*GroupDescriptionUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{47} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{48} } func (x *GroupDescriptionUpdate) GetUpdaterAci() []byte { @@ -6375,7 +6427,7 @@ type GroupMembershipAccessLevelChangeUpdate struct { func (x *GroupMembershipAccessLevelChangeUpdate) Reset() { *x = GroupMembershipAccessLevelChangeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[48] + mi := &file_backuppb_Backup_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6387,7 +6439,7 @@ func (x *GroupMembershipAccessLevelChangeUpdate) String() string { func (*GroupMembershipAccessLevelChangeUpdate) ProtoMessage() {} func (x *GroupMembershipAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[48] + mi := &file_backuppb_Backup_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6400,7 +6452,7 @@ func (x *GroupMembershipAccessLevelChangeUpdate) ProtoReflect() protoreflect.Mes // Deprecated: Use GroupMembershipAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. func (*GroupMembershipAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{48} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{49} } func (x *GroupMembershipAccessLevelChangeUpdate) GetUpdaterAci() []byte { @@ -6427,7 +6479,7 @@ type GroupAttributesAccessLevelChangeUpdate struct { func (x *GroupAttributesAccessLevelChangeUpdate) Reset() { *x = GroupAttributesAccessLevelChangeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[49] + mi := &file_backuppb_Backup_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6439,7 +6491,7 @@ func (x *GroupAttributesAccessLevelChangeUpdate) String() string { func (*GroupAttributesAccessLevelChangeUpdate) ProtoMessage() {} func (x *GroupAttributesAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[49] + mi := &file_backuppb_Backup_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6452,7 +6504,7 @@ func (x *GroupAttributesAccessLevelChangeUpdate) ProtoReflect() protoreflect.Mes // Deprecated: Use GroupAttributesAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. func (*GroupAttributesAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{49} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{50} } func (x *GroupAttributesAccessLevelChangeUpdate) GetUpdaterAci() []byte { @@ -6469,6 +6521,102 @@ func (x *GroupAttributesAccessLevelChangeUpdate) GetAccessLevel() GroupV2AccessL return GroupV2AccessLevel_UNKNOWN } +type GroupMemberLabelAccessLevelChangeUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + AccessLevel GroupV2AccessLevel `protobuf:"varint,2,opt,name=accessLevel,proto3,enum=signal.backup.GroupV2AccessLevel" json:"accessLevel,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupMemberLabelAccessLevelChangeUpdate) Reset() { + *x = GroupMemberLabelAccessLevelChangeUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupMemberLabelAccessLevelChangeUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupMemberLabelAccessLevelChangeUpdate) ProtoMessage() {} + +func (x *GroupMemberLabelAccessLevelChangeUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[51] + 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 GroupMemberLabelAccessLevelChangeUpdate.ProtoReflect.Descriptor instead. +func (*GroupMemberLabelAccessLevelChangeUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{51} +} + +func (x *GroupMemberLabelAccessLevelChangeUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + +func (x *GroupMemberLabelAccessLevelChangeUpdate) GetAccessLevel() GroupV2AccessLevel { + if x != nil { + return x.AccessLevel + } + return GroupV2AccessLevel_UNKNOWN +} + +type GroupTerminateChangeUpdate struct { + state protoimpl.MessageState `protogen:"open.v1"` + UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupTerminateChangeUpdate) Reset() { + *x = GroupTerminateChangeUpdate{} + mi := &file_backuppb_Backup_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupTerminateChangeUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupTerminateChangeUpdate) ProtoMessage() {} + +func (x *GroupTerminateChangeUpdate) ProtoReflect() protoreflect.Message { + mi := &file_backuppb_Backup_proto_msgTypes[52] + 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 GroupTerminateChangeUpdate.ProtoReflect.Descriptor instead. +func (*GroupTerminateChangeUpdate) Descriptor() ([]byte, []int) { + return file_backuppb_Backup_proto_rawDescGZIP(), []int{52} +} + +func (x *GroupTerminateChangeUpdate) GetUpdaterAci() []byte { + if x != nil { + return x.UpdaterAci + } + return nil +} + type GroupAnnouncementOnlyChangeUpdate struct { state protoimpl.MessageState `protogen:"open.v1"` UpdaterAci []byte `protobuf:"bytes,1,opt,name=updaterAci,proto3,oneof" json:"updaterAci,omitempty"` @@ -6479,7 +6627,7 @@ type GroupAnnouncementOnlyChangeUpdate struct { func (x *GroupAnnouncementOnlyChangeUpdate) Reset() { *x = GroupAnnouncementOnlyChangeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[50] + mi := &file_backuppb_Backup_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6491,7 +6639,7 @@ func (x *GroupAnnouncementOnlyChangeUpdate) String() string { func (*GroupAnnouncementOnlyChangeUpdate) ProtoMessage() {} func (x *GroupAnnouncementOnlyChangeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[50] + mi := &file_backuppb_Backup_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6504,7 +6652,7 @@ func (x *GroupAnnouncementOnlyChangeUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use GroupAnnouncementOnlyChangeUpdate.ProtoReflect.Descriptor instead. func (*GroupAnnouncementOnlyChangeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{50} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{53} } func (x *GroupAnnouncementOnlyChangeUpdate) GetUpdaterAci() []byte { @@ -6533,7 +6681,7 @@ type GroupAdminStatusUpdate struct { func (x *GroupAdminStatusUpdate) Reset() { *x = GroupAdminStatusUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[51] + mi := &file_backuppb_Backup_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6545,7 +6693,7 @@ func (x *GroupAdminStatusUpdate) String() string { func (*GroupAdminStatusUpdate) ProtoMessage() {} func (x *GroupAdminStatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[51] + mi := &file_backuppb_Backup_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6558,7 +6706,7 @@ func (x *GroupAdminStatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupAdminStatusUpdate.ProtoReflect.Descriptor instead. func (*GroupAdminStatusUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{51} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{54} } func (x *GroupAdminStatusUpdate) GetUpdaterAci() []byte { @@ -6591,7 +6739,7 @@ type GroupMemberLeftUpdate struct { func (x *GroupMemberLeftUpdate) Reset() { *x = GroupMemberLeftUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[52] + mi := &file_backuppb_Backup_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6603,7 +6751,7 @@ func (x *GroupMemberLeftUpdate) String() string { func (*GroupMemberLeftUpdate) ProtoMessage() {} func (x *GroupMemberLeftUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[52] + mi := &file_backuppb_Backup_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6616,7 +6764,7 @@ func (x *GroupMemberLeftUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberLeftUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberLeftUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{52} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{55} } func (x *GroupMemberLeftUpdate) GetAci() []byte { @@ -6636,7 +6784,7 @@ type GroupMemberRemovedUpdate struct { func (x *GroupMemberRemovedUpdate) Reset() { *x = GroupMemberRemovedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[53] + mi := &file_backuppb_Backup_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6648,7 +6796,7 @@ func (x *GroupMemberRemovedUpdate) String() string { func (*GroupMemberRemovedUpdate) ProtoMessage() {} func (x *GroupMemberRemovedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[53] + mi := &file_backuppb_Backup_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6661,7 +6809,7 @@ func (x *GroupMemberRemovedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberRemovedUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberRemovedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{53} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{56} } func (x *GroupMemberRemovedUpdate) GetRemoverAci() []byte { @@ -6687,7 +6835,7 @@ type SelfInvitedToGroupUpdate struct { func (x *SelfInvitedToGroupUpdate) Reset() { *x = SelfInvitedToGroupUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[54] + mi := &file_backuppb_Backup_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6699,7 +6847,7 @@ func (x *SelfInvitedToGroupUpdate) String() string { func (*SelfInvitedToGroupUpdate) ProtoMessage() {} func (x *SelfInvitedToGroupUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[54] + mi := &file_backuppb_Backup_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6712,7 +6860,7 @@ func (x *SelfInvitedToGroupUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use SelfInvitedToGroupUpdate.ProtoReflect.Descriptor instead. func (*SelfInvitedToGroupUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{54} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{57} } func (x *SelfInvitedToGroupUpdate) GetInviterAci() []byte { @@ -6732,7 +6880,7 @@ type SelfInvitedOtherUserToGroupUpdate struct { func (x *SelfInvitedOtherUserToGroupUpdate) Reset() { *x = SelfInvitedOtherUserToGroupUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[55] + mi := &file_backuppb_Backup_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6744,7 +6892,7 @@ func (x *SelfInvitedOtherUserToGroupUpdate) String() string { func (*SelfInvitedOtherUserToGroupUpdate) ProtoMessage() {} func (x *SelfInvitedOtherUserToGroupUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[55] + mi := &file_backuppb_Backup_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6757,7 +6905,7 @@ func (x *SelfInvitedOtherUserToGroupUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use SelfInvitedOtherUserToGroupUpdate.ProtoReflect.Descriptor instead. func (*SelfInvitedOtherUserToGroupUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{55} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{58} } func (x *SelfInvitedOtherUserToGroupUpdate) GetInviteeServiceId() []byte { @@ -6778,7 +6926,7 @@ type GroupUnknownInviteeUpdate struct { func (x *GroupUnknownInviteeUpdate) Reset() { *x = GroupUnknownInviteeUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[56] + mi := &file_backuppb_Backup_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6790,7 +6938,7 @@ func (x *GroupUnknownInviteeUpdate) String() string { func (*GroupUnknownInviteeUpdate) ProtoMessage() {} func (x *GroupUnknownInviteeUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[56] + mi := &file_backuppb_Backup_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6803,7 +6951,7 @@ func (x *GroupUnknownInviteeUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupUnknownInviteeUpdate.ProtoReflect.Descriptor instead. func (*GroupUnknownInviteeUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{56} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{59} } func (x *GroupUnknownInviteeUpdate) GetInviterAci() []byte { @@ -6830,7 +6978,7 @@ type GroupInvitationAcceptedUpdate struct { func (x *GroupInvitationAcceptedUpdate) Reset() { *x = GroupInvitationAcceptedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[57] + mi := &file_backuppb_Backup_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6842,7 +6990,7 @@ func (x *GroupInvitationAcceptedUpdate) String() string { func (*GroupInvitationAcceptedUpdate) ProtoMessage() {} func (x *GroupInvitationAcceptedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[57] + mi := &file_backuppb_Backup_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6855,7 +7003,7 @@ func (x *GroupInvitationAcceptedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInvitationAcceptedUpdate.ProtoReflect.Descriptor instead. func (*GroupInvitationAcceptedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{57} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{60} } func (x *GroupInvitationAcceptedUpdate) GetInviterAci() []byte { @@ -6883,7 +7031,7 @@ type GroupInvitationDeclinedUpdate struct { func (x *GroupInvitationDeclinedUpdate) Reset() { *x = GroupInvitationDeclinedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[58] + mi := &file_backuppb_Backup_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6895,7 +7043,7 @@ func (x *GroupInvitationDeclinedUpdate) String() string { func (*GroupInvitationDeclinedUpdate) ProtoMessage() {} func (x *GroupInvitationDeclinedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[58] + mi := &file_backuppb_Backup_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6908,7 +7056,7 @@ func (x *GroupInvitationDeclinedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInvitationDeclinedUpdate.ProtoReflect.Descriptor instead. func (*GroupInvitationDeclinedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{58} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{61} } func (x *GroupInvitationDeclinedUpdate) GetInviterAci() []byte { @@ -6934,7 +7082,7 @@ type GroupMemberJoinedUpdate struct { func (x *GroupMemberJoinedUpdate) Reset() { *x = GroupMemberJoinedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[59] + mi := &file_backuppb_Backup_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6946,7 +7094,7 @@ func (x *GroupMemberJoinedUpdate) String() string { func (*GroupMemberJoinedUpdate) ProtoMessage() {} func (x *GroupMemberJoinedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[59] + mi := &file_backuppb_Backup_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6959,7 +7107,7 @@ func (x *GroupMemberJoinedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberJoinedUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberJoinedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{59} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{62} } func (x *GroupMemberJoinedUpdate) GetNewMemberAci() []byte { @@ -6982,7 +7130,7 @@ type GroupMemberAddedUpdate struct { func (x *GroupMemberAddedUpdate) Reset() { *x = GroupMemberAddedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[60] + mi := &file_backuppb_Backup_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6994,7 +7142,7 @@ func (x *GroupMemberAddedUpdate) String() string { func (*GroupMemberAddedUpdate) ProtoMessage() {} func (x *GroupMemberAddedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[60] + mi := &file_backuppb_Backup_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7007,7 +7155,7 @@ func (x *GroupMemberAddedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberAddedUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberAddedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{60} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{63} } func (x *GroupMemberAddedUpdate) GetUpdaterAci() []byte { @@ -7048,7 +7196,7 @@ type GroupSelfInvitationRevokedUpdate struct { func (x *GroupSelfInvitationRevokedUpdate) Reset() { *x = GroupSelfInvitationRevokedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[61] + mi := &file_backuppb_Backup_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7060,7 +7208,7 @@ func (x *GroupSelfInvitationRevokedUpdate) String() string { func (*GroupSelfInvitationRevokedUpdate) ProtoMessage() {} func (x *GroupSelfInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[61] + mi := &file_backuppb_Backup_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7073,7 +7221,7 @@ func (x *GroupSelfInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupSelfInvitationRevokedUpdate.ProtoReflect.Descriptor instead. func (*GroupSelfInvitationRevokedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{61} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{64} } func (x *GroupSelfInvitationRevokedUpdate) GetRevokerAci() []byte { @@ -7099,7 +7247,7 @@ type GroupInvitationRevokedUpdate struct { func (x *GroupInvitationRevokedUpdate) Reset() { *x = GroupInvitationRevokedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[62] + mi := &file_backuppb_Backup_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7111,7 +7259,7 @@ func (x *GroupInvitationRevokedUpdate) String() string { func (*GroupInvitationRevokedUpdate) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[62] + mi := &file_backuppb_Backup_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7124,7 +7272,7 @@ func (x *GroupInvitationRevokedUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInvitationRevokedUpdate.ProtoReflect.Descriptor instead. func (*GroupInvitationRevokedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{62} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{65} } func (x *GroupInvitationRevokedUpdate) GetUpdaterAci() []byte { @@ -7150,7 +7298,7 @@ type GroupJoinRequestUpdate struct { func (x *GroupJoinRequestUpdate) Reset() { *x = GroupJoinRequestUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[63] + mi := &file_backuppb_Backup_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7162,7 +7310,7 @@ func (x *GroupJoinRequestUpdate) String() string { func (*GroupJoinRequestUpdate) ProtoMessage() {} func (x *GroupJoinRequestUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[63] + mi := &file_backuppb_Backup_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7175,7 +7323,7 @@ func (x *GroupJoinRequestUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinRequestUpdate.ProtoReflect.Descriptor instead. func (*GroupJoinRequestUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{63} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{66} } func (x *GroupJoinRequestUpdate) GetRequestorAci() []byte { @@ -7197,7 +7345,7 @@ type GroupJoinRequestApprovalUpdate struct { func (x *GroupJoinRequestApprovalUpdate) Reset() { *x = GroupJoinRequestApprovalUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[64] + mi := &file_backuppb_Backup_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7209,7 +7357,7 @@ func (x *GroupJoinRequestApprovalUpdate) String() string { func (*GroupJoinRequestApprovalUpdate) ProtoMessage() {} func (x *GroupJoinRequestApprovalUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[64] + mi := &file_backuppb_Backup_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7222,7 +7370,7 @@ func (x *GroupJoinRequestApprovalUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinRequestApprovalUpdate.ProtoReflect.Descriptor instead. func (*GroupJoinRequestApprovalUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{64} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{67} } func (x *GroupJoinRequestApprovalUpdate) GetRequestorAci() []byte { @@ -7255,7 +7403,7 @@ type GroupJoinRequestCanceledUpdate struct { func (x *GroupJoinRequestCanceledUpdate) Reset() { *x = GroupJoinRequestCanceledUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[65] + mi := &file_backuppb_Backup_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7267,7 +7415,7 @@ func (x *GroupJoinRequestCanceledUpdate) String() string { func (*GroupJoinRequestCanceledUpdate) ProtoMessage() {} func (x *GroupJoinRequestCanceledUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[65] + mi := &file_backuppb_Backup_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7280,7 +7428,7 @@ func (x *GroupJoinRequestCanceledUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupJoinRequestCanceledUpdate.ProtoReflect.Descriptor instead. func (*GroupJoinRequestCanceledUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{65} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{68} } func (x *GroupJoinRequestCanceledUpdate) GetRequestorAci() []byte { @@ -7306,7 +7454,7 @@ type GroupSequenceOfRequestsAndCancelsUpdate struct { func (x *GroupSequenceOfRequestsAndCancelsUpdate) Reset() { *x = GroupSequenceOfRequestsAndCancelsUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[66] + mi := &file_backuppb_Backup_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7318,7 +7466,7 @@ func (x *GroupSequenceOfRequestsAndCancelsUpdate) String() string { func (*GroupSequenceOfRequestsAndCancelsUpdate) ProtoMessage() {} func (x *GroupSequenceOfRequestsAndCancelsUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[66] + mi := &file_backuppb_Backup_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7331,7 +7479,7 @@ func (x *GroupSequenceOfRequestsAndCancelsUpdate) ProtoReflect() protoreflect.Me // Deprecated: Use GroupSequenceOfRequestsAndCancelsUpdate.ProtoReflect.Descriptor instead. func (*GroupSequenceOfRequestsAndCancelsUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{66} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{69} } func (x *GroupSequenceOfRequestsAndCancelsUpdate) GetRequestorAci() []byte { @@ -7357,7 +7505,7 @@ type GroupInviteLinkResetUpdate struct { func (x *GroupInviteLinkResetUpdate) Reset() { *x = GroupInviteLinkResetUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[67] + mi := &file_backuppb_Backup_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7369,7 +7517,7 @@ func (x *GroupInviteLinkResetUpdate) String() string { func (*GroupInviteLinkResetUpdate) ProtoMessage() {} func (x *GroupInviteLinkResetUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[67] + mi := &file_backuppb_Backup_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7382,7 +7530,7 @@ func (x *GroupInviteLinkResetUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLinkResetUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkResetUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{67} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{70} } func (x *GroupInviteLinkResetUpdate) GetUpdaterAci() []byte { @@ -7402,7 +7550,7 @@ type GroupInviteLinkEnabledUpdate struct { func (x *GroupInviteLinkEnabledUpdate) Reset() { *x = GroupInviteLinkEnabledUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[68] + mi := &file_backuppb_Backup_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7414,7 +7562,7 @@ func (x *GroupInviteLinkEnabledUpdate) String() string { func (*GroupInviteLinkEnabledUpdate) ProtoMessage() {} func (x *GroupInviteLinkEnabledUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[68] + mi := &file_backuppb_Backup_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7427,7 +7575,7 @@ func (x *GroupInviteLinkEnabledUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLinkEnabledUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkEnabledUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{68} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{71} } func (x *GroupInviteLinkEnabledUpdate) GetUpdaterAci() []byte { @@ -7454,7 +7602,7 @@ type GroupInviteLinkAdminApprovalUpdate struct { func (x *GroupInviteLinkAdminApprovalUpdate) Reset() { *x = GroupInviteLinkAdminApprovalUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[69] + mi := &file_backuppb_Backup_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7466,7 +7614,7 @@ func (x *GroupInviteLinkAdminApprovalUpdate) String() string { func (*GroupInviteLinkAdminApprovalUpdate) ProtoMessage() {} func (x *GroupInviteLinkAdminApprovalUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[69] + mi := &file_backuppb_Backup_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7479,7 +7627,7 @@ func (x *GroupInviteLinkAdminApprovalUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use GroupInviteLinkAdminApprovalUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkAdminApprovalUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{69} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{72} } func (x *GroupInviteLinkAdminApprovalUpdate) GetUpdaterAci() []byte { @@ -7505,7 +7653,7 @@ type GroupInviteLinkDisabledUpdate struct { func (x *GroupInviteLinkDisabledUpdate) Reset() { *x = GroupInviteLinkDisabledUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[70] + mi := &file_backuppb_Backup_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7517,7 +7665,7 @@ func (x *GroupInviteLinkDisabledUpdate) String() string { func (*GroupInviteLinkDisabledUpdate) ProtoMessage() {} func (x *GroupInviteLinkDisabledUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[70] + mi := &file_backuppb_Backup_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7530,7 +7678,7 @@ func (x *GroupInviteLinkDisabledUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupInviteLinkDisabledUpdate.ProtoReflect.Descriptor instead. func (*GroupInviteLinkDisabledUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{70} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{73} } func (x *GroupInviteLinkDisabledUpdate) GetUpdaterAci() []byte { @@ -7549,7 +7697,7 @@ type GroupMemberJoinedByLinkUpdate struct { func (x *GroupMemberJoinedByLinkUpdate) Reset() { *x = GroupMemberJoinedByLinkUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[71] + mi := &file_backuppb_Backup_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7561,7 +7709,7 @@ func (x *GroupMemberJoinedByLinkUpdate) String() string { func (*GroupMemberJoinedByLinkUpdate) ProtoMessage() {} func (x *GroupMemberJoinedByLinkUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[71] + mi := &file_backuppb_Backup_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7574,7 +7722,7 @@ func (x *GroupMemberJoinedByLinkUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupMemberJoinedByLinkUpdate.ProtoReflect.Descriptor instead. func (*GroupMemberJoinedByLinkUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{71} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{74} } func (x *GroupMemberJoinedByLinkUpdate) GetNewMemberAci() []byte { @@ -7593,7 +7741,7 @@ type GroupV2MigrationUpdate struct { func (x *GroupV2MigrationUpdate) Reset() { *x = GroupV2MigrationUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[72] + mi := &file_backuppb_Backup_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7605,7 +7753,7 @@ func (x *GroupV2MigrationUpdate) String() string { func (*GroupV2MigrationUpdate) ProtoMessage() {} func (x *GroupV2MigrationUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[72] + mi := &file_backuppb_Backup_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7618,7 +7766,7 @@ func (x *GroupV2MigrationUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupV2MigrationUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{72} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{75} } // Another user migrated gv1->gv2 but was unable to add @@ -7631,7 +7779,7 @@ type GroupV2MigrationSelfInvitedUpdate struct { func (x *GroupV2MigrationSelfInvitedUpdate) Reset() { *x = GroupV2MigrationSelfInvitedUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[73] + mi := &file_backuppb_Backup_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7643,7 +7791,7 @@ func (x *GroupV2MigrationSelfInvitedUpdate) String() string { func (*GroupV2MigrationSelfInvitedUpdate) ProtoMessage() {} func (x *GroupV2MigrationSelfInvitedUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[73] + mi := &file_backuppb_Backup_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7656,7 +7804,7 @@ func (x *GroupV2MigrationSelfInvitedUpdate) ProtoReflect() protoreflect.Message // Deprecated: Use GroupV2MigrationSelfInvitedUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationSelfInvitedUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{73} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{76} } // The local user migrated gv1->gv2 but was unable to @@ -7671,7 +7819,7 @@ type GroupV2MigrationInvitedMembersUpdate struct { func (x *GroupV2MigrationInvitedMembersUpdate) Reset() { *x = GroupV2MigrationInvitedMembersUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[74] + mi := &file_backuppb_Backup_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7683,7 +7831,7 @@ func (x *GroupV2MigrationInvitedMembersUpdate) String() string { func (*GroupV2MigrationInvitedMembersUpdate) ProtoMessage() {} func (x *GroupV2MigrationInvitedMembersUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[74] + mi := &file_backuppb_Backup_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7696,7 +7844,7 @@ func (x *GroupV2MigrationInvitedMembersUpdate) ProtoReflect() protoreflect.Messa // Deprecated: Use GroupV2MigrationInvitedMembersUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationInvitedMembersUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{74} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{77} } func (x *GroupV2MigrationInvitedMembersUpdate) GetInvitedMembersCount() uint32 { @@ -7718,7 +7866,7 @@ type GroupV2MigrationDroppedMembersUpdate struct { func (x *GroupV2MigrationDroppedMembersUpdate) Reset() { *x = GroupV2MigrationDroppedMembersUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[75] + mi := &file_backuppb_Backup_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7730,7 +7878,7 @@ func (x *GroupV2MigrationDroppedMembersUpdate) String() string { func (*GroupV2MigrationDroppedMembersUpdate) ProtoMessage() {} func (x *GroupV2MigrationDroppedMembersUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[75] + mi := &file_backuppb_Backup_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7743,7 +7891,7 @@ func (x *GroupV2MigrationDroppedMembersUpdate) ProtoReflect() protoreflect.Messa // Deprecated: Use GroupV2MigrationDroppedMembersUpdate.ProtoReflect.Descriptor instead. func (*GroupV2MigrationDroppedMembersUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{75} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} } func (x *GroupV2MigrationDroppedMembersUpdate) GetDroppedMembersCount() uint32 { @@ -7764,7 +7912,7 @@ type GroupExpirationTimerUpdate struct { func (x *GroupExpirationTimerUpdate) Reset() { *x = GroupExpirationTimerUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[76] + mi := &file_backuppb_Backup_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7776,7 +7924,7 @@ func (x *GroupExpirationTimerUpdate) String() string { func (*GroupExpirationTimerUpdate) ProtoMessage() {} func (x *GroupExpirationTimerUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[76] + mi := &file_backuppb_Backup_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7789,7 +7937,7 @@ func (x *GroupExpirationTimerUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupExpirationTimerUpdate.ProtoReflect.Descriptor instead. func (*GroupExpirationTimerUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{76} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} } func (x *GroupExpirationTimerUpdate) GetExpiresInMs() uint64 { @@ -7816,7 +7964,7 @@ type PollTerminateUpdate struct { func (x *PollTerminateUpdate) Reset() { *x = PollTerminateUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[77] + mi := &file_backuppb_Backup_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7828,7 +7976,7 @@ func (x *PollTerminateUpdate) String() string { func (*PollTerminateUpdate) ProtoMessage() {} func (x *PollTerminateUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[77] + mi := &file_backuppb_Backup_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7841,7 +7989,7 @@ func (x *PollTerminateUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use PollTerminateUpdate.ProtoReflect.Descriptor instead. func (*PollTerminateUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{77} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{80} } func (x *PollTerminateUpdate) GetTargetSentTimestamp() uint64 { @@ -7868,7 +8016,7 @@ type PinMessageUpdate struct { func (x *PinMessageUpdate) Reset() { *x = PinMessageUpdate{} - mi := &file_backuppb_Backup_proto_msgTypes[78] + mi := &file_backuppb_Backup_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7880,7 +8028,7 @@ func (x *PinMessageUpdate) String() string { func (*PinMessageUpdate) ProtoMessage() {} func (x *PinMessageUpdate) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[78] + mi := &file_backuppb_Backup_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7893,7 +8041,7 @@ func (x *PinMessageUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use PinMessageUpdate.ProtoReflect.Descriptor instead. func (*PinMessageUpdate) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{78} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{81} } func (x *PinMessageUpdate) GetTargetSentTimestamp() uint64 { @@ -7920,7 +8068,7 @@ type StickerPack struct { func (x *StickerPack) Reset() { *x = StickerPack{} - mi := &file_backuppb_Backup_proto_msgTypes[79] + mi := &file_backuppb_Backup_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7932,7 +8080,7 @@ func (x *StickerPack) String() string { func (*StickerPack) ProtoMessage() {} func (x *StickerPack) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[79] + mi := &file_backuppb_Backup_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7945,7 +8093,7 @@ func (x *StickerPack) ProtoReflect() protoreflect.Message { // Deprecated: Use StickerPack.ProtoReflect.Descriptor instead. func (*StickerPack) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{79} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{82} } func (x *StickerPack) GetPackId() []byte { @@ -7986,7 +8134,7 @@ type ChatStyle struct { func (x *ChatStyle) Reset() { *x = ChatStyle{} - mi := &file_backuppb_Backup_proto_msgTypes[80] + mi := &file_backuppb_Backup_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7998,7 +8146,7 @@ func (x *ChatStyle) String() string { func (*ChatStyle) ProtoMessage() {} func (x *ChatStyle) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[80] + mi := &file_backuppb_Backup_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8011,7 +8159,7 @@ func (x *ChatStyle) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle.ProtoReflect.Descriptor instead. func (*ChatStyle) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{83} } func (x *ChatStyle) GetWallpaper() isChatStyle_Wallpaper { @@ -8143,7 +8291,7 @@ type NotificationProfile struct { func (x *NotificationProfile) Reset() { *x = NotificationProfile{} - mi := &file_backuppb_Backup_proto_msgTypes[81] + mi := &file_backuppb_Backup_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8155,7 +8303,7 @@ func (x *NotificationProfile) String() string { func (*NotificationProfile) ProtoMessage() {} func (x *NotificationProfile) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[81] + mi := &file_backuppb_Backup_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8168,7 +8316,7 @@ func (x *NotificationProfile) ProtoReflect() protoreflect.Message { // Deprecated: Use NotificationProfile.ProtoReflect.Descriptor instead. func (*NotificationProfile) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{81} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{84} } func (x *NotificationProfile) GetName() string { @@ -8274,7 +8422,7 @@ type ChatFolder struct { func (x *ChatFolder) Reset() { *x = ChatFolder{} - mi := &file_backuppb_Backup_proto_msgTypes[82] + mi := &file_backuppb_Backup_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8286,7 +8434,7 @@ func (x *ChatFolder) String() string { func (*ChatFolder) ProtoMessage() {} func (x *ChatFolder) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[82] + mi := &file_backuppb_Backup_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8299,7 +8447,7 @@ func (x *ChatFolder) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatFolder.ProtoReflect.Descriptor instead. func (*ChatFolder) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{82} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{85} } func (x *ChatFolder) GetName() string { @@ -8376,7 +8524,7 @@ type AccountData_UsernameLink struct { func (x *AccountData_UsernameLink) Reset() { *x = AccountData_UsernameLink{} - mi := &file_backuppb_Backup_proto_msgTypes[83] + mi := &file_backuppb_Backup_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8388,7 +8536,7 @@ func (x *AccountData_UsernameLink) String() string { func (*AccountData_UsernameLink) ProtoMessage() {} func (x *AccountData_UsernameLink) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[83] + mi := &file_backuppb_Backup_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8437,7 +8585,7 @@ type AccountData_AutoDownloadSettings struct { func (x *AccountData_AutoDownloadSettings) Reset() { *x = AccountData_AutoDownloadSettings{} - mi := &file_backuppb_Backup_proto_msgTypes[84] + mi := &file_backuppb_Backup_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8449,7 +8597,7 @@ func (x *AccountData_AutoDownloadSettings) String() string { func (*AccountData_AutoDownloadSettings) ProtoMessage() {} func (x *AccountData_AutoDownloadSettings) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[84] + mi := &file_backuppb_Backup_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8516,22 +8664,23 @@ type AccountData_AccountSettings struct { CustomChatColors []*ChatStyle_CustomChatColor `protobuf:"bytes,19,rep,name=customChatColors,proto3" json:"customChatColors,omitempty"` OptimizeOnDeviceStorage bool `protobuf:"varint,20,opt,name=optimizeOnDeviceStorage,proto3" json:"optimizeOnDeviceStorage,omitempty"` // See zkgroup for integer particular values. Unset if backups are not enabled. - BackupTier *uint64 `protobuf:"varint,21,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` - DefaultSentMediaQuality AccountData_SentMediaQuality `protobuf:"varint,23,opt,name=defaultSentMediaQuality,proto3,enum=signal.backup.AccountData_SentMediaQuality" json:"defaultSentMediaQuality,omitempty"` - AutoDownloadSettings *AccountData_AutoDownloadSettings `protobuf:"bytes,24,opt,name=autoDownloadSettings,proto3" json:"autoDownloadSettings,omitempty"` - ScreenLockTimeoutMinutes *uint32 `protobuf:"varint,26,opt,name=screenLockTimeoutMinutes,proto3,oneof" json:"screenLockTimeoutMinutes,omitempty"` // If unset, consider screen lock to be disabled. - PinReminders *bool `protobuf:"varint,27,opt,name=pinReminders,proto3,oneof" json:"pinReminders,omitempty"` // If unset, consider pin reminders to be enabled. - AppTheme AccountData_AppTheme `protobuf:"varint,28,opt,name=appTheme,proto3,enum=signal.backup.AccountData_AppTheme" json:"appTheme,omitempty"` // If unset, treat the same as "Unknown" case - CallsUseLessDataSetting AccountData_CallsUseLessDataSetting `protobuf:"varint,29,opt,name=callsUseLessDataSetting,proto3,enum=signal.backup.AccountData_CallsUseLessDataSetting" json:"callsUseLessDataSetting,omitempty"` // If unset, treat the same as "Unknown" case - AllowSealedSenderFromAnyone bool `protobuf:"varint,30,opt,name=allowSealedSenderFromAnyone,proto3" json:"allowSealedSenderFromAnyone,omitempty"` - AllowAutomaticKeyVerification bool `protobuf:"varint,31,opt,name=allowAutomaticKeyVerification,proto3" json:"allowAutomaticKeyVerification,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + BackupTier *uint64 `protobuf:"varint,21,opt,name=backupTier,proto3,oneof" json:"backupTier,omitempty"` + DefaultSentMediaQuality AccountData_SentMediaQuality `protobuf:"varint,23,opt,name=defaultSentMediaQuality,proto3,enum=signal.backup.AccountData_SentMediaQuality" json:"defaultSentMediaQuality,omitempty"` + AutoDownloadSettings *AccountData_AutoDownloadSettings `protobuf:"bytes,24,opt,name=autoDownloadSettings,proto3" json:"autoDownloadSettings,omitempty"` + ScreenLockTimeoutMinutes *uint32 `protobuf:"varint,26,opt,name=screenLockTimeoutMinutes,proto3,oneof" json:"screenLockTimeoutMinutes,omitempty"` // If unset, consider screen lock to be disabled. + PinReminders *bool `protobuf:"varint,27,opt,name=pinReminders,proto3,oneof" json:"pinReminders,omitempty"` // If unset, consider pin reminders to be enabled. + AppTheme AccountData_AppTheme `protobuf:"varint,28,opt,name=appTheme,proto3,enum=signal.backup.AccountData_AppTheme" json:"appTheme,omitempty"` // If unset, treat the same as "Unknown" case + CallsUseLessDataSetting AccountData_CallsUseLessDataSetting `protobuf:"varint,29,opt,name=callsUseLessDataSetting,proto3,enum=signal.backup.AccountData_CallsUseLessDataSetting" json:"callsUseLessDataSetting,omitempty"` // If unset, treat the same as "Unknown" case + AllowSealedSenderFromAnyone bool `protobuf:"varint,30,opt,name=allowSealedSenderFromAnyone,proto3" json:"allowSealedSenderFromAnyone,omitempty"` + AllowAutomaticKeyVerification bool `protobuf:"varint,31,opt,name=allowAutomaticKeyVerification,proto3" json:"allowAutomaticKeyVerification,omitempty"` + HasSeenAdminDeleteEducationDialog bool `protobuf:"varint,32,opt,name=hasSeenAdminDeleteEducationDialog,proto3" json:"hasSeenAdminDeleteEducationDialog,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AccountData_AccountSettings) Reset() { *x = AccountData_AccountSettings{} - mi := &file_backuppb_Backup_proto_msgTypes[85] + mi := &file_backuppb_Backup_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8543,7 +8692,7 @@ func (x *AccountData_AccountSettings) String() string { func (*AccountData_AccountSettings) ProtoMessage() {} func (x *AccountData_AccountSettings) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[85] + mi := &file_backuppb_Backup_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8762,6 +8911,13 @@ func (x *AccountData_AccountSettings) GetAllowAutomaticKeyVerification() bool { return false } +func (x *AccountData_AccountSettings) GetHasSeenAdminDeleteEducationDialog() bool { + if x != nil { + return x.HasSeenAdminDeleteEducationDialog + } + return false +} + type AccountData_SubscriberData struct { state protoimpl.MessageState `protogen:"open.v1"` SubscriberId []byte `protobuf:"bytes,1,opt,name=subscriberId,proto3" json:"subscriberId,omitempty"` @@ -8773,7 +8929,7 @@ type AccountData_SubscriberData struct { func (x *AccountData_SubscriberData) Reset() { *x = AccountData_SubscriberData{} - mi := &file_backuppb_Backup_proto_msgTypes[86] + mi := &file_backuppb_Backup_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8785,7 +8941,7 @@ func (x *AccountData_SubscriberData) String() string { func (*AccountData_SubscriberData) ProtoMessage() {} func (x *AccountData_SubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[86] + mi := &file_backuppb_Backup_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8838,7 +8994,7 @@ type AccountData_IAPSubscriberData struct { func (x *AccountData_IAPSubscriberData) Reset() { *x = AccountData_IAPSubscriberData{} - mi := &file_backuppb_Backup_proto_msgTypes[87] + mi := &file_backuppb_Backup_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8850,7 +9006,7 @@ func (x *AccountData_IAPSubscriberData) String() string { func (*AccountData_IAPSubscriberData) ProtoMessage() {} func (x *AccountData_IAPSubscriberData) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[87] + mi := &file_backuppb_Backup_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8929,7 +9085,7 @@ type AccountData_AndroidSpecificSettings struct { func (x *AccountData_AndroidSpecificSettings) Reset() { *x = AccountData_AndroidSpecificSettings{} - mi := &file_backuppb_Backup_proto_msgTypes[88] + mi := &file_backuppb_Backup_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8941,7 +9097,7 @@ func (x *AccountData_AndroidSpecificSettings) String() string { func (*AccountData_AndroidSpecificSettings) ProtoMessage() {} func (x *AccountData_AndroidSpecificSettings) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[88] + mi := &file_backuppb_Backup_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8986,7 +9142,7 @@ type Contact_Registered struct { func (x *Contact_Registered) Reset() { *x = Contact_Registered{} - mi := &file_backuppb_Backup_proto_msgTypes[89] + mi := &file_backuppb_Backup_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8998,7 +9154,7 @@ func (x *Contact_Registered) String() string { func (*Contact_Registered) ProtoMessage() {} func (x *Contact_Registered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[89] + mi := &file_backuppb_Backup_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9023,7 +9179,7 @@ type Contact_NotRegistered struct { func (x *Contact_NotRegistered) Reset() { *x = Contact_NotRegistered{} - mi := &file_backuppb_Backup_proto_msgTypes[90] + mi := &file_backuppb_Backup_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9035,7 +9191,7 @@ func (x *Contact_NotRegistered) String() string { func (*Contact_NotRegistered) ProtoMessage() {} func (x *Contact_NotRegistered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[90] + mi := &file_backuppb_Backup_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9068,7 +9224,7 @@ type Contact_Name struct { func (x *Contact_Name) Reset() { *x = Contact_Name{} - mi := &file_backuppb_Backup_proto_msgTypes[91] + mi := &file_backuppb_Backup_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9080,7 +9236,7 @@ func (x *Contact_Name) String() string { func (*Contact_Name) ProtoMessage() {} func (x *Contact_Name) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[91] + mi := &file_backuppb_Backup_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9129,13 +9285,14 @@ type Group_GroupSnapshot struct { InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"` MembersBanned []*Group_MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"` + Terminated bool `protobuf:"varint,14,opt,name=terminated,proto3" json:"terminated,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Group_GroupSnapshot) Reset() { *x = Group_GroupSnapshot{} - mi := &file_backuppb_Backup_proto_msgTypes[92] + mi := &file_backuppb_Backup_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9147,7 +9304,7 @@ func (x *Group_GroupSnapshot) String() string { func (*Group_GroupSnapshot) ProtoMessage() {} func (x *Group_GroupSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[92] + mi := &file_backuppb_Backup_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9247,6 +9404,13 @@ func (x *Group_GroupSnapshot) GetMembersBanned() []*Group_MemberBanned { return nil } +func (x *Group_GroupSnapshot) GetTerminated() bool { + if x != nil { + return x.Terminated + } + return false +} + type Group_GroupAttributeBlob struct { state protoimpl.MessageState `protogen:"open.v1"` // If unset, consider the field it represents to not be present @@ -9264,7 +9428,7 @@ type Group_GroupAttributeBlob struct { func (x *Group_GroupAttributeBlob) Reset() { *x = Group_GroupAttributeBlob{} - mi := &file_backuppb_Backup_proto_msgTypes[93] + mi := &file_backuppb_Backup_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9276,7 +9440,7 @@ func (x *Group_GroupAttributeBlob) String() string { func (*Group_GroupAttributeBlob) ProtoMessage() {} func (x *Group_GroupAttributeBlob) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[93] + mi := &file_backuppb_Backup_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9368,13 +9532,15 @@ type Group_Member struct { UserId []byte `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` Role Group_Member_Role `protobuf:"varint,2,opt,name=role,proto3,enum=signal.backup.Group_Member_Role" json:"role,omitempty"` JoinedAtVersion uint32 `protobuf:"varint,5,opt,name=joinedAtVersion,proto3" json:"joinedAtVersion,omitempty"` + LabelEmoji string `protobuf:"bytes,6,opt,name=labelEmoji,proto3" json:"labelEmoji,omitempty"` + LabelString string `protobuf:"bytes,7,opt,name=labelString,proto3" json:"labelString,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Group_Member) Reset() { *x = Group_Member{} - mi := &file_backuppb_Backup_proto_msgTypes[94] + mi := &file_backuppb_Backup_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9386,7 +9552,7 @@ func (x *Group_Member) String() string { func (*Group_Member) ProtoMessage() {} func (x *Group_Member) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[94] + mi := &file_backuppb_Backup_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9423,6 +9589,20 @@ func (x *Group_Member) GetJoinedAtVersion() uint32 { return 0 } +func (x *Group_Member) GetLabelEmoji() string { + if x != nil { + return x.LabelEmoji + } + return "" +} + +func (x *Group_Member) GetLabelString() string { + if x != nil { + return x.LabelString + } + return "" +} + type Group_MemberPendingProfileKey struct { state protoimpl.MessageState `protogen:"open.v1"` Member *Group_Member `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` @@ -9434,7 +9614,7 @@ type Group_MemberPendingProfileKey struct { func (x *Group_MemberPendingProfileKey) Reset() { *x = Group_MemberPendingProfileKey{} - mi := &file_backuppb_Backup_proto_msgTypes[95] + mi := &file_backuppb_Backup_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9446,7 +9626,7 @@ func (x *Group_MemberPendingProfileKey) String() string { func (*Group_MemberPendingProfileKey) ProtoMessage() {} func (x *Group_MemberPendingProfileKey) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[95] + mi := &file_backuppb_Backup_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9493,7 +9673,7 @@ type Group_MemberPendingAdminApproval struct { func (x *Group_MemberPendingAdminApproval) Reset() { *x = Group_MemberPendingAdminApproval{} - mi := &file_backuppb_Backup_proto_msgTypes[96] + mi := &file_backuppb_Backup_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9505,7 +9685,7 @@ func (x *Group_MemberPendingAdminApproval) String() string { func (*Group_MemberPendingAdminApproval) ProtoMessage() {} func (x *Group_MemberPendingAdminApproval) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[96] + mi := &file_backuppb_Backup_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9545,7 +9725,7 @@ type Group_MemberBanned struct { func (x *Group_MemberBanned) Reset() { *x = Group_MemberBanned{} - mi := &file_backuppb_Backup_proto_msgTypes[97] + mi := &file_backuppb_Backup_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9557,7 +9737,7 @@ func (x *Group_MemberBanned) String() string { func (*Group_MemberBanned) ProtoMessage() {} func (x *Group_MemberBanned) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[97] + mi := &file_backuppb_Backup_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9592,13 +9772,14 @@ type Group_AccessControl struct { Attributes Group_AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"attributes,omitempty"` Members Group_AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"members,omitempty"` AddFromInviteLink Group_AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` + MemberLabel Group_AccessControl_AccessRequired `protobuf:"varint,4,opt,name=memberLabel,proto3,enum=signal.backup.Group_AccessControl_AccessRequired" json:"memberLabel,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Group_AccessControl) Reset() { *x = Group_AccessControl{} - mi := &file_backuppb_Backup_proto_msgTypes[98] + mi := &file_backuppb_Backup_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9610,7 +9791,7 @@ func (x *Group_AccessControl) String() string { func (*Group_AccessControl) ProtoMessage() {} func (x *Group_AccessControl) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[98] + mi := &file_backuppb_Backup_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9647,6 +9828,13 @@ func (x *Group_AccessControl) GetAddFromInviteLink() Group_AccessControl_AccessR return Group_AccessControl_UNKNOWN } +func (x *Group_AccessControl) GetMemberLabel() Group_AccessControl_AccessRequired { + if x != nil { + return x.MemberLabel + } + return Group_AccessControl_UNKNOWN +} + type ChatItem_IncomingMessageDetails struct { state protoimpl.MessageState `protogen:"open.v1"` DateReceived uint64 `protobuf:"varint,1,opt,name=dateReceived,proto3" json:"dateReceived,omitempty"` @@ -9659,7 +9847,7 @@ type ChatItem_IncomingMessageDetails struct { func (x *ChatItem_IncomingMessageDetails) Reset() { *x = ChatItem_IncomingMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[99] + mi := &file_backuppb_Backup_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9671,7 +9859,7 @@ func (x *ChatItem_IncomingMessageDetails) String() string { func (*ChatItem_IncomingMessageDetails) ProtoMessage() {} func (x *ChatItem_IncomingMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[99] + mi := &file_backuppb_Backup_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9725,7 +9913,7 @@ type ChatItem_OutgoingMessageDetails struct { func (x *ChatItem_OutgoingMessageDetails) Reset() { *x = ChatItem_OutgoingMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[100] + mi := &file_backuppb_Backup_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9737,7 +9925,7 @@ func (x *ChatItem_OutgoingMessageDetails) String() string { func (*ChatItem_OutgoingMessageDetails) ProtoMessage() {} func (x *ChatItem_OutgoingMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[100] + mi := &file_backuppb_Backup_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9775,7 +9963,7 @@ type ChatItem_DirectionlessMessageDetails struct { func (x *ChatItem_DirectionlessMessageDetails) Reset() { *x = ChatItem_DirectionlessMessageDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[101] + mi := &file_backuppb_Backup_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9787,7 +9975,7 @@ func (x *ChatItem_DirectionlessMessageDetails) String() string { func (*ChatItem_DirectionlessMessageDetails) ProtoMessage() {} func (x *ChatItem_DirectionlessMessageDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[101] + mi := &file_backuppb_Backup_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9817,7 +10005,7 @@ type ChatItem_PinDetails struct { func (x *ChatItem_PinDetails) Reset() { *x = ChatItem_PinDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[102] + mi := &file_backuppb_Backup_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9829,7 +10017,7 @@ func (x *ChatItem_PinDetails) String() string { func (*ChatItem_PinDetails) ProtoMessage() {} func (x *ChatItem_PinDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[102] + mi := &file_backuppb_Backup_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9901,7 +10089,7 @@ type SendStatus_Pending struct { func (x *SendStatus_Pending) Reset() { *x = SendStatus_Pending{} - mi := &file_backuppb_Backup_proto_msgTypes[103] + mi := &file_backuppb_Backup_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9913,7 +10101,7 @@ func (x *SendStatus_Pending) String() string { func (*SendStatus_Pending) ProtoMessage() {} func (x *SendStatus_Pending) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[103] + mi := &file_backuppb_Backup_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9938,7 +10126,7 @@ type SendStatus_Sent struct { func (x *SendStatus_Sent) Reset() { *x = SendStatus_Sent{} - mi := &file_backuppb_Backup_proto_msgTypes[104] + mi := &file_backuppb_Backup_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9950,7 +10138,7 @@ func (x *SendStatus_Sent) String() string { func (*SendStatus_Sent) ProtoMessage() {} func (x *SendStatus_Sent) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[104] + mi := &file_backuppb_Backup_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9982,7 +10170,7 @@ type SendStatus_Delivered struct { func (x *SendStatus_Delivered) Reset() { *x = SendStatus_Delivered{} - mi := &file_backuppb_Backup_proto_msgTypes[105] + mi := &file_backuppb_Backup_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9994,7 +10182,7 @@ func (x *SendStatus_Delivered) String() string { func (*SendStatus_Delivered) ProtoMessage() {} func (x *SendStatus_Delivered) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[105] + mi := &file_backuppb_Backup_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10026,7 +10214,7 @@ type SendStatus_Read struct { func (x *SendStatus_Read) Reset() { *x = SendStatus_Read{} - mi := &file_backuppb_Backup_proto_msgTypes[106] + mi := &file_backuppb_Backup_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10038,7 +10226,7 @@ func (x *SendStatus_Read) String() string { func (*SendStatus_Read) ProtoMessage() {} func (x *SendStatus_Read) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[106] + mi := &file_backuppb_Backup_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10070,7 +10258,7 @@ type SendStatus_Viewed struct { func (x *SendStatus_Viewed) Reset() { *x = SendStatus_Viewed{} - mi := &file_backuppb_Backup_proto_msgTypes[107] + mi := &file_backuppb_Backup_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10082,7 +10270,7 @@ func (x *SendStatus_Viewed) String() string { func (*SendStatus_Viewed) ProtoMessage() {} func (x *SendStatus_Viewed) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[107] + mi := &file_backuppb_Backup_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10114,7 +10302,7 @@ type SendStatus_Skipped struct { func (x *SendStatus_Skipped) Reset() { *x = SendStatus_Skipped{} - mi := &file_backuppb_Backup_proto_msgTypes[108] + mi := &file_backuppb_Backup_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10126,7 +10314,7 @@ func (x *SendStatus_Skipped) String() string { func (*SendStatus_Skipped) ProtoMessage() {} func (x *SendStatus_Skipped) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[108] + mi := &file_backuppb_Backup_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10151,7 +10339,7 @@ type SendStatus_Failed struct { func (x *SendStatus_Failed) Reset() { *x = SendStatus_Failed{} - mi := &file_backuppb_Backup_proto_msgTypes[109] + mi := &file_backuppb_Backup_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10163,7 +10351,7 @@ func (x *SendStatus_Failed) String() string { func (*SendStatus_Failed) ProtoMessage() {} func (x *SendStatus_Failed) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[109] + mi := &file_backuppb_Backup_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10196,7 +10384,7 @@ type DirectStoryReplyMessage_TextReply struct { func (x *DirectStoryReplyMessage_TextReply) Reset() { *x = DirectStoryReplyMessage_TextReply{} - mi := &file_backuppb_Backup_proto_msgTypes[110] + mi := &file_backuppb_Backup_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10208,7 +10396,7 @@ func (x *DirectStoryReplyMessage_TextReply) String() string { func (*DirectStoryReplyMessage_TextReply) ProtoMessage() {} func (x *DirectStoryReplyMessage_TextReply) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[110] + mi := &file_backuppb_Backup_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10253,7 +10441,7 @@ type PaymentNotification_TransactionDetails struct { func (x *PaymentNotification_TransactionDetails) Reset() { *x = PaymentNotification_TransactionDetails{} - mi := &file_backuppb_Backup_proto_msgTypes[111] + mi := &file_backuppb_Backup_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10265,7 +10453,7 @@ func (x *PaymentNotification_TransactionDetails) String() string { func (*PaymentNotification_TransactionDetails) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[111] + mi := &file_backuppb_Backup_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10334,7 +10522,7 @@ type PaymentNotification_TransactionDetails_MobileCoinTxoIdentification struct { func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Reset() { *x = PaymentNotification_TransactionDetails_MobileCoinTxoIdentification{} - mi := &file_backuppb_Backup_proto_msgTypes[112] + mi := &file_backuppb_Backup_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10346,7 +10534,7 @@ func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) Str func (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_MobileCoinTxoIdentification) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[112] + mi := &file_backuppb_Backup_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10385,7 +10573,7 @@ type PaymentNotification_TransactionDetails_FailedTransaction struct { func (x *PaymentNotification_TransactionDetails_FailedTransaction) Reset() { *x = PaymentNotification_TransactionDetails_FailedTransaction{} - mi := &file_backuppb_Backup_proto_msgTypes[113] + mi := &file_backuppb_Backup_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10397,7 +10585,7 @@ func (x *PaymentNotification_TransactionDetails_FailedTransaction) String() stri func (*PaymentNotification_TransactionDetails_FailedTransaction) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_FailedTransaction) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[113] + mi := &file_backuppb_Backup_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10438,7 +10626,7 @@ type PaymentNotification_TransactionDetails_Transaction struct { func (x *PaymentNotification_TransactionDetails_Transaction) Reset() { *x = PaymentNotification_TransactionDetails_Transaction{} - mi := &file_backuppb_Backup_proto_msgTypes[114] + mi := &file_backuppb_Backup_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10450,7 +10638,7 @@ func (x *PaymentNotification_TransactionDetails_Transaction) String() string { func (*PaymentNotification_TransactionDetails_Transaction) ProtoMessage() {} func (x *PaymentNotification_TransactionDetails_Transaction) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[114] + mi := &file_backuppb_Backup_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10529,7 +10717,7 @@ type ContactAttachment_Name struct { func (x *ContactAttachment_Name) Reset() { *x = ContactAttachment_Name{} - mi := &file_backuppb_Backup_proto_msgTypes[115] + mi := &file_backuppb_Backup_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10541,7 +10729,7 @@ func (x *ContactAttachment_Name) String() string { func (*ContactAttachment_Name) ProtoMessage() {} func (x *ContactAttachment_Name) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[115] + mi := &file_backuppb_Backup_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10610,7 +10798,7 @@ type ContactAttachment_Phone struct { func (x *ContactAttachment_Phone) Reset() { *x = ContactAttachment_Phone{} - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10622,7 +10810,7 @@ func (x *ContactAttachment_Phone) String() string { func (*ContactAttachment_Phone) ProtoMessage() {} func (x *ContactAttachment_Phone) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[116] + mi := &file_backuppb_Backup_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10670,7 +10858,7 @@ type ContactAttachment_Email struct { func (x *ContactAttachment_Email) Reset() { *x = ContactAttachment_Email{} - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10682,7 +10870,7 @@ func (x *ContactAttachment_Email) String() string { func (*ContactAttachment_Email) ProtoMessage() {} func (x *ContactAttachment_Email) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[117] + mi := &file_backuppb_Backup_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10736,7 +10924,7 @@ type ContactAttachment_PostalAddress struct { func (x *ContactAttachment_PostalAddress) Reset() { *x = ContactAttachment_PostalAddress{} - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10748,7 +10936,7 @@ func (x *ContactAttachment_PostalAddress) String() string { func (*ContactAttachment_PostalAddress) ProtoMessage() {} func (x *ContactAttachment_PostalAddress) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[118] + mi := &file_backuppb_Backup_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10863,7 +11051,7 @@ type FilePointer_LocatorInfo struct { func (x *FilePointer_LocatorInfo) Reset() { *x = FilePointer_LocatorInfo{} - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10875,7 +11063,7 @@ func (x *FilePointer_LocatorInfo) String() string { func (*FilePointer_LocatorInfo) ProtoMessage() {} func (x *FilePointer_LocatorInfo) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[119] + mi := &file_backuppb_Backup_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10995,7 +11183,7 @@ type Quote_QuotedAttachment struct { func (x *Quote_QuotedAttachment) Reset() { *x = Quote_QuotedAttachment{} - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11007,7 +11195,7 @@ func (x *Quote_QuotedAttachment) String() string { func (*Quote_QuotedAttachment) ProtoMessage() {} func (x *Quote_QuotedAttachment) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[120] + mi := &file_backuppb_Backup_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11054,7 +11242,7 @@ type Poll_PollOption struct { func (x *Poll_PollOption) Reset() { *x = Poll_PollOption{} - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11066,7 +11254,7 @@ func (x *Poll_PollOption) String() string { func (*Poll_PollOption) ProtoMessage() {} func (x *Poll_PollOption) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[121] + mi := &file_backuppb_Backup_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11106,7 +11294,7 @@ type Poll_PollOption_PollVote struct { func (x *Poll_PollOption_PollVote) Reset() { *x = Poll_PollOption_PollVote{} - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11118,7 +11306,7 @@ func (x *Poll_PollOption_PollVote) String() string { func (*Poll_PollOption_PollVote) ProtoMessage() {} func (x *Poll_PollOption_PollVote) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[122] + mi := &file_backuppb_Backup_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11188,6 +11376,8 @@ type GroupChangeChatUpdate_Update struct { // *GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate // *GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate // *GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate + // *GroupChangeChatUpdate_Update_GroupMemberLabelAccessLevelChangeUpdate + // *GroupChangeChatUpdate_Update_GroupTerminateChangeUpdate Update isGroupChangeChatUpdate_Update_Update `protobuf_oneof:"update"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -11195,7 +11385,7 @@ type GroupChangeChatUpdate_Update struct { func (x *GroupChangeChatUpdate_Update) Reset() { *x = GroupChangeChatUpdate_Update{} - mi := &file_backuppb_Backup_proto_msgTypes[123] + mi := &file_backuppb_Backup_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11207,7 +11397,7 @@ func (x *GroupChangeChatUpdate_Update) String() string { func (*GroupChangeChatUpdate_Update) ProtoMessage() {} func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[123] + mi := &file_backuppb_Backup_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11220,7 +11410,7 @@ func (x *GroupChangeChatUpdate_Update) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupChangeChatUpdate_Update.ProtoReflect.Descriptor instead. func (*GroupChangeChatUpdate_Update) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{42, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{43, 0} } func (x *GroupChangeChatUpdate_Update) GetUpdate() isGroupChangeChatUpdate_Update_Update { @@ -11536,6 +11726,24 @@ func (x *GroupChangeChatUpdate_Update) GetGroupExpirationTimerUpdate() *GroupExp return nil } +func (x *GroupChangeChatUpdate_Update) GetGroupMemberLabelAccessLevelChangeUpdate() *GroupMemberLabelAccessLevelChangeUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupMemberLabelAccessLevelChangeUpdate); ok { + return x.GroupMemberLabelAccessLevelChangeUpdate + } + } + return nil +} + +func (x *GroupChangeChatUpdate_Update) GetGroupTerminateChangeUpdate() *GroupTerminateChangeUpdate { + if x != nil { + if x, ok := x.Update.(*GroupChangeChatUpdate_Update_GroupTerminateChangeUpdate); ok { + return x.GroupTerminateChangeUpdate + } + } + return nil +} + type isGroupChangeChatUpdate_Update_Update interface { isGroupChangeChatUpdate_Update_Update() } @@ -11676,6 +11884,14 @@ type GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate struct { GroupExpirationTimerUpdate *GroupExpirationTimerUpdate `protobuf:"bytes,34,opt,name=groupExpirationTimerUpdate,proto3,oneof"` } +type GroupChangeChatUpdate_Update_GroupMemberLabelAccessLevelChangeUpdate struct { + GroupMemberLabelAccessLevelChangeUpdate *GroupMemberLabelAccessLevelChangeUpdate `protobuf:"bytes,35,opt,name=groupMemberLabelAccessLevelChangeUpdate,proto3,oneof"` +} + +type GroupChangeChatUpdate_Update_GroupTerminateChangeUpdate struct { + GroupTerminateChangeUpdate *GroupTerminateChangeUpdate `protobuf:"bytes,36,opt,name=groupTerminateChangeUpdate,proto3,oneof"` +} + func (*GroupChangeChatUpdate_Update_GenericGroupUpdate) isGroupChangeChatUpdate_Update_Update() {} func (*GroupChangeChatUpdate_Update_GroupCreationUpdate) isGroupChangeChatUpdate_Update_Update() {} @@ -11768,6 +11984,12 @@ func (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate) isG func (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate) isGroupChangeChatUpdate_Update_Update() { } +func (*GroupChangeChatUpdate_Update_GroupMemberLabelAccessLevelChangeUpdate) isGroupChangeChatUpdate_Update_Update() { +} + +func (*GroupChangeChatUpdate_Update_GroupTerminateChangeUpdate) isGroupChangeChatUpdate_Update_Update() { +} + type GroupInvitationRevokedUpdate_Invitee struct { state protoimpl.MessageState `protogen:"open.v1"` InviterAci []byte `protobuf:"bytes,1,opt,name=inviterAci,proto3,oneof" json:"inviterAci,omitempty"` @@ -11781,7 +12003,7 @@ type GroupInvitationRevokedUpdate_Invitee struct { func (x *GroupInvitationRevokedUpdate_Invitee) Reset() { *x = GroupInvitationRevokedUpdate_Invitee{} - mi := &file_backuppb_Backup_proto_msgTypes[124] + mi := &file_backuppb_Backup_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11793,7 +12015,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) String() string { func (*GroupInvitationRevokedUpdate_Invitee) ProtoMessage() {} func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[124] + mi := &file_backuppb_Backup_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11806,7 +12028,7 @@ func (x *GroupInvitationRevokedUpdate_Invitee) ProtoReflect() protoreflect.Messa // Deprecated: Use GroupInvitationRevokedUpdate_Invitee.ProtoReflect.Descriptor instead. func (*GroupInvitationRevokedUpdate_Invitee) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{62, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{65, 0} } func (x *GroupInvitationRevokedUpdate_Invitee) GetInviterAci() []byte { @@ -11841,7 +12063,7 @@ type ChatStyle_Gradient struct { func (x *ChatStyle_Gradient) Reset() { *x = ChatStyle_Gradient{} - mi := &file_backuppb_Backup_proto_msgTypes[125] + mi := &file_backuppb_Backup_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11853,7 +12075,7 @@ func (x *ChatStyle_Gradient) String() string { func (*ChatStyle_Gradient) ProtoMessage() {} func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[125] + mi := &file_backuppb_Backup_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11866,7 +12088,7 @@ func (x *ChatStyle_Gradient) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_Gradient.ProtoReflect.Descriptor instead. func (*ChatStyle_Gradient) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 0} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{83, 0} } func (x *ChatStyle_Gradient) GetAngle() uint32 { @@ -11906,7 +12128,7 @@ type ChatStyle_CustomChatColor struct { func (x *ChatStyle_CustomChatColor) Reset() { *x = ChatStyle_CustomChatColor{} - mi := &file_backuppb_Backup_proto_msgTypes[126] + mi := &file_backuppb_Backup_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11918,7 +12140,7 @@ func (x *ChatStyle_CustomChatColor) String() string { func (*ChatStyle_CustomChatColor) ProtoMessage() {} func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[126] + mi := &file_backuppb_Backup_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11931,7 +12153,7 @@ func (x *ChatStyle_CustomChatColor) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_CustomChatColor.ProtoReflect.Descriptor instead. func (*ChatStyle_CustomChatColor) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 1} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{83, 1} } func (x *ChatStyle_CustomChatColor) GetId() uint64 { @@ -11990,7 +12212,7 @@ type ChatStyle_AutomaticBubbleColor struct { func (x *ChatStyle_AutomaticBubbleColor) Reset() { *x = ChatStyle_AutomaticBubbleColor{} - mi := &file_backuppb_Backup_proto_msgTypes[127] + mi := &file_backuppb_Backup_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -12002,7 +12224,7 @@ func (x *ChatStyle_AutomaticBubbleColor) String() string { func (*ChatStyle_AutomaticBubbleColor) ProtoMessage() {} func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { - mi := &file_backuppb_Backup_proto_msgTypes[127] + mi := &file_backuppb_Backup_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -12015,7 +12237,7 @@ func (x *ChatStyle_AutomaticBubbleColor) ProtoReflect() protoreflect.Message { // Deprecated: Use ChatStyle_AutomaticBubbleColor.ProtoReflect.Descriptor instead. func (*ChatStyle_AutomaticBubbleColor) Descriptor() ([]byte, []int) { - return file_backuppb_Backup_proto_rawDescGZIP(), []int{80, 2} + return file_backuppb_Backup_proto_rawDescGZIP(), []int{83, 2} } var File_backuppb_Backup_proto protoreflect.FileDescriptor @@ -12042,7 +12264,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "chatFolder\x18\b \x01(\v2\x19.signal.backup.ChatFolderH\x00R\n" + "chatFolderB\x06\n" + - "\x04item\"\xf9\"\n" + + "\x04item\"\xc7#\n" + "\vAccountData\x12\x1e\n" + "\n" + "profileKey\x18\x01 \x01(\fR\n" + @@ -12088,7 +12310,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\aUNKNOWN\x10\x00\x12\t\n" + "\x05NEVER\x10\x01\x12\b\n" + "\x04WIFI\x10\x02\x12\x15\n" + - "\x11WIFI_AND_CELLULAR\x10\x03\x1a\xc9\x0f\n" + + "\x11WIFI_AND_CELLULAR\x10\x03\x1a\x97\x10\n" + "\x0fAccountSettings\x12\"\n" + "\freadReceipts\x18\x01 \x01(\bR\freadReceipts\x126\n" + "\x16sealedSenderIndicators\x18\x02 \x01(\bR\x16sealedSenderIndicators\x12*\n" + @@ -12121,7 +12343,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\bappTheme\x18\x1c \x01(\x0e2#.signal.backup.AccountData.AppThemeR\bappTheme\x12l\n" + "\x17callsUseLessDataSetting\x18\x1d \x01(\x0e22.signal.backup.AccountData.CallsUseLessDataSettingR\x17callsUseLessDataSetting\x12@\n" + "\x1ballowSealedSenderFromAnyone\x18\x1e \x01(\bR\x1ballowSealedSenderFromAnyone\x12D\n" + - "\x1dallowAutomaticKeyVerification\x18\x1f \x01(\bR\x1dallowAutomaticKeyVerificationB\x1b\n" + + "\x1dallowAutomaticKeyVerification\x18\x1f \x01(\bR\x1dallowAutomaticKeyVerification\x12L\n" + + "!hasSeenAdminDeleteEducationDialog\x18 \x01(\bR!hasSeenAdminDeleteEducationDialogB\x1b\n" + "\x19_storyViewReceiptsEnabledB\r\n" + "\v_backupTierB\x1b\n" + "\x19_screenLockTimeoutMinutesB\x0f\n" + @@ -12234,7 +12457,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x12_profileFamilyNameB\x0e\n" + "\f_identityKeyB\x0e\n" + "\f_avatarColorB\x16\n" + - "\x14_keyTransparencyData\"\x8f\x12\n" + + "\x14_keyTransparencyData\"\xc6\x13\n" + "\x05Group\x12\x1c\n" + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12 \n" + "\vwhitelisted\x18\x02 \x01(\bR\vwhitelisted\x12\x1c\n" + @@ -12242,7 +12465,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\rstorySendMode\x18\x04 \x01(\x0e2\".signal.backup.Group.StorySendModeR\rstorySendMode\x12>\n" + "\bsnapshot\x18\x05 \x01(\v2\".signal.backup.Group.GroupSnapshotR\bsnapshot\x12\x18\n" + "\ablocked\x18\x06 \x01(\bR\ablocked\x12A\n" + - "\vavatarColor\x18\a \x01(\x0e2\x1a.signal.backup.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x1a\xc5\x06\n" + + "\vavatarColor\x18\a \x01(\x0e2\x1a.signal.backup.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x1a\xe5\x06\n" + "\rGroupSnapshot\x12=\n" + "\x05title\x18\x02 \x01(\v2'.signal.backup.Group.GroupAttributeBlobR\x05title\x12I\n" + "\vdescription\x18\v \x01(\v2'.signal.backup.Group.GroupAttributeBlobR\vdescription\x12\x1c\n" + @@ -12256,17 +12479,24 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x12inviteLinkPassword\x18\n" + " \x01(\fR\x12inviteLinkPassword\x12-\n" + "\x12announcements_only\x18\f \x01(\bR\x11announcementsOnly\x12H\n" + - "\x0emembers_banned\x18\r \x03(\v2!.signal.backup.Group.MemberBannedR\rmembersBannedJ\x04\b\x01\x10\x02\x1a\xc3\x01\n" + + "\x0emembers_banned\x18\r \x03(\v2!.signal.backup.Group.MemberBannedR\rmembersBanned\x12\x1e\n" + + "\n" + + "terminated\x18\x0e \x01(\bR\n" + + "terminatedJ\x04\b\x01\x10\x02\x1a\xc3\x01\n" + "\x12GroupAttributeBlob\x12\x16\n" + "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + "\x1cdisappearingMessagesDuration\x18\x03 \x01(\rH\x00R\x1cdisappearingMessagesDuration\x12*\n" + "\x0fdescriptionText\x18\x04 \x01(\tH\x00R\x0fdescriptionTextB\t\n" + - "\acontent\x1a\xc1\x01\n" + + "\acontent\x1a\x83\x02\n" + "\x06Member\x12\x16\n" + "\x06userId\x18\x01 \x01(\fR\x06userId\x124\n" + "\x04role\x18\x02 \x01(\x0e2 .signal.backup.Group.Member.RoleR\x04role\x12(\n" + - "\x0fjoinedAtVersion\x18\x05 \x01(\rR\x0fjoinedAtVersion\"3\n" + + "\x0fjoinedAtVersion\x18\x05 \x01(\rR\x0fjoinedAtVersion\x12\x1e\n" + + "\n" + + "labelEmoji\x18\x06 \x01(\tR\n" + + "labelEmoji\x12 \n" + + "\vlabelString\x18\a \x01(\tR\vlabelString\"3\n" + "\x04Role\x12\v\n" + "\aUNKNOWN\x10\x00\x12\v\n" + "\aDEFAULT\x10\x01\x12\x11\n" + @@ -12280,13 +12510,14 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\ttimestamp\x18\x04 \x01(\x04R\ttimestampJ\x04\b\x02\x10\x03J\x04\b\x03\x10\x04\x1aD\n" + "\fMemberBanned\x12\x16\n" + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + - "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x1a\xea\x02\n" + + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x1a\xbf\x03\n" + "\rAccessControl\x12Q\n" + "\n" + "attributes\x18\x01 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\n" + "attributes\x12K\n" + "\amembers\x18\x02 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\amembers\x12_\n" + - "\x11addFromInviteLink\x18\x03 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + + "\x11addFromInviteLink\x18\x03 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\x11addFromInviteLink\x12S\n" + + "\vmemberLabel\x18\x04 \x01(\x0e21.signal.backup.Group.AccessControl.AccessRequiredR\vmemberLabel\"X\n" + "\x0eAccessRequired\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ANY\x10\x01\x12\n" + @@ -12317,20 +12548,18 @@ const file_backuppb_Backup_proto_rawDesc = "" + " \x01(\rR\x12expireTimerVersionB\x0e\n" + "\f_pinnedOrderB\x14\n" + "\x12_expirationTimerMsB\x0e\n" + - "\f_muteUntilMs\"\xb4\x02\n" + + "\f_muteUntilMs\"\x95\x02\n" + "\bCallLink\x12\x18\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\x1f\n" + "\badminKey\x18\x02 \x01(\fH\x00R\badminKey\x88\x01\x01\x12\x12\n" + "\x04name\x18\x03 \x01(\tR\x04name\x12H\n" + "\frestrictions\x18\x04 \x01(\x0e2$.signal.backup.CallLink.RestrictionsR\frestrictions\x12\"\n" + - "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\x12\x19\n" + - "\x05epoch\x18\x06 \x01(\fH\x01R\x05epoch\x88\x01\x01\"9\n" + + "\fexpirationMs\x18\x05 \x01(\x04R\fexpirationMs\"9\n" + "\fRestrictions\x12\v\n" + "\aUNKNOWN\x10\x00\x12\b\n" + "\x04NONE\x10\x01\x12\x12\n" + "\x0eADMIN_APPROVAL\x10\x02B\v\n" + - "\t_adminKeyB\b\n" + - "\x06_epoch\"\xca\x01\n" + + "\t_adminKeyJ\x04\b\x06\x10\a\"\xca\x01\n" + "\tAdHocCall\x12\x16\n" + "\x06callId\x18\x01 \x01(\x04R\x06callId\x12 \n" + "\vrecipientId\x18\x02 \x01(\x04R\vrecipientId\x124\n" + @@ -12354,7 +12583,7 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tONLY_WITH\x10\x01\x12\x0e\n" + "\n" + "ALL_EXCEPT\x10\x02\x12\a\n" + - "\x03ALL\x10\x03\"\xe5\x0e\n" + + "\x03ALL\x10\x03\"\xbd\x0f\n" + "\bChatItem\x12\x16\n" + "\x06chatId\x18\x01 \x01(\x04R\x06chatId\x12\x1a\n" + "\bauthorId\x18\x02 \x01(\x04R\bauthorId\x12\x1a\n" + @@ -12376,7 +12605,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\tgiftBadge\x18\x11 \x01(\v2\x18.signal.backup.GiftBadgeH\x01R\tgiftBadge\x12J\n" + "\x0fviewOnceMessage\x18\x12 \x01(\v2\x1e.signal.backup.ViewOnceMessageH\x01R\x0fviewOnceMessage\x12b\n" + "\x17directStoryReplyMessage\x18\x13 \x01(\v2&.signal.backup.DirectStoryReplyMessageH\x01R\x17directStoryReplyMessage\x12)\n" + - "\x04poll\x18\x14 \x01(\v2\x13.signal.backup.PollH\x01R\x04poll\x12B\n" + + "\x04poll\x18\x14 \x01(\v2\x13.signal.backup.PollH\x01R\x04poll\x12V\n" + + "\x13adminDeletedMessage\x18\x16 \x01(\v2\".signal.backup.AdminDeletedMessageH\x01R\x13adminDeletedMessage\x12B\n" + "\n" + "pinDetails\x18\x15 \x01(\v2\".signal.backup.ChatItem.PinDetailsR\n" + "pinDetails\x1a\xb4\x01\n" + @@ -12706,7 +12936,9 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x05votes\x18\x02 \x03(\v2'.signal.backup.Poll.PollOption.PollVoteR\x05votes\x1aB\n" + "\bPollVote\x12\x18\n" + "\avoterId\x18\x01 \x01(\x04R\avoterId\x12\x1c\n" + - "\tvoteCount\x18\x02 \x01(\rR\tvoteCount\"\xf7\x06\n" + + "\tvoteCount\x18\x02 \x01(\rR\tvoteCount\"/\n" + + "\x13AdminDeletedMessage\x12\x18\n" + + "\aadminId\x18\x01 \x01(\x04R\aadminId\"\xf7\x06\n" + "\x11ChatUpdateMessage\x12E\n" + "\fsimpleUpdate\x18\x01 \x01(\v2\x1f.signal.backup.SimpleChatUpdateH\x00R\fsimpleUpdate\x12H\n" + "\vgroupChange\x18\x02 \x01(\v2$.signal.backup.GroupChangeChatUpdateH\x00R\vgroupChange\x12`\n" + @@ -12805,9 +13037,9 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\x15ThreadMergeChatUpdate\x12\"\n" + "\fpreviousE164\x18\x01 \x01(\x04R\fpreviousE164\"1\n" + "\x1bSessionSwitchoverChatUpdate\x12\x12\n" + - "\x04e164\x18\x01 \x01(\x04R\x04e164\"\x86\x1f\n" + + "\x04e164\x18\x01 \x01(\x04R\x04e164\"\x88!\n" + "\x15GroupChangeChatUpdate\x12E\n" + - "\aupdates\x18\x01 \x03(\v2+.signal.backup.GroupChangeChatUpdate.UpdateR\aupdates\x1a\xa5\x1e\n" + + "\aupdates\x18\x01 \x03(\v2+.signal.backup.GroupChangeChatUpdate.UpdateR\aupdates\x1a\xa7 \n" + "\x06Update\x12S\n" + "\x12genericGroupUpdate\x18\x01 \x01(\v2!.signal.backup.GenericGroupUpdateH\x00R\x12genericGroupUpdate\x12V\n" + "\x13groupCreationUpdate\x18\x02 \x01(\v2\".signal.backup.GroupCreationUpdateH\x00R\x13groupCreationUpdate\x12J\n" + @@ -12843,7 +13075,9 @@ const file_backuppb_Backup_proto_rawDesc = "" + "$groupV2MigrationInvitedMembersUpdate\x18\x1f \x01(\v23.signal.backup.GroupV2MigrationInvitedMembersUpdateH\x00R$groupV2MigrationInvitedMembersUpdate\x12\x89\x01\n" + "$groupV2MigrationDroppedMembersUpdate\x18 \x01(\v23.signal.backup.GroupV2MigrationDroppedMembersUpdateH\x00R$groupV2MigrationDroppedMembersUpdate\x12\x92\x01\n" + "'groupSequenceOfRequestsAndCancelsUpdate\x18! \x01(\v26.signal.backup.GroupSequenceOfRequestsAndCancelsUpdateH\x00R'groupSequenceOfRequestsAndCancelsUpdate\x12k\n" + - "\x1agroupExpirationTimerUpdate\x18\" \x01(\v2).signal.backup.GroupExpirationTimerUpdateH\x00R\x1agroupExpirationTimerUpdateB\b\n" + + "\x1agroupExpirationTimerUpdate\x18\" \x01(\v2).signal.backup.GroupExpirationTimerUpdateH\x00R\x1agroupExpirationTimerUpdate\x12\x92\x01\n" + + "'groupMemberLabelAccessLevelChangeUpdate\x18# \x01(\v26.signal.backup.GroupMemberLabelAccessLevelChangeUpdateH\x00R'groupMemberLabelAccessLevelChangeUpdate\x12k\n" + + "\x1agroupTerminateChangeUpdate\x18$ \x01(\v2).signal.backup.GroupTerminateChangeUpdateH\x00R\x1agroupTerminateChangeUpdateB\b\n" + "\x06update\"H\n" + "\x12GenericGroupUpdate\x12#\n" + "\n" + @@ -12888,6 +13122,17 @@ const file_backuppb_Backup_proto_rawDesc = "" + "updaterAci\x18\x01 \x01(\fH\x00R\n" + "updaterAci\x88\x01\x01\x12C\n" + "\vaccessLevel\x18\x02 \x01(\x0e2!.signal.backup.GroupV2AccessLevelR\vaccessLevelB\r\n" + + "\v_updaterAci\"\xa2\x01\n" + + "'GroupMemberLabelAccessLevelChangeUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01\x12C\n" + + "\vaccessLevel\x18\x02 \x01(\x0e2!.signal.backup.GroupV2AccessLevelR\vaccessLevelB\r\n" + + "\v_updaterAci\"P\n" + + "\x1aGroupTerminateChangeUpdate\x12#\n" + + "\n" + + "updaterAci\x18\x01 \x01(\fH\x00R\n" + + "updaterAci\x88\x01\x01B\r\n" + "\v_updaterAci\"\x87\x01\n" + "!GroupAnnouncementOnlyChangeUpdate\x12#\n" + "\n" + @@ -13176,8 +13421,8 @@ const file_backuppb_Backup_proto_rawDesc = "" + "\n" + "\x06MEMBER\x10\x02\x12\x11\n" + "\rADMINISTRATOR\x10\x03\x12\x11\n" + - "\rUNSATISFIABLE\x10\x04B;\n" + - "*org.thoughtcrime.securesms.backup.v2.proto\xba\x02\fBackupProto_b\x06proto3" + "\rUNSATISFIABLE\x10\x04B)\n" + + "\x18org.signal.archive.proto\xba\x02\fBackupProto_b\x06proto3" var ( file_backuppb_Backup_proto_rawDescOnce sync.Once @@ -13192,7 +13437,7 @@ func file_backuppb_Backup_proto_rawDescGZIP() []byte { } var file_backuppb_Backup_proto_enumTypes = make([]protoimpl.EnumInfo, 36) -var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 128) +var file_backuppb_Backup_proto_msgTypes = make([]protoimpl.MessageInfo, 131) var file_backuppb_Backup_proto_goTypes = []any{ (AvatarColor)(0), // 0: signal.backup.AvatarColor (GroupV2AccessLevel)(0), // 1: signal.backup.GroupV2AccessLevel @@ -13263,116 +13508,119 @@ var file_backuppb_Backup_proto_goTypes = []any{ (*BodyRange)(nil), // 66: signal.backup.BodyRange (*Reaction)(nil), // 67: signal.backup.Reaction (*Poll)(nil), // 68: signal.backup.Poll - (*ChatUpdateMessage)(nil), // 69: signal.backup.ChatUpdateMessage - (*IndividualCall)(nil), // 70: signal.backup.IndividualCall - (*GroupCall)(nil), // 71: signal.backup.GroupCall - (*SimpleChatUpdate)(nil), // 72: signal.backup.SimpleChatUpdate - (*ExpirationTimerChatUpdate)(nil), // 73: signal.backup.ExpirationTimerChatUpdate - (*ProfileChangeChatUpdate)(nil), // 74: signal.backup.ProfileChangeChatUpdate - (*LearnedProfileChatUpdate)(nil), // 75: signal.backup.LearnedProfileChatUpdate - (*ThreadMergeChatUpdate)(nil), // 76: signal.backup.ThreadMergeChatUpdate - (*SessionSwitchoverChatUpdate)(nil), // 77: signal.backup.SessionSwitchoverChatUpdate - (*GroupChangeChatUpdate)(nil), // 78: signal.backup.GroupChangeChatUpdate - (*GenericGroupUpdate)(nil), // 79: signal.backup.GenericGroupUpdate - (*GroupCreationUpdate)(nil), // 80: signal.backup.GroupCreationUpdate - (*GroupNameUpdate)(nil), // 81: signal.backup.GroupNameUpdate - (*GroupAvatarUpdate)(nil), // 82: signal.backup.GroupAvatarUpdate - (*GroupDescriptionUpdate)(nil), // 83: signal.backup.GroupDescriptionUpdate - (*GroupMembershipAccessLevelChangeUpdate)(nil), // 84: signal.backup.GroupMembershipAccessLevelChangeUpdate - (*GroupAttributesAccessLevelChangeUpdate)(nil), // 85: signal.backup.GroupAttributesAccessLevelChangeUpdate - (*GroupAnnouncementOnlyChangeUpdate)(nil), // 86: signal.backup.GroupAnnouncementOnlyChangeUpdate - (*GroupAdminStatusUpdate)(nil), // 87: signal.backup.GroupAdminStatusUpdate - (*GroupMemberLeftUpdate)(nil), // 88: signal.backup.GroupMemberLeftUpdate - (*GroupMemberRemovedUpdate)(nil), // 89: signal.backup.GroupMemberRemovedUpdate - (*SelfInvitedToGroupUpdate)(nil), // 90: signal.backup.SelfInvitedToGroupUpdate - (*SelfInvitedOtherUserToGroupUpdate)(nil), // 91: signal.backup.SelfInvitedOtherUserToGroupUpdate - (*GroupUnknownInviteeUpdate)(nil), // 92: signal.backup.GroupUnknownInviteeUpdate - (*GroupInvitationAcceptedUpdate)(nil), // 93: signal.backup.GroupInvitationAcceptedUpdate - (*GroupInvitationDeclinedUpdate)(nil), // 94: signal.backup.GroupInvitationDeclinedUpdate - (*GroupMemberJoinedUpdate)(nil), // 95: signal.backup.GroupMemberJoinedUpdate - (*GroupMemberAddedUpdate)(nil), // 96: signal.backup.GroupMemberAddedUpdate - (*GroupSelfInvitationRevokedUpdate)(nil), // 97: signal.backup.GroupSelfInvitationRevokedUpdate - (*GroupInvitationRevokedUpdate)(nil), // 98: signal.backup.GroupInvitationRevokedUpdate - (*GroupJoinRequestUpdate)(nil), // 99: signal.backup.GroupJoinRequestUpdate - (*GroupJoinRequestApprovalUpdate)(nil), // 100: signal.backup.GroupJoinRequestApprovalUpdate - (*GroupJoinRequestCanceledUpdate)(nil), // 101: signal.backup.GroupJoinRequestCanceledUpdate - (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 102: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - (*GroupInviteLinkResetUpdate)(nil), // 103: signal.backup.GroupInviteLinkResetUpdate - (*GroupInviteLinkEnabledUpdate)(nil), // 104: signal.backup.GroupInviteLinkEnabledUpdate - (*GroupInviteLinkAdminApprovalUpdate)(nil), // 105: signal.backup.GroupInviteLinkAdminApprovalUpdate - (*GroupInviteLinkDisabledUpdate)(nil), // 106: signal.backup.GroupInviteLinkDisabledUpdate - (*GroupMemberJoinedByLinkUpdate)(nil), // 107: signal.backup.GroupMemberJoinedByLinkUpdate - (*GroupV2MigrationUpdate)(nil), // 108: signal.backup.GroupV2MigrationUpdate - (*GroupV2MigrationSelfInvitedUpdate)(nil), // 109: signal.backup.GroupV2MigrationSelfInvitedUpdate - (*GroupV2MigrationInvitedMembersUpdate)(nil), // 110: signal.backup.GroupV2MigrationInvitedMembersUpdate - (*GroupV2MigrationDroppedMembersUpdate)(nil), // 111: signal.backup.GroupV2MigrationDroppedMembersUpdate - (*GroupExpirationTimerUpdate)(nil), // 112: signal.backup.GroupExpirationTimerUpdate - (*PollTerminateUpdate)(nil), // 113: signal.backup.PollTerminateUpdate - (*PinMessageUpdate)(nil), // 114: signal.backup.PinMessageUpdate - (*StickerPack)(nil), // 115: signal.backup.StickerPack - (*ChatStyle)(nil), // 116: signal.backup.ChatStyle - (*NotificationProfile)(nil), // 117: signal.backup.NotificationProfile - (*ChatFolder)(nil), // 118: signal.backup.ChatFolder - (*AccountData_UsernameLink)(nil), // 119: signal.backup.AccountData.UsernameLink - (*AccountData_AutoDownloadSettings)(nil), // 120: signal.backup.AccountData.AutoDownloadSettings - (*AccountData_AccountSettings)(nil), // 121: signal.backup.AccountData.AccountSettings - (*AccountData_SubscriberData)(nil), // 122: signal.backup.AccountData.SubscriberData - (*AccountData_IAPSubscriberData)(nil), // 123: signal.backup.AccountData.IAPSubscriberData - (*AccountData_AndroidSpecificSettings)(nil), // 124: signal.backup.AccountData.AndroidSpecificSettings - (*Contact_Registered)(nil), // 125: signal.backup.Contact.Registered - (*Contact_NotRegistered)(nil), // 126: signal.backup.Contact.NotRegistered - (*Contact_Name)(nil), // 127: signal.backup.Contact.Name - (*Group_GroupSnapshot)(nil), // 128: signal.backup.Group.GroupSnapshot - (*Group_GroupAttributeBlob)(nil), // 129: signal.backup.Group.GroupAttributeBlob - (*Group_Member)(nil), // 130: signal.backup.Group.Member - (*Group_MemberPendingProfileKey)(nil), // 131: signal.backup.Group.MemberPendingProfileKey - (*Group_MemberPendingAdminApproval)(nil), // 132: signal.backup.Group.MemberPendingAdminApproval - (*Group_MemberBanned)(nil), // 133: signal.backup.Group.MemberBanned - (*Group_AccessControl)(nil), // 134: signal.backup.Group.AccessControl - (*ChatItem_IncomingMessageDetails)(nil), // 135: signal.backup.ChatItem.IncomingMessageDetails - (*ChatItem_OutgoingMessageDetails)(nil), // 136: signal.backup.ChatItem.OutgoingMessageDetails - (*ChatItem_DirectionlessMessageDetails)(nil), // 137: signal.backup.ChatItem.DirectionlessMessageDetails - (*ChatItem_PinDetails)(nil), // 138: signal.backup.ChatItem.PinDetails - (*SendStatus_Pending)(nil), // 139: signal.backup.SendStatus.Pending - (*SendStatus_Sent)(nil), // 140: signal.backup.SendStatus.Sent - (*SendStatus_Delivered)(nil), // 141: signal.backup.SendStatus.Delivered - (*SendStatus_Read)(nil), // 142: signal.backup.SendStatus.Read - (*SendStatus_Viewed)(nil), // 143: signal.backup.SendStatus.Viewed - (*SendStatus_Skipped)(nil), // 144: signal.backup.SendStatus.Skipped - (*SendStatus_Failed)(nil), // 145: signal.backup.SendStatus.Failed - (*DirectStoryReplyMessage_TextReply)(nil), // 146: signal.backup.DirectStoryReplyMessage.TextReply - (*PaymentNotification_TransactionDetails)(nil), // 147: signal.backup.PaymentNotification.TransactionDetails - (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 148: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 149: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - (*PaymentNotification_TransactionDetails_Transaction)(nil), // 150: signal.backup.PaymentNotification.TransactionDetails.Transaction - (*ContactAttachment_Name)(nil), // 151: signal.backup.ContactAttachment.Name - (*ContactAttachment_Phone)(nil), // 152: signal.backup.ContactAttachment.Phone - (*ContactAttachment_Email)(nil), // 153: signal.backup.ContactAttachment.Email - (*ContactAttachment_PostalAddress)(nil), // 154: signal.backup.ContactAttachment.PostalAddress - (*FilePointer_LocatorInfo)(nil), // 155: signal.backup.FilePointer.LocatorInfo - (*Quote_QuotedAttachment)(nil), // 156: signal.backup.Quote.QuotedAttachment - (*Poll_PollOption)(nil), // 157: signal.backup.Poll.PollOption - (*Poll_PollOption_PollVote)(nil), // 158: signal.backup.Poll.PollOption.PollVote - (*GroupChangeChatUpdate_Update)(nil), // 159: signal.backup.GroupChangeChatUpdate.Update - (*GroupInvitationRevokedUpdate_Invitee)(nil), // 160: signal.backup.GroupInvitationRevokedUpdate.Invitee - (*ChatStyle_Gradient)(nil), // 161: signal.backup.ChatStyle.Gradient - (*ChatStyle_CustomChatColor)(nil), // 162: signal.backup.ChatStyle.CustomChatColor - (*ChatStyle_AutomaticBubbleColor)(nil), // 163: signal.backup.ChatStyle.AutomaticBubbleColor + (*AdminDeletedMessage)(nil), // 69: signal.backup.AdminDeletedMessage + (*ChatUpdateMessage)(nil), // 70: signal.backup.ChatUpdateMessage + (*IndividualCall)(nil), // 71: signal.backup.IndividualCall + (*GroupCall)(nil), // 72: signal.backup.GroupCall + (*SimpleChatUpdate)(nil), // 73: signal.backup.SimpleChatUpdate + (*ExpirationTimerChatUpdate)(nil), // 74: signal.backup.ExpirationTimerChatUpdate + (*ProfileChangeChatUpdate)(nil), // 75: signal.backup.ProfileChangeChatUpdate + (*LearnedProfileChatUpdate)(nil), // 76: signal.backup.LearnedProfileChatUpdate + (*ThreadMergeChatUpdate)(nil), // 77: signal.backup.ThreadMergeChatUpdate + (*SessionSwitchoverChatUpdate)(nil), // 78: signal.backup.SessionSwitchoverChatUpdate + (*GroupChangeChatUpdate)(nil), // 79: signal.backup.GroupChangeChatUpdate + (*GenericGroupUpdate)(nil), // 80: signal.backup.GenericGroupUpdate + (*GroupCreationUpdate)(nil), // 81: signal.backup.GroupCreationUpdate + (*GroupNameUpdate)(nil), // 82: signal.backup.GroupNameUpdate + (*GroupAvatarUpdate)(nil), // 83: signal.backup.GroupAvatarUpdate + (*GroupDescriptionUpdate)(nil), // 84: signal.backup.GroupDescriptionUpdate + (*GroupMembershipAccessLevelChangeUpdate)(nil), // 85: signal.backup.GroupMembershipAccessLevelChangeUpdate + (*GroupAttributesAccessLevelChangeUpdate)(nil), // 86: signal.backup.GroupAttributesAccessLevelChangeUpdate + (*GroupMemberLabelAccessLevelChangeUpdate)(nil), // 87: signal.backup.GroupMemberLabelAccessLevelChangeUpdate + (*GroupTerminateChangeUpdate)(nil), // 88: signal.backup.GroupTerminateChangeUpdate + (*GroupAnnouncementOnlyChangeUpdate)(nil), // 89: signal.backup.GroupAnnouncementOnlyChangeUpdate + (*GroupAdminStatusUpdate)(nil), // 90: signal.backup.GroupAdminStatusUpdate + (*GroupMemberLeftUpdate)(nil), // 91: signal.backup.GroupMemberLeftUpdate + (*GroupMemberRemovedUpdate)(nil), // 92: signal.backup.GroupMemberRemovedUpdate + (*SelfInvitedToGroupUpdate)(nil), // 93: signal.backup.SelfInvitedToGroupUpdate + (*SelfInvitedOtherUserToGroupUpdate)(nil), // 94: signal.backup.SelfInvitedOtherUserToGroupUpdate + (*GroupUnknownInviteeUpdate)(nil), // 95: signal.backup.GroupUnknownInviteeUpdate + (*GroupInvitationAcceptedUpdate)(nil), // 96: signal.backup.GroupInvitationAcceptedUpdate + (*GroupInvitationDeclinedUpdate)(nil), // 97: signal.backup.GroupInvitationDeclinedUpdate + (*GroupMemberJoinedUpdate)(nil), // 98: signal.backup.GroupMemberJoinedUpdate + (*GroupMemberAddedUpdate)(nil), // 99: signal.backup.GroupMemberAddedUpdate + (*GroupSelfInvitationRevokedUpdate)(nil), // 100: signal.backup.GroupSelfInvitationRevokedUpdate + (*GroupInvitationRevokedUpdate)(nil), // 101: signal.backup.GroupInvitationRevokedUpdate + (*GroupJoinRequestUpdate)(nil), // 102: signal.backup.GroupJoinRequestUpdate + (*GroupJoinRequestApprovalUpdate)(nil), // 103: signal.backup.GroupJoinRequestApprovalUpdate + (*GroupJoinRequestCanceledUpdate)(nil), // 104: signal.backup.GroupJoinRequestCanceledUpdate + (*GroupSequenceOfRequestsAndCancelsUpdate)(nil), // 105: signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + (*GroupInviteLinkResetUpdate)(nil), // 106: signal.backup.GroupInviteLinkResetUpdate + (*GroupInviteLinkEnabledUpdate)(nil), // 107: signal.backup.GroupInviteLinkEnabledUpdate + (*GroupInviteLinkAdminApprovalUpdate)(nil), // 108: signal.backup.GroupInviteLinkAdminApprovalUpdate + (*GroupInviteLinkDisabledUpdate)(nil), // 109: signal.backup.GroupInviteLinkDisabledUpdate + (*GroupMemberJoinedByLinkUpdate)(nil), // 110: signal.backup.GroupMemberJoinedByLinkUpdate + (*GroupV2MigrationUpdate)(nil), // 111: signal.backup.GroupV2MigrationUpdate + (*GroupV2MigrationSelfInvitedUpdate)(nil), // 112: signal.backup.GroupV2MigrationSelfInvitedUpdate + (*GroupV2MigrationInvitedMembersUpdate)(nil), // 113: signal.backup.GroupV2MigrationInvitedMembersUpdate + (*GroupV2MigrationDroppedMembersUpdate)(nil), // 114: signal.backup.GroupV2MigrationDroppedMembersUpdate + (*GroupExpirationTimerUpdate)(nil), // 115: signal.backup.GroupExpirationTimerUpdate + (*PollTerminateUpdate)(nil), // 116: signal.backup.PollTerminateUpdate + (*PinMessageUpdate)(nil), // 117: signal.backup.PinMessageUpdate + (*StickerPack)(nil), // 118: signal.backup.StickerPack + (*ChatStyle)(nil), // 119: signal.backup.ChatStyle + (*NotificationProfile)(nil), // 120: signal.backup.NotificationProfile + (*ChatFolder)(nil), // 121: signal.backup.ChatFolder + (*AccountData_UsernameLink)(nil), // 122: signal.backup.AccountData.UsernameLink + (*AccountData_AutoDownloadSettings)(nil), // 123: signal.backup.AccountData.AutoDownloadSettings + (*AccountData_AccountSettings)(nil), // 124: signal.backup.AccountData.AccountSettings + (*AccountData_SubscriberData)(nil), // 125: signal.backup.AccountData.SubscriberData + (*AccountData_IAPSubscriberData)(nil), // 126: signal.backup.AccountData.IAPSubscriberData + (*AccountData_AndroidSpecificSettings)(nil), // 127: signal.backup.AccountData.AndroidSpecificSettings + (*Contact_Registered)(nil), // 128: signal.backup.Contact.Registered + (*Contact_NotRegistered)(nil), // 129: signal.backup.Contact.NotRegistered + (*Contact_Name)(nil), // 130: signal.backup.Contact.Name + (*Group_GroupSnapshot)(nil), // 131: signal.backup.Group.GroupSnapshot + (*Group_GroupAttributeBlob)(nil), // 132: signal.backup.Group.GroupAttributeBlob + (*Group_Member)(nil), // 133: signal.backup.Group.Member + (*Group_MemberPendingProfileKey)(nil), // 134: signal.backup.Group.MemberPendingProfileKey + (*Group_MemberPendingAdminApproval)(nil), // 135: signal.backup.Group.MemberPendingAdminApproval + (*Group_MemberBanned)(nil), // 136: signal.backup.Group.MemberBanned + (*Group_AccessControl)(nil), // 137: signal.backup.Group.AccessControl + (*ChatItem_IncomingMessageDetails)(nil), // 138: signal.backup.ChatItem.IncomingMessageDetails + (*ChatItem_OutgoingMessageDetails)(nil), // 139: signal.backup.ChatItem.OutgoingMessageDetails + (*ChatItem_DirectionlessMessageDetails)(nil), // 140: signal.backup.ChatItem.DirectionlessMessageDetails + (*ChatItem_PinDetails)(nil), // 141: signal.backup.ChatItem.PinDetails + (*SendStatus_Pending)(nil), // 142: signal.backup.SendStatus.Pending + (*SendStatus_Sent)(nil), // 143: signal.backup.SendStatus.Sent + (*SendStatus_Delivered)(nil), // 144: signal.backup.SendStatus.Delivered + (*SendStatus_Read)(nil), // 145: signal.backup.SendStatus.Read + (*SendStatus_Viewed)(nil), // 146: signal.backup.SendStatus.Viewed + (*SendStatus_Skipped)(nil), // 147: signal.backup.SendStatus.Skipped + (*SendStatus_Failed)(nil), // 148: signal.backup.SendStatus.Failed + (*DirectStoryReplyMessage_TextReply)(nil), // 149: signal.backup.DirectStoryReplyMessage.TextReply + (*PaymentNotification_TransactionDetails)(nil), // 150: signal.backup.PaymentNotification.TransactionDetails + (*PaymentNotification_TransactionDetails_MobileCoinTxoIdentification)(nil), // 151: signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + (*PaymentNotification_TransactionDetails_FailedTransaction)(nil), // 152: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + (*PaymentNotification_TransactionDetails_Transaction)(nil), // 153: signal.backup.PaymentNotification.TransactionDetails.Transaction + (*ContactAttachment_Name)(nil), // 154: signal.backup.ContactAttachment.Name + (*ContactAttachment_Phone)(nil), // 155: signal.backup.ContactAttachment.Phone + (*ContactAttachment_Email)(nil), // 156: signal.backup.ContactAttachment.Email + (*ContactAttachment_PostalAddress)(nil), // 157: signal.backup.ContactAttachment.PostalAddress + (*FilePointer_LocatorInfo)(nil), // 158: signal.backup.FilePointer.LocatorInfo + (*Quote_QuotedAttachment)(nil), // 159: signal.backup.Quote.QuotedAttachment + (*Poll_PollOption)(nil), // 160: signal.backup.Poll.PollOption + (*Poll_PollOption_PollVote)(nil), // 161: signal.backup.Poll.PollOption.PollVote + (*GroupChangeChatUpdate_Update)(nil), // 162: signal.backup.GroupChangeChatUpdate.Update + (*GroupInvitationRevokedUpdate_Invitee)(nil), // 163: signal.backup.GroupInvitationRevokedUpdate.Invitee + (*ChatStyle_Gradient)(nil), // 164: signal.backup.ChatStyle.Gradient + (*ChatStyle_CustomChatColor)(nil), // 165: signal.backup.ChatStyle.CustomChatColor + (*ChatStyle_AutomaticBubbleColor)(nil), // 166: signal.backup.ChatStyle.AutomaticBubbleColor } var file_backuppb_Backup_proto_depIdxs = []int32{ 38, // 0: signal.backup.Frame.account:type_name -> signal.backup.AccountData 39, // 1: signal.backup.Frame.recipient:type_name -> signal.backup.Recipient 44, // 2: signal.backup.Frame.chat:type_name -> signal.backup.Chat 49, // 3: signal.backup.Frame.chatItem:type_name -> signal.backup.ChatItem - 115, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack + 118, // 4: signal.backup.Frame.stickerPack:type_name -> signal.backup.StickerPack 46, // 5: signal.backup.Frame.adHocCall:type_name -> signal.backup.AdHocCall - 117, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile - 118, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder - 119, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink - 122, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData - 121, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings - 123, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData - 124, // 12: signal.backup.AccountData.androidSpecificSettings:type_name -> signal.backup.AccountData.AndroidSpecificSettings + 120, // 6: signal.backup.Frame.notificationProfile:type_name -> signal.backup.NotificationProfile + 121, // 7: signal.backup.Frame.chatFolder:type_name -> signal.backup.ChatFolder + 122, // 8: signal.backup.AccountData.usernameLink:type_name -> signal.backup.AccountData.UsernameLink + 125, // 9: signal.backup.AccountData.donationSubscriberData:type_name -> signal.backup.AccountData.SubscriberData + 124, // 10: signal.backup.AccountData.accountSettings:type_name -> signal.backup.AccountData.AccountSettings + 126, // 11: signal.backup.AccountData.backupsSubscriberData:type_name -> signal.backup.AccountData.IAPSubscriberData + 127, // 12: signal.backup.AccountData.androidSpecificSettings:type_name -> signal.backup.AccountData.AndroidSpecificSettings 40, // 13: signal.backup.Recipient.contact:type_name -> signal.backup.Contact 41, // 14: signal.backup.Recipient.group:type_name -> signal.backup.Group 47, // 15: signal.backup.Recipient.distributionList:type_name -> signal.backup.DistributionListItem @@ -13380,181 +13628,186 @@ var file_backuppb_Backup_proto_depIdxs = []int32{ 43, // 17: signal.backup.Recipient.releaseNotes:type_name -> signal.backup.ReleaseNotes 45, // 18: signal.backup.Recipient.callLink:type_name -> signal.backup.CallLink 10, // 19: signal.backup.Contact.visibility:type_name -> signal.backup.Contact.Visibility - 125, // 20: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered - 126, // 21: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered + 128, // 20: signal.backup.Contact.registered:type_name -> signal.backup.Contact.Registered + 129, // 21: signal.backup.Contact.notRegistered:type_name -> signal.backup.Contact.NotRegistered 9, // 22: signal.backup.Contact.identityState:type_name -> signal.backup.Contact.IdentityState - 127, // 23: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name + 130, // 23: signal.backup.Contact.nickname:type_name -> signal.backup.Contact.Name 0, // 24: signal.backup.Contact.avatarColor:type_name -> signal.backup.AvatarColor 11, // 25: signal.backup.Group.storySendMode:type_name -> signal.backup.Group.StorySendMode - 128, // 26: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot + 131, // 26: signal.backup.Group.snapshot:type_name -> signal.backup.Group.GroupSnapshot 0, // 27: signal.backup.Group.avatarColor:type_name -> signal.backup.AvatarColor 0, // 28: signal.backup.Self.avatarColor:type_name -> signal.backup.AvatarColor - 116, // 29: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle + 119, // 29: signal.backup.Chat.style:type_name -> signal.backup.ChatStyle 14, // 30: signal.backup.CallLink.restrictions:type_name -> signal.backup.CallLink.Restrictions 15, // 31: signal.backup.AdHocCall.state:type_name -> signal.backup.AdHocCall.State 48, // 32: signal.backup.DistributionListItem.distributionList:type_name -> signal.backup.DistributionList 16, // 33: signal.backup.DistributionList.privacyMode:type_name -> signal.backup.DistributionList.PrivacyMode 49, // 34: signal.backup.ChatItem.revisions:type_name -> signal.backup.ChatItem - 135, // 35: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails - 136, // 36: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails - 137, // 37: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails + 138, // 35: signal.backup.ChatItem.incoming:type_name -> signal.backup.ChatItem.IncomingMessageDetails + 139, // 36: signal.backup.ChatItem.outgoing:type_name -> signal.backup.ChatItem.OutgoingMessageDetails + 140, // 37: signal.backup.ChatItem.directionless:type_name -> signal.backup.ChatItem.DirectionlessMessageDetails 52, // 38: signal.backup.ChatItem.standardMessage:type_name -> signal.backup.StandardMessage 53, // 39: signal.backup.ChatItem.contactMessage:type_name -> signal.backup.ContactMessage 59, // 40: signal.backup.ChatItem.stickerMessage:type_name -> signal.backup.StickerMessage 60, // 41: signal.backup.ChatItem.remoteDeletedMessage:type_name -> signal.backup.RemoteDeletedMessage - 69, // 42: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage + 70, // 42: signal.backup.ChatItem.updateMessage:type_name -> signal.backup.ChatUpdateMessage 55, // 43: signal.backup.ChatItem.paymentNotification:type_name -> signal.backup.PaymentNotification 56, // 44: signal.backup.ChatItem.giftBadge:type_name -> signal.backup.GiftBadge 57, // 45: signal.backup.ChatItem.viewOnceMessage:type_name -> signal.backup.ViewOnceMessage 54, // 46: signal.backup.ChatItem.directStoryReplyMessage:type_name -> signal.backup.DirectStoryReplyMessage 68, // 47: signal.backup.ChatItem.poll:type_name -> signal.backup.Poll - 138, // 48: signal.backup.ChatItem.pinDetails:type_name -> signal.backup.ChatItem.PinDetails - 139, // 49: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending - 140, // 50: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent - 141, // 51: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered - 142, // 52: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read - 143, // 53: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed - 144, // 54: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped - 145, // 55: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed - 66, // 56: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange - 65, // 57: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote - 51, // 58: signal.backup.StandardMessage.text:type_name -> signal.backup.Text - 63, // 59: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment - 62, // 60: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview - 64, // 61: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer - 67, // 62: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction - 58, // 63: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment - 67, // 64: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction - 146, // 65: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply - 67, // 66: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction - 147, // 67: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails - 20, // 68: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State - 63, // 69: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment - 67, // 70: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction - 151, // 71: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name - 152, // 72: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone - 153, // 73: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email - 154, // 74: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress - 64, // 75: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer - 61, // 76: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker - 67, // 77: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction - 64, // 78: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer - 64, // 79: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer - 64, // 80: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer - 24, // 81: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag - 155, // 82: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo - 51, // 83: signal.backup.Quote.text:type_name -> signal.backup.Text - 156, // 84: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment - 25, // 85: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type - 26, // 86: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style - 157, // 87: signal.backup.Poll.options:type_name -> signal.backup.Poll.PollOption - 67, // 88: signal.backup.Poll.reactions:type_name -> signal.backup.Reaction - 72, // 89: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate - 78, // 90: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate - 73, // 91: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate - 74, // 92: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate - 76, // 93: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate - 77, // 94: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate - 70, // 95: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall - 71, // 96: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall - 75, // 97: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate - 113, // 98: signal.backup.ChatUpdateMessage.pollTerminate:type_name -> signal.backup.PollTerminateUpdate - 114, // 99: signal.backup.ChatUpdateMessage.pinMessage:type_name -> signal.backup.PinMessageUpdate - 27, // 100: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type - 28, // 101: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction - 29, // 102: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State - 30, // 103: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State - 31, // 104: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type - 159, // 105: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update - 1, // 106: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 1, // 107: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel - 160, // 108: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee - 32, // 109: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset - 64, // 110: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer - 163, // 111: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor - 33, // 112: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset - 34, // 113: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek - 35, // 114: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType - 6, // 115: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color - 7, // 116: signal.backup.AccountData.AutoDownloadSettings.images:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption - 7, // 117: signal.backup.AccountData.AutoDownloadSettings.audio:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption - 7, // 118: signal.backup.AccountData.AutoDownloadSettings.video:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption - 7, // 119: signal.backup.AccountData.AutoDownloadSettings.documents:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption - 2, // 120: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode - 116, // 121: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle - 162, // 122: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor - 3, // 123: signal.backup.AccountData.AccountSettings.defaultSentMediaQuality:type_name -> signal.backup.AccountData.SentMediaQuality - 120, // 124: signal.backup.AccountData.AccountSettings.autoDownloadSettings:type_name -> signal.backup.AccountData.AutoDownloadSettings - 4, // 125: signal.backup.AccountData.AccountSettings.appTheme:type_name -> signal.backup.AccountData.AppTheme - 5, // 126: signal.backup.AccountData.AccountSettings.callsUseLessDataSetting:type_name -> signal.backup.AccountData.CallsUseLessDataSetting - 8, // 127: signal.backup.AccountData.AndroidSpecificSettings.navigationBarSize:type_name -> signal.backup.AccountData.AndroidSpecificSettings.NavigationBarSize - 129, // 128: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob - 129, // 129: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob - 129, // 130: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob - 134, // 131: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl - 130, // 132: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member - 131, // 133: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey - 132, // 134: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval - 133, // 135: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned - 12, // 136: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role - 130, // 137: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member - 13, // 138: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired - 13, // 139: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired - 13, // 140: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired - 50, // 141: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus - 17, // 142: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason - 51, // 143: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text - 64, // 144: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer - 150, // 145: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction - 149, // 146: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction - 18, // 147: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason - 19, // 148: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status - 148, // 149: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification - 21, // 150: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type - 22, // 151: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type - 23, // 152: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type - 63, // 153: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment - 158, // 154: signal.backup.Poll.PollOption.votes:type_name -> signal.backup.Poll.PollOption.PollVote - 79, // 155: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate - 80, // 156: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate - 81, // 157: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate - 82, // 158: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate - 83, // 159: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate - 84, // 160: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate - 85, // 161: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate - 86, // 162: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate - 87, // 163: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate - 88, // 164: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate - 89, // 165: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate - 90, // 166: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate - 91, // 167: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate - 92, // 168: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate - 93, // 169: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate - 94, // 170: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate - 95, // 171: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate - 96, // 172: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate - 97, // 173: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate - 98, // 174: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate - 99, // 175: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate - 100, // 176: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate - 101, // 177: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate - 103, // 178: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate - 104, // 179: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate - 105, // 180: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate - 106, // 181: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate - 107, // 182: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate - 108, // 183: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate - 109, // 184: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate - 110, // 185: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate - 111, // 186: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate - 102, // 187: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate - 112, // 188: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate - 161, // 189: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient - 190, // [190:190] is the sub-list for method output_type - 190, // [190:190] is the sub-list for method input_type - 190, // [190:190] is the sub-list for extension type_name - 190, // [190:190] is the sub-list for extension extendee - 0, // [0:190] is the sub-list for field type_name + 69, // 48: signal.backup.ChatItem.adminDeletedMessage:type_name -> signal.backup.AdminDeletedMessage + 141, // 49: signal.backup.ChatItem.pinDetails:type_name -> signal.backup.ChatItem.PinDetails + 142, // 50: signal.backup.SendStatus.pending:type_name -> signal.backup.SendStatus.Pending + 143, // 51: signal.backup.SendStatus.sent:type_name -> signal.backup.SendStatus.Sent + 144, // 52: signal.backup.SendStatus.delivered:type_name -> signal.backup.SendStatus.Delivered + 145, // 53: signal.backup.SendStatus.read:type_name -> signal.backup.SendStatus.Read + 146, // 54: signal.backup.SendStatus.viewed:type_name -> signal.backup.SendStatus.Viewed + 147, // 55: signal.backup.SendStatus.skipped:type_name -> signal.backup.SendStatus.Skipped + 148, // 56: signal.backup.SendStatus.failed:type_name -> signal.backup.SendStatus.Failed + 66, // 57: signal.backup.Text.bodyRanges:type_name -> signal.backup.BodyRange + 65, // 58: signal.backup.StandardMessage.quote:type_name -> signal.backup.Quote + 51, // 59: signal.backup.StandardMessage.text:type_name -> signal.backup.Text + 63, // 60: signal.backup.StandardMessage.attachments:type_name -> signal.backup.MessageAttachment + 62, // 61: signal.backup.StandardMessage.linkPreview:type_name -> signal.backup.LinkPreview + 64, // 62: signal.backup.StandardMessage.longText:type_name -> signal.backup.FilePointer + 67, // 63: signal.backup.StandardMessage.reactions:type_name -> signal.backup.Reaction + 58, // 64: signal.backup.ContactMessage.contact:type_name -> signal.backup.ContactAttachment + 67, // 65: signal.backup.ContactMessage.reactions:type_name -> signal.backup.Reaction + 149, // 66: signal.backup.DirectStoryReplyMessage.textReply:type_name -> signal.backup.DirectStoryReplyMessage.TextReply + 67, // 67: signal.backup.DirectStoryReplyMessage.reactions:type_name -> signal.backup.Reaction + 150, // 68: signal.backup.PaymentNotification.transactionDetails:type_name -> signal.backup.PaymentNotification.TransactionDetails + 20, // 69: signal.backup.GiftBadge.state:type_name -> signal.backup.GiftBadge.State + 63, // 70: signal.backup.ViewOnceMessage.attachment:type_name -> signal.backup.MessageAttachment + 67, // 71: signal.backup.ViewOnceMessage.reactions:type_name -> signal.backup.Reaction + 154, // 72: signal.backup.ContactAttachment.name:type_name -> signal.backup.ContactAttachment.Name + 155, // 73: signal.backup.ContactAttachment.number:type_name -> signal.backup.ContactAttachment.Phone + 156, // 74: signal.backup.ContactAttachment.email:type_name -> signal.backup.ContactAttachment.Email + 157, // 75: signal.backup.ContactAttachment.address:type_name -> signal.backup.ContactAttachment.PostalAddress + 64, // 76: signal.backup.ContactAttachment.avatar:type_name -> signal.backup.FilePointer + 61, // 77: signal.backup.StickerMessage.sticker:type_name -> signal.backup.Sticker + 67, // 78: signal.backup.StickerMessage.reactions:type_name -> signal.backup.Reaction + 64, // 79: signal.backup.Sticker.data:type_name -> signal.backup.FilePointer + 64, // 80: signal.backup.LinkPreview.image:type_name -> signal.backup.FilePointer + 64, // 81: signal.backup.MessageAttachment.pointer:type_name -> signal.backup.FilePointer + 24, // 82: signal.backup.MessageAttachment.flag:type_name -> signal.backup.MessageAttachment.Flag + 158, // 83: signal.backup.FilePointer.locatorInfo:type_name -> signal.backup.FilePointer.LocatorInfo + 51, // 84: signal.backup.Quote.text:type_name -> signal.backup.Text + 159, // 85: signal.backup.Quote.attachments:type_name -> signal.backup.Quote.QuotedAttachment + 25, // 86: signal.backup.Quote.type:type_name -> signal.backup.Quote.Type + 26, // 87: signal.backup.BodyRange.style:type_name -> signal.backup.BodyRange.Style + 160, // 88: signal.backup.Poll.options:type_name -> signal.backup.Poll.PollOption + 67, // 89: signal.backup.Poll.reactions:type_name -> signal.backup.Reaction + 73, // 90: signal.backup.ChatUpdateMessage.simpleUpdate:type_name -> signal.backup.SimpleChatUpdate + 79, // 91: signal.backup.ChatUpdateMessage.groupChange:type_name -> signal.backup.GroupChangeChatUpdate + 74, // 92: signal.backup.ChatUpdateMessage.expirationTimerChange:type_name -> signal.backup.ExpirationTimerChatUpdate + 75, // 93: signal.backup.ChatUpdateMessage.profileChange:type_name -> signal.backup.ProfileChangeChatUpdate + 77, // 94: signal.backup.ChatUpdateMessage.threadMerge:type_name -> signal.backup.ThreadMergeChatUpdate + 78, // 95: signal.backup.ChatUpdateMessage.sessionSwitchover:type_name -> signal.backup.SessionSwitchoverChatUpdate + 71, // 96: signal.backup.ChatUpdateMessage.individualCall:type_name -> signal.backup.IndividualCall + 72, // 97: signal.backup.ChatUpdateMessage.groupCall:type_name -> signal.backup.GroupCall + 76, // 98: signal.backup.ChatUpdateMessage.learnedProfileChange:type_name -> signal.backup.LearnedProfileChatUpdate + 116, // 99: signal.backup.ChatUpdateMessage.pollTerminate:type_name -> signal.backup.PollTerminateUpdate + 117, // 100: signal.backup.ChatUpdateMessage.pinMessage:type_name -> signal.backup.PinMessageUpdate + 27, // 101: signal.backup.IndividualCall.type:type_name -> signal.backup.IndividualCall.Type + 28, // 102: signal.backup.IndividualCall.direction:type_name -> signal.backup.IndividualCall.Direction + 29, // 103: signal.backup.IndividualCall.state:type_name -> signal.backup.IndividualCall.State + 30, // 104: signal.backup.GroupCall.state:type_name -> signal.backup.GroupCall.State + 31, // 105: signal.backup.SimpleChatUpdate.type:type_name -> signal.backup.SimpleChatUpdate.Type + 162, // 106: signal.backup.GroupChangeChatUpdate.updates:type_name -> signal.backup.GroupChangeChatUpdate.Update + 1, // 107: signal.backup.GroupMembershipAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 108: signal.backup.GroupAttributesAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 1, // 109: signal.backup.GroupMemberLabelAccessLevelChangeUpdate.accessLevel:type_name -> signal.backup.GroupV2AccessLevel + 163, // 110: signal.backup.GroupInvitationRevokedUpdate.invitees:type_name -> signal.backup.GroupInvitationRevokedUpdate.Invitee + 32, // 111: signal.backup.ChatStyle.wallpaperPreset:type_name -> signal.backup.ChatStyle.WallpaperPreset + 64, // 112: signal.backup.ChatStyle.wallpaperPhoto:type_name -> signal.backup.FilePointer + 166, // 113: signal.backup.ChatStyle.autoBubbleColor:type_name -> signal.backup.ChatStyle.AutomaticBubbleColor + 33, // 114: signal.backup.ChatStyle.bubbleColorPreset:type_name -> signal.backup.ChatStyle.BubbleColorPreset + 34, // 115: signal.backup.NotificationProfile.scheduleDaysEnabled:type_name -> signal.backup.NotificationProfile.DayOfWeek + 35, // 116: signal.backup.ChatFolder.folderType:type_name -> signal.backup.ChatFolder.FolderType + 6, // 117: signal.backup.AccountData.UsernameLink.color:type_name -> signal.backup.AccountData.UsernameLink.Color + 7, // 118: signal.backup.AccountData.AutoDownloadSettings.images:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 7, // 119: signal.backup.AccountData.AutoDownloadSettings.audio:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 7, // 120: signal.backup.AccountData.AutoDownloadSettings.video:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 7, // 121: signal.backup.AccountData.AutoDownloadSettings.documents:type_name -> signal.backup.AccountData.AutoDownloadSettings.AutoDownloadOption + 2, // 122: signal.backup.AccountData.AccountSettings.phoneNumberSharingMode:type_name -> signal.backup.AccountData.PhoneNumberSharingMode + 119, // 123: signal.backup.AccountData.AccountSettings.defaultChatStyle:type_name -> signal.backup.ChatStyle + 165, // 124: signal.backup.AccountData.AccountSettings.customChatColors:type_name -> signal.backup.ChatStyle.CustomChatColor + 3, // 125: signal.backup.AccountData.AccountSettings.defaultSentMediaQuality:type_name -> signal.backup.AccountData.SentMediaQuality + 123, // 126: signal.backup.AccountData.AccountSettings.autoDownloadSettings:type_name -> signal.backup.AccountData.AutoDownloadSettings + 4, // 127: signal.backup.AccountData.AccountSettings.appTheme:type_name -> signal.backup.AccountData.AppTheme + 5, // 128: signal.backup.AccountData.AccountSettings.callsUseLessDataSetting:type_name -> signal.backup.AccountData.CallsUseLessDataSetting + 8, // 129: signal.backup.AccountData.AndroidSpecificSettings.navigationBarSize:type_name -> signal.backup.AccountData.AndroidSpecificSettings.NavigationBarSize + 132, // 130: signal.backup.Group.GroupSnapshot.title:type_name -> signal.backup.Group.GroupAttributeBlob + 132, // 131: signal.backup.Group.GroupSnapshot.description:type_name -> signal.backup.Group.GroupAttributeBlob + 132, // 132: signal.backup.Group.GroupSnapshot.disappearingMessagesTimer:type_name -> signal.backup.Group.GroupAttributeBlob + 137, // 133: signal.backup.Group.GroupSnapshot.accessControl:type_name -> signal.backup.Group.AccessControl + 133, // 134: signal.backup.Group.GroupSnapshot.members:type_name -> signal.backup.Group.Member + 134, // 135: signal.backup.Group.GroupSnapshot.membersPendingProfileKey:type_name -> signal.backup.Group.MemberPendingProfileKey + 135, // 136: signal.backup.Group.GroupSnapshot.membersPendingAdminApproval:type_name -> signal.backup.Group.MemberPendingAdminApproval + 136, // 137: signal.backup.Group.GroupSnapshot.members_banned:type_name -> signal.backup.Group.MemberBanned + 12, // 138: signal.backup.Group.Member.role:type_name -> signal.backup.Group.Member.Role + 133, // 139: signal.backup.Group.MemberPendingProfileKey.member:type_name -> signal.backup.Group.Member + 13, // 140: signal.backup.Group.AccessControl.attributes:type_name -> signal.backup.Group.AccessControl.AccessRequired + 13, // 141: signal.backup.Group.AccessControl.members:type_name -> signal.backup.Group.AccessControl.AccessRequired + 13, // 142: signal.backup.Group.AccessControl.addFromInviteLink:type_name -> signal.backup.Group.AccessControl.AccessRequired + 13, // 143: signal.backup.Group.AccessControl.memberLabel:type_name -> signal.backup.Group.AccessControl.AccessRequired + 50, // 144: signal.backup.ChatItem.OutgoingMessageDetails.sendStatus:type_name -> signal.backup.SendStatus + 17, // 145: signal.backup.SendStatus.Failed.reason:type_name -> signal.backup.SendStatus.Failed.FailureReason + 51, // 146: signal.backup.DirectStoryReplyMessage.TextReply.text:type_name -> signal.backup.Text + 64, // 147: signal.backup.DirectStoryReplyMessage.TextReply.longText:type_name -> signal.backup.FilePointer + 153, // 148: signal.backup.PaymentNotification.TransactionDetails.transaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction + 152, // 149: signal.backup.PaymentNotification.TransactionDetails.failedTransaction:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction + 18, // 150: signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.reason:type_name -> signal.backup.PaymentNotification.TransactionDetails.FailedTransaction.FailureReason + 19, // 151: signal.backup.PaymentNotification.TransactionDetails.Transaction.status:type_name -> signal.backup.PaymentNotification.TransactionDetails.Transaction.Status + 151, // 152: signal.backup.PaymentNotification.TransactionDetails.Transaction.mobileCoinIdentification:type_name -> signal.backup.PaymentNotification.TransactionDetails.MobileCoinTxoIdentification + 21, // 153: signal.backup.ContactAttachment.Phone.type:type_name -> signal.backup.ContactAttachment.Phone.Type + 22, // 154: signal.backup.ContactAttachment.Email.type:type_name -> signal.backup.ContactAttachment.Email.Type + 23, // 155: signal.backup.ContactAttachment.PostalAddress.type:type_name -> signal.backup.ContactAttachment.PostalAddress.Type + 63, // 156: signal.backup.Quote.QuotedAttachment.thumbnail:type_name -> signal.backup.MessageAttachment + 161, // 157: signal.backup.Poll.PollOption.votes:type_name -> signal.backup.Poll.PollOption.PollVote + 80, // 158: signal.backup.GroupChangeChatUpdate.Update.genericGroupUpdate:type_name -> signal.backup.GenericGroupUpdate + 81, // 159: signal.backup.GroupChangeChatUpdate.Update.groupCreationUpdate:type_name -> signal.backup.GroupCreationUpdate + 82, // 160: signal.backup.GroupChangeChatUpdate.Update.groupNameUpdate:type_name -> signal.backup.GroupNameUpdate + 83, // 161: signal.backup.GroupChangeChatUpdate.Update.groupAvatarUpdate:type_name -> signal.backup.GroupAvatarUpdate + 84, // 162: signal.backup.GroupChangeChatUpdate.Update.groupDescriptionUpdate:type_name -> signal.backup.GroupDescriptionUpdate + 85, // 163: signal.backup.GroupChangeChatUpdate.Update.groupMembershipAccessLevelChangeUpdate:type_name -> signal.backup.GroupMembershipAccessLevelChangeUpdate + 86, // 164: signal.backup.GroupChangeChatUpdate.Update.groupAttributesAccessLevelChangeUpdate:type_name -> signal.backup.GroupAttributesAccessLevelChangeUpdate + 89, // 165: signal.backup.GroupChangeChatUpdate.Update.groupAnnouncementOnlyChangeUpdate:type_name -> signal.backup.GroupAnnouncementOnlyChangeUpdate + 90, // 166: signal.backup.GroupChangeChatUpdate.Update.groupAdminStatusUpdate:type_name -> signal.backup.GroupAdminStatusUpdate + 91, // 167: signal.backup.GroupChangeChatUpdate.Update.groupMemberLeftUpdate:type_name -> signal.backup.GroupMemberLeftUpdate + 92, // 168: signal.backup.GroupChangeChatUpdate.Update.groupMemberRemovedUpdate:type_name -> signal.backup.GroupMemberRemovedUpdate + 93, // 169: signal.backup.GroupChangeChatUpdate.Update.selfInvitedToGroupUpdate:type_name -> signal.backup.SelfInvitedToGroupUpdate + 94, // 170: signal.backup.GroupChangeChatUpdate.Update.selfInvitedOtherUserToGroupUpdate:type_name -> signal.backup.SelfInvitedOtherUserToGroupUpdate + 95, // 171: signal.backup.GroupChangeChatUpdate.Update.groupUnknownInviteeUpdate:type_name -> signal.backup.GroupUnknownInviteeUpdate + 96, // 172: signal.backup.GroupChangeChatUpdate.Update.groupInvitationAcceptedUpdate:type_name -> signal.backup.GroupInvitationAcceptedUpdate + 97, // 173: signal.backup.GroupChangeChatUpdate.Update.groupInvitationDeclinedUpdate:type_name -> signal.backup.GroupInvitationDeclinedUpdate + 98, // 174: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedUpdate:type_name -> signal.backup.GroupMemberJoinedUpdate + 99, // 175: signal.backup.GroupChangeChatUpdate.Update.groupMemberAddedUpdate:type_name -> signal.backup.GroupMemberAddedUpdate + 100, // 176: signal.backup.GroupChangeChatUpdate.Update.groupSelfInvitationRevokedUpdate:type_name -> signal.backup.GroupSelfInvitationRevokedUpdate + 101, // 177: signal.backup.GroupChangeChatUpdate.Update.groupInvitationRevokedUpdate:type_name -> signal.backup.GroupInvitationRevokedUpdate + 102, // 178: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestUpdate:type_name -> signal.backup.GroupJoinRequestUpdate + 103, // 179: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestApprovalUpdate:type_name -> signal.backup.GroupJoinRequestApprovalUpdate + 104, // 180: signal.backup.GroupChangeChatUpdate.Update.groupJoinRequestCanceledUpdate:type_name -> signal.backup.GroupJoinRequestCanceledUpdate + 106, // 181: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkResetUpdate:type_name -> signal.backup.GroupInviteLinkResetUpdate + 107, // 182: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkEnabledUpdate:type_name -> signal.backup.GroupInviteLinkEnabledUpdate + 108, // 183: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkAdminApprovalUpdate:type_name -> signal.backup.GroupInviteLinkAdminApprovalUpdate + 109, // 184: signal.backup.GroupChangeChatUpdate.Update.groupInviteLinkDisabledUpdate:type_name -> signal.backup.GroupInviteLinkDisabledUpdate + 110, // 185: signal.backup.GroupChangeChatUpdate.Update.groupMemberJoinedByLinkUpdate:type_name -> signal.backup.GroupMemberJoinedByLinkUpdate + 111, // 186: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationUpdate:type_name -> signal.backup.GroupV2MigrationUpdate + 112, // 187: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationSelfInvitedUpdate:type_name -> signal.backup.GroupV2MigrationSelfInvitedUpdate + 113, // 188: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationInvitedMembersUpdate:type_name -> signal.backup.GroupV2MigrationInvitedMembersUpdate + 114, // 189: signal.backup.GroupChangeChatUpdate.Update.groupV2MigrationDroppedMembersUpdate:type_name -> signal.backup.GroupV2MigrationDroppedMembersUpdate + 105, // 190: signal.backup.GroupChangeChatUpdate.Update.groupSequenceOfRequestsAndCancelsUpdate:type_name -> signal.backup.GroupSequenceOfRequestsAndCancelsUpdate + 115, // 191: signal.backup.GroupChangeChatUpdate.Update.groupExpirationTimerUpdate:type_name -> signal.backup.GroupExpirationTimerUpdate + 87, // 192: signal.backup.GroupChangeChatUpdate.Update.groupMemberLabelAccessLevelChangeUpdate:type_name -> signal.backup.GroupMemberLabelAccessLevelChangeUpdate + 88, // 193: signal.backup.GroupChangeChatUpdate.Update.groupTerminateChangeUpdate:type_name -> signal.backup.GroupTerminateChangeUpdate + 164, // 194: signal.backup.ChatStyle.CustomChatColor.gradient:type_name -> signal.backup.ChatStyle.Gradient + 195, // [195:195] is the sub-list for method output_type + 195, // [195:195] is the sub-list for method input_type + 195, // [195:195] is the sub-list for extension type_name + 195, // [195:195] is the sub-list for extension extendee + 0, // [0:195] is the sub-list for field type_name } func init() { file_backuppb_Backup_proto_init() } @@ -13607,6 +13860,7 @@ func file_backuppb_Backup_proto_init() { (*ChatItem_ViewOnceMessage)(nil), (*ChatItem_DirectStoryReplyMessage)(nil), (*ChatItem_Poll)(nil), + (*ChatItem_AdminDeletedMessage)(nil), } file_backuppb_Backup_proto_msgTypes[14].OneofWrappers = []any{ (*SendStatus_Pending_)(nil), @@ -13633,7 +13887,7 @@ func file_backuppb_Backup_proto_init() { (*BodyRange_MentionAci)(nil), (*BodyRange_Style_)(nil), } - file_backuppb_Backup_proto_msgTypes[33].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[34].OneofWrappers = []any{ (*ChatUpdateMessage_SimpleUpdate)(nil), (*ChatUpdateMessage_GroupChange)(nil), (*ChatUpdateMessage_ExpirationTimerChange)(nil), @@ -13646,13 +13900,12 @@ func file_backuppb_Backup_proto_init() { (*ChatUpdateMessage_PollTerminate)(nil), (*ChatUpdateMessage_PinMessage)(nil), } - file_backuppb_Backup_proto_msgTypes[34].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[35].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[39].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[36].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[40].OneofWrappers = []any{ (*LearnedProfileChatUpdate_E164)(nil), (*LearnedProfileChatUpdate_Username)(nil), } - file_backuppb_Backup_proto_msgTypes[43].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[44].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[45].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[46].OneofWrappers = []any{} @@ -13661,55 +13914,58 @@ func file_backuppb_Backup_proto_init() { file_backuppb_Backup_proto_msgTypes[49].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[50].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[51].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[52].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[53].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[54].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[56].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[57].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[58].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[59].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[60].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[61].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[62].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[63].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[64].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[65].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[67].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[68].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[69].OneofWrappers = []any{} file_backuppb_Backup_proto_msgTypes[70].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[76].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[80].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[71].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[72].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[73].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[79].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[83].OneofWrappers = []any{ (*ChatStyle_WallpaperPreset_)(nil), (*ChatStyle_WallpaperPhoto)(nil), (*ChatStyle_AutoBubbleColor)(nil), (*ChatStyle_BubbleColorPreset_)(nil), (*ChatStyle_CustomColorId)(nil), } - file_backuppb_Backup_proto_msgTypes[81].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[85].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[87].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[84].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[88].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[90].OneofWrappers = []any{ (*AccountData_IAPSubscriberData_PurchaseToken)(nil), (*AccountData_IAPSubscriberData_OriginalTransactionId)(nil), } - file_backuppb_Backup_proto_msgTypes[93].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[96].OneofWrappers = []any{ (*Group_GroupAttributeBlob_Title)(nil), (*Group_GroupAttributeBlob_Avatar)(nil), (*Group_GroupAttributeBlob_DisappearingMessagesDuration)(nil), (*Group_GroupAttributeBlob_DescriptionText)(nil), } - file_backuppb_Backup_proto_msgTypes[99].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[102].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[102].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[105].OneofWrappers = []any{ (*ChatItem_PinDetails_PinExpiresAtTimestamp)(nil), (*ChatItem_PinDetails_PinNeverExpires)(nil), } - file_backuppb_Backup_proto_msgTypes[111].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{ (*PaymentNotification_TransactionDetails_Transaction_)(nil), (*PaymentNotification_TransactionDetails_FailedTransaction_)(nil), } - file_backuppb_Backup_proto_msgTypes[114].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[119].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[117].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[122].OneofWrappers = []any{ (*FilePointer_LocatorInfo_PlaintextHash)(nil), (*FilePointer_LocatorInfo_EncryptedDigest)(nil), } - file_backuppb_Backup_proto_msgTypes[120].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[123].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[123].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[126].OneofWrappers = []any{ (*GroupChangeChatUpdate_Update_GenericGroupUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupCreationUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupNameUpdate)(nil), @@ -13744,9 +14000,11 @@ func file_backuppb_Backup_proto_init() { (*GroupChangeChatUpdate_Update_GroupV2MigrationDroppedMembersUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupSequenceOfRequestsAndCancelsUpdate)(nil), (*GroupChangeChatUpdate_Update_GroupExpirationTimerUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupMemberLabelAccessLevelChangeUpdate)(nil), + (*GroupChangeChatUpdate_Update_GroupTerminateChangeUpdate)(nil), } - file_backuppb_Backup_proto_msgTypes[124].OneofWrappers = []any{} - file_backuppb_Backup_proto_msgTypes[126].OneofWrappers = []any{ + file_backuppb_Backup_proto_msgTypes[127].OneofWrappers = []any{} + file_backuppb_Backup_proto_msgTypes[129].OneofWrappers = []any{ (*ChatStyle_CustomChatColor_Solid)(nil), (*ChatStyle_CustomChatColor_Gradient)(nil), } @@ -13756,7 +14014,7 @@ func file_backuppb_Backup_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_backuppb_Backup_proto_rawDesc), len(file_backuppb_Backup_proto_rawDesc)), NumEnums: 36, - NumMessages: 128, + NumMessages: 131, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.proto b/pkg/signalmeow/protobuf/backuppb/Backup.proto index 1b70167..d7407cb 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.proto +++ b/pkg/signalmeow/protobuf/backuppb/Backup.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package signal.backup; -option java_package = "org.thoughtcrime.securesms.backup.v2.proto"; +option java_package = "org.signal.archive.proto"; option swift_prefix = "BackupProto_"; message BackupInfo { @@ -135,6 +135,7 @@ message AccountData { CallsUseLessDataSetting callsUseLessDataSetting = 29; // If unset, treat the same as "Unknown" case bool allowSealedSenderFromAnyone = 30; bool allowAutomaticKeyVerification = 31; + bool hasSeenAdminDeleteEducationDialog = 32; } message SubscriberData { @@ -307,6 +308,7 @@ message Group { bytes inviteLinkPassword = 10; bool announcements_only = 12; repeated MemberBanned members_banned = 13; + bool terminated = 14; } message GroupAttributeBlob { @@ -331,6 +333,8 @@ message Group { reserved /*profileKey*/ 3; // This field is ignored in Backups, in favor of Contact frames for members reserved /*presentation*/ 4; // This field is deprecated in the context of static group state uint32 joinedAtVersion = 5; + string labelEmoji = 6; + string labelString = 7; } message MemberPendingProfileKey { @@ -363,6 +367,7 @@ message Group { AccessRequired attributes = 1; AccessRequired members = 2; AccessRequired addFromInviteLink = 3; + AccessRequired memberLabel = 4; } } @@ -405,7 +410,7 @@ message CallLink { string name = 3; Restrictions restrictions = 4; uint64 expirationMs = 5; - optional bytes epoch = 6; // May be absent/empty for older links + reserved /*epoch*/ 6; } message AdHocCall { @@ -498,6 +503,7 @@ message ChatItem { ViewOnceMessage viewOnceMessage = 18; DirectStoryReplyMessage directStoryReplyMessage = 19; // group story reply messages are not backed up Poll poll = 20; + AdminDeletedMessage adminDeletedMessage = 22; } PinDetails pinDetails = 21; // only set if message is pinned @@ -898,6 +904,10 @@ message Poll { repeated Reaction reactions = 5; } +message AdminDeletedMessage { + uint64 adminId = 1; // id of the admin that deleted the message +} + message ChatUpdateMessage { // If unset, importers should ignore the update message without throwing an error. oneof update { @@ -1068,6 +1078,8 @@ message GroupChangeChatUpdate { GroupV2MigrationDroppedMembersUpdate groupV2MigrationDroppedMembersUpdate = 32; GroupSequenceOfRequestsAndCancelsUpdate groupSequenceOfRequestsAndCancelsUpdate = 33; GroupExpirationTimerUpdate groupExpirationTimerUpdate = 34; + GroupMemberLabelAccessLevelChangeUpdate groupMemberLabelAccessLevelChangeUpdate = 35; + GroupTerminateChangeUpdate groupTerminateChangeUpdate = 36; } } @@ -1119,6 +1131,15 @@ message GroupAttributesAccessLevelChangeUpdate { GroupV2AccessLevel accessLevel = 2; } +message GroupMemberLabelAccessLevelChangeUpdate { + optional bytes updaterAci = 1; + GroupV2AccessLevel accessLevel = 2; +} + +message GroupTerminateChangeUpdate { + optional bytes updaterAci = 1; +} + message GroupAnnouncementOnlyChangeUpdate { optional bytes updaterAci = 1; bool isAnnouncementOnly = 2; diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index d65567c..ffaa697 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-bc6114f6e0d3a4b1dcdc472331505f2644185264} -DESKTOP_GIT_REVISION=${1:-a9063ec0c3c1079072c1e30e0749c1ae8be5500a} +ANDROID_GIT_REVISION=${1:-dfd2f7baf96825834f784900ce644e9ead8a9a89} +DESKTOP_GIT_REVISION=${1:-60a1e125452ee672d8747564d0055d5bfec9f679} update_proto() { case "$1" in @@ -11,9 +11,9 @@ update_proto() { prefix="lib/libsignal-service/src/main/protowire/" GIT_REVISION=$ANDROID_GIT_REVISION ;; - Signal-Android-App) + Signal-Android-Archive) REPO="Signal-Android" - prefix="app/src/main/protowire/" + prefix="lib/archive/src/main/protowire/" GIT_REVISION=$ANDROID_GIT_REVISION ;; Signal-Desktop) @@ -34,11 +34,10 @@ update_proto Signal-Android StickerResources.proto update_proto Signal-Android WebSocketResources.proto update_proto Signal-Android StorageService.proto -update_proto Signal-Android-App Backup.proto +update_proto Signal-Android-Archive Backup.proto mv Backup.proto backuppb/Backup.proto update_proto Signal-Desktop DeviceName.proto -# TODO this was moved to libsignal only +# TODO these were moved to libsignal only #update_proto Signal-Desktop UnidentifiedDelivery.proto -# Android has CDSI.proto too, but the types have more generic names (since android uses a different package name) -update_proto Signal-Desktop ContactDiscovery.proto +#update_proto Signal-Desktop ContactDiscovery.proto diff --git a/pkg/signalmeow/provisioning.go b/pkg/signalmeow/provisioning.go index 48a8042..8e0fa96 100644 --- a/pkg/signalmeow/provisioning.go +++ b/pkg/signalmeow/provisioning.go @@ -18,7 +18,6 @@ package signalmeow import ( "context" - "crypto/hmac" "encoding/base64" "encoding/json" "fmt" @@ -166,24 +165,19 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev DeviceID: deviceId, Number: *provisioningMessage.Number, Password: password, - MasterKey: provisioningMessage.GetMasterKey(), AccountEntropyPool: libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()), EphemeralBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetEphemeralBackupKey()), MediaRootBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetMediaRootBackupKey()), } if provisioningMessage.GetAccountEntropyPool() != "" { - var masterKey []byte - masterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey() + data.MasterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey() if err != nil { log.Err(err).Msg("Failed to derive master key from account entropy pool") } else { log.Debug().Msg("Derived master key from account entropy pool") } - if data.MasterKey == nil { - data.MasterKey = masterKey - } else if !hmac.Equal(data.MasterKey, masterKey) { - log.Warn().Msg("Master key mismatch") - } + } else { + log.Warn().Msg("No account entropy pool in provisioning message") } // Store the provisioning data diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 9fa4b84..6b92d04 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -357,7 +357,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. return nil, err } log = log.With(). - Uint64("envelope_timestamp", envelope.GetTimestamp()). + Uint64("envelope_timestamp", envelope.GetClientTimestamp()). Uint64("server_timestamp", envelope.GetServerTimestamp()). Logger() ctx = log.WithContext(ctx) @@ -368,7 +368,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. Str("source_service_id", envelope.GetSourceServiceId()). Hex("destination_service_id_bytes", envelope.GetDestinationServiceIdBinary()). Hex("source_service_id_bytes", envelope.GetSourceServiceIdBinary()). - Uint32("source_device_id", envelope.GetSourceDevice()). + Uint32("source_device_id", envelope.GetSourceDeviceId()). Object("parsed_destination_service_id", destinationServiceID). Object("parsed_source_service_id", sourceServiceID). Int32("envelope_type_id", int32(envelope.GetType())). @@ -436,20 +436,20 @@ func (cli *Client) handleDecryptedResult( Bool("urgent", envelope.GetUrgent()). Stringer("content_hint", result.ContentHint). Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). + Uint64("client_ts", envelope.GetClientTimestamp()). Msg("No sender address received") return nil } else if theirServiceID, err = result.SenderAddress.NameServiceID(); err != nil { log.Warn(). Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). + Uint64("client_ts", envelope.GetClientTimestamp()). Msg("Failed to get sender name as service ID") return fmt.Errorf("failed to get sender name as service ID: %w", err) } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn(). Any("their_service_id", theirServiceID). Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). + Uint64("client_ts", envelope.GetClientTimestamp()). Msg("Dropping message from non-ACI sender") return nil } @@ -469,7 +469,7 @@ func (cli *Client) handleDecryptedResult( Bool("urgent", envelope.GetUrgent()). Stringer("content_hint", result.ContentHint). Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). + Uint64("client_ts", envelope.GetClientTimestamp()). Stringer("sender", theirServiceID). Msg("Ignoring already processed event") return nil @@ -478,7 +478,7 @@ func (cli *Client) handleDecryptedResult( Bool("urgent", envelope.GetUrgent()). Stringer("content_hint", result.ContentHint). Uint64("server_ts", envelope.GetServerTimestamp()). - Uint64("client_ts", envelope.GetTimestamp()). + Uint64("client_ts", envelope.GetClientTimestamp()). Stringer("sender", theirServiceID). Msg("Decryption error with known sender") // Only send decryption error event if the message was urgent, @@ -489,12 +489,12 @@ func (cli *Client) handleDecryptedResult( handlerSuccess = cli.handleEvent(&events.DecryptionError{ Sender: theirServiceID.UUID, Err: result.Err, - Timestamp: envelope.GetTimestamp(), + Timestamp: envelope.GetClientTimestamp(), }) } if result.Retriable { go func() { - err := cli.sendRetryRequest(ctx, result, envelope.GetTimestamp()) + err := cli.sendRetryRequest(ctx, result, envelope.GetClientTimestamp()) if err != nil { log.Err(err).Msg("Failed to send retry request in background") } @@ -506,15 +506,15 @@ func (cli *Client) handleDecryptedResult( return nil } - content := result.Content - if content == nil { + rawContent := result.Content + if rawContent == nil { log.Warn().Msg("Decrypted content is nil") return nil } deviceID, _ := result.SenderAddress.DeviceID() log.Trace(). - Any("raw_data", content). + Any("raw_data", rawContent). Stringer("sender", theirServiceID). Uint("sender_device", deviceID). Msg("Raw event data") @@ -531,9 +531,10 @@ func (cli *Client) handleDecryptedResult( } logEvt.Bool("unencrypted", result.Unencrypted).Msg("Decrypted message") - if content.DecryptionErrorMessage != nil { + // Handle unencrypted types early and refuse any other unencrypted message + if rawContent.GetDecryptionErrorMessage() != nil { handlerSuccess = true - dem, err := libsignalgo.DeserializeDecryptionErrorMessage(content.DecryptionErrorMessage) + dem, err := libsignalgo.DeserializeDecryptionErrorMessage(rawContent.GetDecryptionErrorMessage()) if err != nil { log.Warn().Err(err).Msg("Failed to unmarshal decryption error message") } else { @@ -551,9 +552,9 @@ func (cli *Client) handleDecryptedResult( } // If there's a sender key distribution message, process it - if content.GetSenderKeyDistributionMessage() != nil { + if rawContent.SenderKeyDistributionMessage != nil { log.Debug().Msg("content includes sender key distribution message") - skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(content.GetSenderKeyDistributionMessage()) + skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(rawContent.SenderKeyDistributionMessage) if err != nil { log.Err(err).Msg("DeserializeSenderKeyDistributionMessage error") return err @@ -570,6 +571,7 @@ func (cli *Client) handleDecryptedResult( } } + // If we're getting a message to our PNI, mark it as needing a PNI signature message on the next send if destinationServiceID == cli.Store.PNIServiceID() { _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { if recipient.Whitelisted == nil { @@ -589,86 +591,100 @@ func (cli *Client) handleDecryptedResult( } } - if content.PniSignatureMessage != nil { + // If we receive a PNI signature message (because we sent to a PNI earlier), process it + if rawContent.PniSignatureMessage != nil { log.Debug().Msg("Content includes PNI signature message") - err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.PniSignatureMessage) + err = cli.handlePNISignatureMessage(ctx, theirServiceID, rawContent.PniSignatureMessage) if err != nil { log.Err(err). - Hex("pni_raw", content.PniSignatureMessage.GetPni()). + Hex("pni_raw", rawContent.PniSignatureMessage.GetPni()). Stringer("aci", theirServiceID.UUID). Msg("Failed to verify ACI-PNI mapping") } } - if content.SyncMessage != nil && theirServiceID == cli.Store.ACIServiceID() { - handlerSuccess = cli.handleSyncMessage(ctx, content.SyncMessage, envelope) - return nil - } - isBlocked, err := cli.Store.RecipientStore.IsBlocked(ctx, theirServiceID.UUID) if err != nil { log.Err(err).Stringer("sender", theirServiceID).Msg("Failed to check if sender is blocked") } var sendDeliveryReceipt bool - if content.DataMessage != nil { + var deliveryReceiptTS uint64 + switch content := rawContent.Content.(type) { + case *signalpb.Content_SyncMessage: + if theirServiceID == cli.Store.ACIServiceID() { + handlerSuccess = cli.handleSyncMessage(ctx, content.SyncMessage, envelope) + } + return nil + case *signalpb.Content_DataMessage: handlerSuccess, sendDeliveryReceipt = cli.incomingDataMessage( ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked, ) - } else if content.EditMessage != nil { + deliveryReceiptTS = content.DataMessage.GetTimestamp() + case *signalpb.Content_EditMessage: handlerSuccess, sendDeliveryReceipt = cli.incomingEditMessage( ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked, ) - } - if sendDeliveryReceipt && handlerSuccess { - err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) - if err != nil { - log.Err(err).Msg("sendDeliveryReceipts error") - } - } - - if content.TypingMessage != nil && (!isBlocked || content.TypingMessage.GetGroupId() != nil) { - var groupID types.GroupIdentifier - if content.TypingMessage.GetGroupId() != nil { - gidBytes := content.TypingMessage.GetGroupId() - groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) - } - // No handler success check here, nobody cares if typing notifications are dropped - cli.handleEvent(&events.ChatEvent{ - Info: events.MessageInfo{ - Sender: theirServiceID.UUID, - ChatID: groupOrUserID(groupID, theirServiceID), - ServerTimestamp: envelope.GetServerTimestamp(), - }, - Event: content.TypingMessage, - }) - } - - // DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) - if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) && !isBlocked { - handlerSuccess = cli.handleEvent(&events.Call{ - Info: events.MessageInfo{ - Sender: theirServiceID.UUID, - ChatID: theirServiceID.String(), - ServerTimestamp: envelope.GetServerTimestamp(), - }, - // CallMessage doesn't have its own timestamp, use one from the envelope - Timestamp: envelope.GetTimestamp(), - IsRinging: content.CallMessage.Offer != nil, - }) && handlerSuccess - } - - // Read and delivery receipts - if content.ReceiptMessage != nil { - if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() { + deliveryReceiptTS = content.EditMessage.GetDataMessage().GetTimestamp() + case *signalpb.Content_ReceiptMessage: + if content.ReceiptMessage.GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() { // Ignore delivery receipts from other own devices return nil } handlerSuccess = cli.handleEvent(&events.Receipt{ Sender: theirServiceID.UUID, Content: content.ReceiptMessage, - }) && handlerSuccess + }) + case *signalpb.Content_TypingMessage: + var groupID types.GroupIdentifier + if content.TypingMessage.GetGroupId() != nil { + gidBytes := content.TypingMessage.GetGroupId() + groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) + } + if !isBlocked || groupID != "" { + // No handler success check here, nobody cares if typing notifications are dropped + cli.handleEvent(&events.ChatEvent{ + Info: events.MessageInfo{ + Sender: theirServiceID.UUID, + ChatID: groupOrUserID(groupID, theirServiceID), + ServerTimestamp: envelope.GetServerTimestamp(), + }, + Event: content.TypingMessage, + }) + } + case *signalpb.Content_CallMessage: + if !isBlocked && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) { + handlerSuccess = cli.handleEvent(&events.Call{ + Info: events.MessageInfo{ + Sender: theirServiceID.UUID, + ChatID: theirServiceID.String(), + ServerTimestamp: envelope.GetServerTimestamp(), + }, + // CallMessage doesn't have its own timestamp, use one from the envelope + Timestamp: envelope.GetClientTimestamp(), + IsRinging: content.CallMessage.Offer != nil, + }) + } + case *signalpb.Content_DecryptionErrorMessage: + // These should've been handled earlier + log.Warn().Msg("Unexpected decryption error message content in decrypted message") + case *signalpb.Content_NullMessage: + // This is intentionally ignored + case *signalpb.Content_StoryMessage: + // This is also ignored for now + default: + if rawContent.PniSignatureMessage == nil && rawContent.SenderKeyDistributionMessage == nil { + log.Warn().Type("content_type", content).Msg("Unrecognized message content type") + } } + + if sendDeliveryReceipt && handlerSuccess { + err = cli.sendDeliveryReceipts(ctx, []uint64{deliveryReceiptTS}, theirServiceID.UUID) + if err != nil { + log.Err(err).Msg("sendDeliveryReceipts error") + } + } + return nil } @@ -683,9 +699,9 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess // TODO: handle more sync messages handlerSuccess = true log := zerolog.Ctx(ctx) - if msg.Keys != nil { - aep := libsignalgo.AccountEntropyPool(msg.Keys.GetAccountEntropyPool()) - cli.Store.MasterKey = msg.Keys.GetMaster() + switch content := msg.Content.(type) { + case *signalpb.SyncMessage_Keys_: + aep := libsignalgo.AccountEntropyPool(content.Keys.GetAccountEntropyPool()) if aep != "" { aepMasterKey, err := aep.DeriveSVRKey() if err != nil { @@ -708,59 +724,65 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess log.Info().Msg("Received master key") go cli.SyncStorage(ctx) } - } else if msg.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { - log.Debug().Msg("Received storage manifest fetch latest notice") - go cli.SyncStorage(ctx) - } - syncSent := msg.GetSent() - if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { - syncDestinationServiceID, err := ParseStringOrBinaryServiceID(syncSent.GetDestinationServiceId(), syncSent.GetDestinationServiceIdBinary()) - if err != nil && !errors.Is(err, ErrEmptyUUIDInput) { - log.Err(err).Msg("Sync message destination parse error") + case *signalpb.SyncMessage_FetchLatest_: + switch content.FetchLatest.GetType() { + case signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST: + log.Debug().Msg("Received storage manifest fetch latest notice") + go cli.SyncStorage(ctx) + default: + log.Debug(). + Stringer("fetch_latest_type", content.FetchLatest.GetType()). + Msg("Received unknown fetch latest notice") } - if syncSent.GetDestinationE164() != "" && !syncDestinationServiceID.IsEmpty() { - aci, pni := syncDestinationServiceID.ToACIAndPNI() - _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) - if err != nil { - log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") + case *signalpb.SyncMessage_Sent_: + syncSent := content.Sent + if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { + syncDestinationServiceID, err := ParseStringOrBinaryServiceID(syncSent.GetDestinationServiceId(), syncSent.GetDestinationServiceIdBinary()) + if err != nil && !errors.Is(err, ErrEmptyUUIDInput) { + log.Err(err).Msg("Sync message destination parse error") } - } - for _, unident := range syncSent.GetUnidentifiedStatus() { - serviceID, err := ParseStringOrBinaryServiceID(unident.GetDestinationServiceId(), unident.GetDestinationServiceIdBinary()) - if err != nil { - log.Err(err). - Str("destination_service_id", unident.GetDestinationServiceId()). - Hex("destination_service_id_bytes", unident.GetDestinationServiceIdBinary()). - Msg("Failed to parse destination service ID of unidentified send") - continue + if syncSent.GetDestinationE164() != "" && !syncDestinationServiceID.IsEmpty() { + aci, pni := syncDestinationServiceID.ToACIAndPNI() + _, err = cli.Store.RecipientStore.UpdateRecipientE164(ctx, aci, pni, syncSent.GetDestinationE164()) + if err != nil { + log.Err(err).Msg("Failed to update recipient E164 after receiving sync message") + } } - changed, err := cli.saveSyncPNIIdentityKey(ctx, serviceID, unident.GetDestinationPniIdentityKey()) - if err != nil { - log.Err(err). - Stringer("destination_service_id", serviceID). - Msg("Failed to save PNI identity key from sync message") - } else if changed { - log.Debug(). - Stringer("destination_service_id", serviceID). - Msg("Saved new PNI identity key from sync message") + for _, unident := range syncSent.GetUnidentifiedStatus() { + serviceID, err := ParseStringOrBinaryServiceID(unident.GetDestinationServiceId(), unident.GetDestinationServiceIdBinary()) + if err != nil { + log.Err(err). + Str("destination_service_id", unident.GetDestinationServiceId()). + Hex("destination_service_id_bytes", unident.GetDestinationServiceIdBinary()). + Msg("Failed to parse destination service ID of unidentified send") + continue + } + changed, err := cli.saveSyncPNIIdentityKey(ctx, serviceID, unident.GetDestinationPniIdentityKey()) + if err != nil { + log.Err(err). + Stringer("destination_service_id", serviceID). + Msg("Failed to save PNI identity key from sync message") + } else if changed { + log.Debug(). + Stringer("destination_service_id", serviceID). + Msg("Saved new PNI identity key from sync message") + } } - } - if syncDestinationServiceID.IsEmpty() && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { - log.Warn().Msg("sync message sent destination is nil") - } else if msg.Sent.Message != nil { - // TODO handle expiration start ts, and maybe the sync message ts? - cli.incomingDataMessage(ctx, msg.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) - } else if msg.Sent.EditMessage != nil { - cli.incomingEditMessage(ctx, msg.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) + if syncDestinationServiceID.IsEmpty() && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { + log.Warn().Msg("sync message sent destination is nil") + } else if syncSent.Message != nil { + // TODO handle expiration start ts, and maybe the sync message ts? + cli.incomingDataMessage(ctx, syncSent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) + } else if syncSent.EditMessage != nil { + cli.incomingEditMessage(ctx, syncSent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) + } } - } - if msg.Contacts != nil { + case *signalpb.SyncMessage_Contacts_: log.Debug().Msg("Recieved sync message contacts") - blob := msg.Contacts.Blob - if blob != nil { + if content.Contacts.Blob != nil { // TODO roundtrip via disk to save memory - contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil, nil) + contactsBytes, err := DownloadAttachmentWithPointer(ctx, content.Contacts.Blob, nil, nil) if err != nil { log.Err(err).Msg("Contacts Sync DownloadAttachment error") } @@ -796,22 +818,14 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess }) } } - } - if msg.Read != nil { - handlerSuccess = cli.handleEvent(&events.ReadSelf{ - Timestamp: envelope.GetTimestamp(), - Messages: msg.GetRead(), - }) - } - if msg.DeleteForMe != nil { + case *signalpb.SyncMessage_DeleteForMe_: handlerSuccess = cli.handleEvent(&events.DeleteForMe{ - Timestamp: envelope.GetTimestamp(), - SyncMessage_DeleteForMe: msg.DeleteForMe, + Timestamp: envelope.GetClientTimestamp(), + SyncMessage_DeleteForMe: content.DeleteForMe, }) - } - if msg.MessageRequestResponse != nil { - aciUUID, _ := ParseStringOrBinaryUUID(msg.MessageRequestResponse.GetThreadAci(), msg.MessageRequestResponse.GetThreadAciBinary()) - if aciUUID != uuid.Nil && msg.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT { + case *signalpb.SyncMessage_MessageRequestResponse_: + aciUUID, _ := ParseStringOrBinaryUUID(content.MessageRequestResponse.GetThreadAci(), content.MessageRequestResponse.GetThreadAciBinary()) + if aciUUID != uuid.Nil && content.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT { _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aciUUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { changed = !ptr.Val(recipient.Whitelisted) || recipient.NeedsPNISignature recipient.Whitelisted = ptr.Ptr(true) @@ -823,16 +837,23 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess } } var groupID *libsignalgo.GroupIdentifier - if len(msg.MessageRequestResponse.GroupId) == libsignalgo.GroupIdentifierLength { - groupID = (*libsignalgo.GroupIdentifier)(msg.MessageRequestResponse.GroupId) + if len(content.MessageRequestResponse.GroupId) == libsignalgo.GroupIdentifierLength { + groupID = (*libsignalgo.GroupIdentifier)(content.MessageRequestResponse.GroupId) } handlerSuccess = cli.handleEvent(&events.MessageRequestResponse{ - Timestamp: envelope.GetTimestamp(), + Timestamp: envelope.GetClientTimestamp(), ThreadACI: aciUUID, GroupID: groupID, - Type: msg.MessageRequestResponse.GetType(), - Raw: msg.MessageRequestResponse, + Type: content.MessageRequestResponse.GetType(), + Raw: content.MessageRequestResponse, }) + default: + if msg.Read != nil { + handlerSuccess = cli.handleEvent(&events.ReadSelf{ + Timestamp: envelope.GetClientTimestamp(), + Messages: msg.Read, + }) + } } return } diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 24b76ff..6296f00 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -64,14 +64,14 @@ func (cli *Client) decryptEnvelope( } return result - case signalpb.Envelope_PREKEY_BUNDLE, signalpb.Envelope_CIPHERTEXT: - sender, err := sourceServiceID.Address(uint(envelope.GetSourceDevice())) + case signalpb.Envelope_PREKEY_MESSAGE, signalpb.Envelope_DOUBLE_RATCHET: + sender, err := sourceServiceID.Address(uint(envelope.GetSourceDeviceId())) if err != nil { return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} } var result *DecryptionResult var bundleType string - if *envelope.Type == signalpb.Envelope_PREKEY_BUNDLE { + if *envelope.Type == signalpb.Envelope_PREKEY_MESSAGE { result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content, envelope.GetServerTimestamp()) bundleType = "prekey bundle" } else { @@ -90,7 +90,7 @@ func (cli *Client) decryptEnvelope( return *result case signalpb.Envelope_PLAINTEXT_CONTENT: - addr, err := sourceServiceID.Address(uint(envelope.GetSourceDevice())) + addr, err := sourceServiceID.Address(uint(envelope.GetSourceDeviceId())) if err != nil { return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} } @@ -100,16 +100,13 @@ func (cli *Client) decryptEnvelope( } return DecryptionResult{ SenderAddress: addr, - Content: &signalpb.Content{DecryptionErrorMessage: content}, + Content: &signalpb.Content{Content: &signalpb.Content_DecryptionErrorMessage{DecryptionErrorMessage: content}}, Unencrypted: true, } case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} - case signalpb.Envelope_SENDERKEY_MESSAGE: - return DecryptionResult{Err: fmt.Errorf("senderkey message envelopes are not yet supported")} - case signalpb.Envelope_UNKNOWN: return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} @@ -399,7 +396,9 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin } result.Unencrypted = true result.Content = &signalpb.Content{ - DecryptionErrorMessage: usmcContents, + Content: &signalpb.Content_DecryptionErrorMessage{ + DecryptionErrorMessage: usmcContents, + }, } return result, err default: diff --git a/pkg/signalmeow/retry.go b/pkg/signalmeow/retry.go index 2c89ecc..a581075 100644 --- a/pkg/signalmeow/retry.go +++ b/pkg/signalmeow/retry.go @@ -19,10 +19,12 @@ package signalmeow import ( "context" "fmt" + "math/rand/v2" "slices" "time" "github.com/rs/zerolog" + "go.mau.fi/util/random" "go.mau.fi/mautrix-signal/pkg/libsignalgo" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" @@ -63,7 +65,9 @@ func (cli *Client) sendRetryRequest(ctx context.Context, result DecryptionResult return fmt.Errorf("failed to create ciphertext message from plaintext content: %w", err) } _, err = cli.sendContent(ctx, serviceID, uint64(time.Now().UnixMilli()), &signalpb.Content{ - DecryptionErrorMessage: demBytes, + Content: &signalpb.Content_DecryptionErrorMessage{ + DecryptionErrorMessage: demBytes, + }, }, 0, true, result.GroupID, ctm) if err != nil { return fmt.Errorf("failed to send decryption error message: %w", err) @@ -182,7 +186,11 @@ func (cli *Client) handleRetryRequest( Msg("Not responding to decryption error message") return nil } - retryContent.NullMessage = &signalpb.NullMessage{} + retryContent.Content = &signalpb.Content_NullMessage{ + NullMessage: &signalpb.NullMessage{ + Padding: random.Bytes(rand.IntN(511) + 1), + }, + } } responseTimestamp := uint64(time.Now().UnixMilli()) if cacheHit { diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 94f1dcf..769798a 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "math/rand/v2" "net/http" "strconv" "strings" @@ -31,6 +32,7 @@ import ( "github.com/rs/zerolog" "go.mau.fi/util/exfmt" "go.mau.fi/util/ptr" + "go.mau.fi/util/random" "google.golang.org/protobuf/proto" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -222,11 +224,9 @@ func (cli *Client) buildMessagesToSend( func ctmTypeToEnvelopeType(ctmType libsignalgo.CiphertextMessageType) signalpb.Envelope_Type { switch ctmType { case libsignalgo.CiphertextMessageTypeWhisper: - return signalpb.Envelope_CIPHERTEXT // 2 -> 1 + return signalpb.Envelope_DOUBLE_RATCHET // 2 -> 1 case libsignalgo.CiphertextMessageTypePreKey: - return signalpb.Envelope_PREKEY_BUNDLE // 3 -> 3 - case libsignalgo.CiphertextMessageTypeSenderKey: - return signalpb.Envelope_SENDERKEY_MESSAGE // 7 -> 7 + return signalpb.Envelope_PREKEY_MESSAGE // 3 -> 3 case libsignalgo.CiphertextMessageTypePlaintext: return signalpb.Envelope_PLAINTEXT_CONTENT // 8 -> 8 default: @@ -302,11 +302,21 @@ type SendResult interface { func (gmsr *GroupMessageSendResult) isSendResult() {} func (smsr *SendMessageResult) isSendResult() {} -func contentFromDataMessage(dataMessage *signalpb.DataMessage) *signalpb.Content { +func WrapSyncMessage(content *signalpb.SyncMessage) *signalpb.Content { + content.Padding = random.Bytes(rand.IntN(511) + 1) return &signalpb.Content{ - DataMessage: dataMessage, + Content: &signalpb.Content_SyncMessage{SyncMessage: content}, } } + +func syncSentMessage(sent *signalpb.SyncMessage_Sent) *signalpb.Content { + return WrapSyncMessage(&signalpb.SyncMessage{ + Content: &signalpb.SyncMessage_Sent_{ + Sent: sent, + }, + }) +} + func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results []SuccessfulSendResult) *signalpb.Content { unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} for _, result := range results { @@ -315,17 +325,14 @@ func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results Unidentified: &result.Unidentified, }) } - return &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ - Sent: &signalpb.SyncMessage_Sent{ - Message: dataMessage, - Timestamp: dataMessage.Timestamp, - UnidentifiedStatus: unidentifiedStatuses, - ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), - }, - }, - } + return syncSentMessage(&signalpb.SyncMessage_Sent{ + Message: dataMessage, + Timestamp: dataMessage.Timestamp, + UnidentifiedStatus: unidentifiedStatuses, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), + }) } + func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results []SuccessfulSendResult) *signalpb.Content { unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} for _, result := range results { @@ -334,58 +341,46 @@ func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results Unidentified: &result.Unidentified, }) } - return &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ - Sent: &signalpb.SyncMessage_Sent{ - EditMessage: editMessage, - Timestamp: editMessage.GetDataMessage().Timestamp, - UnidentifiedStatus: unidentifiedStatuses, - ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), - }, - }, - } + return syncSentMessage(&signalpb.SyncMessage_Sent{ + EditMessage: editMessage, + Timestamp: editMessage.GetDataMessage().Timestamp, + UnidentifiedStatus: unidentifiedStatuses, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), + }) } func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result SuccessfulSendResult) *signalpb.Content { - return &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ - Sent: &signalpb.SyncMessage_Sent{ - Message: dataMessage, - DestinationE164: result.RecipientE164, + return syncSentMessage(&signalpb.SyncMessage_Sent{ + Message: dataMessage, + DestinationE164: result.RecipientE164, + DestinationServiceIdBinary: result.Recipient.Bytes(), + Timestamp: dataMessage.Timestamp, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), + UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ + { DestinationServiceIdBinary: result.Recipient.Bytes(), - Timestamp: dataMessage.Timestamp, - ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), - UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ - { - DestinationServiceIdBinary: result.Recipient.Bytes(), - Unidentified: &result.Unidentified, - DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), - }, - }, + Unidentified: &result.Unidentified, + DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, }, - } + }) } func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result SuccessfulSendResult) *signalpb.Content { - return &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ - Sent: &signalpb.SyncMessage_Sent{ - EditMessage: editMessage, - DestinationE164: result.RecipientE164, + return syncSentMessage(&signalpb.SyncMessage_Sent{ + EditMessage: editMessage, + DestinationE164: result.RecipientE164, + DestinationServiceIdBinary: result.Recipient.Bytes(), + Timestamp: editMessage.DataMessage.Timestamp, + ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), + UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ + { DestinationServiceIdBinary: result.Recipient.Bytes(), - Timestamp: editMessage.DataMessage.Timestamp, - ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), - UnidentifiedStatus: []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{ - { - DestinationServiceIdBinary: result.Recipient.Bytes(), - Unidentified: &result.Unidentified, - DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), - }, - }, + Unidentified: &result.Unidentified, + DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), }, }, - } + }) } func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender libsignalgo.ServiceID) *signalpb.Content { @@ -407,11 +402,9 @@ func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *sign SenderAci: proto.String(messageSender.UUID.String()), }) } - return &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ - Read: read, - }, - } + return WrapSyncMessage(&signalpb.SyncMessage{ + Read: read, + }) } func (cli *Client) SendContactSyncRequest(ctx context.Context) error { @@ -427,13 +420,13 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error { } cli.LastContactRequestTime = time.Now() - _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ + _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), WrapSyncMessage(&signalpb.SyncMessage{ + Content: &signalpb.SyncMessage_Request_{ Request: &signalpb.SyncMessage_Request{ Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), }, }, - }, 0, false, nil, nil) + }), 0, false, nil, nil) if err != nil { log.Err(err).Msg("Failed to send contact sync request message to myself") return err @@ -447,13 +440,13 @@ func (cli *Client) SendStorageMasterKeyRequest(ctx context.Context) error { Logger() ctx = log.WithContext(ctx) - _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), &signalpb.Content{ - SyncMessage: &signalpb.SyncMessage{ + _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), WrapSyncMessage(&signalpb.SyncMessage{ + Content: &signalpb.SyncMessage_Request_{ Request: &signalpb.SyncMessage_Request{ Type: signalpb.SyncMessage_Request_KEYS.Enum(), }, }, - }, 0, false, nil, nil) + }), 0, false, nil, nil) if err != nil { log.Err(err).Msg("Failed to send key sync request message to myself") return err @@ -473,38 +466,47 @@ func TypingMessage(isTyping bool) *signalpb.Content { } else { action = signalpb.TypingMessage_STOPPED } - tm := &signalpb.TypingMessage{ - Timestamp: ×tamp, - Action: &action, - } return &signalpb.Content{ - TypingMessage: tm, + Content: &signalpb.Content_TypingMessage{ + TypingMessage: &signalpb.TypingMessage{ + Timestamp: ×tamp, + Action: &action, + }, + }, } } func DeliveredReceiptMessageForTimestamps(timestamps []uint64) *signalpb.Content { - rm := &signalpb.ReceiptMessage{ - Timestamp: timestamps, - Type: signalpb.ReceiptMessage_DELIVERY.Enum(), - } return &signalpb.Content{ - ReceiptMessage: rm, + Content: &signalpb.Content_ReceiptMessage{ + ReceiptMessage: &signalpb.ReceiptMessage{ + Timestamp: timestamps, + Type: signalpb.ReceiptMessage_DELIVERY.Enum(), + }, + }, } } func ReadReceptMessageForTimestamps(timestamps []uint64) *signalpb.Content { - rm := &signalpb.ReceiptMessage{ - Timestamp: timestamps, - Type: signalpb.ReceiptMessage_READ.Enum(), - } return &signalpb.Content{ - ReceiptMessage: rm, + Content: &signalpb.Content_ReceiptMessage{ + ReceiptMessage: &signalpb.ReceiptMessage{ + Timestamp: timestamps, + Type: signalpb.ReceiptMessage_READ.Enum(), + }, + }, } } -func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { +func WrapDataMessage(dm *signalpb.DataMessage) *signalpb.Content { return &signalpb.Content{ - DataMessage: dm, + Content: &signalpb.Content_DataMessage{DataMessage: dm}, + } +} + +func WrapEditMessage(dm *signalpb.EditMessage) *signalpb.Content { + return &signalpb.Content{ + Content: &signalpb.Content_EditMessage{EditMessage: dm}, } } @@ -531,7 +533,7 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte Timestamp: ×tamp, GroupV2: groupContext, } - content := wrapDataMessageInContent(dm) + content := WrapDataMessage(dm) var recipients []libsignalgo.ServiceID for _, member := range group.Members { serviceID := member.UserServiceID() @@ -569,13 +571,14 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi return nil, err } var messageTimestamp uint64 - if content.GetDataMessage() != nil { + switch content := content.Content.(type) { + case *signalpb.Content_DataMessage: messageTimestamp = content.DataMessage.GetTimestamp() content.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) - } else if content.GetEditMessage().GetDataMessage() != nil { + case *signalpb.Content_EditMessage: messageTimestamp = content.EditMessage.DataMessage.GetTimestamp() content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) - } else if content.GetTypingMessage() != nil { + case *signalpb.Content_TypingMessage: messageTimestamp = content.TypingMessage.GetTimestamp() groupIDBytes, err := group.GroupIdentifier.Bytes() if err != nil { @@ -611,7 +614,7 @@ func (cli *Client) sendToGroup( FailedToSendTo: []FailedSendResult{}, } } - if content.TypingMessage != nil { + if content.GetTypingMessage() != nil { // Never send typing messages via fallback path return result, nil } @@ -653,15 +656,16 @@ func (cli *Client) sendToGroup( func (cli *Client) sendGroupSyncCopy( ctx context.Context, - content *signalpb.Content, + rawContent *signalpb.Content, messageTimestamp uint64, result *GroupMessageSendResult, groupID *libsignalgo.GroupIdentifier, ) { var syncContent *signalpb.Content - if content.GetDataMessage() != nil { + switch content := rawContent.Content.(type) { + case *signalpb.Content_DataMessage: syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo) - } else if content.GetEditMessage() != nil { + case *signalpb.Content_EditMessage: syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) } if syncContent != nil { @@ -672,16 +676,17 @@ func (cli *Client) sendGroupSyncCopy( } } -func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool { +func (cli *Client) sendSyncCopy(ctx context.Context, rawContent *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool { var syncContent *signalpb.Content - if content.GetDataMessage() != nil { + switch content := rawContent.Content.(type) { + case *signalpb.Content_DataMessage: syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result) - } else if content.GetEditMessage() != nil { + case *signalpb.Content_EditMessage: syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) - } else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { + case *signalpb.Content_ReceiptMessage: syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) - } else if content.GetSyncMessage() != nil { - syncContent = content + case *signalpb.Content_SyncMessage: + syncContent = rawContent } if syncContent != nil { _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, nil, nil) @@ -697,22 +702,25 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.ServiceID, content *signalpb.Content) SendMessageResult { // Assemble the content to send var messageTimestamp uint64 - switch { - case content.DataMessage != nil: - messageTimestamp = *content.DataMessage.Timestamp - case content.EditMessage != nil: - messageTimestamp = *content.EditMessage.DataMessage.Timestamp - case content.TypingMessage != nil: - messageTimestamp = *content.TypingMessage.Timestamp - case content.SyncMessage != nil, - content.NullMessage != nil, - content.ReceiptMessage != nil, - content.PniSignatureMessage != nil, - content.SenderKeyDistributionMessage != nil, - content.DecryptionErrorMessage != nil: + switch realContent := content.Content.(type) { + case *signalpb.Content_DataMessage: + messageTimestamp = *realContent.DataMessage.Timestamp + case *signalpb.Content_EditMessage: + messageTimestamp = *realContent.EditMessage.DataMessage.Timestamp + case *signalpb.Content_TypingMessage: + messageTimestamp = *realContent.TypingMessage.Timestamp + case *signalpb.Content_SyncMessage, + *signalpb.Content_NullMessage, + *signalpb.Content_ReceiptMessage, + *signalpb.Content_DecryptionErrorMessage: messageTimestamp = currentMessageTimestamp() + case *signalpb.Content_StoryMessage: + // not yet supported default: - panic(fmt.Errorf("unsupported payload in SendMessage")) + if content.SenderKeyDistributionMessage == nil && content.PniSignatureMessage == nil { + panic(fmt.Errorf("unsupported payload in SendMessage")) + } + messageTimestamp = currentMessageTimestamp() } var aci, pni uuid.UUID if recipientID.Type == libsignalgo.ServiceIDTypeACI { @@ -720,7 +728,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv } else if recipientID.Type == libsignalgo.ServiceIDTypePNI { pni = recipientID.UUID } - isTypingOrReceipt := content.TypingMessage != nil || content.ReceiptMessage != nil + isTypingOrReceipt := content.GetTypingMessage() != nil || content.GetReceiptMessage() != nil recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { if content.GetDataMessage().GetFlags() == uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE) { recipientData.Whitelisted = ptr.Ptr(true) @@ -758,7 +766,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv cli.sendSyncCopy(ctx, content, messageTimestamp, &res) } return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} - } else if content.TypingMessage != nil && cli.Store.DeviceData.AccountRecord != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() { + } else if content.GetTypingMessage() != nil && cli.Store.DeviceData.AccountRecord != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() { zerolog.Ctx(ctx).Debug().Msg("Not sending typing message as typing indicators are disabled") res := SuccessfulSendResult{Recipient: recipientID} return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} @@ -770,7 +778,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} } - isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY + isDeliveryReceipt := content.GetReceiptMessage() != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY if recipientID == cli.Store.ACIServiceID() && !isDeliveryReceipt { res := SuccessfulSendResult{ Recipient: recipientID, @@ -824,25 +832,38 @@ func currentMessageTimestamp() uint64 { } func isSyncMessageUrgent(content *signalpb.SyncMessage) bool { - return content.Sent != nil || content.Request != nil + switch content.Content.(type) { + case *signalpb.SyncMessage_Request_, + *signalpb.SyncMessage_Sent_: + return true + default: + return false + } } -func isUrgent(content *signalpb.Content) bool { - return content.DataMessage != nil || - content.CallMessage != nil || - content.StoryMessage != nil || - content.EditMessage != nil || - (content.SyncMessage != nil && isSyncMessageUrgent(content.SyncMessage)) +func isUrgent(rawContent *signalpb.Content) bool { + switch content := rawContent.Content.(type) { + case *signalpb.Content_SyncMessage: + return isSyncMessageUrgent(content.SyncMessage) + case *signalpb.Content_DataMessage, + *signalpb.Content_EditMessage, + *signalpb.Content_CallMessage, + *signalpb.Content_StoryMessage: + return true + default: + return false + } } -func getContentHint(content *signalpb.Content) libsignalgo.UnidentifiedSenderMessageContentHint { - if content.DataMessage != nil || content.EditMessage != nil { +func getContentHint(rawContent *signalpb.Content) libsignalgo.UnidentifiedSenderMessageContentHint { + switch rawContent.Content.(type) { + case *signalpb.Content_DataMessage, *signalpb.Content_EditMessage: return libsignalgo.UnidentifiedSenderMessageContentHintResendable - } - if content.TypingMessage != nil || content.ReceiptMessage != nil { + case *signalpb.Content_TypingMessage, *signalpb.Content_ReceiptMessage: return libsignalgo.UnidentifiedSenderMessageContentHintImplicit + default: + return libsignalgo.UnidentifiedSenderMessageContentHintDefault } - return libsignalgo.UnidentifiedSenderMessageContentHintDefault } func (cli *Client) sendContent( @@ -863,12 +884,12 @@ func (cli *Client) sendContent( ctx = log.WithContext(ctx) // If it's a data message, add our profile key - if content.DataMessage != nil && content.DataMessage.ProfileKey == nil { + if content.GetDataMessage() != nil && content.GetDataMessage().ProfileKey == nil { profileKey, err := cli.ProfileKeyForSignalID(ctx, cli.Store.ACI) if err != nil { log.Err(err).Msg("Error getting profile key, not adding to outgoing message") } else { - content.DataMessage.ProfileKey = profileKey.Slice() + content.GetDataMessage().ProfileKey = profileKey.Slice() } } From e0901b648fbd6504da03ff3c2eb88754232309eb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 13 Apr 2026 16:58:43 +0300 Subject: [PATCH 696/718] handlesignal: add support for admin deletes --- pkg/connector/handlesignal.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 4438cb0..329b2cf 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -184,7 +184,7 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType { return bridgev2.RemoteEventReactionRemove } return bridgev2.RemoteEventReaction - case innerEvt.Delete != nil: + case innerEvt.Delete != nil, innerEvt.AdminDelete != nil: return bridgev2.RemoteEventMessageRemove case innerEvt.GetGroupV2().GetGroupChange() != nil: return bridgev2.RemoteEventChatInfoChange @@ -303,6 +303,11 @@ func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID { targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp() case innerEvt.Delete != nil: targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() + case innerEvt.AdminDelete != nil: + if len(innerEvt.AdminDelete.GetTargetAuthorAciBinary()) == 16 { + targetAuthorACI = uuid.UUID(innerEvt.AdminDelete.GetTargetAuthorAciBinary()) + } + targetSentTS = innerEvt.AdminDelete.GetTargetSentTimestamp() default: return "" } @@ -421,7 +426,7 @@ func (b *Bv2Receipt) GetReadUpTo() time.Time { return time.Time{} } -var _ bridgev2.RemoteReceipt = (*Bv2Receipt)(nil) +var _ bridgev2.RemoteReadReceipt = (*Bv2Receipt)(nil) func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt { log := zerolog.Ctx(ctx) From fd61f51ed9e3220d70710433a501275de7963529 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 15 Apr 2026 14:28:57 +0300 Subject: [PATCH 697/718] signalmeow/storageservice: handle binary uuids in contact records --- pkg/signalmeow/storageservice.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/storageservice.go b/pkg/signalmeow/storageservice.go index fcf6848..899c54b 100644 --- a/pkg/signalmeow/storageservice.go +++ b/pkg/signalmeow/storageservice.go @@ -66,12 +66,14 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat switch data := record.StorageRecord.GetRecord().(type) { case *signalpb.StorageRecord_Contact: log.Trace().Any("contact_record", data.Contact).Msg("Handling contact record") - aci, _ := uuid.Parse(data.Contact.Aci) - pni, _ := uuid.Parse(data.Contact.Pni) + aci, _ := ParseStringOrBinaryUUID(data.Contact.Aci, data.Contact.AciBinary) + pni, _ := ParseStringOrBinaryUUID(data.Contact.Pni, data.Contact.PniBinary) if aci == uuid.Nil && pni == uuid.Nil { log.Warn(). Str("raw_aci", data.Contact.Aci). Str("raw_pni", data.Contact.Pni). + Hex("raw_aci_binary", data.Contact.AciBinary). + Hex("raw_pni_binary", data.Contact.PniBinary). Str("raw_e164", data.Contact.E164). Msg("Storage service has contact record with no ACI or PNI") continue From 1f45d1af1a64a96265647ee74a80aa454b0b7296 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 16 Apr 2026 16:44:51 +0300 Subject: [PATCH 698/718] Bump version to v26.04 --- CHANGELOG.md | 9 ++++++++ cmd/mautrix-signal/main.go | 2 +- go.mod | 24 ++++++++++----------- go.sum | 44 +++++++++++++++++++------------------- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d992cab..1bf9682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# v26.04 + +* Updated libsignal to v0.92.1 +* Added support for admin message deletes from Signal. +* Added support for binary service IDs in storage service. +* Fixed `private_chat_portal_meta` option not setting DM room names correctly. +* Fixed panic if user is logged out during initial chat sync. +* Fixed avatar upload failing when creating new Signal group. + # v26.03 * Switched to sending binary service ID fields in outgoing messages. diff --git a/cmd/mautrix-signal/main.go b/cmd/mautrix-signal/main.go index cc1ec10..6440669 100644 --- a/cmd/mautrix-signal/main.go +++ b/cmd/mautrix-signal/main.go @@ -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.03", + Version: "26.04", SemCalVer: true, Connector: &connector.SignalConnector{}, diff --git a/go.mod b/go.mod index 78ca5a0..1106eb6 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal go 1.25.0 -toolchain go1.26.1 +toolchain go1.26.2 tool go.mau.fi/util/cmd/maubuild @@ -14,13 +14,13 @@ require ( github.com/rs/zerolog v1.35.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a - golang.org/x/crypto v0.49.0 - golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 - golang.org/x/net v0.52.0 + go.mau.fi/util v0.9.8 + golang.org/x/crypto v0.50.0 + golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f + golang.org/x/net v0.53.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.26.5-0.20260410220226-744570e6f1f5 + maunium.net/go/mautrix v0.27.0 ) require ( @@ -28,11 +28,11 @@ require ( 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.0 // 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.37 // indirect - github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect + github.com/mattn/go-sqlite3 v1.14.42 // indirect + github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -42,10 +42,10 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/yuin/goldmark v1.8.2 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect - golang.org/x/mod v0.34.0 // indirect + golang.org/x/mod v0.35.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/text v0.35.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect maunium.net/go/mauflag v1.0.0 // indirect diff --git a/go.sum b/go.sum index 57a3b8d..0f27daa 100644 --- a/go.sum +++ b/go.sum @@ -22,18 +22,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.12.0 h1:mC1zeiNamwKBecjHarAr26c/+d8V5w/u4J0I/yASbJo= -github.com/lib/pq v1.12.0/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= +github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= +github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/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.37 h1:3DOZp4cXis1cUIpCfXLtmlGolNLp2VEqhiB/PARNBIg= -github.com/mattn/go-sqlite3 v1.14.37/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= -github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo= +github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= +github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM= +github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -61,25 +61,25 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a h1:OQQF3rTJH10l6+dcP0OKnYbNDMBTGoIZZINNJm8QBG8= -go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a/go.mod h1:5T2f3ZWZFAGgmFwg3dGw7YK6kIsb9lryDzvynoR98pE= +go.mau.fi/util v0.9.8 h1:+/jf8eM2dAT2wx9UidmaneH28r/CSCKCniCyby1qWz8= +go.mau.fi/util v0.9.8/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= -golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.26.5-0.20260410220226-744570e6f1f5 h1:icMEYdJZfRKWXf5AyPk/2jncA84DmfxzrjhCZ4Mm/PE= -maunium.net/go/mautrix v0.26.5-0.20260410220226-744570e6f1f5/go.mod h1:MX4DQLiBe0c7sI/wizruqdxHinSOWs42/DYsP9GH7Q4= +maunium.net/go/mautrix v0.27.0 h1:yfEYwoIluVWkofUgbZl9gP4i5nQTF+QNsxtb+r5bKlM= +maunium.net/go/mautrix v0.27.0/go.mod h1:7QpEQiTy6p4LHkXXaZI+N46tGYy8HMhD0JjzZAFoFWs= From d4b2659f96d1b5fbabc7fc8794ebf57b0a71a1d7 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 23 Apr 2026 20:39:33 +0300 Subject: [PATCH 699/718] signalmeow/sending: remove unnecessary warnings for receipt sync messages --- pkg/signalmeow/sending.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 769798a..a485b54 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -384,15 +384,7 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su } func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender libsignalgo.ServiceID) *signalpb.Content { - if *receiptMessage.Type != signalpb.ReceiptMessage_READ { - zerolog.Ctx(ctx).Warn(). - Any("receipt_message_type", receiptMessage.Type). - Msg("syncMessageFromReadReceiptMessage called with non-read receipt message") - return nil - } else if messageSender.Type != libsignalgo.ServiceIDTypeACI { - zerolog.Ctx(ctx).Warn(). - Stringer("message_sender", messageSender). - Msg("syncMessageFromReadReceiptMessage called with non-ACI message sender") + if *receiptMessage.Type != signalpb.ReceiptMessage_READ || messageSender.Type != libsignalgo.ServiceIDTypeACI { return nil } read := []*signalpb.SyncMessage_Read{} From 2b2a3b036f5d8095d9603e414055f770c1a2a0b9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 27 Apr 2026 12:19:52 +0300 Subject: [PATCH 700/718] signalmeow/attachments: use go-util for pkcs7 padding --- go.mod | 2 +- go.sum | 4 ++-- pkg/signalmeow/attachments.go | 44 ++++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index 1106eb6..8df1d19 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/rs/zerolog v1.35.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.8 + go.mau.fi/util v0.9.9-0.20260424160448-fd0d9737ad38 golang.org/x/crypto v0.50.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/net v0.53.0 diff --git a/go.sum b/go.sum index 0f27daa..af95348 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.8 h1:+/jf8eM2dAT2wx9UidmaneH28r/CSCKCniCyby1qWz8= -go.mau.fi/util v0.9.8/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= +go.mau.fi/util v0.9.9-0.20260424160448-fd0d9737ad38 h1:D4OKITjyvlud39Q10oMnfhdeNkzEIVkXrEeCW6nvgLk= +go.mau.fi/util v0.9.9-0.20260424160448-fd0d9737ad38/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index a48414e..c091827 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -35,6 +35,7 @@ import ( "github.com/rs/zerolog" "go.mau.fi/util/fallocate" + "go.mau.fi/util/pkcs7" "go.mau.fi/util/random" "google.golang.org/protobuf/proto" @@ -136,6 +137,15 @@ func DownloadAttachment( const MACLength = 32 const IVLength = 16 +func macAndAESDecrypt(body, key []byte) ([]byte, error) { + l := len(body) - MACLength + if !verifyMAC(key[MACLength:], body[:l], body[l:]) { + return nil, ErrInvalidMACForAttachment + } + + return aesDecrypt(key[:MACLength], body[:l]) +} + func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) { if !plaintextDigest { hash := sha256.Sum256(body) @@ -143,12 +153,7 @@ func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint return nil, ErrInvalidDigestForAttachment } } - l := len(body) - MACLength - if !verifyMAC(key[MACLength:], body[:l], body[l:]) { - return nil, ErrInvalidMACForAttachment - } - - decrypted, err := aesDecrypt(key[:MACLength], body[:l]) + decrypted, err := macAndAESDecrypt(body, key) if err != nil { return nil, err } @@ -240,6 +245,14 @@ func extend(data []byte, paddedLen int) []byte { } } +func macAndAESEncrypt(keys, plaintext []byte) ([]byte, error) { + encrypted, err := aesEncrypt(keys[:32], plaintext) + if err != nil { + return nil, err + } + return appendMAC(keys[32:], encrypted), nil +} + func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb.AttachmentPointer, error) { log := zerolog.Ctx(ctx).With().Str("func", "upload attachment").Logger() keys := random.Bytes(64) // combined AES and MAC keys @@ -255,11 +268,10 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb } body = extend(body, paddedLen) - encrypted, err := aesEncrypt(keys[:32], body) + encryptedWithMAC, err := macAndAESEncrypt(keys, body) if err != nil { return nil, err } - encryptedWithMAC := appendMAC(keys[32:], encrypted) // Get upload attributes from Signal server attributesPath := "/v4/attachments/form/upload" @@ -467,13 +479,10 @@ func aesDecrypt(key, ciphertext []byte) ([]byte, error) { } iv := ciphertext[:IVLength] + ciphertext = ciphertext[IVLength:] mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(ciphertext, ciphertext) - pad := ciphertext[len(ciphertext)-1] - if pad > aes.BlockSize { - return nil, fmt.Errorf("pad value (%d) larger than AES blocksize (%d)", pad, aes.BlockSize) - } - return ciphertext[aes.BlockSize : len(ciphertext)-int(pad)], nil + return pkcs7.Unpad(ciphertext) } func aesDecryptFile(key []byte, file *os.File, downloadedSize int64) (int64, error) { @@ -533,14 +542,11 @@ func aesEncrypt(key, plaintext []byte) ([]byte, error) { return nil, err } - pad := aes.BlockSize - len(plaintext)%aes.BlockSize - plaintext = append(plaintext, bytes.Repeat([]byte{byte(pad)}, pad)...) - - ciphertext := make([]byte, len(plaintext)) + plaintext = pkcs7.Pad(plaintext, aes.BlockSize) iv := random.Bytes(16) mode := cipher.NewCBCEncrypter(block, iv) - mode.CryptBlocks(ciphertext, plaintext) + mode.CryptBlocks(plaintext, plaintext) - return append(iv, ciphertext...), nil + return append(iv, plaintext...), nil } From 6beb2faa9fa2ee2dda264f813766bd6517db5d84 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 23 Apr 2026 20:39:21 +0300 Subject: [PATCH 701/718] msgconv/from-matrix: preserve sticker pack metadata when sending to signal --- go.mod | 2 +- go.sum | 4 +-- pkg/msgconv/from-matrix.go | 29 ++++++++++--------- pkg/msgconv/from-signal.go | 20 ++++++------- pkg/msgconv/imagepack.go | 57 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 28 deletions(-) create mode 100644 pkg/msgconv/imagepack.go diff --git a/go.mod b/go.mod index 8df1d19..a4718d6 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/net v0.53.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.0 + maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436 ) require ( diff --git a/go.sum b/go.sum index af95348..ddff313 100644 --- a/go.sum +++ b/go.sum @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.0 h1:yfEYwoIluVWkofUgbZl9gP4i5nQTF+QNsxtb+r5bKlM= -maunium.net/go/mautrix v0.27.0/go.mod h1:7QpEQiTy6p4LHkXXaZI+N46tGYy8HMhD0JjzZAFoFWs= +maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436 h1:vga9ypiOLJmGguxq4D1aquDPFihOuD99EGPEwva12UI= +maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 89b0181..a334afd 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -110,21 +110,24 @@ func (mc *MessageConverter) ToSignal( return nil, fmt.Errorf("failed to convert sticker: %w", err) } att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_BORDERLESS)) - var emoji *string - // TODO check for single grapheme cluster? - if len([]rune(content.Body)) == 1 { - emoji = proto.String(variationselector.Remove(content.Body)) - } - dm.Sticker = &signalpb.DataMessage_Sticker{ - // Signal iOS validates that pack id/key are of the correct length. - // Android is fine with any non-nil values (like a zero-length byte string). - PackId: make([]byte, 16), - PackKey: make([]byte, 32), - StickerId: proto.Uint32(0), - Data: att, - Emoji: emoji, + dm.Sticker = ParseStickerMeta(content.Info.BridgedSticker) + if dm.Sticker == nil { + var emoji *string + // TODO check for single grapheme cluster? + if len([]rune(content.Body)) == 1 { + emoji = proto.String(variationselector.Remove(content.Body)) + } + dm.Sticker = &signalpb.DataMessage_Sticker{ + // Signal iOS validates that pack id/key are of the correct length. + // Android is fine with any non-nil values (like a zero-length byte string). + PackId: make([]byte, 16), + PackKey: make([]byte, 32), + StickerId: proto.Uint32(0), + Emoji: emoji, + } } + dm.Sticker.Data = att case event.MsgLocation: lat, lon, err := parseGeoURI(content.GeoURI) if err != nil { diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index 96b4f10..defbe44 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -468,20 +468,16 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker converted.Content.Info.Height = 200 } converted.Content.Body = sticker.GetEmoji() + if len(sticker.GetPackId()) == PackIDLength && len(sticker.GetPackKey()) == PackKeyLength && !bytes.Equal(sticker.GetPackId(), zeroPackID) { + converted.Content.Info.BridgedSticker = &event.BridgedSticker{ + Network: StickerSourceID, + ID: strconv.FormatUint(uint64(sticker.GetStickerId()), 10), + Emoji: sticker.GetEmoji(), + PackURL: fmt.Sprintf(PackURLFormat, sticker.GetPackId(), sticker.GetPackKey()), + } + } converted.Type = event.EventSticker converted.Content.MsgType = "" - if converted.Extra == nil { - converted.Extra = map[string]any{} - } - // TODO fetch full pack metadata like the old bridge did? - converted.Extra["fi.mau.signal.sticker"] = map[string]any{ - "id": sticker.GetStickerId(), - "emoji": sticker.GetEmoji(), - "pack": map[string]any{ - "id": sticker.GetPackId(), - "key": sticker.GetPackKey(), - }, - } return converted } diff --git a/pkg/msgconv/imagepack.go b/pkg/msgconv/imagepack.go new file mode 100644 index 0000000..910b5bc --- /dev/null +++ b/pkg/msgconv/imagepack.go @@ -0,0 +1,57 @@ +// mautrix-signal - A Matrix-Signal puppeting bridge. +// Copyright (C) 2026 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package msgconv + +import ( + "fmt" + "strconv" + + "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix/event" + + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" +) + +const StickerSourceID = "signal" +const PackURLFormat = "https://signal.art/addstickers/#pack_id=%x&pack_key=%x" + +const PackIDLength = 16 +const PackKeyLength = 32 +const PackURLLength = len(PackURLFormat) - len("%x")*2 + PackIDLength*2 + PackKeyLength*2 + +var zeroPackID = make([]byte, PackIDLength) + +func ParseStickerMeta(info *event.BridgedSticker) *signalpb.DataMessage_Sticker { + if info.Network != StickerSourceID || len(info.PackURL) != PackURLLength { + return nil + } + stickerID, err := strconv.ParseUint(info.ID, 10, 32) + if err != nil { + return nil + } + var packID, packKey []byte + _, err = fmt.Sscanf(info.PackURL, PackURLFormat, &packID, &packKey) + if err != nil || len(packID) != PackIDLength || len(packKey) != PackKeyLength { + return nil + } + return &signalpb.DataMessage_Sticker{ + PackId: packID, + PackKey: packKey, + StickerId: proto.Uint32(uint32(stickerID)), + Emoji: &info.Emoji, + } +} From c2afb9f1135e125f6baa3252b4faf8a4ea960eba Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 27 Apr 2026 12:22:20 +0300 Subject: [PATCH 702/718] signalmeow/web: sent ContentLength field in request --- pkg/signalmeow/web/web.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index d0fcd01..e617b40 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -129,6 +129,7 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe } else { req.Header.Set("Content-Type", string(ContentTypeJSON)) } + req.ContentLength = int64(len(opt.Body)) req.Header.Set("Content-Length", fmt.Sprintf("%d", len(opt.Body))) req.Header.Set("User-Agent", UserAgent) req.Header.Set("X-Signal-Agent", SignalAgent) From 9e9dc8b548b35a8a964358d835ae12b161d020fc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 27 Apr 2026 12:30:54 +0300 Subject: [PATCH 703/718] signalmeow/sticker: add methods for creating and fetching sticker packs --- go.mod | 2 +- pkg/signalmeow/sticker.go | 251 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 pkg/signalmeow/sticker.go diff --git a/go.mod b/go.mod index a4718d6..030ad61 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( golang.org/x/crypto v0.50.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/net v0.53.0 + golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436 @@ -43,7 +44,6 @@ require ( github.com/yuin/goldmark v1.8.2 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect golang.org/x/mod v0.35.0 // indirect - golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.43.0 // indirect golang.org/x/text v0.36.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/pkg/signalmeow/sticker.go b/pkg/signalmeow/sticker.go new file mode 100644 index 0000000..2759d18 --- /dev/null +++ b/pkg/signalmeow/sticker.go @@ -0,0 +1,251 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2026 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "bytes" + "context" + "crypto/hkdf" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/textproto" + "sync" + + "go.mau.fi/util/exerrors" + "go.mau.fi/util/random" + "golang.org/x/sync/semaphore" + "google.golang.org/protobuf/proto" + + signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +func DownloadStickerPackManifest(ctx context.Context, packID, packKey []byte) (*signalpb.Pack, error) { + if len(packID) != 16 { + return nil, fmt.Errorf("invalid pack ID length: %d", len(packID)) + } + resp, err := downloadStickerData(ctx, fmt.Sprintf("/stickers/%x/manifest.proto", packID), packKey) + if err != nil { + return nil, err + } + var pack signalpb.Pack + err = proto.Unmarshal(resp, &pack) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal decrypted manifest: %w", err) + } + return &pack, nil +} + +func DownloadStickerPackItem(ctx context.Context, packID, packKey []byte, stickerID uint32) ([]byte, error) { + if len(packID) != 16 { + return nil, fmt.Errorf("invalid pack ID length: %d", len(packID)) + } + return downloadStickerData(ctx, fmt.Sprintf("/stickers/%x/full/%d", packID, stickerID), packKey) +} + +func downloadStickerData(ctx context.Context, path string, packKey []byte) ([]byte, error) { + if len(packKey) != 32 { + return nil, fmt.Errorf("invalid pack key length: %d", len(packKey)) + } + var body, decrypted []byte + resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodGet, path, nil) + defer web.CloseBody(resp) + if err != nil { + return nil, fmt.Errorf("failed to make request: %w", err) + } else if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) + } else if body, err = io.ReadAll(resp.Body); err != nil { + return nil, fmt.Errorf("failed to read response: %w", err) + } else if decrypted, err = decryptSticker(packKey, body); err != nil { + return nil, fmt.Errorf("failed to decrypt response: %w", err) + } else { + return decrypted, nil + } +} + +type stickerUploadAttributes struct { + ACL string `json:"acl"` + Algorithm string `json:"algorithm"` + Credential string `json:"credential"` + Date string `json:"date"` + ID int `json:"id"` + Key string `json:"key"` + Policy string `json:"policy"` + Signature string `json:"signature"` +} + +func (sua *stickerUploadAttributes) makeFormBody(encryptedData []byte) (*web.HTTPReqOpt, error) { + var buf bytes.Buffer + writer := multipart.NewWriter(&buf) + var closed bool + // This isn't necessary in practice, just do it to avoid linter warnings + defer func() { + if !closed { + _ = writer.Close() + } + }() + fields := map[string]string{ + "key": sua.Key, + "acl": sua.ACL, + "policy": sua.Policy, + "x-amz-algorithm": sua.Algorithm, + "x-amz-credential": sua.Credential, + "x-amz-date": sua.Date, + "Content-Type": "application/octet-stream", + } + for key, value := range fields { + err := writer.WriteField(key, value) + if err != nil { + return nil, fmt.Errorf("failed to write multipart field %s: %w", key, err) + } + } + filePart, err := writer.CreatePart(textproto.MIMEHeader{ + "Content-Type": []string{"application/octet-stream"}, + "Content-Disposition": []string{`form-data; name="file"`}, + }) + if err != nil { + return nil, fmt.Errorf("failed to create multipart file part: %w", err) + } + _, err = filePart.Write(encryptedData) + if err != nil { + return nil, fmt.Errorf("failed to write file data to multipart body: %w", err) + } + err = writer.Close() + if err != nil { + return nil, fmt.Errorf("failed to close multipart writer: %w", err) + } + closed = true + return &web.HTTPReqOpt{ + Body: buf.Bytes(), + ContentType: web.ContentType(writer.FormDataContentType()), + }, nil +} + +func (sua *stickerUploadAttributes) upload(ctx context.Context, packKey, fileData []byte) error { + encryptedData, err := macAndAESEncrypt(fileData, deriveStickerPackKey(packKey)) + if err != nil { + return fmt.Errorf("failed to encrypt sticker data: %w", err) + } + req, err := sua.makeFormBody(encryptedData) + if err != nil { + return fmt.Errorf("failed to prepare request: %w", err) + } + resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodPost, "/", req) + if err != nil { + return err + } + _ = resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + return nil +} + +func (sua *stickerUploadAttributes) uploadAsync( + ctx context.Context, + packKey []byte, + getFileData func(context.Context) ([]byte, error), + sema *semaphore.Weighted, + done func(), + onError func(error), +) { + defer done() + err := sema.Acquire(ctx, 1) + if err != nil { + return + } + defer sema.Release(1) + fileData, err := getFileData(ctx) + if err == nil { + err = sua.upload(ctx, packKey, fileData) + } + if err != nil { + onError(err) + } +} + +type stickerPackUploadAttributes struct { + PackID string `json:"packId"` + Manifest *stickerUploadAttributes `json:"manifest"` + Stickers []*stickerUploadAttributes `json:"stickers"` +} + +var StickerUploadParallelism = 4 + +func (cli *Client) UploadStickerPack(ctx context.Context, pack *signalpb.Pack, stickerData []func(context.Context) ([]byte, error)) (packID, packKey []byte, err error) { + for i, sticker := range pack.Stickers { + if sticker.GetId() >= uint32(len(stickerData)) { + return nil, nil, fmt.Errorf("sticker ID %d at index %d is out of bounds, only %d sticker blobs provided", sticker.GetId(), i, len(stickerData)) + } + } + marshaledPack, err := proto.Marshal(pack) + if err != nil { + return nil, nil, fmt.Errorf("failed to marshal pack: %w", err) + } + packKey = random.Bytes(32) + resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, fmt.Sprintf("/v1/sticker/pack/form/%d", len(stickerData)), nil, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to get upload form: %w", err) + } + var packAttributes stickerPackUploadAttributes + err = web.DecodeWSResponseBody(ctx, &packAttributes, resp) + if err != nil { + return nil, nil, fmt.Errorf("failed to decode pack attributes: %w", err) + } + if len(packAttributes.Stickers) != len(stickerData) { + return nil, nil, fmt.Errorf("expected %d sticker upload attribute sets, got %d", len(stickerData), len(packAttributes.Stickers)) + } + packID, err = hex.DecodeString(packAttributes.PackID) + if err != nil { + return nil, nil, fmt.Errorf("invalid pack ID in response: %w", err) + } + err = packAttributes.Manifest.upload(ctx, packKey, marshaledPack) + if err != nil { + return nil, nil, fmt.Errorf("failed to upload manifest: %w", err) + } + var wg sync.WaitGroup + wg.Add(len(packAttributes.Stickers)) + sema := semaphore.NewWeighted(int64(StickerUploadParallelism)) + var errorList []error + var errorLock sync.Mutex + for i, attrs := range packAttributes.Stickers { + go attrs.uploadAsync(ctx, packKey, stickerData[i], sema, wg.Done, func(err error) { + errorLock.Lock() + errorList = append(errorList, fmt.Errorf("failed to upload sticker #%d: %w", i+1, err)) + errorLock.Unlock() + }) + } + wg.Wait() + err = ctx.Err() + if err == nil { + err = errors.Join(errorList...) + } + return +} + +func decryptSticker(packKey, ciphertext []byte) ([]byte, error) { + return macAndAESDecrypt(ciphertext, deriveStickerPackKey(packKey)) +} + +func deriveStickerPackKey(key []byte) []byte { + return exerrors.Must(hkdf.Key(sha256.New, key, make([]byte, 32), "Sticker Pack", 2*32)) +} From a27b6745b2eeb7720ad74a1c890a1b58e969848c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 29 Apr 2026 09:10:31 +0300 Subject: [PATCH 704/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 030ad61..0a53f3b 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436 + maunium.net/go/mautrix v0.27.1-0.20260429060852-d7aad0e862c7 ) require ( diff --git a/go.sum b/go.sum index ddff313..f291411 100644 --- a/go.sum +++ b/go.sum @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436 h1:vga9ypiOLJmGguxq4D1aquDPFihOuD99EGPEwva12UI= -maunium.net/go/mautrix v0.27.1-0.20260428110059-49a05bf06436/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= +maunium.net/go/mautrix v0.27.1-0.20260429060852-d7aad0e862c7 h1:ZL/dTgBuj7ZzH543brFUvxZo2lJGsCMBvnfKIvjdHC4= +maunium.net/go/mautrix v0.27.1-0.20260429060852-d7aad0e862c7/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= From 14559977fc5d1d796a39170c7c1b39b4ab3303c5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Apr 2026 12:05:00 +0300 Subject: [PATCH 705/718] directmedia: fix response metadata for avatars --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/directmedia.go | 40 ++++++++++++++---------------------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 0a53f3b..9ef0f7b 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260429060852-d7aad0e862c7 + maunium.net/go/mautrix v0.27.1-0.20260430090139-beddfdeef6c9 ) require ( diff --git a/go.sum b/go.sum index f291411..1ae8e5f 100644 --- a/go.sum +++ b/go.sum @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.1-0.20260429060852-d7aad0e862c7 h1:ZL/dTgBuj7ZzH543brFUvxZo2lJGsCMBvnfKIvjdHC4= -maunium.net/go/mautrix v0.27.1-0.20260429060852-d7aad0e862c7/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= +maunium.net/go/mautrix v0.27.1-0.20260430090139-beddfdeef6c9 h1:ffaVxcARQCkNq4Vw+AaXMUH4HcU5StEWOrfphM/jEfw= +maunium.net/go/mautrix v0.27.1-0.20260430090139-beddfdeef6c9/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go index 0877d66..4f010f6 100644 --- a/pkg/connector/directmedia.go +++ b/pkg/connector/directmedia.go @@ -4,7 +4,6 @@ import ( "context" "encoding/base64" "fmt" - "io" "os" "maunium.net/go/mautrix/bridgev2" @@ -30,6 +29,7 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI return nil, fmt.Errorf("failed to parse direct media id: %w", err) } + var rawDataResp []byte switch info := info.(type) { case *signalid.DirectMediaAttachment: log.Info(). @@ -76,18 +76,11 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI return nil, fmt.Errorf("failed to to get group master key: %w", err) } - return &mediaproxy.GetMediaResponseCallback{ - Callback: func(w io.Writer) (int64, error) { - data, err := client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) - if err != nil { - log.Err(err).Msg("Direct download failed") - return 0, err - } - - _, err = w.Write(data) - return int64(len(data)), err - }, - }, nil + rawDataResp, err = client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) + if err != nil { + log.Err(err).Msg("Direct download failed") + return nil, err + } case *signalid.DirectMediaProfileAvatar: log.Info(). Stringer("user_id", info.UserID). @@ -111,19 +104,16 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI return nil, fmt.Errorf("profile key not found") } - return &mediaproxy.GetMediaResponseCallback{ - Callback: func(w io.Writer) (int64, error) { - data, err := client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) - if err != nil { - log.Err(err).Msg("Direct download failed") - return 0, err - } - - _, err = w.Write(data) - return int64(len(data)), err - }, - }, nil + rawDataResp, err = client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) + if err != nil { + log.Err(err).Msg("Direct download failed") + return nil, err + } default: return nil, fmt.Errorf("no downloader for direct media type: %T", info) } + if rawDataResp == nil { + return nil, fmt.Errorf("unexpected fallthrough with no data") + } + return mediaproxy.GetMediaResponseRawData(rawDataResp), nil } From 1f1b645213c02b7142338ae7d6aaf2e803410f70 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Apr 2026 12:26:24 +0300 Subject: [PATCH 706/718] client: add support for importing Signal sticker packs --- go.mod | 2 +- go.sum | 4 +- pkg/connector/client.go | 5 ++ pkg/connector/directmedia.go | 11 +++ pkg/msgconv/imagepack.go | 147 ++++++++++++++++++++++++++++++++++- pkg/signalid/media.go | 35 +++++++++ 6 files changed, 198 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 9ef0f7b..f409215 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/rs/zerolog v1.35.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.9-0.20260424160448-fd0d9737ad38 + go.mau.fi/util v0.9.9-0.20260430092340-8772e7714ea5 golang.org/x/crypto v0.50.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/net v0.53.0 diff --git a/go.sum b/go.sum index 1ae8e5f..abe70ca 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.9-0.20260424160448-fd0d9737ad38 h1:D4OKITjyvlud39Q10oMnfhdeNkzEIVkXrEeCW6nvgLk= -go.mau.fi/util v0.9.9-0.20260424160448-fd0d9737ad38/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= +go.mau.fi/util v0.9.9-0.20260430092340-8772e7714ea5 h1:cNm4gkt7j907g1Q4XvyNKW8tTM8BaU91Kbfa5GGyiCs= +go.mau.fi/util v0.9.9-0.20260430092340-8772e7714ea5/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 17ee216..1f69191 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -46,6 +46,7 @@ type SignalClient struct { var ( _ bridgev2.NetworkAPI = (*SignalClient)(nil) _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) + _ bridgev2.StickerImportingNetworkAPI = (*SignalClient)(nil) ) var pushCfg = &bridgev2.PushConfig{ @@ -76,6 +77,10 @@ func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType b } } +func (s *SignalClient) DownloadImagePack(ctx context.Context, url string) (*bridgev2.ImportedImagePack, error) { + return s.Main.MsgConv.DownloadImagePack(ctx, url) +} + func (s *SignalClient) LogoutRemote(ctx context.Context) { if s.Client == nil { return diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go index 4f010f6..05e2a07 100644 --- a/pkg/connector/directmedia.go +++ b/pkg/connector/directmedia.go @@ -109,6 +109,17 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI log.Err(err).Msg("Direct download failed") return nil, err } + case *signalid.DirectMediaSticker: + log.Info(). + Hex("pack_id", info.PackID). + Uint32("sticker_id", info.StickerID). + Msg("Direct downloading sticker") + + rawDataResp, err = signalmeow.DownloadStickerPackItem(ctx, info.PackID, info.PackKey, info.StickerID) + if err != nil { + log.Err(err).Msg("Direct download failed") + return nil, err + } default: return nil, fmt.Errorf("no downloader for direct media type: %T", info) } diff --git a/pkg/msgconv/imagepack.go b/pkg/msgconv/imagepack.go index 910b5bc..8d538bf 100644 --- a/pkg/msgconv/imagepack.go +++ b/pkg/msgconv/imagepack.go @@ -17,12 +17,23 @@ package msgconv import ( + "bytes" + "context" + "encoding/hex" "fmt" + "net/url" "strconv" + "strings" + "go.mau.fi/util/emojishortcodes" "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" + "go.mau.fi/mautrix-signal/pkg/signalid" + "go.mau.fi/mautrix-signal/pkg/signalmeow" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" ) @@ -43,9 +54,8 @@ func ParseStickerMeta(info *event.BridgedSticker) *signalpb.DataMessage_Sticker if err != nil { return nil } - var packID, packKey []byte - _, err = fmt.Sscanf(info.PackURL, PackURLFormat, &packID, &packKey) - if err != nil || len(packID) != PackIDLength || len(packKey) != PackKeyLength { + packID, packKey, err := parsePackURL(info.PackURL) + if err != nil || len(packID) != PackIDLength || len(packKey) != PackKeyLength || bytes.Equal(packID, zeroPackID) { return nil } return &signalpb.DataMessage_Sticker{ @@ -55,3 +65,134 @@ func ParseStickerMeta(info *event.BridgedSticker) *signalpb.DataMessage_Sticker Emoji: &info.Emoji, } } + +func parsePackURL(rawURL string) (packID, packKey []byte, err error) { + parsed, err := url.Parse(rawURL) + if err != nil { + return nil, nil, fmt.Errorf("invalid URL: %w", err) + } else if parsed.Host != "signal.art" || !strings.HasPrefix(parsed.Path, "/addstickers") { + return nil, nil, fmt.Errorf("invalid host or path in URL") + } + q, err := url.ParseQuery(parsed.Fragment) + if err != nil { + return nil, nil, fmt.Errorf("invalid URL fragment: %w", err) + } + packID, err = hex.DecodeString(q.Get("pack_id")) + if err != nil { + return nil, nil, fmt.Errorf("invalid pack ID in URL: %w", err) + } + packKey, err = hex.DecodeString(q.Get("pack_key")) + if err != nil { + return nil, nil, fmt.Errorf("invalid pack key in URL: %w", err) + } + return +} + +func (mc *MessageConverter) DownloadImagePack(ctx context.Context, url string) (*bridgev2.ImportedImagePack, error) { + packID, packKey, err := parsePackURL(url) + if err != nil { + return nil, err + } + manifest, err := signalmeow.DownloadStickerPackManifest(ctx, packID, packKey) + if err != nil { + return nil, fmt.Errorf("failed to download sticker pack manifest: %w", err) + } + topLevelExtra := map[string]any{ + "fi.mau.signal.stickerpack": map[string]any{ + "pack_id": hex.EncodeToString(packID), + "pack_key": hex.EncodeToString(packKey), + }, + } + content := &event.ImagePackEventContent{ + Images: make(map[string]*event.ImagePackImage, len(manifest.Stickers)), + Metadata: event.ImagePackMetadata{ + DisplayName: manifest.GetTitle(), + AvatarURL: "", + Usage: []event.ImagePackUsage{event.ImagePackUsageSticker}, + Attribution: manifest.GetAuthor(), + BridgedPack: &event.BridgedStickerPack{ + Network: StickerSourceID, + URL: fmt.Sprintf(PackURLFormat, packID, packKey), + }, + }, + } + imagesByID := make(map[uint32]id.ContentURIString, len(manifest.Stickers)) + uploadImage := func(sticker *signalpb.Pack_Sticker) (id.ContentURIString, error) { + stickerID := sticker.GetId() + existing, ok := imagesByID[stickerID] + if ok { + return existing, nil + } + var mxc id.ContentURIString + if mc.DirectMedia { + mediaID, err := signalid.DirectMediaSticker{ + PackID: packID, + PackKey: packKey, + StickerID: stickerID, + }.AsMediaID() + if err != nil { + return "", fmt.Errorf("failed to create media ID for sticker %d: %w", stickerID, err) + } + mxc, err = mc.Bridge.Matrix.GenerateContentURI(ctx, mediaID) + if err != nil { + return "", fmt.Errorf("failed to generate content URI for sticker %d: %w", stickerID, err) + } + } else { + dbKey := database.Key(fmt.Sprintf("stickercache:%x:%d", packID, stickerID)) + if cached := mc.Bridge.DB.KV.Get(ctx, dbKey); cached != "" { + mxc = id.ContentURIString(cached) + imagesByID[stickerID] = mxc + return mxc, nil + } + data, err := signalmeow.DownloadStickerPackItem(ctx, packID, packKey, stickerID) + if err != nil { + return "", fmt.Errorf("failed to download sticker %d: %w", stickerID, err) + } + mxc, _, err = mc.Bridge.Bot.UploadMedia(ctx, "", data, "", sticker.GetContentType()) + if err != nil { + return "", fmt.Errorf("failed to upload sticker %d: %w", stickerID, err) + } + mc.Bridge.DB.KV.Set(ctx, dbKey, string(mxc)) + } + imagesByID[stickerID] = mxc + return mxc, nil + } + for _, sticker := range manifest.Stickers { + mxc, err := uploadImage(sticker) + if err != nil { + return nil, err + } + shortcode := emojishortcodes.Get(sticker.GetEmoji()) + realShortcode := shortcode + i := 2 + for _, alreadyExists := content.Images[realShortcode]; alreadyExists; i++ { + realShortcode = fmt.Sprintf("%s_%d", shortcode, i) + } + content.Images[realShortcode] = &event.ImagePackImage{ + URL: mxc, + Body: sticker.GetEmoji(), + Info: &event.FileInfo{ + MimeType: sticker.GetContentType(), + Width: 200, + Height: 200, + BridgedSticker: &event.BridgedSticker{ + Network: StickerSourceID, + ID: strconv.FormatUint(uint64(sticker.GetId()), 10), + Emoji: sticker.GetEmoji(), + PackURL: content.Metadata.BridgedPack.URL, + }, + }, + } + } + if manifest.Cover != nil { + content.Metadata.AvatarURL, err = uploadImage(manifest.Cover) + if err != nil { + return nil, fmt.Errorf("failed to upload sticker pack cover: %w", err) + } + } + return &bridgev2.ImportedImagePack{ + Content: content, + Extra: topLevelExtra, + Shortcode: hex.EncodeToString(packID), + }, nil +} diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go index 8c91b6a..a530c22 100644 --- a/pkg/signalid/media.go +++ b/pkg/signalid/media.go @@ -34,6 +34,7 @@ const ( directMediaTypeGroupAvatar directMediaType = 1 directMediaTypeProfileAvatar directMediaType = 2 directMediaTypePlaintextDigestAttachment directMediaType = 3 + directMediaTypeSticker directMediaType = 4 ) type DirectMediaInfo interface { @@ -44,6 +45,7 @@ var ( _ DirectMediaInfo = (*DirectMediaAttachment)(nil) _ DirectMediaInfo = (*DirectMediaGroupAvatar)(nil) _ DirectMediaInfo = (*DirectMediaProfileAvatar)(nil) + _ DirectMediaInfo = (*DirectMediaSticker)(nil) ) type DirectMediaAttachment struct { @@ -127,6 +129,30 @@ func (m DirectMediaProfileAvatar) AsMediaID() (mediaID networkid.MediaID, err er return networkid.MediaID(buf.Bytes()), nil } +type DirectMediaSticker struct { + PackID []byte + PackKey []byte + StickerID uint32 +} + +const packIDLen = 16 +const packKeyLen = 32 +const directMediaStickerLen = 1 + packIDLen + packKeyLen + 4 + +func (m DirectMediaSticker) AsMediaID() (mediaID networkid.MediaID, err error) { + if len(m.PackID) != packIDLen { + return nil, fmt.Errorf("invalid pack ID length: %d", len(m.PackID)) + } else if len(m.PackKey) != packKeyLen { + return nil, fmt.Errorf("invalid pack key length: %d", len(m.PackKey)) + } + mediaID = make(networkid.MediaID, directMediaStickerLen) + mediaID[0] = byte(directMediaTypeSticker) + copy(mediaID[1:], m.PackID) + copy(mediaID[1+packIDLen:], m.PackKey) + binary.BigEndian.PutUint32(mediaID[1+packIDLen+packKeyLen:], m.StickerID) + return mediaID, nil +} + func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err error) { mediaIDLen := len(mediaID) if mediaIDLen == 0 { @@ -200,6 +226,15 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err info.ProfileAvatarPath = string(profileAvatarPath) } return &info, nil + case directMediaTypeSticker: + var info DirectMediaSticker + if len(mediaID) != directMediaStickerLen { + return info, fmt.Errorf("invalid media ID length for sticker: %d", len(mediaID)) + } + info.PackID = mediaID[1 : 1+packIDLen] + info.PackKey = mediaID[1+packIDLen : 1+packIDLen+packKeyLen] + info.StickerID = binary.BigEndian.Uint32(mediaID[1+packIDLen+packKeyLen:]) + return &info, nil } return nil, fmt.Errorf("invalid direct media type %d", mediaType) From 9ebd8d4dd09fbbbf3b39deaf673e01d9c611fe2d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Apr 2026 13:23:08 +0300 Subject: [PATCH 707/718] .github: add another item to bug report template --- .github/ISSUE_TEMPLATE/bug.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index c10630f..06ba9e8 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -11,7 +11,8 @@ type: Bug ### Checklist - + * [ ] This is an actual bug, not just a setup issue (see the [troubleshooting docs](https://docs.mau.fi/bridges/general/troubleshooting.html) or ask in the Matrix room for setup help). * [ ] I am certain that sufficient information is included. Ask in the Matrix room first if not. +* [ ] The bug is still present on the main branch. From 694858478c710b08a7a61e18a57b402d5d35eafc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 30 Apr 2026 15:15:08 +0300 Subject: [PATCH 708/718] client: add stub ListImagePacks method --- go.mod | 2 +- go.sum | 4 ++-- pkg/connector/capabilities.go | 1 + pkg/connector/client.go | 5 +++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f409215..a936973 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260430090139-beddfdeef6c9 + maunium.net/go/mautrix v0.27.1-0.20260430124810-125ac2c48014 ) require ( diff --git a/go.sum b/go.sum index abe70ca..f817e1d 100644 --- a/go.sum +++ b/go.sum @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.1-0.20260430090139-beddfdeef6c9 h1:ffaVxcARQCkNq4Vw+AaXMUH4HcU5StEWOrfphM/jEfw= -maunium.net/go/mautrix v0.27.1-0.20260430090139-beddfdeef6c9/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= +maunium.net/go/mautrix v0.27.1-0.20260430124810-125ac2c48014 h1:KwXGBWwUHYJKVTYWgbZEFcaM6uYLMvfjzHJg/TLwvKc= +maunium.net/go/mautrix v0.27.1-0.20260430124810-125ac2c48014/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index e791324..d23285c 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -211,6 +211,7 @@ var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ AggressiveUpdateInfo: true, ImplicitReadReceipts: true, Provisioning: bridgev2.ProvisioningCapabilities{ + ImagePackImport: true, ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{ CreateDM: true, LookupPhone: true, diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 1f69191..4fcf188 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -27,6 +27,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/bridgev2/status" + "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" @@ -81,6 +82,10 @@ func (s *SignalClient) DownloadImagePack(ctx context.Context, url string) (*brid return s.Main.MsgConv.DownloadImagePack(ctx, url) } +func (s *SignalClient) ListImagePacks(ctx context.Context) ([]*event.ImagePackMetadata, error) { + return []*event.ImagePackMetadata{}, nil +} + func (s *SignalClient) LogoutRemote(ctx context.Context) { if s.Client == nil { return From 0214ecc6005359dcb41bacd56cd07de5bc4521a3 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 4 May 2026 17:32:04 +0300 Subject: [PATCH 709/718] msgconv/imagepack: fix stickers with no bridged metadata --- pkg/msgconv/imagepack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/msgconv/imagepack.go b/pkg/msgconv/imagepack.go index 8d538bf..e8f91cb 100644 --- a/pkg/msgconv/imagepack.go +++ b/pkg/msgconv/imagepack.go @@ -47,7 +47,7 @@ const PackURLLength = len(PackURLFormat) - len("%x")*2 + PackIDLength*2 + PackKe var zeroPackID = make([]byte, PackIDLength) func ParseStickerMeta(info *event.BridgedSticker) *signalpb.DataMessage_Sticker { - if info.Network != StickerSourceID || len(info.PackURL) != PackURLLength { + if info == nil || info.Network != StickerSourceID || len(info.PackURL) != PackURLLength { return nil } stickerID, err := strconv.ParseUint(info.ID, 10, 32) From 0813d3909524ec4db44284cc180a75685557c847 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 6 May 2026 13:23:56 +0300 Subject: [PATCH 710/718] .github: add version command to bug report template --- .github/ISSUE_TEMPLATE/bug.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 06ba9e8..cba1054 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -15,4 +15,4 @@ type: Bug * [ ] This is an actual bug, not just a setup issue (see the [troubleshooting docs](https://docs.mau.fi/bridges/general/troubleshooting.html) or ask in the Matrix room for setup help). * [ ] I am certain that sufficient information is included. Ask in the Matrix room first if not. -* [ ] The bug is still present on the main branch. +* [ ] The bug is still present on the main branch. The `!signal version` command output is: `` From 90487a25e048d9677e059291d44d8f80a6a5a391 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 6 May 2026 13:47:09 +0300 Subject: [PATCH 711/718] imagepack: return 404 on incorrectly formatted link --- pkg/msgconv/imagepack.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/msgconv/imagepack.go b/pkg/msgconv/imagepack.go index e8f91cb..a2529af 100644 --- a/pkg/msgconv/imagepack.go +++ b/pkg/msgconv/imagepack.go @@ -27,6 +27,7 @@ import ( "go.mau.fi/util/emojishortcodes" "google.golang.org/protobuf/proto" + "maunium.net/go/mautrix" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/event" @@ -91,7 +92,7 @@ func parsePackURL(rawURL string) (packID, packKey []byte, err error) { func (mc *MessageConverter) DownloadImagePack(ctx context.Context, url string) (*bridgev2.ImportedImagePack, error) { packID, packKey, err := parsePackURL(url) if err != nil { - return nil, err + return nil, bridgev2.WrapRespErr(err, mautrix.MNotFound) } manifest, err := signalmeow.DownloadStickerPackManifest(ctx, packID, packKey) if err != nil { From 06bdbfc2cab281e91af2dc97f2cdc15512d00b7e Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 8 May 2026 16:55:42 +0300 Subject: [PATCH 712/718] libsignal: update to v0.93.2 --- pkg/libsignalgo/identitykeystore.go | 12 +- pkg/libsignalgo/kyberprekeystore.go | 8 +- pkg/libsignalgo/libsignal | 2 +- pkg/libsignalgo/libsignal-ffi.h | 191 ++++++++++++++------------- pkg/libsignalgo/message.go | 3 +- pkg/libsignalgo/prekeybundle.go | 3 +- pkg/libsignalgo/prekeystore.go | 8 +- pkg/libsignalgo/senderkeystore.go | 6 +- pkg/libsignalgo/session_test.go | 19 +-- pkg/libsignalgo/sessionstore.go | 6 +- pkg/libsignalgo/signedprekeystore.go | 6 +- pkg/libsignalgo/version.go | 2 +- pkg/signalmeow/keys.go | 5 + pkg/signalmeow/receiving_decrypt.go | 5 + 14 files changed, 147 insertions(+), 129 deletions(-) diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index 43941da..ba26f06 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -159,11 +159,11 @@ func signal_destroy_identity_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct { return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{ ctx: wrapStore(ctx, store), - get_local_identity_key_pair: C.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), - get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), - get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), - save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), - is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), - destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), + get_local_identity_key_pair: C.SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), + get_local_registration_id: C.SignalFfiIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), + get_identity_key: C.SignalFfiIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), + save_identity_key: C.SignalFfiIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), + is_trusted_identity: C.SignalFfiIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), + destroy: C.SignalFfiIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), }} } diff --git a/pkg/libsignalgo/kyberprekeystore.go b/pkg/libsignalgo/kyberprekeystore.go index ebb5a9f..9deea17 100644 --- a/pkg/libsignalgo/kyberprekeystore.go +++ b/pkg/libsignalgo/kyberprekeystore.go @@ -77,9 +77,9 @@ func signal_destroy_kyber_pre_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) C.SignalConstPointerFfiKyberPreKeyStoreStruct { return C.SignalConstPointerFfiKyberPreKeyStoreStruct{&C.SignalKyberPreKeyStore{ ctx: wrapStore(ctx, store), - load_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), - store_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), - mark_kyber_pre_key_used: C.SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), - destroy: C.SignalFfiBridgeKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), + load_kyber_pre_key: C.SignalFfiKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), + store_kyber_pre_key: C.SignalFfiKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), + mark_kyber_pre_key_used: C.SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), + destroy: C.SignalFfiKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index b58bd7d..bbc1688 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit b58bd7d5dfa0a391486df4210fd83bab96b9b479 +Subproject commit bbc16886cae2feab1cd1fe271ccc651e8860ce96 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index fe3bf52..b75462a 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -629,13 +629,6 @@ typedef struct { const SignalHttpRequest *raw; } SignalConstPointerHttpRequest; -/** - * A wrapper type for raw UUIDs, because C treats arrays specially in argument position. - */ -typedef struct { - uint8_t bytes[16]; -} SignalUuid; - /** * The fixed-width binary representation of a ServiceId. * @@ -643,6 +636,27 @@ typedef struct { */ typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; +typedef struct { + const uint32_t *base; + size_t length; +} SignalBorrowedSliceOfu32; + +typedef struct { + const SignalCiphertextMessage *raw; +} SignalConstPointerCiphertextMessage; + +typedef struct { + const SignalConstPointerCiphertextMessage *base; + size_t length; +} SignalBorrowedSliceOfConstPointerCiphertextMessage; + +/** + * A wrapper type for raw UUIDs, because C treats arrays specially in argument position. + */ +typedef struct { + uint8_t bytes[16]; +} SignalUuid; + typedef struct { SignalPrivateKey *raw; } SignalMutPointerPrivateKey; @@ -754,10 +768,6 @@ typedef struct { const SignalPlaintextContent *raw; } SignalConstPointerPlaintextContent; -typedef struct { - const SignalCiphertextMessage *raw; -} SignalConstPointerCiphertextMessage; - typedef struct { SignalConnectionInfo *raw; } SignalMutPointerConnectionInfo; @@ -782,20 +792,18 @@ typedef struct { SignalSessionRecord *raw; } SignalMutPointerSessionRecord; -typedef int (*SignalFfiBridgeSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address); +typedef int (*SignalFfiSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address); -typedef int (*SignalFfiBridgeSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); +typedef int (*SignalFfiSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); -typedef void (*SignalFfiBridgeSessionStoreDestroy)(void *ctx); +typedef void (*SignalFfiSessionStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeSessionStoreLoadSession load_session; - SignalFfiBridgeSessionStoreStoreSession store_session; - SignalFfiBridgeSessionStoreDestroy destroy; -} SignalFfiBridgeSessionStoreStruct; - -typedef SignalFfiBridgeSessionStoreStruct SignalSessionStore; + SignalFfiSessionStoreLoadSession load_session; + SignalFfiSessionStoreStoreSession store_session; + SignalFfiSessionStoreDestroy destroy; +} SignalSessionStore; typedef struct { const SignalSessionStore *raw; @@ -810,29 +818,27 @@ typedef struct { SignalMutPointerPublicKey second; } SignalPairOfMutPointerPrivateKeyMutPointerPublicKey; -typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out); +typedef int (*SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out); -typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); +typedef int (*SignalFfiIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); -typedef int (*SignalFfiBridgeIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); +typedef int (*SignalFfiIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); -typedef int (*SignalFfiBridgeIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); +typedef int (*SignalFfiIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); -typedef int (*SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); +typedef int (*SignalFfiIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); -typedef void (*SignalFfiBridgeIdentityKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiIdentityKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; - SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; - SignalFfiBridgeIdentityKeyStoreGetIdentityKey get_identity_key; - SignalFfiBridgeIdentityKeyStoreSaveIdentityKey save_identity_key; - SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity is_trusted_identity; - SignalFfiBridgeIdentityKeyStoreDestroy destroy; -} SignalFfiBridgeIdentityKeyStoreStruct; - -typedef SignalFfiBridgeIdentityKeyStoreStruct SignalIdentityKeyStore; + SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; + SignalFfiIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; + SignalFfiIdentityKeyStoreGetIdentityKey get_identity_key; + SignalFfiIdentityKeyStoreSaveIdentityKey save_identity_key; + SignalFfiIdentityKeyStoreIsTrustedIdentity is_trusted_identity; + SignalFfiIdentityKeyStoreDestroy destroy; +} SignalIdentityKeyStore; typedef struct { const SignalIdentityKeyStore *raw; @@ -846,23 +852,21 @@ typedef struct { SignalPreKeyRecord *raw; } SignalMutPointerPreKeyRecord; -typedef int (*SignalFfiBridgePreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id); +typedef int (*SignalFfiPreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id); -typedef int (*SignalFfiBridgePreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record); +typedef int (*SignalFfiPreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record); -typedef int (*SignalFfiBridgePreKeyStoreRemovePreKey)(void *ctx, uint32_t id); +typedef int (*SignalFfiPreKeyStoreRemovePreKey)(void *ctx, uint32_t id); -typedef void (*SignalFfiBridgePreKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgePreKeyStoreLoadPreKey load_pre_key; - SignalFfiBridgePreKeyStoreStorePreKey store_pre_key; - SignalFfiBridgePreKeyStoreRemovePreKey remove_pre_key; - SignalFfiBridgePreKeyStoreDestroy destroy; -} SignalFfiBridgePreKeyStoreStruct; - -typedef SignalFfiBridgePreKeyStoreStruct SignalPreKeyStore; + SignalFfiPreKeyStoreLoadPreKey load_pre_key; + SignalFfiPreKeyStoreStorePreKey store_pre_key; + SignalFfiPreKeyStoreRemovePreKey remove_pre_key; + SignalFfiPreKeyStoreDestroy destroy; +} SignalPreKeyStore; typedef struct { const SignalPreKeyStore *raw; @@ -872,20 +876,18 @@ typedef struct { SignalSignedPreKeyRecord *raw; } SignalMutPointerSignedPreKeyRecord; -typedef int (*SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id); +typedef int (*SignalFfiSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id); -typedef int (*SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); +typedef int (*SignalFfiSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); -typedef void (*SignalFfiBridgeSignedPreKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiSignedPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; - SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; - SignalFfiBridgeSignedPreKeyStoreDestroy destroy; -} SignalFfiBridgeSignedPreKeyStoreStruct; - -typedef SignalFfiBridgeSignedPreKeyStoreStruct SignalSignedPreKeyStore; + SignalFfiSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; + SignalFfiSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; + SignalFfiSignedPreKeyStoreDestroy destroy; +} SignalSignedPreKeyStore; typedef struct { const SignalSignedPreKeyStore *raw; @@ -895,23 +897,21 @@ typedef struct { SignalKyberPreKeyRecord *raw; } SignalMutPointerKyberPreKeyRecord; -typedef int (*SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id); +typedef int (*SignalFfiKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id); -typedef int (*SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); +typedef int (*SignalFfiKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); -typedef int (*SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); +typedef int (*SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); -typedef void (*SignalFfiBridgeKyberPreKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiKyberPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; - SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; - SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; - SignalFfiBridgeKyberPreKeyStoreDestroy destroy; -} SignalFfiBridgeKyberPreKeyStoreStruct; - -typedef SignalFfiBridgeKyberPreKeyStoreStruct SignalKyberPreKeyStore; + SignalFfiKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; + SignalFfiKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; + SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; + SignalFfiKyberPreKeyStoreDestroy destroy; +} SignalKyberPreKeyStore; typedef struct { const SignalKyberPreKeyStore *raw; @@ -1047,20 +1047,18 @@ typedef struct { SignalSenderKeyRecord *raw; } SignalMutPointerSenderKeyRecord; -typedef int (*SignalFfiBridgeSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); +typedef int (*SignalFfiSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); -typedef int (*SignalFfiBridgeSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); +typedef int (*SignalFfiSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); -typedef void (*SignalFfiBridgeSenderKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiSenderKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeSenderKeyStoreLoadSenderKey load_sender_key; - SignalFfiBridgeSenderKeyStoreStoreSenderKey store_sender_key; - SignalFfiBridgeSenderKeyStoreDestroy destroy; -} SignalFfiBridgeSenderKeyStoreStruct; - -typedef SignalFfiBridgeSenderKeyStoreStruct SignalSenderKeyStore; + SignalFfiSenderKeyStoreLoadSenderKey load_sender_key; + SignalFfiSenderKeyStoreStoreSenderKey store_sender_key; + SignalFfiSenderKeyStoreDestroy destroy; +} SignalSenderKeyStore; typedef struct { const SignalSenderKeyStore *raw; @@ -1117,6 +1115,11 @@ typedef struct { SignalFfiLoggerDestroy destroy; } SignalFfiLoggerStruct; +typedef struct { + SignalOwnedBuffer first; + SignalOwnedBuffer second; +} SignalPairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar; + /** * A C callback used to report the results of Rust futures. * @@ -1127,10 +1130,10 @@ typedef struct { * completed once. */ typedef struct { - void (*complete)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); + void (*complete)(SignalFfiError *error, const SignalPairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar *result, const void *context); const void *context; SignalCancellationId cancellation_id; -} SignalCPromiseOwnedBufferOfc_uchar; +} SignalCPromisePairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar; typedef struct { const SignalUnauthenticatedChatConnection *raw; @@ -1200,20 +1203,18 @@ typedef struct { const SignalMessageBackupValidationOutcome *raw; } SignalConstPointerMessageBackupValidationOutcome; -typedef int (*SignalFfiBridgeInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf); +typedef int (*SignalFfiInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf); -typedef int (*SignalFfiBridgeInputStreamSkip)(void *ctx, uint64_t amount); +typedef int (*SignalFfiInputStreamSkip)(void *ctx, uint64_t amount); -typedef void (*SignalFfiBridgeInputStreamDestroy)(void *ctx); +typedef void (*SignalFfiInputStreamDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiBridgeInputStreamRead read; - SignalFfiBridgeInputStreamSkip skip; - SignalFfiBridgeInputStreamDestroy destroy; -} SignalFfiBridgeInputStreamStruct; - -typedef SignalFfiBridgeInputStreamStruct SignalInputStream; + SignalFfiInputStreamRead read; + SignalFfiInputStreamSkip skip; + SignalFfiInputStreamDestroy destroy; +} SignalInputStream; typedef struct { const SignalInputStream *raw; @@ -1647,9 +1648,7 @@ typedef struct { SignalValidatingMac *raw; } SignalMutPointerValidatingMac; -typedef SignalFfiBridgeInputStreamStruct SignalFfiBridgeSyncInputStreamStruct; - -typedef SignalFfiBridgeSyncInputStreamStruct SignalSyncInputStream; +typedef SignalInputStream SignalSyncInputStream; typedef struct { const SignalSyncInputStream *raw; @@ -1737,6 +1736,10 @@ SignalFfiError *signal_authenticated_chat_connection_preconnect(SignalCPromisebo SignalFfiError *signal_authenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); +SignalFfiError *signal_authenticated_chat_connection_send_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *destination, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfConstPointerCiphertextMessage contents, bool online_only, bool is_urgent); + +SignalFfiError *signal_authenticated_chat_connection_send_sync_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfConstPointerCiphertextMessage contents, bool is_urgent); + SignalFfiError *signal_backup_auth_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalBorrowedBuffer credential_bytes); @@ -1897,7 +1900,7 @@ SignalFfiError *signal_create_call_link_credential_request_issue_deterministic(S SignalFfiError *signal_create_call_link_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); +SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); @@ -2118,9 +2121,7 @@ bool signal_init_logger(SignalLogLevel max_level, SignalFfiLoggerStruct logger); SignalFfiError *signal_key_transparency_aci_search_key(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *aci); -SignalFfiError *signal_key_transparency_check(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head, bool is_self_check, bool is_e164_discoverable); - -SignalFfiError *signal_key_transparency_distinguished(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head); +SignalFfiError *signal_key_transparency_check(SignalCPromisePairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head, bool is_self_check, bool is_e164_discoverable); SignalFfiError *signal_key_transparency_e164_search_key(SignalOwnedBuffer *out, const char *e164); @@ -2354,7 +2355,7 @@ SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstP SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); -SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); +SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); @@ -2782,6 +2783,8 @@ SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_link(Sig SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); +SignalFfiError *signal_unauthenticated_chat_connection_send_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *destination, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfBuffers contents, uint8_t auth_kind, SignalOptionalBorrowedSliceOfc_uchar auth_buffer, bool online_only, bool is_urgent); + SignalFfiError *signal_unauthenticated_chat_connection_send_multi_recipient_message(SignalCPromiseOwnedBufferOfServiceIdFixedWidthBinaryBytes *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer payload, uint64_t timestamp, SignalBorrowedBuffer auth, bool online_only, bool is_urgent); SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); diff --git a/pkg/libsignalgo/message.go b/pkg/libsignalgo/message.go index 1b581c0..6cba873 100644 --- a/pkg/libsignalgo/message.go +++ b/pkg/libsignalgo/message.go @@ -49,7 +49,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress, localAddress *Ad return wrapCiphertextMessage(ciphertextMessage.raw), nil } -func Decrypt(ctx context.Context, message *Message, fromAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { +func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} @@ -57,6 +57,7 @@ func Decrypt(ctx context.Context, message *Message, fromAddress *Address, sessio &decrypted, message.constPtr(), fromAddress.constPtr(), + localAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), ) diff --git a/pkg/libsignalgo/prekeybundle.go b/pkg/libsignalgo/prekeybundle.go index 4cd5547..8a6fcaa 100644 --- a/pkg/libsignalgo/prekeybundle.go +++ b/pkg/libsignalgo/prekeybundle.go @@ -27,13 +27,14 @@ import ( "time" ) -func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) error { +func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress, localAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) error { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() var now C.uint64_t = C.uint64_t(time.Now().Unix()) signalFfiError := C.signal_process_prekey_bundle( bundle.constPtr(), forAddress.constPtr(), + localAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), now, diff --git a/pkg/libsignalgo/prekeystore.go b/pkg/libsignalgo/prekeystore.go index ed8ea21..8c3c36f 100644 --- a/pkg/libsignalgo/prekeystore.go +++ b/pkg/libsignalgo/prekeystore.go @@ -76,9 +76,9 @@ func signal_destroy_pre_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) C.SignalConstPointerFfiPreKeyStoreStruct { return C.SignalConstPointerFfiPreKeyStoreStruct{&C.SignalPreKeyStore{ ctx: wrapStore(ctx, store), - load_pre_key: C.SignalFfiBridgePreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), - store_pre_key: C.SignalFfiBridgePreKeyStoreStorePreKey(C.signal_store_pre_key_callback), - remove_pre_key: C.SignalFfiBridgePreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), - destroy: C.SignalFfiBridgePreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), + load_pre_key: C.SignalFfiPreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), + store_pre_key: C.SignalFfiPreKeyStoreStorePreKey(C.signal_store_pre_key_callback), + remove_pre_key: C.SignalFfiPreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), + destroy: C.SignalFfiPreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/senderkeystore.go b/pkg/libsignalgo/senderkeystore.go index a07a287..1649216 100644 --- a/pkg/libsignalgo/senderkeystore.go +++ b/pkg/libsignalgo/senderkeystore.go @@ -70,8 +70,8 @@ func signal_destroy_sender_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) C.SignalConstPointerFfiSenderKeyStoreStruct { return C.SignalConstPointerFfiSenderKeyStoreStruct{&C.SignalSenderKeyStore{ ctx: wrapStore(ctx, store), - load_sender_key: C.SignalFfiBridgeSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), - store_sender_key: C.SignalFfiBridgeSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), - destroy: C.SignalFfiBridgeSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), + load_sender_key: C.SignalFfiSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), + store_sender_key: C.SignalFfiSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), + destroy: C.SignalFfiSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), }} } diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index 4bde894..dd05718 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -30,7 +30,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtocolStore, bobAddress *libsignalgo.Address) { +func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtocolStore, bobAddress, aliceAddress *libsignalgo.Address) { ctx := context.TODO() bobPreKey, err := libsignalgo.GeneratePrivateKey() @@ -86,7 +86,7 @@ func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtoc assert.NoError(t, err) // Alice processes the bundle - err = libsignalgo.ProcessPreKeyBundle(ctx, bobBundle, bobAddress, aliceStore, aliceStore) + err = libsignalgo.ProcessPreKeyBundle(ctx, bobBundle, bobAddress, aliceAddress, aliceStore, aliceStore) assert.NoError(t, err) record, err := aliceStore.LoadSession(ctx, bobAddress) @@ -132,7 +132,7 @@ func TestSessionCipher(t *testing.T) { aliceStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} @@ -163,7 +163,7 @@ func TestSessionCipher(t *testing.T) { assert.NoError(t, err) aliceCiphertext2, err := libsignalgo.DeserializeMessage(bobCiphertext2Serialized) assert.NoError(t, err) - alicePlaintext2, err := libsignalgo.Decrypt(ctx, aliceCiphertext2, bobAddress, aliceStore, aliceStore) + alicePlaintext2, err := libsignalgo.Decrypt(ctx, aliceCiphertext2, bobAddress, aliceAddress, aliceStore, aliceStore) assert.NoError(t, err) assert.Equal(t, bobPlaintext2, alicePlaintext2) } @@ -183,7 +183,7 @@ func TestSessionCipherWithBadStore(t *testing.T) { aliceStore := NewInMemorySignalProtocolStore() bobStore := &BadInMemorySignalProtocolStore{NewInMemorySignalProtocolStore()} - initializeSessions(t, aliceStore, bobStore.InMemorySignalProtocolStore, bobAddress) + initializeSessions(t, aliceStore, bobStore.InMemorySignalProtocolStore, bobAddress, aliceAddress) alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} @@ -216,7 +216,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) { aliceStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) trustRoot, err := libsignalgo.GenerateIdentityKeyPair() assert.NoError(t, err) @@ -252,15 +252,18 @@ func TestArchiveSession(t *testing.T) { ctx := context.TODO() setupLogging() + aliceACI := uuid.New() bobACI := uuid.New() + aliceAddress, err := libsignalgo.NewACIServiceID(aliceACI).Address(1) + assert.NoError(t, err) bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1) assert.NoError(t, err) aliceStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) session, err := aliceStore.LoadSession(ctx, bobAddress) assert.NoError(t, err) @@ -315,7 +318,7 @@ func TestSealedSenderGroupCipher(t *testing.T) { bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) trustRoot, err := libsignalgo.GenerateIdentityKeyPair() assert.NoError(t, err) diff --git a/pkg/libsignalgo/sessionstore.go b/pkg/libsignalgo/sessionstore.go index 2515232..99000e5 100644 --- a/pkg/libsignalgo/sessionstore.go +++ b/pkg/libsignalgo/sessionstore.go @@ -67,8 +67,8 @@ func signal_destroy_session_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapSessionStore(store SessionStore) C.SignalConstPointerFfiSessionStoreStruct { return C.SignalConstPointerFfiSessionStoreStruct{&C.SignalSessionStore{ ctx: wrapStore(ctx, store), - load_session: C.SignalFfiBridgeSessionStoreLoadSession(C.signal_load_session_callback), - store_session: C.SignalFfiBridgeSessionStoreStoreSession(C.signal_store_session_callback), - destroy: C.SignalFfiBridgeSessionStoreDestroy(C.signal_destroy_session_store_callback), + load_session: C.SignalFfiSessionStoreLoadSession(C.signal_load_session_callback), + store_session: C.SignalFfiSessionStoreStoreSession(C.signal_store_session_callback), + destroy: C.SignalFfiSessionStoreDestroy(C.signal_destroy_session_store_callback), }} } diff --git a/pkg/libsignalgo/signedprekeystore.go b/pkg/libsignalgo/signedprekeystore.go index cfb3015..b1306e2 100644 --- a/pkg/libsignalgo/signedprekeystore.go +++ b/pkg/libsignalgo/signedprekeystore.go @@ -67,8 +67,8 @@ func signal_destroy_signed_pre_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) C.SignalConstPointerFfiSignedPreKeyStoreStruct { return C.SignalConstPointerFfiSignedPreKeyStoreStruct{&C.SignalSignedPreKeyStore{ ctx: wrapStore(ctx, store), - load_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), - store_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), - destroy: C.SignalFfiBridgeSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), + load_signed_pre_key: C.SignalFfiSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), + store_signed_pre_key: C.SignalFfiSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), + destroy: C.SignalFfiSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index bd14084..1f7e94d 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.92.1" +const Version = "v0.93.2" diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index f1801e5..5439755 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -413,6 +413,10 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib if cli.Store.RecipientStore.IsUnregistered(ctx, theirServiceID) { return fmt.Errorf("%w (cached)", ErrUnregisteredUser) } + localAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)) + if err != nil { + return fmt.Errorf("failed to get own address: %w", err) + } // Fetch prekey deviceIDPath := "/*" if specificDeviceID >= 0 { @@ -518,6 +522,7 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib ctx, preKeyBundle, address, + localAddress, cli.Store.ACISessionStore, cli.Store.ACIIdentityStore, ) diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 6296f00..1d2c8cc 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -243,11 +243,16 @@ func (cli *Client) decryptCiphertextEnvelope( if identityStore == nil { return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) } + destinationAddress, err := destinationServiceID.Address(uint(cli.Store.DeviceID)) + if err != nil { + return nil, fmt.Errorf("failed to get own address: %w", err) + } plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, ciphertext, serverTimestamp, func(ctx context.Context) ([]byte, error) { return libsignalgo.Decrypt( ctx, message, senderAddress, + destinationAddress, sessionStore, identityStore, ) From 4f1ebf7aa2708374c0e71d3f76913e07485aad96 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 8 May 2026 16:56:40 +0300 Subject: [PATCH 713/718] dependencies: update mautrix-go --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index a936973..c9cf551 100644 --- a/go.mod +++ b/go.mod @@ -11,17 +11,17 @@ require ( github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 github.com/mattn/go-pointer v0.0.1 - github.com/rs/zerolog v1.35.0 + github.com/rs/zerolog v1.35.1 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.9-0.20260430092340-8772e7714ea5 + go.mau.fi/util v0.9.9-0.20260508133822-4207002539ff golang.org/x/crypto v0.50.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/net v0.53.0 golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260430124810-125ac2c48014 + maunium.net/go/mautrix v0.27.1-0.20260507230413-b25744aa7730 ) require ( @@ -32,7 +32,7 @@ require ( github.com/lib/pq v1.12.3 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.42 // indirect + github.com/mattn/go-sqlite3 v1.14.44 // indirect github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect diff --git a/go.sum b/go.sum index f817e1d..69eb732 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= -github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo= -github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= +github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8= +github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM= github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -42,8 +42,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI= -github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= +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= @@ -61,8 +61,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.9-0.20260430092340-8772e7714ea5 h1:cNm4gkt7j907g1Q4XvyNKW8tTM8BaU91Kbfa5GGyiCs= -go.mau.fi/util v0.9.9-0.20260430092340-8772e7714ea5/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= +go.mau.fi/util v0.9.9-0.20260508133822-4207002539ff h1:nH8zuwSw5uu2pal7p9x5BSAvavuiJqRFN558XvcTtKg= +go.mau.fi/util v0.9.9-0.20260508133822-4207002539ff/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.1-0.20260430124810-125ac2c48014 h1:KwXGBWwUHYJKVTYWgbZEFcaM6uYLMvfjzHJg/TLwvKc= -maunium.net/go/mautrix v0.27.1-0.20260430124810-125ac2c48014/go.mod h1:4fZ0M0xB5ZtueQI65RilX28J/3794BeK+LaCg4U61Jk= +maunium.net/go/mautrix v0.27.1-0.20260507230413-b25744aa7730 h1:GcBSD72Ez7D3LoFVprsFFQx3mKcaRh983KpLIiifw68= +maunium.net/go/mautrix v0.27.1-0.20260507230413-b25744aa7730/go.mod h1:2ANjihDB+wv2UAqJapkRekmNXw7khSisccAkE5Jg3P0= From 9cdd4c9963726af2d1f2eaaeec41f18adf3284c9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 8 May 2026 16:57:56 +0300 Subject: [PATCH 714/718] signalmeow: update protobufs --- pkg/signalmeow/protobuf/ContactDiscovery.pb.go | 2 +- pkg/signalmeow/protobuf/DeviceName.pb.go | 2 +- pkg/signalmeow/protobuf/Groups.pb.go | 2 +- pkg/signalmeow/protobuf/Provisioning.pb.go | 2 +- pkg/signalmeow/protobuf/SignalService.pb.go | 2 +- pkg/signalmeow/protobuf/StickerResources.pb.go | 2 +- pkg/signalmeow/protobuf/StorageService.pb.go | 15 ++++++++++++--- pkg/signalmeow/protobuf/StorageService.proto | 1 + .../protobuf/UnidentifiedDelivery.pb.go | 2 +- pkg/signalmeow/protobuf/WebSocketResources.pb.go | 2 +- pkg/signalmeow/protobuf/backuppb/Backup.pb.go | 2 +- pkg/signalmeow/protobuf/update-protos.sh | 4 ++-- 12 files changed, 24 insertions(+), 14 deletions(-) diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 637a2d2..5cb232c 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: ContactDiscovery.proto // Copyright 2021 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 5666b7e..31b5704 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: DeviceName.proto // Copyright 2018 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 0c2b81b..8d4e2e3 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: Groups.proto package signalpb diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index c925fe6..88ebe90 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: Provisioning.proto package signalpb diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index 32842bf..c4268dd 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: SignalService.proto package signalpb diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index e83cda1..f8194aa 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -6,7 +6,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: StickerResources.proto package signalpb diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index 619221f..bbe88ef 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -6,7 +6,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: StorageService.proto package signalpb @@ -1401,6 +1401,7 @@ type GroupV2Record struct { HideStory bool `protobuf:"varint,8,opt,name=hideStory,proto3" json:"hideStory,omitempty"` StorySendMode GroupV2Record_StorySendMode `protobuf:"varint,10,opt,name=storySendMode,proto3,enum=signalservice.GroupV2Record_StorySendMode" json:"storySendMode,omitempty"` AvatarColor *AvatarColor `protobuf:"varint,11,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` + VerifiedNameHash []byte `protobuf:"bytes,12,opt,name=verifiedNameHash,proto3" json:"verifiedNameHash,omitempty"` // SHA-256 of UTF-8 encoded decrypted group title that was last verified unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1505,6 +1506,13 @@ func (x *GroupV2Record) GetAvatarColor() AvatarColor { return AvatarColor_A100 } +func (x *GroupV2Record) GetVerifiedNameHash() []byte { + if x != nil { + return x.VerifiedNameHash + } + return nil +} + type Payments struct { state protoimpl.MessageState `protogen:"open.v1"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` @@ -3195,7 +3203,7 @@ const file_StorageService_proto_rawDesc = "" + "\vwhitelisted\x18\x03 \x01(\bR\vwhitelisted\x12\x1a\n" + "\barchived\x18\x04 \x01(\bR\barchived\x12\"\n" + "\fmarkedUnread\x18\x05 \x01(\bR\fmarkedUnread\x120\n" + - "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\"\xa1\x04\n" + + "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\"\xcd\x04\n" + "\rGroupV2Record\x12\x1c\n" + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x18\n" + "\ablocked\x18\x02 \x01(\bR\ablocked\x12 \n" + @@ -3207,7 +3215,8 @@ const file_StorageService_proto_rawDesc = "" + "\thideStory\x18\b \x01(\bR\thideStory\x12P\n" + "\rstorySendMode\x18\n" + " \x01(\x0e2*.signalservice.GroupV2Record.StorySendModeR\rstorySendMode\x12A\n" + - "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\"7\n" + + "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x12*\n" + + "\x10verifiedNameHash\x18\f \x01(\fR\x10verifiedNameHash\"7\n" + "\rStorySendMode\x12\v\n" + "\aDEFAULT\x10\x00\x12\f\n" + "\bDISABLED\x10\x01\x12\v\n" + diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index d22babc..dd232ca 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -172,6 +172,7 @@ message GroupV2Record { reserved /* storySendEnabled */ 9; StorySendMode storySendMode = 10; optional AvatarColor avatarColor = 11; + bytes verifiedNameHash = 12; // SHA-256 of UTF-8 encoded decrypted group title that was last verified } message Payments { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index e30f6d6..5979a4c 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: UnidentifiedDelivery.proto // Copyright 2018 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index f35110d..66520eb 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -6,7 +6,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: WebSocketResources.proto package signalpb diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index 326c170..bc488e7 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v6.33.5 +// protoc v7.34.1 // source: backuppb/Backup.proto package backuppb diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index ffaa697..f9c86fc 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-dfd2f7baf96825834f784900ce644e9ead8a9a89} -DESKTOP_GIT_REVISION=${1:-60a1e125452ee672d8747564d0055d5bfec9f679} +ANDROID_GIT_REVISION=${1:-439760e7732585bfd078d92d93732c04cc31e29e} +DESKTOP_GIT_REVISION=${1:-1b2a3e7b283c32c5654a39da12fc04139fd26dbd} update_proto() { case "$1" in From 4545def01787e39cf9c86b5fa7e726330de17b28 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 11 May 2026 16:16:36 +0300 Subject: [PATCH 715/718] signalmeow/web: log request durations --- pkg/signalmeow/web/web.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index e617b40..f211b77 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -28,6 +28,7 @@ import ( "net/http" "runtime" "strings" + "time" "github.com/rs/zerolog" @@ -140,12 +141,14 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe httpReqCounter++ log = log.With().Int("request_number", httpReqCounter).Logger() log.Trace().Msg("Sending HTTP request") + start := time.Now() resp, err := SignalHTTPClient.Do(req) + dur := time.Since(start) if err != nil { - log.Err(err).Msg("Error sending request") + log.Err(err).Dur("duration", dur).Msg("Error sending request") return nil, err } - log.Debug().Int("status_code", resp.StatusCode).Msg("received HTTP response") + log.Debug().Int("status_code", resp.StatusCode).Dur("duration", dur).Msg("Received HTTP response") return resp, nil } From 41a37cd1844c63737b1ccca80d54118cf5c02819 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Tue, 12 May 2026 11:43:06 +0200 Subject: [PATCH 716/718] capabilities: drop webp to only partial support (#649) Co-authored-by: Tulir Asokan --- pkg/connector/capabilities.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index d23285c..5eab6a8 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2025_12_09" + base := "fi.mau.signal.capabilities.2026_05_12" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -111,7 +111,8 @@ var signalCaps = &event.RoomFeatures{ }, event.CapMsgSticker: { MimeTypes: map[string]event.CapabilitySupportLevel{ - "image/webp": event.CapLevelFullySupported, + // Signal clients will only render static webp, so apng is preferred + "image/webp": event.CapLevelPartialSupport, "image/png": event.CapLevelFullySupported, "image/apng": event.CapLevelFullySupported, "image/gif": supportedIfFFmpeg(), @@ -236,5 +237,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 7 + return 1, 8 } From 14592ffdccac3ea222a2ac787c7405133d227cfa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 12 May 2026 16:00:56 +0300 Subject: [PATCH 717/718] dependencies: update mautrix-go --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index c9cf551..db72345 100644 --- a/go.mod +++ b/go.mod @@ -14,14 +14,14 @@ require ( github.com/rs/zerolog v1.35.1 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.9-0.20260508133822-4207002539ff + go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25 golang.org/x/crypto v0.50.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/net v0.53.0 golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260507230413-b25744aa7730 + maunium.net/go/mautrix v0.27.1-0.20260512144923-7c0986318ff8 ) require ( diff --git a/go.sum b/go.sum index 69eb732..753b96d 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.9-0.20260508133822-4207002539ff h1:nH8zuwSw5uu2pal7p9x5BSAvavuiJqRFN558XvcTtKg= -go.mau.fi/util v0.9.9-0.20260508133822-4207002539ff/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs= +go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25 h1:YPEmc+li7TF6C9AdRTcSLMb6yCHdF27/wNT7kFLIVNg= +go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.1-0.20260507230413-b25744aa7730 h1:GcBSD72Ez7D3LoFVprsFFQx3mKcaRh983KpLIiifw68= -maunium.net/go/mautrix v0.27.1-0.20260507230413-b25744aa7730/go.mod h1:2ANjihDB+wv2UAqJapkRekmNXw7khSisccAkE5Jg3P0= +maunium.net/go/mautrix v0.27.1-0.20260512144923-7c0986318ff8 h1:8eHwxv8J9b8ebVwL4H98mlKE4SSAeqhqwD251oSiEkc= +maunium.net/go/mautrix v0.27.1-0.20260512144923-7c0986318ff8/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM= From 0df937749bfc3dfa5c06d657b29f49c7548ef4d4 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 13 May 2026 15:05:37 +0300 Subject: [PATCH 718/718] dependencies: update mautrix-go --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index db72345..931af45 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260512144923-7c0986318ff8 + maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4 ) require ( diff --git a/go.sum b/go.sum index 753b96d..2f02866 100644 --- a/go.sum +++ b/go.sum @@ -91,5 +91,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.27.1-0.20260512144923-7c0986318ff8 h1:8eHwxv8J9b8ebVwL4H98mlKE4SSAeqhqwD251oSiEkc= -maunium.net/go/mautrix v0.27.1-0.20260512144923-7c0986318ff8/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM= +maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4 h1:zNC9eVAhw8FhKpM3AxNAh/iy75UEYX91uJUvqqAYlvo= +maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM=