syntax = "proto3"; option java_multiple_files = true; package org.signal.chat.account; import "google/protobuf/empty.proto"; import "org/signal/chat/common.proto"; import "org/signal/chat/errors.proto"; import "org/signal/chat/messages.proto"; import "org/signal/chat/require.proto"; import "org/signal/chat/tag.proto"; // Provides methods for working with Signal accounts. service Accounts { option (require.auth) = AUTH_ONLY_AUTHENTICATED; // Returns basic identifiers for the authenticated account. rpc GetAccountIdentity(GetAccountIdentityRequest) returns (GetAccountIdentityResponse) {} // Returns entitlements for the authenticated account. rpc GetEntitlements(GetEntitlementsRequest) returns (GetEntitlementsResponse) {} // Deletes the authenticated account, purging all associated data in the // process. rpc DeleteAccount(DeleteAccountRequest) returns (DeleteAccountResponse) {} // Sets the registration lock secret for the authenticated account. To remove // a registration lock, please use `ClearRegistrationLock`. rpc SetRegistrationLock(SetRegistrationLockRequest) returns (SetRegistrationLockResponse) {} // Removes any registration lock credentials from the authenticated account. rpc ClearRegistrationLock(ClearRegistrationLockRequest) returns (ClearRegistrationLockResponse) {} // Attempts to reserve one of multiple given username hashes. Reserved // usernames may be claimed later via `ConfirmUsernameHash`. rpc ReserveUsernameHash(ReserveUsernameHashRequest) returns (ReserveUsernameHashResponse) {} // Sets the username hash/encrypted username to a previously-reserved value // (see `ReserveUsernameHash`). rpc ConfirmUsernameHash(ConfirmUsernameHashRequest) returns (ConfirmUsernameHashResponse) {} // Clears the current username hash, ciphertext, and link for the // authenticated user. rpc DeleteUsernameHash(DeleteUsernameHashRequest) returns (DeleteUsernameHashResponse) {} // Associates the given username ciphertext with the account, replacing any // previously stored ciphertext. A new link handle will optionally be created, // and the link handle to use will be returned in any event. rpc SetUsernameLink(SetUsernameLinkRequest) returns (SetUsernameLinkResponse) {} // Clears any username link associated with the authenticated account. rpc DeleteUsernameLink(DeleteUsernameLinkRequest) returns (DeleteUsernameLinkResponse) {} // Configures "unidentified access" keys and preferences for the authenticated // account. Other users permitted to interact with this account anonymously // may take actions like fetching pre-keys and profiles for this account or // sending sealed-sender messages without providing identifying credentials. rpc ConfigureUnidentifiedAccess(ConfigureUnidentifiedAccessRequest) returns (ConfigureUnidentifiedAccessResponse) {} // Sets whether the authenticated account may be discovered by phone number // via the Contact Discovery Service (CDS). rpc SetDiscoverableByPhoneNumber(SetDiscoverableByPhoneNumberRequest) returns (SetDiscoverableByPhoneNumberResponse) {} // Sets the registration recovery password for the authenticated account. rpc SetRegistrationRecoveryPassword(SetRegistrationRecoveryPasswordRequest) returns (SetRegistrationRecoveryPasswordResponse) {} // Store a public key used to issue and verify zero-knowledge (anonymous) credentials for the account. rpc SetZkCredentialKey(SetZkCredentialKeyRequest) returns (SetZkCredentialKeyResponse) {} // Changes the phone number associated with the authenticated account. rpc ChangeNumber(ChangeNumberRequest) returns (ChangeNumberResponse) {} // Produces a report of non-ephemeral account data stored by the service rpc GetAccountDataReport(GetAccountDataReportRequest) returns (GetAccountDataReportResponse) {} // Gets the capabilities for the authenticated account. rpc GetCapabilities(GetCapabilitiesRequest) returns (GetCapabilitiesResponse) {} // Generates and stores a pending TOTP key for the authenticated account. // To "activate" the key, callers must call the `ConfirmTotpKey` endpoint. rpc GenerateTotpKey(GenerateTotpKeyRequest) returns (GenerateTotpKeyResponse) {} // Confirms that the caller has stored and can derive one-time passwords from // a pending TOTP key generated via `GenerateTotpKey` and stores/activates the // key for the caller's account rpc ConfirmTotpKey(ConfirmTotpKeyRequest) returns (ConfirmTotpKeyResponse) {} // Returns a list of confirmed TOTP keys for the authenticated account rpc ListTotpKeys(ListTotpKeysRequest) returns (ListTotpKeysResponse) {} // Updates encrypted, user-supplied metadata (e.g. a human-readable name and // creation timestamp) for an existing, confirmed TOTP key rpc SetTotpKeyMetadata(SetTotpKeyMetadataRequest) returns (SetTotpKeyMetadataResponse) {} // Removes a TOTP from the authenticated account rpc RemoveTotpKey(RemoveTotpKeyRequest) returns (RemoveTotpKeyResponse) {} } // Provides methods for looking up Signal accounts. Callers must not provide // identifying credentials when calling methods in this service. service AccountsAnonymous { option (require.auth) = AUTH_ONLY_ANONYMOUS; // Checks whether an account with the given service identifier exists. rpc CheckAccountExistence(CheckAccountExistenceRequest) returns (CheckAccountExistenceResponse) {} // Finds the service identifier of the account associated with the given // username hash. rpc LookupUsernameHash(LookupUsernameHashRequest) returns (LookupUsernameHashResponse) {} // Finds the encrypted username identified by a given username link handle. rpc LookupUsernameLink(LookupUsernameLinkRequest) returns (LookupUsernameLinkResponse) {} // Gets the publicly-visible capabilities enabled on the account identified by // the provided ACI. rpc GetCapabilities(GetCapabilitiesAnonymousRequest) returns (GetCapabilitiesAnonymousResponse) {} } message GetAccountIdentityRequest { } message GetAccountIdentityResponse { // The identifiers for the authenticated account. common.AccountIdentifiers account_identifiers = 1; } message GetEntitlementsRequest { } message GetEntitlementsResponse { message BadgeEntitlement { // The id of the badge the account is entitled. Metadata to display for // badges may be obtained by cross-referencing badge ids with // RemoteConfiguration.GetBadges. string badge_id = 1; // When the badge expires, in number of seconds since epoch uint64 expiration_epoch_seconds = 2; // Whether the badge is currently configured to be visible bool visible = 3; } message BackupEntitlement { // The backup level of the account uint64 level = 1; // When the backup entitlement expires, in number of seconds since epoch uint64 expiration_epoch_seconds = 2; } // Active badges added via Donations.redeemReceipt repeated BadgeEntitlement badges = 1; // If present, the backup level set via Backups.redeemReceipt BackupEntitlement backup = 2; } message DeleteAccountRequest { } message DeleteAccountResponse { } message SetRegistrationLockRequest { // The new registration lock secret for the authenticated account. bytes registration_lock = 1 [(require.exactlySize) = 32]; } message SetRegistrationLockResponse { } message ClearRegistrationLockRequest { } message ClearRegistrationLockResponse { } message ReserveUsernameHashRequest { // A prioritized list of username hashes to attempt to reserve. repeated bytes username_hashes = 1 [(require.size) = {min: 1, max: 20}, (require.each) = {exactlySize: 32}]; } message UsernameNotAvailable {} message ReserveUsernameHashResponse { oneof response { // The first username hash that was available (and actually reserved). bytes username_hash = 1; // Indicates that, of all of the candidate hashes provided, none were // available. Callers may generate a new set of hashes and and retry. UsernameNotAvailable username_not_available = 2 [(tag.reason) = "username_not_available"]; } } message ConfirmUsernameHashRequest { // The username hash to claim for the authenticated account. bytes username_hash = 1 [(require.exactlySize) = 32]; // A zero-knowledge proof that the given username hash was generated by the // Signal username algorithm. bytes zk_proof = 2 [(require.nonEmpty) = true]; // The ciphertext of the chosen username for use in public-facing contexts // (e.g. links and QR codes). bytes username_ciphertext = 3 [(require.size) = {min: 1, max: 128}]; } message ConfirmUsernameHashResponse { message ConfirmedUsernameHash { reserved 1; // username_hash // The server-generated username link handle for the newly-confirmed username. bytes username_link_handle = 2; } oneof response { // The details of the successfully confirmed username. ConfirmedUsernameHash confirmed_username_hash = 1; // The provided hash was not reserved for the account. errors.FailedPrecondition reservation_not_found = 2 [(tag.reason) = "reservation_not_found"]; // The reservation has lapsed and the requested username has been claimed by // another caller. UsernameNotAvailable username_not_available = 3 [(tag.reason) = "username_not_available"]; } } message DeleteUsernameHashRequest { } message DeleteUsernameHashResponse { } message SetUsernameLinkRequest { // The username ciphertext for which to generate a new link handle. bytes username_ciphertext = 1 [(require.size) = {min: 1, max: 128}]; // If true and the account already had an encrypted username stored, the // existing link handle will be reused. Otherwise a new link handle will be // created. bool keep_link_handle = 2; } message SetUsernameLinkResponse { oneof response { // A new link handle for the given username ciphertext. bytes username_link_handle = 1; // The authenticated account did not have a username set. errors.FailedPrecondition no_username_set = 2 [(tag.reason) = "no_username_set"]; } } message DeleteUsernameLinkRequest { } message DeleteUsernameLinkResponse { } message ConfigureUnidentifiedAccessRequest { oneof configuration { // The key that other users must provide to interact with this account // anonymously (i.e. to retrieve keys or profiles or to send messages) unless // unrestricted unidentified access is permitted. Must be present if // unrestricted unidentified access is not allowed. bytes unidentified_access_key = 1 [(require.exactlySize) = 16]; // If set, any user may interact with this account anonymously without // providing an unidentified access key. Otherwise, users must provide the // given unidentified access key to interact with this account anonymously. // Setting unrestricted unidentified access will clear any existing // unidentified_access_key google.protobuf.Empty allow_unrestricted_unidentified_access = 2; } } message ConfigureUnidentifiedAccessResponse { } message SetDiscoverableByPhoneNumberRequest { // If true, the authenticated account may be discovered by phone number via // the Contact Discovery Service (CDS). Otherwise, other users must discover // this account by other means (i.e. by username). bool discoverable_by_phone_number = 1; } message SetDiscoverableByPhoneNumberResponse { } message SetRegistrationRecoveryPasswordRequest { // The new registration recovery password for the authenticated account. bytes registration_recovery_password = 1 [(require.exactlySize) = 32]; } message SetRegistrationRecoveryPasswordResponse { } message CheckAccountExistenceRequest { // The service identifier of an account that may or may not exist. common.ServiceIdentifier service_identifier = 1; } message CheckAccountExistenceResponse { // True if an account exists with the given service identifier or false if no // account was found. bool account_exists = 1; } message LookupUsernameHashRequest { // A 32-byte username hash for which to find an account. bytes username_hash = 1 [(require.exactlySize) = 32]; } message LookupUsernameHashResponse { oneof response { // The service identifier associated with the provided username hash. common.ServiceIdentifier service_identifier = 1; // No account was found for the provided username hash. errors.NotFound not_found = 2 [(tag.reason) = "not_found"]; } } message LookupUsernameLinkRequest { // The link handle for which to find an encrypted username. Link handles are // 16-byte representations of UUIDs. bytes username_link_handle = 1 [(require.exactlySize) = 16]; } message LookupUsernameLinkResponse { oneof response { // The ciphertext of the username identified by the provided link handle. bytes username_ciphertext = 1; // No username was found for the provided link handle. errors.NotFound not_found = 2 [(tag.reason) = "not_found"]; } } message SetZkCredentialKeyRequest { // A serialized libsignal ZkCredentialPublicKey bytes public_key = 1 [(require.exactlySize) = 33]; } message SetZkCredentialKeyResponse { // A random, non-zero, value that must be included in credential requests using the key. // // This value allows the server to ratchet the resulting binding identity, // as reverting to the previous key will result in a new rotation ID. uint64 rotation_id = 1; } message ChangeNumberRequest { // A means of authenticating the change-number request for the new phone // number. Exactly one must be provided. oneof verification { // A verified registration session ID (as returned by the registration // service) for the new phone number. bytes session_id = 1 [(require.nonEmpty) = true]; // A registration recovery password for the new phone number. bytes recovery_password = 2 [(require.exactlySize) = 32]; } // The new phone number for the authenticated account. string number = 3 [(require.e164) = true]; // The registration lock secret for the new phone number, if the account // associated with the new phone number has a registration lock configured. bytes registration_lock = 4 [(require.exactlySize) = 0, (require.exactlySize) = 32]; // The new public identity key to use for the phone-number identity (PNI) // associated with the new phone number. bytes pni_identity_key = 5 [(require.nonEmpty) = true]; // Synchronization messages to send to companion devices to supply the private // keys associated with the new identity key and their new pre-keys. Exactly // one message must be supplied for each device other than the sending // (primary) device. May be omitted if no companion devices are linked to the // account. messages.IndividualRecipientMessageBundle device_messages = 6; // A new signed EC pre-key for each device on the account, including the // sending device, keyed by device ID. Each must be accompanied by a valid // signature from the identity key in this request. map device_pni_signed_pre_keys = 7; // A new signed post-quantum last-resort pre-key for each device on the // account, including the sending device, keyed by device ID. Each must be // accompanied by a valid signature from the identity key in this request. map device_pni_pq_last_resort_pre_keys = 8; // The new phone-number-identity registration ID for each device on the // account, including the sending device, keyed by device ID. map pni_registration_ids = 9; } message ChangeNumberResponse { oneof response { // The identifiers of the account after the successful // number change. common.AccountIdentifiers account_identifiers = 1; // Mismatched number of devices or device ids in 'devices to notify' list messages.MismatchedDevices mismatched_devices = 2 [(tag.reason) = "mismatched_devices"]; // The account associated with the new phone number has a registration lock, // and the provided registration lock secret was missing or incorrect. RegistrationLockFailure registration_lock_failure = 3 [(tag.reason) = "registration_lock_failure"]; // Mismatched registration ids in 'devices to notify' list StaleDevices stale_devices = 4 [(tag.reason) = "stale_devices"]; // One or more device messages was too large errors.FailedPrecondition message_too_large = 5 [(tag.reason) = "message_too_large"]; // The registration session is unverified errors.FailedPrecondition unverified_registration_session = 6 [(tag.reason) = "unverified_registration_session"]; // The number does not match the registration session, or the registration session is invalid errors.FailedPrecondition invalid_registration_session = 7 [(tag.reason) = "invalid_registration_session"]; errors.FailedPrecondition recovery_password_verification_failed = 8 [(tag.reason) = "recovery_password_verification_failed"]; } } // Information about the current Registration lock and SVR credentials. With a correct PIN, the credentials can // be used to recover the secret used to derive the registration lock password. message RegistrationLockFailure { // Time remaining in milliseconds before the existing registration lock expires uint64 time_remaining_millis = 1; // Credentials that can be used with SVR2 ExternalServiceCredentials svr2_credentials = 2; } // A username/password pair for authenticating with an external service. message ExternalServiceCredentials { // A username that can be presented to authenticate with the external service. string username = 1; // A password that can be presented to authenticate with the external service. string password = 2; } // A list of devices that are linked to the account but presented a stale // registration ID (indicating the device has likely been replaced by another // device). message StaleDevices { // The IDs of devices that are no longer active. repeated uint32 stale_devices = 1 [(require.each) = {range: {max: 0x7f}}]; } message GetAccountDataReportRequest { } message GetAccountDataReportResponse { // The JSON representation of the data report string json = 3; // A plaintext representation of the data report string text = 4; } message GetCapabilitiesRequest { } message Capabilities { // A list of capabilities enabled on the account. repeated common.DeviceCapability capabilities = 1; } message GetCapabilitiesResponse { // A list of capabilities enabled on the account. Capabilities capabilities = 1; } message GetCapabilitiesAnonymousRequest { // The ACI of the account for which to get capabilities. common.ServiceIdentifier account_identifier = 1 [(require.present) = true, (require.identityType) = IDENTITY_TYPE_ACI]; oneof authentication { // The unidentified access key for the targeted account. bytes unidentified_access_key = 2 [(require.exactlySize) = 16]; // A group send endorsement token for the targeted account. bytes group_send_token = 3 [(require.nonEmpty) = true]; } } message GetCapabilitiesAnonymousResponse { oneof response { // A list of capabilities enabled on the account. Capabilities capabilities = 1; errors.NotFound not_found = 2 [(tag.reason) = "not_found"]; errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"]; } } message TotpParameters { // The HMAC algorithm (e.g. "HmacSHA256") used by the TOTP generator string algorithm = 1; // The length of one-time passwords (in decimal digits) produced and expected // by the TOTP generator uint32 password_length = 2; // The time step (in seconds) used by the TOTP generator uint32 time_step_seconds = 3; } message GenerateTotpKeyRequest { } message GenerateTotpKeyResponse { message KeyGenerated { // The raw TOTP key bytes key = 1; // The TOTP parameters associated with the generated key TotpParameters totp_parameters = 2; } oneof response { // A new, pending TOTP key has been generated and added to the authenticated // account KeyGenerated key_generated = 1; // The authenticated account already has too many TOTP keys, and the caller // must remove one before adding more errors.FailedPrecondition too_many_totp_keys = 2 [(tag.reason) = "too_many_totp_keys"]; } } message ConfirmTotpKeyRequest { // A one-time password derived from the current pending TOTP key uint32 one_time_password = 1; // The ciphertext of user-provided metadata (presumably including a // human-readable name and creation timestamp) to be attached to the // newly-confirmed key bytes metadata_ciphertext = 2 [(require.exactlySize) = 160]; } message ConfirmTotpKeyResponse { message KeyConfirmed { // The account-specific identifier for the newly-confirmed TOTP key uint32 key_id = 1; } oneof response { // The provided one-time password was accepted and the pending TOTP key was // stored with the provided name ciphertext KeyConfirmed key_confirmed = 1; // The provided one-time password was not valid for any reason (including // incorrect passwords, misaligned clocks, or missing account records) errors.FailedPrecondition one_time_password_not_verified = 2 [(tag.reason) = "one_time_password_not_verified"]; } } message ListTotpKeysRequest {} message ListTotpKeysResponse { message TotpKeyMetadata { // The user-provided ciphertext for metadata associated with this TOTP key bytes metadata_ciphertext = 1; // The TOTP parameters associated with this key TotpParameters totp_parameters = 2; } map keys = 1; } message SetTotpKeyMetadataRequest { // The account-specific identifier of the TOTP key to modify uint32 key_id = 1; // The ciphertext of the new user-provided metadata to be attached to the // identified key bytes metadata_ciphertext = 2 [(require.exactlySize) = 160]; } message SetTotpKeyMetadataResponse { message MetadataUpdated { } oneof response { // New metadata was stored for the identified TOTP key MetadataUpdated metadata_updated = 1; // No TOTP was found with the given ID errors.NotFound key_not_found = 2 [(tag.reason) = "key_not_found"]; } } message RemoveTotpKeyRequest { // The account-specific identifier of the TOTP key to remove uint32 key_id = 1; } message RemoveTotpKeyResponse { }