/* * Copyright 2020-2021 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ syntax = "proto3"; package signalservice; option java_package = "org.signal.storageservice.storage.protos.contacts"; option java_outer_classname = "StorageProtos"; option java_multiple_files = true; enum OptionalBool { UNSET = 0; ENABLED = 1; DISABLED = 2; } message StorageManifest { uint64 version = 1; bytes value = 2; } message StorageItem { bytes key = 1; bytes value = 2; } message StorageItems { repeated StorageItem items = 1; } message WriteOperation { StorageManifest manifest = 1; repeated StorageItem insertItem = 2; repeated bytes deleteKey = 3; bool clearAll = 4; } message ReadOperation { repeated bytes readKey = 1; } message ManifestRecord { message Identifier { enum Type { UNKNOWN = 0; CONTACT = 1; GROUPV1 = 2; GROUPV2 = 3; ACCOUNT = 4; STORY_DISTRIBUTION_LIST = 5; STICKER_PACK = 6; CALL_LINK = 7; CHAT_FOLDER = 8; NOTIFICATION_PROFILE = 9; } bytes raw = 1; Type type = 2; } uint64 version = 1; uint32 sourceDevice = 3; repeated Identifier identifiers = 2; bytes recordIkm = 4; // Next ID: 5 } message StorageRecord { oneof record { ContactRecord contact = 1; GroupV1Record groupV1 = 2; GroupV2Record groupV2 = 3; AccountRecord account = 4; StoryDistributionListRecord storyDistributionList = 5; StickerPackRecord stickerPack = 6; CallLinkRecord callLink = 7; ChatFolderRecord chatFolder = 8; NotificationProfile notificationProfile = 9; } } // If unset - computed as the value of the first byte of SHA-256(msg=CONTACT_ID) // modulo the count of colors. Once set the avatar color for a recipient is // never recomputed or changed. // // `CONTACT_ID` is the first available identifier from the list: // - ServiceIdToBinary(ACI) // - E164 // - ServiceIdToBinary(PNI) // - Group Id enum AvatarColor { A100 = 0; A110 = 1; A120 = 2; A130 = 3; A140 = 4; A150 = 5; A160 = 6; A170 = 7; A180 = 8; A190 = 9; A200 = 10; A210 = 11; } message ContactRecord { enum IdentityState { DEFAULT = 0; VERIFIED = 1; UNVERIFIED = 2; } message Name { string given = 1; string family = 2; } string aci = 1; string e164 = 2; string pni = 15; bytes profileKey = 3; bytes identityKey = 4; IdentityState identityState = 5; string givenName = 6; string familyName = 7; string username = 8; bool blocked = 9; bool whitelisted = 10; bool archived = 11; bool markedUnread = 12; uint64 mutedUntilTimestamp = 13; bool hideStory = 14; uint64 unregisteredAtTimestamp = 16; string systemGivenName = 17; string systemFamilyName = 18; string systemNickname = 19; bool hidden = 20; bool pniSignatureVerified = 21; Name nickname = 22; string note = 23; optional AvatarColor avatarColor = 24; bytes aciBinary = 25; // 16-byte UUID bytes pniBinary = 26; // 16-byte UUID // Next ID: 27 } message GroupV1Record { bytes id = 1; reserved /*blocked*/ 2; reserved /*whitelisted*/ 3; reserved /*archived*/ 4; reserved /*markedUnread*/ 5; reserved /*mutedUntilTimestamp*/ 6; } message GroupV2Record { enum StorySendMode { DEFAULT = 0; DISABLED = 1; ENABLED = 2; } bytes masterKey = 1; bool blocked = 2; bool whitelisted = 3; bool archived = 4; bool markedUnread = 5; uint64 mutedUntilTimestamp = 6; bool dontNotifyForMentionsIfMuted = 7; bool hideStory = 8; reserved 9; StorySendMode storySendMode = 10; optional AvatarColor avatarColor = 11; } message Payments { bool enabled = 1; bytes entropy = 2; } message AccountRecord { enum PhoneNumberSharingMode { UNKNOWN = 0; EVERYBODY = 1; NOBODY = 2; } message PinnedConversation { message Contact { string serviceId = 1; string e164 = 2; bytes serviceIdBinary = 3; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } oneof identifier { Contact contact = 1; bytes legacyGroupId = 3; bytes groupMasterKey = 4; } } 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; // color of the QR code itself } message IAPSubscriberData { bytes subscriberId = 1; oneof iapSubscriptionId { // Identifies an Android Play Store IAP subscription. string purchaseToken = 2; // Identifies an iOS App Store IAP subscription. uint64 originalTransactionId = 3; } } message BackupTierHistory { // See zkgroup for integer particular values. Unset if backups are not enabled. optional uint64 backupTier = 1; optional uint64 endedAtTimestamp = 2; } message NotificationProfileManualOverride { message ManuallyEnabled { bytes id = 1; // This will be unset if no timespan was chosen in the UI. uint64 endAtTimestampMs = 3; } oneof override { uint64 disabledAtTimestampMs = 1; ManuallyEnabled enabled = 2; } } bytes profileKey = 1; string givenName = 2; string familyName = 3; string avatarUrlPath = 4; bool noteToSelfArchived = 5; bool readReceipts = 6; bool sealedSenderIndicators = 7; bool typingIndicators = 8; reserved 9; // proxiedLinkPreviews bool noteToSelfMarkedUnread = 10; bool linkPreviews = 11; PhoneNumberSharingMode phoneNumberSharingMode = 12; bool unlistedPhoneNumber = 13; repeated PinnedConversation pinnedConversations = 14; bool preferContactAvatars = 15; uint32 universalExpireTimer = 17; reserved 18; // primarySendsSms reserved 19; // deprecatedE164 repeated string preferredReactionEmoji = 20; bytes donorSubscriberId = 21; string donorSubscriberCurrencyCode = 22; bool displayBadgesOnProfile = 23; bool donorSubscriptionManuallyCancelled = 24; bool keepMutedChatsArchived = 25; bool hasSetMyStoriesPrivacy = 26; bool hasViewedOnboardingStory = 27; // Whether the user has opened and played back the // onboarding story in the story viewer. reserved 28; // deprecatedStoriesDisabled bool storiesDisabled = 29; OptionalBool storyViewReceiptsEnabled = 30; reserved 31; // hasReadOnboardingStory bool hasSeenGroupStoryEducationSheet = 32; // Whether the user has seen the group story education // sheet. This is a sticky value. string username = 33; // Format: `nickname.discriminator`, e.g. `signalapp.123` // Updated only when username is confirmed or deleted on server. bool hasCompletedUsernameOnboarding = 34; // Whether the user has completed username // onboarding. UsernameLink usernameLink = 35; reserved /*backupsSubscriberId*/ 36; reserved /*backupsSubscriberCurrencyCode*/ 37; reserved /*backupsSubscriptionManuallyCancelled*/ 38; // Set to true after backups are enabled and one is uploaded. optional bool hasBackup = 39; // See zkgroup for integer particular values. Unset if backups are not enabled. optional uint64 backupTier = 40; IAPSubscriberData backupSubscriberData = 41; optional AvatarColor avatarColor = 42; NotificationProfileManualOverride notificationProfileManualOverride = 44; } message StoryDistributionListRecord { bytes identifier = 1; string name = 2; repeated string recipientServiceIds = 3; uint64 deletedAtTimestamp = 4; bool allowsReplies = 5; bool isBlockList = 6; repeated bytes recipientServiceIdsBinary = 7; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } message StickerPackRecord { bytes packId = 1; // 16 bytes bytes packKey = 2; // 32 bytes, used to derive the AES-256 key // aesKey = HKDF( // input = packKey, // salt = 32 zero bytes, // info = "Sticker Pack" // ) uint32 position = 3; // When displayed sticker packs should be first sorted // in descending order by zero-based `position` and // then by ascending `packId` (lexicographically, // packId can be treated as a hex string). // When installing a sticker pack the client should find // the maximum `position` among currently known stickers // and use `max_position + 1` as the value for the new // `position`. uint64 deletedAtTimestamp = 4; // Timestamp in milliseconds. When present and // non-zero - `packKey` and `position` should // be unset } message CallLinkRecord { bytes rootKey = 1; // 16 bytes bytes adminPasskey = 2; // Non-empty when the current user is an admin uint64 deletedAtTimestampMs = 3; // When present and non-zero, `adminPasskey` // should be cleared } message Recipient { message Contact { string serviceId = 1; string e164 = 2; bytes serviceIdBinary = 3; // service ID binary (i.e. 16 byte UUID for ACI, 1 byte prefix + 16 byte UUID for PNI) } oneof identifier { Contact contact = 1; bytes legacyGroupId = 2; bytes groupMasterKey = 3; } } message ChatFolderRecord { // Represents the default "All chats" folder record vs all other custom folders enum FolderType { UNKNOWN = 0; ALL = 1; CUSTOM = 2; } bytes id = 1; string name = 2; uint32 position = 3; // Position order of folder, low-to-high from start-to-end bool showOnlyUnread = 4; bool showMutedChats = 5; bool includeAllIndividualChats = 6; // Folder includes all 1:1 chats, unless excluded bool includeAllGroupChats = 7; // Folder includes all group chats, unless excluded FolderType folderType = 8; repeated Recipient includedRecipients = 9; repeated Recipient excludedRecipients = 10; uint64 deletedAtTimestampMs = 11; // When non-zero, `position` should be set to -1 and `includedRecipients` should be empty } message NotificationProfile { enum DayOfWeek { UNKNOWN = 0; // Interpret as "Monday" MONDAY = 1; TUESDAY = 2; WEDNESDAY = 3; THURSDAY = 4; FRIDAY = 5; SATURDAY = 6; SUNDAY = 7; } bytes id = 1; string name = 2; optional string emoji = 3; fixed32 color = 4; // 0xAARRGGBB uint64 createdAtMs = 5; bool allowAllCalls = 6; bool allowAllMentions = 7; repeated Recipient allowedMembers = 8; bool scheduleEnabled = 9; uint32 scheduleStartTime = 10; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) uint32 scheduleEndTime = 11; // 24-hour clock int, 0000-2359 (e.g., 15, 900, 1130, 2345) repeated DayOfWeek scheduleDaysEnabled = 12; uint64 deletedAtTimestampMs = 13; }