mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 03:52:17 +02:00
Update message backup proto definition
This commit is contained in:
parent
4791773954
commit
24c234a5fe
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2093,6 +2093,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"usernames",
|
||||
"uuid",
|
||||
"zkcredential",
|
||||
"zkgroup",
|
||||
]
|
||||
|
||||
|
@ -26,6 +26,7 @@ libsignal-message-backup-macros = { path = "macros" }
|
||||
libsignal-protocol = { path = "../protocol" }
|
||||
signal-crypto = { path = "../crypto" }
|
||||
usernames = { path = "../usernames" }
|
||||
zkcredential = { path = "../zkcredential", features = ["rayon"] }
|
||||
zkgroup = { path = "../zkgroup" }
|
||||
|
||||
aes = "0.8.3"
|
||||
|
@ -393,7 +393,7 @@ impl<M: Method> ChatsData<M> {
|
||||
fn add_chat_item(
|
||||
&mut self,
|
||||
chat_id: ChatId,
|
||||
mut item: ChatItemData,
|
||||
mut item: ChatItemData<M>,
|
||||
) -> Result<(), ChatFrameError> {
|
||||
let Self {
|
||||
chat_items_count,
|
||||
|
@ -25,6 +25,9 @@ use contact_message::*;
|
||||
|
||||
pub(crate) mod chat_style;
|
||||
|
||||
mod gift_badge;
|
||||
use gift_badge::*;
|
||||
|
||||
mod group;
|
||||
use group::*;
|
||||
|
||||
@ -103,6 +106,8 @@ pub enum ChatItemError {
|
||||
StickerMessageMissingSticker,
|
||||
/// sticker message: {0}
|
||||
StickerMessage(#[from] MessageStickerError),
|
||||
/// gift badge: {0}
|
||||
GiftBadge(#[from] GiftBadgeError),
|
||||
/// ChatItem.directionalDetails is a oneof but is empty
|
||||
NoDirection,
|
||||
/// outgoing message {0}
|
||||
@ -132,10 +137,10 @@ pub struct InvalidExpiration {
|
||||
|
||||
/// Validated version of [`proto::Chat`].
|
||||
#[derive_where(Debug)]
|
||||
#[cfg_attr(test, derive_where(PartialEq; M::List<ChatItemData>: PartialEq))]
|
||||
#[cfg_attr(test, derive_where(PartialEq; M::List<ChatItemData<M>>: PartialEq))]
|
||||
pub struct ChatData<M: Method> {
|
||||
pub recipient: RecipientId,
|
||||
pub(super) items: M::List<ChatItemData>,
|
||||
pub(super) items: M::List<ChatItemData<M>>,
|
||||
pub expiration_timer: Option<Duration>,
|
||||
pub mute_until: Option<Timestamp>,
|
||||
pub style: Option<ChatStyle>,
|
||||
@ -149,12 +154,12 @@ pub struct ChatData<M: Method> {
|
||||
pub struct PinOrder(NonZeroU32);
|
||||
|
||||
/// Validated version of [`proto::ChatItem`].
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct ChatItemData {
|
||||
#[derive_where(Debug)]
|
||||
#[cfg_attr(test, derive_where(PartialEq; ChatItemMessage<M>: PartialEq))]
|
||||
pub struct ChatItemData<M: Method> {
|
||||
pub author: RecipientId,
|
||||
pub message: ChatItemMessage,
|
||||
pub revisions: Vec<ChatItemData>,
|
||||
pub message: ChatItemMessage<M>,
|
||||
pub revisions: Vec<ChatItemData<M>>,
|
||||
pub direction: Direction,
|
||||
pub expire_start: Option<Timestamp>,
|
||||
pub expires_in: Option<Duration>,
|
||||
@ -167,9 +172,9 @@ pub struct ChatItemData {
|
||||
}
|
||||
|
||||
/// Validated version of [`proto::chat_item::Item`].
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub enum ChatItemMessage {
|
||||
#[derive_where(Debug)]
|
||||
#[cfg_attr(test, derive_where(PartialEq; M::BoxedValue<GiftBadge>: PartialEq))]
|
||||
pub enum ChatItemMessage<M: Method> {
|
||||
Standard(StandardMessage),
|
||||
Contact(ContactMessage),
|
||||
Voice(VoiceMessage),
|
||||
@ -177,6 +182,7 @@ pub enum ChatItemMessage {
|
||||
RemoteDeleted,
|
||||
Update(UpdateMessage),
|
||||
PaymentNotification(PaymentNotification),
|
||||
GiftBadge(M::BoxedValue<GiftBadge>),
|
||||
}
|
||||
|
||||
/// Validated version of [`proto::Reaction`].
|
||||
@ -317,8 +323,8 @@ impl<M: Method, C: Contains<RecipientId> + Lookup<PinOrder, RecipientId>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Contains<RecipientId> + AsRef<BackupMeta>> TryFromWith<proto::ChatItem, R>
|
||||
for ChatItemData
|
||||
impl<R: Contains<RecipientId> + AsRef<BackupMeta>, M: Method> TryFromWith<proto::ChatItem, R>
|
||||
for ChatItemData<M>
|
||||
{
|
||||
type Error = ChatItemError;
|
||||
|
||||
@ -353,7 +359,7 @@ impl<R: Contains<RecipientId> + AsRef<BackupMeta>> TryFromWith<proto::ChatItem,
|
||||
let revisions: Vec<_> = revisions
|
||||
.into_iter()
|
||||
.map(|rev| {
|
||||
let item: ChatItemData = rev.try_into_with(context)?;
|
||||
let item: ChatItemData<M> = rev.try_into_with(context)?;
|
||||
match &item.message {
|
||||
ChatItemMessage::Update(update) => match update {
|
||||
UpdateMessage::GroupCall(_) | UpdateMessage::IndividualCall(_) => {
|
||||
@ -375,6 +381,7 @@ impl<R: Contains<RecipientId> + AsRef<BackupMeta>> TryFromWith<proto::ChatItem,
|
||||
| ChatItemMessage::Voice(_)
|
||||
| ChatItemMessage::PaymentNotification(_)
|
||||
| ChatItemMessage::Sticker(_)
|
||||
| ChatItemMessage::GiftBadge(_)
|
||||
| ChatItemMessage::RemoteDeleted => (),
|
||||
};
|
||||
Ok(item)
|
||||
@ -517,8 +524,8 @@ impl<R: Contains<RecipientId>> TryFromWith<proto::SendStatus, R> for OutgoingSen
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Contains<RecipientId> + AsRef<BackupMeta>> TryFromWith<proto::chat_item::Item, R>
|
||||
for ChatItemMessage
|
||||
impl<R: Contains<RecipientId> + AsRef<BackupMeta>, M: Method> TryFromWith<proto::chat_item::Item, R>
|
||||
for ChatItemMessage<M>
|
||||
{
|
||||
type Error = ChatItemError;
|
||||
|
||||
@ -554,6 +561,7 @@ impl<R: Contains<RecipientId> + AsRef<BackupMeta>> TryFromWith<proto::chat_item:
|
||||
Item::PaymentNotification(message) => {
|
||||
ChatItemMessage::PaymentNotification(message.try_into()?)
|
||||
}
|
||||
Item::GiftBadge(badge) => ChatItemMessage::GiftBadge(M::boxed_value(badge.try_into()?)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -731,7 +739,7 @@ mod test {
|
||||
fn valid_chat_item() {
|
||||
assert_eq!(
|
||||
proto::ChatItem::test_data().try_into_with(&TestContext::default()),
|
||||
Ok(ChatItemData {
|
||||
Ok(ChatItemData::<Store> {
|
||||
author: RecipientId(proto::Recipient::TEST_ID),
|
||||
message: ChatItemMessage::Standard(StandardMessage::from_proto_test_data()),
|
||||
revisions: vec![],
|
||||
@ -806,7 +814,7 @@ mod test {
|
||||
|
||||
let result = message
|
||||
.try_into_with(&TestContext::default())
|
||||
.map(|_: ChatItemData| ());
|
||||
.map(|_: ChatItemData<Store>| ());
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
@ -880,7 +888,7 @@ mod test {
|
||||
.unwrap();
|
||||
item.expiresInMs = until_expiration_ms;
|
||||
|
||||
let result = ChatItemData::try_from_with(item, &TestContext(meta))
|
||||
let result = ChatItemData::<Store>::try_from_with(item, &TestContext(meta))
|
||||
.map(|_| ())
|
||||
.map_err(|e| assert_matches!(e, ChatItemError::InvalidExpiration(e) => e).to_string());
|
||||
assert_eq!(result, expected.map_err(ToString::to_string));
|
||||
@ -893,7 +901,7 @@ mod test {
|
||||
item.expiresInMs = 0;
|
||||
|
||||
assert_matches!(
|
||||
ChatItemData::try_from_with(item, &TestContext::default()),
|
||||
ChatItemData::<Store>::try_from_with(item, &TestContext::default()),
|
||||
Err(ChatItemError::ExpirationMismatch)
|
||||
);
|
||||
}
|
||||
|
130
rust/message-backup/src/backup/chat/gift_badge.rs
Normal file
130
rust/message-backup/src/backup/chat/gift_badge.rs
Normal file
@ -0,0 +1,130 @@
|
||||
//
|
||||
// Copyright (C) 2024 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
use zkgroup::receipts::ReceiptCredentialPresentation;
|
||||
use zkgroup::ZkGroupDeserializationFailure;
|
||||
|
||||
use crate::proto::backup as proto;
|
||||
|
||||
pub struct GiftBadge {
|
||||
receipt_credential_presentation: ReceiptCredentialPresentation,
|
||||
state: proto::gift_badge::State,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for GiftBadge {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("GiftBadge")
|
||||
.field(
|
||||
"receipt_credential_presentation",
|
||||
&zkcredential::PrintAsHex(
|
||||
zkgroup::serialize(&self.receipt_credential_presentation).as_slice(),
|
||||
),
|
||||
)
|
||||
.field("state", &self.state)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl PartialEq for GiftBadge {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
zkgroup::serialize(&self.receipt_credential_presentation)
|
||||
== zkgroup::serialize(&other.receipt_credential_presentation)
|
||||
&& self.state == other.state
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, displaydoc::Display)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub enum GiftBadgeError {
|
||||
/// receipt credential presentation failed to deserialize
|
||||
InvalidReceiptCredentialPresentation,
|
||||
}
|
||||
|
||||
impl TryFrom<proto::GiftBadge> for GiftBadge {
|
||||
type Error = GiftBadgeError;
|
||||
|
||||
fn try_from(value: proto::GiftBadge) -> Result<Self, Self::Error> {
|
||||
let proto::GiftBadge {
|
||||
receiptCredentialPresentation,
|
||||
state,
|
||||
special_fields: _,
|
||||
} = value;
|
||||
|
||||
let receipt_credential_presentation = zkgroup::deserialize(&receiptCredentialPresentation)
|
||||
.map_err(|_: ZkGroupDeserializationFailure| {
|
||||
GiftBadgeError::InvalidReceiptCredentialPresentation
|
||||
})?;
|
||||
|
||||
use proto::gift_badge::State;
|
||||
let state = match state.enum_value_or_default() {
|
||||
s @ (State::UNOPENED | State::OPENED | State::REDEEMED | State::FAILED) => s,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
receipt_credential_presentation,
|
||||
state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use zkgroup::RANDOMNESS_LEN;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl proto::GiftBadge {
|
||||
fn test_data_presentation() -> ReceiptCredentialPresentation {
|
||||
const RANDOMNESS: [u8; RANDOMNESS_LEN] = [33; 32];
|
||||
|
||||
let server_params = zkgroup::ServerSecretParams::generate(RANDOMNESS);
|
||||
let server_public_params = server_params.get_public_params();
|
||||
let request_context = &server_public_params
|
||||
.create_receipt_credential_request_context(RANDOMNESS, [59; 16]);
|
||||
let request = request_context.get_request();
|
||||
let response = server_params.issue_receipt_credential(
|
||||
RANDOMNESS,
|
||||
&request,
|
||||
zkgroup::Timestamp::from_epoch_seconds(123456789),
|
||||
6,
|
||||
);
|
||||
let credential = server_public_params
|
||||
.receive_receipt_credential(request_context, &response)
|
||||
.expect("valid request");
|
||||
server_public_params.create_receipt_credential_presentation(RANDOMNESS, &credential)
|
||||
}
|
||||
|
||||
fn test_data() -> Self {
|
||||
Self {
|
||||
receiptCredentialPresentation: zkgroup::serialize(&Self::test_data_presentation()),
|
||||
state: proto::gift_badge::State::REDEEMED.into(),
|
||||
special_fields: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_gift_badge() {
|
||||
assert_eq!(
|
||||
proto::GiftBadge::test_data().try_into(),
|
||||
Ok(GiftBadge {
|
||||
receipt_credential_presentation: proto::GiftBadge::test_data_presentation(),
|
||||
state: proto::gift_badge::State::REDEEMED,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_presentation() {
|
||||
let mut badge = proto::GiftBadge::test_data();
|
||||
badge.receiptCredentialPresentation = vec![];
|
||||
|
||||
assert_eq!(
|
||||
GiftBadge::try_from(badge),
|
||||
Err(GiftBadgeError::InvalidReceiptCredentialPresentation)
|
||||
);
|
||||
}
|
||||
}
|
@ -81,10 +81,12 @@ where
|
||||
|
||||
pub trait Method {
|
||||
type Value<T: Debug>: Debug;
|
||||
type BoxedValue<T: Debug>: Debug;
|
||||
type Map<K: Eq + Hash + Debug, V: Debug>: Map<K, V> + Debug;
|
||||
type List<T: Debug>: Extend<T> + Default + Debug;
|
||||
|
||||
fn value<T: Debug>(value: T) -> Self::Value<T>;
|
||||
fn boxed_value<T: Debug>(value: T) -> Self::BoxedValue<T>;
|
||||
}
|
||||
|
||||
pub enum ValidateOnly {}
|
||||
@ -100,22 +102,28 @@ impl<T> Extend<T> for ValidateOnlyList {
|
||||
|
||||
impl Method for ValidateOnly {
|
||||
type Value<T: Debug> = ();
|
||||
type BoxedValue<T: Debug> = ();
|
||||
type Map<K: Eq + Hash + Debug, V: Debug> = HashSet<K>;
|
||||
type List<T: Debug> = ValidateOnlyList;
|
||||
|
||||
fn value<T: Debug>(_value: T) -> Self::Value<T> {}
|
||||
fn boxed_value<T: Debug>(_value: T) -> Self::BoxedValue<T> {}
|
||||
}
|
||||
|
||||
pub enum Store {}
|
||||
|
||||
impl Method for Store {
|
||||
type Value<T: Debug> = T;
|
||||
type BoxedValue<T: Debug> = Box<T>;
|
||||
type Map<K: Eq + Hash + Debug, V: Debug> = HashMap<K, V>;
|
||||
type List<T: Debug> = Vec<T>;
|
||||
|
||||
fn value<T: Debug>(value: T) -> Self::Value<T> {
|
||||
value
|
||||
}
|
||||
fn boxed_value<T: Debug>(value: T) -> Self::BoxedValue<T> {
|
||||
Box::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -10,30 +10,16 @@
|
||||
|
||||
use derive_where::derive_where;
|
||||
|
||||
use crate::backup::method::{KeyExists, Map as _, Method};
|
||||
use crate::backup::WithId;
|
||||
use crate::backup::method::Method;
|
||||
use crate::proto::backup as proto;
|
||||
|
||||
/// Validated version of [`proto::StickerPack`].
|
||||
#[derive_where(Debug)]
|
||||
#[cfg_attr(test, derive_where(PartialEq;
|
||||
M::Map<StickerId, PackSticker>: PartialEq,
|
||||
M::Value<Key>: PartialEq,
|
||||
M::Value<String>: PartialEq
|
||||
))]
|
||||
pub struct StickerPack<M: Method> {
|
||||
pub key: M::Value<Key>,
|
||||
pub stickers: M::Map<StickerId, PackSticker>,
|
||||
pub title: M::Value<String>,
|
||||
pub author: M::Value<String>,
|
||||
_limit_construction_to_module: (),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct PackSticker {
|
||||
pub id: StickerId,
|
||||
pub emoji: String,
|
||||
_limit_construction_to_module: (),
|
||||
}
|
||||
|
||||
@ -69,22 +55,11 @@ impl TryFrom<Vec<u8>> for Key {
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct StickerId(u32);
|
||||
|
||||
impl WithId for proto::StickerPackSticker {
|
||||
type Id = StickerId;
|
||||
fn id(&self) -> Self::Id {
|
||||
StickerId(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, displaydoc::Display)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub enum StickerPackError {
|
||||
/// key is invalid
|
||||
InvalidKey,
|
||||
/// sticker pack ID is invalid
|
||||
InvalidPackId,
|
||||
/// {0:?} contains more than one sticker with {0:?}
|
||||
DuplicateId(PackId, StickerId),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, displaydoc::Display)]
|
||||
@ -100,57 +75,17 @@ impl<M: Method> TryFrom<proto::StickerPack> for StickerPack<M> {
|
||||
type Error = StickerPackError;
|
||||
fn try_from(value: proto::StickerPack) -> Result<Self, Self::Error> {
|
||||
let proto::StickerPack {
|
||||
packId,
|
||||
packId: _,
|
||||
packKey,
|
||||
stickers,
|
||||
title,
|
||||
author,
|
||||
special_fields: _,
|
||||
} = value;
|
||||
|
||||
let pack_id = PackId(
|
||||
packId
|
||||
.try_into()
|
||||
.map_err(|_| StickerPackError::InvalidPackId)?,
|
||||
);
|
||||
|
||||
let key = packKey
|
||||
.try_into()
|
||||
.map_err(|_| StickerPackError::InvalidKey)?;
|
||||
|
||||
let stickers = {
|
||||
let mut out = M::Map::default();
|
||||
for sticker in stickers {
|
||||
let sticker: PackSticker = sticker.try_into()?;
|
||||
let id = sticker.id;
|
||||
out.insert(id, sticker)
|
||||
.map_err(|KeyExists| StickerPackError::DuplicateId(pack_id, id))?;
|
||||
}
|
||||
out
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
key: M::value(key),
|
||||
stickers,
|
||||
title: M::value(title),
|
||||
author: M::value(author),
|
||||
_limit_construction_to_module: (),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<proto::StickerPackSticker> for PackSticker {
|
||||
type Error = StickerPackError;
|
||||
fn try_from(value: proto::StickerPackSticker) -> Result<Self, Self::Error> {
|
||||
let proto::StickerPackSticker {
|
||||
id,
|
||||
emoji,
|
||||
special_fields: _,
|
||||
} = value;
|
||||
|
||||
Ok(Self {
|
||||
id: StickerId(id),
|
||||
emoji,
|
||||
_limit_construction_to_module: (),
|
||||
})
|
||||
}
|
||||
@ -190,8 +125,6 @@ impl TryFrom<proto::Sticker> for MessageSticker {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::backup::method::Store;
|
||||
@ -208,31 +141,19 @@ mod test {
|
||||
Self {
|
||||
packId: Self::TEST_ID_BYTES.into(),
|
||||
packKey: Self::TEST_KEY.into(),
|
||||
stickers: vec![proto::StickerPackSticker::test_data()],
|
||||
author: "author".to_owned(),
|
||||
title: "title".to_owned(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl proto::StickerPackSticker {
|
||||
impl proto::Sticker {
|
||||
pub(crate) const TEST_ID: StickerId = StickerId(9988);
|
||||
|
||||
fn test_data() -> Self {
|
||||
Self {
|
||||
id: Self::TEST_ID.0,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl proto::Sticker {
|
||||
pub(crate) fn test_data() -> Self {
|
||||
Self {
|
||||
packId: proto::StickerPack::TEST_ID_BYTES.into(),
|
||||
packKey: proto::StickerPack::TEST_KEY.into(),
|
||||
stickerId: proto::StickerPackSticker::TEST_ID.0,
|
||||
stickerId: Self::TEST_ID.0,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@ -244,16 +165,6 @@ mod test {
|
||||
proto::StickerPack::test_data().try_into(),
|
||||
Ok(StickerPack::<Store> {
|
||||
key: Key(proto::StickerPack::TEST_KEY),
|
||||
stickers: HashMap::from([(
|
||||
proto::StickerPackSticker::TEST_ID,
|
||||
PackSticker {
|
||||
id: proto::StickerPackSticker::TEST_ID,
|
||||
emoji: "".to_owned(),
|
||||
_limit_construction_to_module: (),
|
||||
}
|
||||
)]),
|
||||
title: "title".to_owned(),
|
||||
author: "author".to_owned(),
|
||||
_limit_construction_to_module: ()
|
||||
})
|
||||
)
|
||||
@ -273,19 +184,8 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_key(pack: &mut impl StickerPackFields) {
|
||||
*pack.pack_key_mut() = vec![0xaa; 45];
|
||||
}
|
||||
fn no_key(pack: &mut impl StickerPackFields) {
|
||||
*pack.pack_key_mut() = vec![];
|
||||
}
|
||||
fn no_stickers(pack: &mut proto::StickerPack) {
|
||||
pack.stickers = vec![];
|
||||
}
|
||||
|
||||
#[test_case(invalid_key, Err(StickerPackError::InvalidKey))]
|
||||
#[test_case(no_key, Err(StickerPackError::InvalidKey))]
|
||||
#[test_case(no_stickers, Ok(()))]
|
||||
fn sticker_pack(mutator: fn(&mut proto::StickerPack), expected: Result<(), StickerPackError>) {
|
||||
let mut sticker_pack = proto::StickerPack::test_data();
|
||||
mutator(&mut sticker_pack);
|
||||
@ -316,6 +216,12 @@ mod test {
|
||||
fn unknown_sticker_id(input: &mut proto::Sticker) {
|
||||
input.stickerId = 555555;
|
||||
}
|
||||
fn invalid_key(pack: &mut impl StickerPackFields) {
|
||||
*pack.pack_key_mut() = vec![0xaa; 45];
|
||||
}
|
||||
fn no_key(pack: &mut impl StickerPackFields) {
|
||||
*pack.pack_key_mut() = vec![];
|
||||
}
|
||||
|
||||
#[test_case(invalid_key, Err(MessageStickerError::InvalidPackKey))]
|
||||
#[test_case(no_key, Err(MessageStickerError::InvalidPackKey))]
|
||||
|
@ -301,15 +301,6 @@ message DistributionList {
|
||||
repeated uint64 memberRecipientIds = 4; // generated recipient id
|
||||
}
|
||||
|
||||
message Identity {
|
||||
bytes serviceId = 1;
|
||||
bytes identityKey = 2;
|
||||
uint64 timestamp = 3;
|
||||
bool firstUse = 4;
|
||||
bool verified = 5;
|
||||
bool nonblockingApproval = 6;
|
||||
}
|
||||
|
||||
message ChatItem {
|
||||
message IncomingMessageDetails {
|
||||
uint64 dateReceived = 1;
|
||||
@ -346,6 +337,7 @@ message ChatItem {
|
||||
RemoteDeletedMessage remoteDeletedMessage = 14;
|
||||
ChatUpdateMessage updateMessage = 15;
|
||||
PaymentNotification paymentNotification = 16;
|
||||
GiftBadge giftBadge = 17;
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,6 +428,18 @@ message PaymentNotification {
|
||||
|
||||
}
|
||||
|
||||
message GiftBadge {
|
||||
enum State {
|
||||
UNOPENED = 0;
|
||||
OPENED = 1;
|
||||
REDEEMED = 2;
|
||||
FAILED = 3;
|
||||
}
|
||||
|
||||
bytes receiptCredentialPresentation = 1;
|
||||
State state = 2;
|
||||
}
|
||||
|
||||
message ContactAttachment {
|
||||
message Name {
|
||||
optional string givenName = 1;
|
||||
@ -501,12 +505,6 @@ message ContactAttachment {
|
||||
optional string organization = 7;
|
||||
}
|
||||
|
||||
message DocumentMessage {
|
||||
Text text = 1;
|
||||
FilePointer document = 2;
|
||||
repeated Reaction reactions = 3;
|
||||
}
|
||||
|
||||
message StickerMessage {
|
||||
Sticker sticker = 1;
|
||||
repeated Reaction reactions = 2;
|
||||
@ -1027,17 +1025,8 @@ message GroupExpirationTimerUpdate {
|
||||
message StickerPack {
|
||||
bytes packId = 1;
|
||||
bytes packKey = 2;
|
||||
string title = 3;
|
||||
string author = 4;
|
||||
repeated StickerPackSticker stickers = 5; // First one should be cover sticker.
|
||||
}
|
||||
|
||||
message StickerPackSticker {
|
||||
string emoji = 1;
|
||||
uint32 id = 2;
|
||||
}
|
||||
|
||||
|
||||
message ChatStyle {
|
||||
message Gradient {
|
||||
uint32 angle = 1; // degrees
|
||||
|
Loading…
Reference in New Issue
Block a user