mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 03:52:17 +02:00
Update to latest Backup.proto
- expireTimerVersion must not be 0 when an expirationTimer is set - group members no longer have profile keys
This commit is contained in:
parent
6daa60f395
commit
26bf02e1e3
@ -69,6 +69,8 @@ pub enum ChatError {
|
|||||||
NoRecipient(RecipientId),
|
NoRecipient(RecipientId),
|
||||||
/// cannot have a chat with recipient {0:?}, a {1:?}
|
/// cannot have a chat with recipient {0:?}, a {1:?}
|
||||||
InvalidRecipient(RecipientId, DestinationKind),
|
InvalidRecipient(RecipientId, DestinationKind),
|
||||||
|
/// chat with {0:?} has an expirationTimerMs but no expireTimerVersion
|
||||||
|
MissingExpireTimerVersion(RecipientId),
|
||||||
/// chat item: {0}
|
/// chat item: {0}
|
||||||
ChatItem(#[from] ChatItemError),
|
ChatItem(#[from] ChatItemError),
|
||||||
/// {0:?} already appeared
|
/// {0:?} already appeared
|
||||||
@ -172,6 +174,7 @@ pub struct ChatData<M: Method + ReferencedTypes> {
|
|||||||
#[serde(bound(serialize = "M::List<ChatItemData<M>>: serde::Serialize"))]
|
#[serde(bound(serialize = "M::List<ChatItemData<M>>: serde::Serialize"))]
|
||||||
pub items: M::List<ChatItemData<M>>,
|
pub items: M::List<ChatItemData<M>>,
|
||||||
pub expiration_timer: Option<Duration>,
|
pub expiration_timer: Option<Duration>,
|
||||||
|
pub expiration_timer_version: u32,
|
||||||
pub mute_until: Option<Timestamp>,
|
pub mute_until: Option<Timestamp>,
|
||||||
pub style: Option<ChatStyle<M>>,
|
pub style: Option<ChatStyle<M>>,
|
||||||
pub pinned_order: Option<PinOrder>,
|
pub pinned_order: Option<PinOrder>,
|
||||||
@ -349,6 +352,7 @@ impl<
|
|||||||
id: _,
|
id: _,
|
||||||
recipientId,
|
recipientId,
|
||||||
expirationTimerMs,
|
expirationTimerMs,
|
||||||
|
expireTimerVersion,
|
||||||
muteUntilMs,
|
muteUntilMs,
|
||||||
pinnedOrder,
|
pinnedOrder,
|
||||||
archived,
|
archived,
|
||||||
@ -389,9 +393,15 @@ impl<
|
|||||||
let mute_until = NonZeroU64::new(muteUntilMs)
|
let mute_until = NonZeroU64::new(muteUntilMs)
|
||||||
.map(|t| Timestamp::from_millis(t.get(), "Chat.muteUntilMs"));
|
.map(|t| Timestamp::from_millis(t.get(), "Chat.muteUntilMs"));
|
||||||
|
|
||||||
|
if expiration_timer.is_some() && expireTimerVersion == 0 {
|
||||||
|
return Err(ChatError::MissingExpireTimerVersion(recipient_id));
|
||||||
|
}
|
||||||
|
let expiration_timer_version = expireTimerVersion;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
recipient,
|
recipient,
|
||||||
expiration_timer,
|
expiration_timer,
|
||||||
|
expiration_timer_version,
|
||||||
mute_until,
|
mute_until,
|
||||||
items: Default::default(),
|
items: Default::default(),
|
||||||
style,
|
style,
|
||||||
@ -869,6 +879,7 @@ mod test {
|
|||||||
recipient: TestContext::test_recipient().clone(),
|
recipient: TestContext::test_recipient().clone(),
|
||||||
items: Vec::default(),
|
items: Vec::default(),
|
||||||
expiration_timer: None,
|
expiration_timer: None,
|
||||||
|
expiration_timer_version: 0,
|
||||||
mute_until: None,
|
mute_until: None,
|
||||||
style: None,
|
style: None,
|
||||||
pinned_order: None,
|
pinned_order: None,
|
||||||
@ -879,7 +890,12 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(|x| x.expirationTimerMs = 123456 => Ok(()); "with_expiration_timer")]
|
#[test_case(|x| {
|
||||||
|
x.expirationTimerMs = 123456;
|
||||||
|
x.expireTimerVersion = 3;
|
||||||
|
} => Ok(()); "with_expiration_timer")]
|
||||||
|
#[test_case(|x| x.expirationTimerMs = 123456 => Err(ChatError::MissingExpireTimerVersion(TestContext::SELF_ID)); "with_expiration_timer_only")]
|
||||||
|
#[test_case(|x| x.expireTimerVersion = 3 => Ok(()); "with_expire_timer_version_only")]
|
||||||
#[test_case(|x| x.muteUntilMs = MillisecondsSinceEpoch::TEST_VALUE.0 => Ok(()); "with mute until")]
|
#[test_case(|x| x.muteUntilMs = MillisecondsSinceEpoch::TEST_VALUE.0 => Ok(()); "with mute until")]
|
||||||
#[test_case(
|
#[test_case(
|
||||||
|x| x.pinnedOrder = TestContext::DUPLICATE_PINNED_ORDER.0.get() =>
|
|x| x.pinnedOrder = TestContext::DUPLICATE_PINNED_ORDER.0.get() =>
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
use libsignal_core::{Aci, ServiceId, WrongKindOfServiceIdError};
|
use libsignal_core::{Aci, ServiceId, WrongKindOfServiceIdError};
|
||||||
use zkgroup::ProfileKeyBytes;
|
|
||||||
|
|
||||||
use super::GroupError;
|
use super::GroupError;
|
||||||
use crate::backup::serialize::{self, SerializeOrder};
|
use crate::backup::serialize::{self, SerializeOrder};
|
||||||
@ -23,8 +22,6 @@ pub struct GroupMember {
|
|||||||
#[serde(serialize_with = "serialize::service_id_as_string")]
|
#[serde(serialize_with = "serialize::service_id_as_string")]
|
||||||
pub user_id: Aci,
|
pub user_id: Aci,
|
||||||
pub role: Role,
|
pub role: Role,
|
||||||
#[serde(with = "hex")]
|
|
||||||
pub profile_key: ProfileKeyBytes,
|
|
||||||
pub joined_at_version: u32,
|
pub joined_at_version: u32,
|
||||||
pub(super) _limit_construction_to_module: (),
|
pub(super) _limit_construction_to_module: (),
|
||||||
}
|
}
|
||||||
@ -42,7 +39,6 @@ impl TryFrom<proto::group::Member> for GroupMember {
|
|||||||
let proto::group::Member {
|
let proto::group::Member {
|
||||||
userId,
|
userId,
|
||||||
role,
|
role,
|
||||||
profileKey,
|
|
||||||
joinedAtVersion,
|
joinedAtVersion,
|
||||||
special_fields: _,
|
special_fields: _,
|
||||||
} = value;
|
} = value;
|
||||||
@ -61,14 +57,11 @@ impl TryFrom<proto::group::Member> for GroupMember {
|
|||||||
proto::group::member::Role::DEFAULT => Role::Default,
|
proto::group::member::Role::DEFAULT => Role::Default,
|
||||||
proto::group::member::Role::ADMINISTRATOR => Role::Administrator,
|
proto::group::member::Role::ADMINISTRATOR => Role::Administrator,
|
||||||
};
|
};
|
||||||
let profile_key = ProfileKeyBytes::try_from(profileKey)
|
|
||||||
.map_err(|_| GroupError::MemberInvalidProfileKey)?;
|
|
||||||
let joined_at_version = joinedAtVersion;
|
let joined_at_version = joinedAtVersion;
|
||||||
|
|
||||||
Ok(GroupMember {
|
Ok(GroupMember {
|
||||||
user_id,
|
user_id,
|
||||||
role,
|
role,
|
||||||
profile_key,
|
|
||||||
joined_at_version,
|
joined_at_version,
|
||||||
_limit_construction_to_module: (),
|
_limit_construction_to_module: (),
|
||||||
})
|
})
|
||||||
@ -108,7 +101,6 @@ impl TryFrom<proto::group::MemberPendingProfileKey> for GroupMemberPendingProfil
|
|||||||
let proto::group::Member {
|
let proto::group::Member {
|
||||||
userId,
|
userId,
|
||||||
role,
|
role,
|
||||||
profileKey,
|
|
||||||
joinedAtVersion,
|
joinedAtVersion,
|
||||||
special_fields: _,
|
special_fields: _,
|
||||||
} = member
|
} = member
|
||||||
@ -125,9 +117,6 @@ impl TryFrom<proto::group::MemberPendingProfileKey> for GroupMemberPendingProfil
|
|||||||
proto::group::member::Role::DEFAULT => Role::Default,
|
proto::group::member::Role::DEFAULT => Role::Default,
|
||||||
proto::group::member::Role::ADMINISTRATOR => Role::Administrator,
|
proto::group::member::Role::ADMINISTRATOR => Role::Administrator,
|
||||||
};
|
};
|
||||||
if !profileKey.is_empty() {
|
|
||||||
return Err(GroupError::MemberPendingProfileKeyHasProfileKey);
|
|
||||||
}
|
|
||||||
let joined_at_version = joinedAtVersion;
|
let joined_at_version = joinedAtVersion;
|
||||||
|
|
||||||
let added_by_user_id = ServiceId::parse_from_service_id_binary(&addedByUserId)
|
let added_by_user_id = ServiceId::parse_from_service_id_binary(&addedByUserId)
|
||||||
@ -162,8 +151,6 @@ impl TryFrom<proto::group::MemberPendingProfileKey> for GroupMemberPendingProfil
|
|||||||
pub struct GroupMemberPendingAdminApproval {
|
pub struct GroupMemberPendingAdminApproval {
|
||||||
#[serde(serialize_with = "serialize::service_id_as_string")]
|
#[serde(serialize_with = "serialize::service_id_as_string")]
|
||||||
pub user_id: Aci,
|
pub user_id: Aci,
|
||||||
#[serde(with = "hex")]
|
|
||||||
pub profile_key: ProfileKeyBytes,
|
|
||||||
pub timestamp: Timestamp,
|
pub timestamp: Timestamp,
|
||||||
pub(super) _limit_construction_to_module: (),
|
pub(super) _limit_construction_to_module: (),
|
||||||
}
|
}
|
||||||
@ -180,7 +167,6 @@ impl TryFrom<proto::group::MemberPendingAdminApproval> for GroupMemberPendingAdm
|
|||||||
fn try_from(member: proto::group::MemberPendingAdminApproval) -> Result<Self, Self::Error> {
|
fn try_from(member: proto::group::MemberPendingAdminApproval) -> Result<Self, Self::Error> {
|
||||||
let proto::group::MemberPendingAdminApproval {
|
let proto::group::MemberPendingAdminApproval {
|
||||||
userId,
|
userId,
|
||||||
profileKey,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
special_fields: _,
|
special_fields: _,
|
||||||
} = member;
|
} = member;
|
||||||
@ -196,13 +182,10 @@ impl TryFrom<proto::group::MemberPendingAdminApproval> for GroupMemberPendingAdm
|
|||||||
found: e.actual,
|
found: e.actual,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let profile_key = ProfileKeyBytes::try_from(profileKey)
|
|
||||||
.map_err(|_| GroupError::MemberInvalidProfileKey)?;
|
|
||||||
let timestamp = Timestamp::from_millis(timestamp, "MemberPendingAdminApproval");
|
let timestamp = Timestamp::from_millis(timestamp, "MemberPendingAdminApproval");
|
||||||
|
|
||||||
Ok(GroupMemberPendingAdminApproval {
|
Ok(GroupMemberPendingAdminApproval {
|
||||||
user_id,
|
user_id,
|
||||||
profile_key,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
_limit_construction_to_module: (),
|
_limit_construction_to_module: (),
|
||||||
})
|
})
|
||||||
@ -262,7 +245,6 @@ mod tests {
|
|||||||
Self {
|
Self {
|
||||||
userId: proto::Contact::TEST_ACI.to_vec(),
|
userId: proto::Contact::TEST_ACI.to_vec(),
|
||||||
role: proto::group::member::Role::DEFAULT.into(),
|
role: proto::group::member::Role::DEFAULT.into(),
|
||||||
profileKey: proto::Contact::TEST_PROFILE_KEY.to_vec(),
|
|
||||||
joinedAtVersion: 1,
|
joinedAtVersion: 1,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@ -274,7 +256,6 @@ mod tests {
|
|||||||
Self {
|
Self {
|
||||||
user_id: Aci::from_uuid_bytes(proto::Contact::TEST_ACI),
|
user_id: Aci::from_uuid_bytes(proto::Contact::TEST_ACI),
|
||||||
role: Role::Default,
|
role: Role::Default,
|
||||||
profile_key: proto::Contact::TEST_PROFILE_KEY,
|
|
||||||
joined_at_version: 1,
|
joined_at_version: 1,
|
||||||
_limit_construction_to_module: (),
|
_limit_construction_to_module: (),
|
||||||
}
|
}
|
||||||
@ -293,7 +274,6 @@ mod tests {
|
|||||||
#[test_case(|x| x.userId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "member" }); "empty userId")]
|
#[test_case(|x| x.userId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "member" }); "empty userId")]
|
||||||
#[test_case(|x| x.role = proto::group::member::Role::ADMINISTRATOR.into() => Ok(()); "administrator")]
|
#[test_case(|x| x.role = proto::group::member::Role::ADMINISTRATOR.into() => Ok(()); "administrator")]
|
||||||
#[test_case(|x| x.role = proto::group::member::Role::UNKNOWN.into() => Err(GroupError::MemberRoleUnknown); "role unknown")]
|
#[test_case(|x| x.role = proto::group::member::Role::UNKNOWN.into() => Err(GroupError::MemberRoleUnknown); "role unknown")]
|
||||||
#[test_case(|x| x.profileKey = vec![] => Err(GroupError::MemberInvalidProfileKey); "empty profileKey")]
|
|
||||||
fn member(modifier: impl FnOnce(&mut proto::group::Member)) -> Result<(), GroupError> {
|
fn member(modifier: impl FnOnce(&mut proto::group::Member)) -> Result<(), GroupError> {
|
||||||
let mut member = proto::group::Member::test_data();
|
let mut member = proto::group::Member::test_data();
|
||||||
modifier(&mut member);
|
modifier(&mut member);
|
||||||
@ -305,11 +285,7 @@ mod tests {
|
|||||||
|
|
||||||
pub(crate) fn test_data() -> Self {
|
pub(crate) fn test_data() -> Self {
|
||||||
Self {
|
Self {
|
||||||
member: Some(proto::group::Member {
|
member: Some(proto::group::Member::test_data()).into(),
|
||||||
profileKey: vec![],
|
|
||||||
..proto::group::Member::test_data()
|
|
||||||
})
|
|
||||||
.into(),
|
|
||||||
timestamp: MillisecondsSinceEpoch::TEST_VALUE.0,
|
timestamp: MillisecondsSinceEpoch::TEST_VALUE.0,
|
||||||
addedByUserId: Self::INVITER_ACI.to_vec(),
|
addedByUserId: Self::INVITER_ACI.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -348,7 +324,6 @@ mod tests {
|
|||||||
#[test_case(|x| x.member.as_mut().unwrap().userId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "invited member" }); "empty userId")]
|
#[test_case(|x| x.member.as_mut().unwrap().userId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "invited member" }); "empty userId")]
|
||||||
#[test_case(|x| x.member.as_mut().unwrap().role = proto::group::member::Role::ADMINISTRATOR.into() => Ok(()); "administrator")]
|
#[test_case(|x| x.member.as_mut().unwrap().role = proto::group::member::Role::ADMINISTRATOR.into() => Ok(()); "administrator")]
|
||||||
#[test_case(|x| x.member.as_mut().unwrap().role = proto::group::member::Role::UNKNOWN.into() => Err(GroupError::MemberRoleUnknown); "role unknown")]
|
#[test_case(|x| x.member.as_mut().unwrap().role = proto::group::member::Role::UNKNOWN.into() => Err(GroupError::MemberRoleUnknown); "role unknown")]
|
||||||
#[test_case(|x| x.member.as_mut().unwrap().profileKey = proto::Contact::TEST_PROFILE_KEY.to_vec() => Err(GroupError::MemberPendingProfileKeyHasProfileKey); "valid profileKey")]
|
|
||||||
#[test_case(|x| x.addedByUserId = Pni::from_uuid_bytes(proto::Contact::TEST_PNI).service_id_binary() => Err(GroupError::MemberInvalidAci { which: "inviter", found: ServiceIdKind::Pni }); "PNI inviter")]
|
#[test_case(|x| x.addedByUserId = Pni::from_uuid_bytes(proto::Contact::TEST_PNI).service_id_binary() => Err(GroupError::MemberInvalidAci { which: "inviter", found: ServiceIdKind::Pni }); "PNI inviter")]
|
||||||
#[test_case(|x| x.addedByUserId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "inviter" }); "empty inviter")]
|
#[test_case(|x| x.addedByUserId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "inviter" }); "empty inviter")]
|
||||||
#[test_case(|x| x.addedByUserId = proto::Contact::TEST_ACI.to_vec() => Err(GroupError::MemberPendingProfileKeyWasInvitedBySelf); "self-invite")]
|
#[test_case(|x| x.addedByUserId = proto::Contact::TEST_ACI.to_vec() => Err(GroupError::MemberPendingProfileKeyWasInvitedBySelf); "self-invite")]
|
||||||
@ -364,7 +339,6 @@ mod tests {
|
|||||||
pub(crate) fn test_data() -> Self {
|
pub(crate) fn test_data() -> Self {
|
||||||
Self {
|
Self {
|
||||||
userId: proto::Contact::TEST_ACI.to_vec(),
|
userId: proto::Contact::TEST_ACI.to_vec(),
|
||||||
profileKey: proto::Contact::TEST_PROFILE_KEY.to_vec(),
|
|
||||||
timestamp: MillisecondsSinceEpoch::TEST_VALUE.0,
|
timestamp: MillisecondsSinceEpoch::TEST_VALUE.0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@ -375,7 +349,6 @@ mod tests {
|
|||||||
pub(crate) fn from_proto_test_data() -> Self {
|
pub(crate) fn from_proto_test_data() -> Self {
|
||||||
Self {
|
Self {
|
||||||
user_id: Aci::from_uuid_bytes(proto::Contact::TEST_ACI),
|
user_id: Aci::from_uuid_bytes(proto::Contact::TEST_ACI),
|
||||||
profile_key: proto::Contact::TEST_PROFILE_KEY,
|
|
||||||
timestamp: Timestamp::test_value(),
|
timestamp: Timestamp::test_value(),
|
||||||
_limit_construction_to_module: (),
|
_limit_construction_to_module: (),
|
||||||
}
|
}
|
||||||
@ -395,7 +368,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test_case(|x| x.userId = Pni::from_uuid_bytes(proto::Contact::TEST_PNI).service_id_binary() => Err(GroupError::MemberInvalidAci { which: "requesting member", found: ServiceIdKind::Pni }); "PNI userId")]
|
#[test_case(|x| x.userId = Pni::from_uuid_bytes(proto::Contact::TEST_PNI).service_id_binary() => Err(GroupError::MemberInvalidAci { which: "requesting member", found: ServiceIdKind::Pni }); "PNI userId")]
|
||||||
#[test_case(|x| x.userId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "requesting member" }); "empty userId")]
|
#[test_case(|x| x.userId = vec![] => Err(GroupError::MemberInvalidServiceId { which: "requesting member" }); "empty userId")]
|
||||||
#[test_case(|x| x.profileKey = vec![] => Err(GroupError::MemberInvalidProfileKey); "empty profileKey")]
|
|
||||||
fn member_pending_admin_approval(
|
fn member_pending_admin_approval(
|
||||||
modifier: impl FnOnce(&mut proto::group::MemberPendingAdminApproval),
|
modifier: impl FnOnce(&mut proto::group::MemberPendingAdminApproval),
|
||||||
) -> Result<(), GroupError> {
|
) -> Result<(), GroupError> {
|
||||||
|
@ -191,8 +191,8 @@ message Group {
|
|||||||
|
|
||||||
bytes userId = 1;
|
bytes userId = 1;
|
||||||
Role role = 2;
|
Role role = 2;
|
||||||
bytes profileKey = 3;
|
reserved /*profileKey*/ 3; // This field is ignored in Backups, in favor of Contact frames for members
|
||||||
reserved /*presentation*/ 4; // The field is deprecated in the context of static group state
|
reserved /*presentation*/ 4; // This field is deprecated in the context of static group state
|
||||||
uint32 joinedAtVersion = 5;
|
uint32 joinedAtVersion = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,8 +204,8 @@ message Group {
|
|||||||
|
|
||||||
message MemberPendingAdminApproval {
|
message MemberPendingAdminApproval {
|
||||||
bytes userId = 1;
|
bytes userId = 1;
|
||||||
bytes profileKey = 2;
|
reserved /*profileKey*/ 2; // This field is ignored in Backups, in favor of Contact frames for members
|
||||||
reserved /*presentation*/ 3; // The field is deprecated in the context of static group state
|
reserved /*presentation*/ 3; // This field is deprecated in the context of static group state
|
||||||
uint64 timestamp = 4;
|
uint64 timestamp = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,6 +243,7 @@ message Chat {
|
|||||||
bool markedUnread = 7;
|
bool markedUnread = 7;
|
||||||
bool dontNotifyForMentionsIfMuted = 8;
|
bool dontNotifyForMentionsIfMuted = 8;
|
||||||
ChatStyle style = 9;
|
ChatStyle style = 9;
|
||||||
|
uint32 expireTimerVersion = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1066,7 +1067,7 @@ message StickerPack {
|
|||||||
message ChatStyle {
|
message ChatStyle {
|
||||||
message Gradient {
|
message Gradient {
|
||||||
uint32 angle = 1; // degrees
|
uint32 angle = 1; // degrees
|
||||||
repeated fixed32 colors = 2;
|
repeated fixed32 colors = 2; // 0xAARRGGBB
|
||||||
repeated float positions = 3; // percent from 0 to 1
|
repeated float positions = 3; // percent from 0 to 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1074,7 +1075,7 @@ message ChatStyle {
|
|||||||
uint64 id = 1;
|
uint64 id = 1;
|
||||||
|
|
||||||
oneof color {
|
oneof color {
|
||||||
fixed32 solid = 2;
|
fixed32 solid = 2; // 0xAARRGGBB
|
||||||
Gradient gradient = 3;
|
Gradient gradient = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1135,6 +1136,8 @@ message ChatStyle {
|
|||||||
|
|
||||||
oneof wallpaper {
|
oneof wallpaper {
|
||||||
WallpaperPreset wallpaperPreset = 1;
|
WallpaperPreset wallpaperPreset = 1;
|
||||||
|
// This `FilePointer` is expected not to contain a `fileName`, `width`,
|
||||||
|
// `height`, or `caption`.
|
||||||
FilePointer wallpaperPhoto = 2;
|
FilePointer wallpaperPhoto = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,13 +113,11 @@
|
|||||||
{
|
{
|
||||||
"userId": "CujGyCcHTqeyJHQXIn04kA==", // Chewie's ACI
|
"userId": "CujGyCcHTqeyJHQXIn04kA==", // Chewie's ACI
|
||||||
"role": "ADMINISTRATOR",
|
"role": "ADMINISTRATOR",
|
||||||
"profileKey": "cM4PAiE6xclFBl2wesio4S/tpbDfZHFpYf7BBAsnZI4=",
|
|
||||||
"joinedAtVersion": 0,
|
"joinedAtVersion": 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"userId": "X4xWjQEZR72BqruHybcZlQ==", // Han's ACI
|
"userId": "X4xWjQEZR72BqruHybcZlQ==", // Han's ACI
|
||||||
"role": "ADMINISTRATOR",
|
"role": "ADMINISTRATOR",
|
||||||
"profileKey": "YtHHVK+Wo4nPcVpWhC3roMEDu2Tw6kYc9JpLRMq1Q94=",
|
|
||||||
"joinedAtVersion": 0,
|
"joinedAtVersion": 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user