signal-desktop/protos/Backups.proto
2024-09-18 22:26:52 -07:00

1156 lines
30 KiB
Protocol Buffer

// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
syntax = "proto3";
package signalbackups;
option java_package = "org.thoughtcrime.securesms.backup.v2.proto";
message BackupInfo {
uint64 version = 1;
uint64 backupTimeMs = 2;
}
// 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.)
//
// Recipients, Chats, StickerPacks, and AdHocCalls 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;
}
}
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;
}
bytes profileKey = 1;
optional string username = 2;
UsernameLink usernameLink = 3;
string givenName = 4;
string familyName = 5;
string avatarUrlPath = 6;
SubscriberData donationSubscriberData = 7;
SubscriberData backupsSubscriberData = 8;
AccountSettings accountSettings = 9;
}
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 {
message Registered { }
message NotRegistered {
uint64 unregisteredTimestamp = 1;
}
enum Visibility {
VISIBLE = 0;
HIDDEN = 1;
HIDDEN_MESSAGE_REQUEST = 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;
}
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;
uint32 pinnedOrder = 4; // 0 = unpinned, otherwise chat is considered pinned and will be displayed in ascending order
uint64 expirationTimerMs = 5; // 0 = no expire timer.
uint64 muteUntilMs = 6;
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 {
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;
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;
uint64 expireStartDate = 4; // timestamp of when expiration timer started ticking down
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;
}
}
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 {
repeated ContactAttachment contact = 1;
repeated Reaction reactions = 2;
}
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 ContactAttachment {
message Name {
optional string givenName = 1;
optional string familyName = 2;
optional string prefix = 3;
optional string suffix = 4;
optional string middleName = 5;
}
message Phone {
enum Type {
UNKNOWN = 0;
HOME = 1;
MOBILE = 2;
WORK = 3;
CUSTOM = 4;
}
optional string value = 1;
optional Type type = 2;
optional string label = 3;
}
message Email {
enum Type {
UNKNOWN = 0;
HOME = 1;
MOBILE = 2;
WORK = 3;
CUSTOM = 4;
}
optional string value = 1;
optional Type type = 2;
optional string label = 3;
}
message PostalAddress {
enum Type {
UNKNOWN = 0;
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;
}
optional Name name = 1;
repeated Phone number = 3;
repeated Email email = 4;
repeated PostalAddress address = 5;
optional FilePointer avatar = 6;
optional 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;
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;
GIFTBADGE = 2;
}
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;
// The time the call ended. 0 indicates an unknown time.
uint64 endedCallTimestamp = 6;
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 {
// Note: group expiration timer changes are represented as ExpirationTimerChatUpdate.
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;
}