1174 lines
31 KiB
Protocol Buffer
1174 lines
31 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;
|
|
bytes mediaRootBackupKey = 3; // 32-byte random value generated when the backup is uploaded for the first time.
|
|
}
|
|
|
|
// 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 {
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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; // UINT64_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;
|
|
optional 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;
|
|
}
|
|
}
|
|
|
|
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 ViewOnceMessage {
|
|
// Will be null for viewed messages
|
|
MessageAttachment attachment = 1;
|
|
repeated Reaction reactions = 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;
|
|
optional string nickname = 6;
|
|
}
|
|
|
|
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;
|
|
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;
|
|
}
|