If there are several group changes being returned at once, deserializing all of them up front can lead to excessive memory use, especially for very large groups. This commit switches to deserializing each change as it is used, which doubles the amount of CPU work (because we loop through the changes twice) in exchange for only ever having one Change object graph in memory at a time. It does also mean we can get a protobuf deserialization error a bit later in the process if the data is ever corrupted, but that shouldn't cause additional issues at these particular call sites.
241 lines
8.8 KiB
Protocol Buffer
241 lines
8.8 KiB
Protocol Buffer
/**
|
||
* Copyright (C) 2019 Open Whisper Systems
|
||
*
|
||
* Licensed according to the LICENSE file in this repository.
|
||
*/
|
||
syntax = "proto3";
|
||
|
||
// iOS - package name determines class prefix
|
||
package GroupsProtos;
|
||
|
||
option java_package = "org.signal.storageservice.protos.groups";
|
||
option java_multiple_files = true;
|
||
|
||
message AvatarUploadAttributes {
|
||
string key = 1;
|
||
string credential = 2;
|
||
string acl = 3;
|
||
string algorithm = 4;
|
||
string date = 5;
|
||
string policy = 6;
|
||
string signature = 7;
|
||
}
|
||
|
||
message Member {
|
||
enum Role {
|
||
UNKNOWN = 0;
|
||
DEFAULT = 1; // Normal member
|
||
ADMINISTRATOR = 2; // Group admin
|
||
}
|
||
|
||
bytes userId = 1; // The UuidCiphertext
|
||
Role role = 2;
|
||
bytes profileKey = 3; // The ProfileKeyCiphertext
|
||
bytes presentation = 4; // ProfileKeyCredentialPresentation
|
||
uint32 joinedAtRevision = 5; // The Group.revision this member joined at
|
||
}
|
||
|
||
message PendingMember {
|
||
Member member = 1; // The “invited” member
|
||
bytes addedByUserId = 2; // The UID who invited this member
|
||
uint64 timestamp = 3; // The time the invitation occurred
|
||
}
|
||
|
||
message RequestingMember {
|
||
bytes userId = 1;
|
||
bytes profileKey = 2;
|
||
bytes presentation = 3;
|
||
uint64 timestamp = 4;
|
||
}
|
||
|
||
message AccessControl {
|
||
enum AccessRequired {
|
||
UNKNOWN = 0;
|
||
ANY = 1;
|
||
MEMBER = 2; // Any group member can make the modification
|
||
ADMINISTRATOR = 3; // Only administrators can make the modification
|
||
UNSATISFIABLE = 4;
|
||
}
|
||
|
||
AccessRequired attributes = 1; // Who can modify the group title, avatar, disappearing messages timer
|
||
AccessRequired members = 2; // Who can add people to the group
|
||
AccessRequired addFromInviteLink = 3;
|
||
}
|
||
|
||
message Group {
|
||
bytes publicKey = 1; // GroupPublicParams
|
||
bytes title = 2; // Encrypted title
|
||
string avatar = 3; // Pointer to encrypted avatar (‘key’ from AvatarUploadAttributes)
|
||
bytes disappearingMessagesTimer = 4; // Encrypted timer
|
||
AccessControl accessControl = 5;
|
||
uint32 revision = 6; // Current group revision number
|
||
repeated Member members = 7;
|
||
repeated PendingMember pendingMembers = 8;
|
||
repeated RequestingMember requestingMembers = 9;
|
||
bytes inviteLinkPassword = 10;
|
||
bytes descriptionBytes = 11;
|
||
bool announcementsOnly = 12;
|
||
// next: 13
|
||
}
|
||
|
||
message GroupChange {
|
||
|
||
message Actions {
|
||
|
||
message AddMemberAction {
|
||
Member added = 1;
|
||
bool joinFromInviteLink = 2;
|
||
}
|
||
|
||
message DeleteMemberAction {
|
||
bytes deletedUserId = 1;
|
||
}
|
||
|
||
message ModifyMemberRoleAction {
|
||
bytes userId = 1;
|
||
Member.Role role = 2;
|
||
}
|
||
|
||
message ModifyMemberProfileKeyAction {
|
||
bytes presentation = 1;
|
||
}
|
||
|
||
message AddPendingMemberAction {
|
||
PendingMember added = 1;
|
||
}
|
||
|
||
message DeletePendingMemberAction {
|
||
bytes deletedUserId = 1;
|
||
}
|
||
|
||
message PromotePendingMemberAction {
|
||
bytes presentation = 1;
|
||
}
|
||
|
||
message AddRequestingMemberAction {
|
||
RequestingMember added = 1;
|
||
}
|
||
|
||
message DeleteRequestingMemberAction {
|
||
bytes deletedUserId = 1;
|
||
}
|
||
|
||
message PromoteRequestingMemberAction {
|
||
bytes userId = 1;
|
||
Member.Role role = 2;
|
||
}
|
||
|
||
message ModifyTitleAction {
|
||
bytes title = 1;
|
||
}
|
||
|
||
message ModifyAvatarAction {
|
||
string avatar = 1;
|
||
}
|
||
|
||
message ModifyDisappearingMessagesTimerAction {
|
||
bytes timer = 1;
|
||
}
|
||
|
||
message ModifyAttributesAccessControlAction {
|
||
AccessControl.AccessRequired attributesAccess = 1;
|
||
}
|
||
|
||
message ModifyAvatarAccessControlAction {
|
||
AccessControl.AccessRequired avatarAccess = 1;
|
||
}
|
||
|
||
message ModifyMembersAccessControlAction {
|
||
AccessControl.AccessRequired membersAccess = 1;
|
||
}
|
||
|
||
message ModifyAddFromInviteLinkAccessControlAction {
|
||
AccessControl.AccessRequired addFromInviteLinkAccess = 1;
|
||
}
|
||
|
||
message ModifyInviteLinkPasswordAction {
|
||
bytes inviteLinkPassword = 1;
|
||
}
|
||
|
||
message ModifyDescriptionAction {
|
||
bytes descriptionBytes = 1;
|
||
}
|
||
|
||
message ModifyAnnouncementsOnlyAction {
|
||
bool announcementsOnly = 1;
|
||
}
|
||
|
||
bytes sourceUuid = 1; // Who made the change
|
||
uint32 revision = 2; // The change revision number
|
||
repeated AddMemberAction addMembers = 3; // Members added
|
||
repeated DeleteMemberAction deleteMembers = 4; // Members deleted
|
||
repeated ModifyMemberRoleAction modifyMemberRoles = 5; // Modified member roles
|
||
repeated ModifyMemberProfileKeyAction modifyMemberProfileKeys = 6; // Modified member profile keys
|
||
repeated AddPendingMemberAction addPendingMembers = 7; // Pending members added
|
||
repeated DeletePendingMemberAction deletePendingMembers = 8; // Pending members deleted
|
||
repeated PromotePendingMemberAction promotePendingMembers = 9; // Pending invitations accepted
|
||
ModifyTitleAction modifyTitle = 10; // Changed title
|
||
ModifyAvatarAction modifyAvatar = 11; // Changed avatar
|
||
ModifyDisappearingMessagesTimerAction modifyDisappearingMessagesTimer = 12; // Changed timer
|
||
ModifyAttributesAccessControlAction modifyAttributesAccess = 13; // Changed attributes access control
|
||
ModifyMembersAccessControlAction modifyMemberAccess = 14; // Changed membership access control
|
||
ModifyAddFromInviteLinkAccessControlAction modifyAddFromInviteLinkAccess = 15; // change epoch = 1
|
||
repeated AddRequestingMemberAction addRequestingMembers = 16; // change epoch = 1
|
||
repeated DeleteRequestingMemberAction deleteRequestingMembers = 17; // change epoch = 1
|
||
repeated PromoteRequestingMemberAction promoteRequestingMembers = 18; // change epoch = 1
|
||
ModifyInviteLinkPasswordAction modifyInviteLinkPassword = 19; // change epoch = 1
|
||
ModifyDescriptionAction modifyDescription = 20; // change epoch = 2
|
||
ModifyAnnouncementsOnlyAction modifyAnnouncementsOnly = 21; // change epoch = 3
|
||
}
|
||
|
||
bytes actions = 1; // The serialized actions
|
||
bytes serverSignature = 2; // Server’s signature over serialized actions
|
||
uint32 changeEpoch = 3;
|
||
}
|
||
|
||
message GroupChanges {
|
||
message GroupChangeState {
|
||
GroupChange groupChange = 1;
|
||
Group groupState = 2;
|
||
}
|
||
|
||
repeated bytes /*GroupChangeState*/ groupChanges = 1;
|
||
}
|
||
|
||
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 {
|
||
// I have renamed this field to work around a limitation
|
||
// in our code generation.
|
||
GroupInviteLinkContentsV1 contentsV1 = 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 descriptionBytes = 8;
|
||
}
|
||
|
||
message GroupExternalCredential {
|
||
string token = 1;
|
||
}
|