2026-09-04 22:59:22 +03:00
/ *
* Copyright 2020 - 2021 Signal Messenger , LLC
* SPDX - License - Identifier : AGPL - 3.0 - only
2024-01-14 20:36:15 +02:00
* /
syntax = "proto3" ;
package signalservice ;
option java_package = "org.whispersystems.signalservice.internal.storage.protos" ;
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 ReadOperation {
repeated bytes readKey = 1 ;
}
message WriteOperation {
StorageManifest manifest = 1 ;
repeated StorageItem insertItem = 2 ;
repeated bytes deleteKey = 3 ;
bool clearAll = 4 ;
}
message ManifestRecord {
message Identifier {
enum Type {
UNKNOWN = 0 ;
CONTACT = 1 ;
GROUPV1 = 2 ;
GROUPV2 = 3 ;
ACCOUNT = 4 ;
STORY_DISTRIBUTION_LIST = 5 ;
2026-09-04 22:59:22 +03:00
STICKER_PACK = 6 ;
2024-10-02 21:24:47 +03:00
CALL_LINK = 7 ;
2025-04-15 15:22:31 +03:00
CHAT_FOLDER = 8 ;
2025-06-30 13:22:34 +03:00
NOTIFICATION_PROFILE = 9 ;
2024-01-14 20:36:15 +02:00
}
bytes raw = 1 ;
Type type = 2 ;
}
uint64 version = 1 ;
uint32 sourceDevice = 3 ;
repeated Identifier identifiers = 2 ;
2024-12-02 13:14:44 +02:00
bytes recordIkm = 4 ;
// Next ID: 5
2024-01-14 20:36:15 +02:00
}
message StorageRecord {
oneof record {
ContactRecord contact = 1 ;
GroupV1Record groupV1 = 2 ;
GroupV2Record groupV2 = 3 ;
AccountRecord account = 4 ;
StoryDistributionListRecord storyDistributionList = 5 ;
2026-09-04 22:59:22 +03:00
StickerPackRecord stickerPack = 6 ;
2024-10-02 21:24:47 +03:00
CallLinkRecord callLink = 7 ;
2025-04-15 15:22:31 +03:00
ChatFolderRecord chatFolder = 8 ;
2025-06-30 13:22:34 +03:00
NotificationProfile notificationProfile = 9 ;
2024-01-14 20:36:15 +02:00
}
}
2025-04-15 15:22:31 +03:00
// 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 ;
}
2024-01-14 20:36:15 +02:00
message ContactRecord {
enum IdentityState {
DEFAULT = 0 ;
VERIFIED = 1 ;
UNVERIFIED = 2 ;
}
2024-06-14 15:43:59 +03:00
message Name {
string given = 1 ;
string family = 2 ;
}
2024-01-14 20:36:15 +02:00
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 ;
2024-03-08 23:26:16 +02:00
bool pniSignatureVerified = 21 ;
2024-06-14 15:43:59 +03:00
Name nickname = 22 ;
string note = 23 ;
2025-04-15 15:22:31 +03:00
optional AvatarColor avatarColor = 24 ;
2026-02-09 14:13:18 +02:00
bytes aciBinary = 25 ; // 16-byte UUID
bytes pniBinary = 26 ; // 16-byte UUID
2026-09-04 22:59:22 +03:00
uint64 blockedAtTimestamp = 27 ; // 0 means the blocked time is unknown
OptionalBool notifyForCallsIfMuted = 28 ; // If unset, use the default settings
OptionalBool showUnreadReminders = 29 ; // If unset, use the default settings
// Next ID: 30
2024-01-14 20:36:15 +02:00
}
message GroupV1Record {
bytes id = 1 ;
bool blocked = 2 ;
bool whitelisted = 3 ;
bool archived = 4 ;
bool markedUnread = 5 ;
uint64 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 ;
2026-09-04 22:59:22 +03:00
bool dontNotifyForMentionsIfMuted = 7 ; // will be deprecated in favor of [notifyForMentionsIfMuted]
2024-01-14 20:36:15 +02:00
bool hideStory = 8 ;
reserved /* storySendEnabled */ 9 ;
StorySendMode storySendMode = 10 ;
2025-04-15 15:22:31 +03:00
optional AvatarColor avatarColor = 11 ;
2026-05-08 16:57:56 +03:00
bytes verifiedNameHash = 12 ; // SHA-256 of UTF-8 encoded decrypted group title that was last verified
2026-09-04 22:59:22 +03:00
uint64 blockedAtTimestamp = 13 ; // 0 means the blocked time is unknown
OptionalBool notifyForCallsIfMuted = 14 ; // If unset, use the default settings
OptionalBool notifyForMentionsIfMuted = 15 ; // If unset, use the default settings. If [dontNotifyForMentionsIfMuted] is true, this should be initialized to false.
OptionalBool notifyForRepliesIfMuted = 16 ; // If unset, use the default settings
OptionalBool showUnreadReminders = 17 ; // If unset, use the default settings
2024-01-14 20:36:15 +02:00
}
message Payments {
bool enabled = 1 ;
bytes entropy = 2 ;
}
message AccountRecord {
2026-09-04 22:59:22 +03:00
enum UnreadBadgeType {
UNKNOWN_BADGE_TYPE = 0 ; // Interpret as "Unread messages"
UNREAD_MESSAGES = 1 ;
UNREAD_CHATS = 2 ;
}
2024-01-14 20:36:15 +02:00
enum PhoneNumberSharingMode {
UNKNOWN = 0 ;
EVERYBODY = 1 ;
NOBODY = 2 ;
}
message PinnedConversation {
message Contact {
2026-02-09 14:13:18 +02:00
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)
2024-01-14 20:36:15 +02:00
}
2026-06-05 00:07:51 +03:00
message ReleaseNotes { }
2024-01-14 20:36:15 +02:00
oneof identifier {
2026-06-05 00:07:51 +03:00
Contact contact = 1 ;
bytes legacyGroupId = 3 ;
bytes groupMasterKey = 4 ;
ReleaseNotes releaseNotes = 5 ;
2024-01-14 20:36:15 +02:00
}
}
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 ;
}
2025-01-14 14:13:46 +02:00
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 ;
}
}
2025-06-30 13:22:34 +03:00
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 /* proxiedLinkPreviews */ 9 ;
bool noteToSelfMarkedUnread = 10 ;
bool linkPreviews = 11 ;
PhoneNumberSharingMode phoneNumberSharingMode = 12 ;
bool unlistedPhoneNumber = 13 ;
repeated PinnedConversation pinnedConversations = 14 ;
bool preferContactAvatars = 15 ;
Payments payments = 16 ;
uint32 universalExpireTimer = 17 ;
bool primarySendsSms = 18 ;
reserved /* e164 */ 19 ;
repeated string preferredReactionEmoji = 20 ;
bytes subscriberId = 21 ;
string subscriberCurrencyCode = 22 ;
bool displayBadgesOnProfile = 23 ;
bool subscriptionManuallyCancelled = 24 ;
bool keepMutedChatsArchived = 25 ;
bool hasSetMyStoriesPrivacy = 26 ;
bool hasViewedOnboardingStory = 27 ;
reserved /* storiesDisabled */ 28 ;
bool storiesDisabled = 29 ;
OptionalBool storyViewReceiptsEnabled = 30 ;
reserved /* hasReadOnboardingStory */ 31 ;
bool hasSeenGroupStoryEducationSheet = 32 ;
string username = 33 ;
bool hasCompletedUsernameOnboarding = 34 ;
UsernameLink usernameLink = 35 ;
reserved /* backupsSubscriberId */ 36 ;
reserved /* backupsSubscriberCurrencyCode */ 37 ;
reserved /* backupsSubscriptionManuallyCancelled */ 38 ;
2026-06-05 00:07:51 +03:00
reserved /* hasBackup */ 39 ;
2025-06-30 13:22:34 +03:00
optional uint64 backupTier = 40 ; // See zkgroup for integer particular values. Unset if backups are not enabled.
IAPSubscriberData backupSubscriberData = 41 ;
optional AvatarColor avatarColor = 42 ;
2026-09-04 22:59:22 +03:00
reserved /* backupTierHistory */ 43 ;
2025-06-30 13:22:34 +03:00
NotificationProfileManualOverride notificationProfileManualOverride = 44 ;
2026-02-09 14:13:18 +02:00
bool notificationProfileSyncDisabled = 45 ;
bool automaticKeyVerificationDisabled = 46 ;
2026-04-13 16:32:10 +03:00
bool hasSeenAdminDeleteEducationDialog = 47 ;
2026-06-05 00:07:51 +03:00
optional bool releaseNotesChatArchived = 48 ;
optional uint64 releaseNotesChatMutedUntilTimestamp = 49 ;
optional bool releaseNotesChatBlocked = 50 ;
optional bool releaseNotesChatMarkedUnread = 51 ;
2026-09-04 22:59:22 +03:00
optional uint64 releaseNotesChatBlockedAt = 52 ; // only set if known (>0)
UnreadBadgeType unreadBadgeType = 53 ; // Only used in desktop/ios
OptionalBool includeMutedChatsInBadge = 54 ; // Only used in desktop/ios. If unset, consider this off. Only used in desktop/ios
OptionalBool reactionNotifications = 55 ; // If unset, consider this on
OptionalBool notifyForCallsIfMuted = 56 ; // If unset, consider this off
OptionalBool notifyForMentionsIfMuted = 57 ; // If unset, consider this on
OptionalBool notifyForRepliesIfMuted = 58 ; // If unset, consider this on
OptionalBool showUnreadReminders = 59 ; // If unset, consider this on
OptionalBool notifyWhenContactJoins = 60 ; // If unset, consider this off
2024-01-14 20:36:15 +02:00
}
message StoryDistributionListRecord {
2026-02-09 14:13:18 +02:00
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)
2024-01-14 20:36:15 +02:00
}
2024-10-02 21:24:47 +03:00
2026-09-04 22:59:22 +03:00
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 ascending 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
}
2024-10-02 21:24:47 +03:00
message CallLinkRecord {
bytes rootKey = 1 ;
bytes adminPasskey = 2 ;
uint64 deletedAtTimestampMs = 3 ;
2026-04-13 16:32:10 +03:00
reserved 4 ; // was epoch field, never used
2024-10-02 21:24:47 +03:00
}
2025-04-15 15:22:31 +03:00
2025-06-30 13:22:34 +03:00
message Recipient {
message Contact {
2026-02-09 14:13:18 +02:00
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)
2025-06-30 13:22:34 +03:00
}
2025-04-15 15:22:31 +03:00
2025-06-30 13:22:34 +03:00
oneof identifier {
Contact contact = 1 ;
bytes legacyGroupId = 2 ;
bytes groupMasterKey = 3 ;
2025-04-15 15:22:31 +03:00
}
2025-06-30 13:22:34 +03:00
}
2025-04-15 15:22:31 +03:00
2025-06-30 13:22:34 +03:00
message ChatFolderRecord {
2025-04-15 15:22:31 +03:00
// Represents the default "All chats" folder record vs all other custom folders
enum FolderType {
UNKNOWN = 0 ;
ALL = 1 ;
CUSTOM = 2 ;
}
bytes identifier = 1 ;
string name = 2 ;
uint32 position = 3 ;
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
}
2025-06-30 13:22:34 +03:00
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 ;
}