syntax = "proto3";

option java_multiple_files = true;

package org.signal.registration.rpc;

service RegistrationService {
  /**
   * Create a new registration session for a given destination phone number.
   */
  rpc CreateSession (CreateRegistrationSessionRequest) returns (CreateRegistrationSessionResponse) {}

  /**
   * Retrieves session metadata for a given session.
   */
  rpc GetSessionMetadata (GetRegistrationSessionMetadataRequest) returns (GetRegistrationSessionMetadataResponse) {}

  /**
   * Sends a verification code to a destination phone number within the context
   * of a previously-created registration session.
   */
  rpc SendVerificationCode (SendVerificationCodeRequest) returns (SendVerificationCodeResponse) {}

  /**
   * Checks a client-provided verification code for a given registration
   * session.
   */
  rpc CheckVerificationCode (CheckVerificationCodeRequest) returns (CheckVerificationCodeResponse) {}
}

message CreateRegistrationSessionRequest {
  /**
   * The phone number for which to create a new registration session.
   */
  uint64 e164 = 1;

  /**
   * Indicates whether an account already exists with the given e164 (i.e. this
   * session represents a "re-registration" attempt).
   */
  bool account_exists_with_e164 = 2;
}

message CreateRegistrationSessionResponse {
  oneof response {
    /**
     * Metadata for the newly-created session.
     */
    RegistrationSessionMetadata session_metadata = 1;

    /**
     * A response explaining why a session could not be created as requested.
     */
    CreateRegistrationSessionError error = 2;
  }
}

message RegistrationSessionMetadata {
  /**
   * An opaque sequence of bytes that uniquely identifies the registration
   * session associated with this registration attempt.
   */
  bytes session_id = 1;

  /**
   * Indicates whether a valid verification code has been submitted in the scope
   * of this session.
   */
  bool verified = 2;

  /**
   * The phone number associated with this registration session.
   */
  uint64 e164 = 3;

  /**
   * Indicates whether the caller may request delivery of a verification code
   * via SMS now or at some time in the future. If true, the time a caller must
   * wait before requesting a verification code via SMS is given in the
   * `next_sms_seconds` field.
   */
  bool may_request_sms = 4;

  /**
   * The duration, in seconds, after which a caller will next be allowed to
   * request delivery of a verification code via SMS if `may_request_sms` is
   * true. If zero, a caller may request a verification code via SMS
   * immediately. If `may_request_sms` is false, this field has no meaning.
   */
  uint64 next_sms_seconds = 5;

  /**
   * Indicates whether the caller may request delivery of a verification code
   * via a phone call now or at some time in the future. If true, the time a
   * caller must wait before requesting a verification code via SMS is given in
   * the `next_voice_call_seconds` field. If false, simply waiting will not
   * allow the caller to request a phone call and the caller may need to
   * perform some other action (like attempting verification code delivery via
   * SMS) before requesting a voice call.
   */
  bool may_request_voice_call = 6;

  /**
   * The duration, in seconds, after which a caller will next be allowed to
   * request delivery of a verification code via a phone call if
   * `may_request_voice_call` is true. If zero, a caller may request a
   * verification code via a phone call immediately. If `may_request_voice_call`
   * is false, this field has no meaning.
   */
  uint64 next_voice_call_seconds = 7;

  /**
   * Indicates whether the caller may submit new verification codes now or at
   * some time in the future. If true, the time a caller must wait before
   * submitting a verification code is given in the `next_code_check_seconds`
   * field. If false, simply waiting will not allow the caller to submit a
   * verification code and the caller may need to perform some other action
   * (like requesting delivery of a verification code) before checking a
   * verification code.
   */
  bool may_check_code = 8;

  /**
   * The duration, in seconds, after which a caller will next be allowed to
   * submit a verification code if `may_check_code` is true. If zero, a caller
   * may submit a verification code immediately. If `may_check_code` is false,
   * this field has no meaning.
   */
  uint64 next_code_check_seconds = 9;

  /**
   * The duration, in seconds, after which this session will expire.
   */
  uint64 expiration_seconds = 10;
}

message CreateRegistrationSessionError {
  /**
   * The type of error that prevented a session from being created.
   */
  CreateRegistrationSessionErrorType error_type = 1;

  /**
   * Indicates that this error may succeed if retried without modification after
   * a delay indicated by `retry_after_seconds`. If false, callers should not
   * retry the request without modification.
   */
  bool may_retry = 2;

  /**
   * If this error may be retried,, indicates the duration in seconds from the
   * present after which the request may be retried without modification. This
   * value has no meaning otherwise.
   */
  uint64 retry_after_seconds = 3;
}

enum CreateRegistrationSessionErrorType {
  CREATE_REGISTRATION_SESSION_ERROR_TYPE_UNSPECIFIED = 0;

  /**
   * Indicates that a session could not be created because too many requests to
   * create a session for the given phone number have been received in some
   * window of time. Callers should wait and try again later.
   */
  CREATE_REGISTRATION_SESSION_ERROR_TYPE_RATE_LIMITED = 1;

  /**
   * Indicates that the provided phone number could not be parsed.
   */
  CREATE_REGISTRATION_SESSION_ERROR_TYPE_ILLEGAL_PHONE_NUMBER = 2;
}

message GetRegistrationSessionMetadataRequest {
  /**
   * The ID of the session for which to retrieve metadata.
   */
  bytes session_id = 1;
}

message GetRegistrationSessionMetadataResponse {
  oneof response {
    RegistrationSessionMetadata session_metadata = 1;
    GetRegistrationSessionMetadataError error = 2;
  }
}

message GetRegistrationSessionMetadataError {
  GetRegistrationSessionMetadataErrorType error_type = 1;
}

enum GetRegistrationSessionMetadataErrorType {
  GET_REGISTRATION_SESSION_METADATA_ERROR_TYPE_UNSPECIFIED = 0;

  /**
   * No session was found with the given identifier.
   */
  GET_REGISTRATION_SESSION_METADATA_ERROR_TYPE_NOT_FOUND = 1;
}

message SendVerificationCodeRequest {

  reserved 1;

  /**
   * The message transport to use to send a verification code to the destination
   * phone number.
   */
  MessageTransport transport = 2;

  /**
   * A prioritized list of languages accepted by the destination; should be
   * provided in the same format as the value of an HTTP Accept-Language header.
   */
  string accept_language = 3;

  /**
   * The type of client requesting a verification code.
   */
  ClientType client_type = 4;

  /**
   * The ID of a session within which to send (or re-send) a verification code.
   */
  bytes session_id = 5;

  /**
   * If provided, always attempt to use the specified sender to send
   * this message.
   */
  string sender_name = 6;
}

enum MessageTransport {
  MESSAGE_TRANSPORT_UNSPECIFIED = 0;
  MESSAGE_TRANSPORT_SMS = 1;
  MESSAGE_TRANSPORT_VOICE = 2;
}

enum ClientType {
  CLIENT_TYPE_UNSPECIFIED = 0;
  CLIENT_TYPE_IOS = 1;
  CLIENT_TYPE_ANDROID_WITH_FCM = 2;
  CLIENT_TYPE_ANDROID_WITHOUT_FCM = 3;
}

message SendVerificationCodeResponse {
  reserved 1;

  /**
   * Metadata for the named session. May be absent if the session could not be
   * found or has expired.
   */
  RegistrationSessionMetadata session_metadata = 2;

  /**
   * If a code could not be sent, explains the underlying error. Will be absent
   * if a code was sent successfully. Note that both an error and session
   * metadata may be present in the same response because the session metadata
   * may include information helpful for resolving the underlying error (i.e.
   * "next attempt" times).
   */
  SendVerificationCodeError error = 3;
}

message SendVerificationCodeError {
  /**
   * The type of error that prevented a verification code from being sent.
   */
  SendVerificationCodeErrorType error_type = 1;

  /**
   * Indicates that this error may succeed if retried without modification after
   * a delay indicated by `retry_after_seconds`. If false, callers should not
   * retry the request without modification.
   */
  bool may_retry = 2;

  /**
   * If this error may be retried,, indicates the duration in seconds from the
   * present after which the request may be retried without modification. This
   * value has no meaning otherwise.
   */
  uint64 retry_after_seconds = 3;
}

enum SendVerificationCodeErrorType {
  SEND_VERIFICATION_CODE_ERROR_TYPE_UNSPECIFIED = 0;

  /**
   * The sender received and understood the request to send a verification code,
   * but declined to do so (i.e. due to rate limits or suspected fraud).
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_SENDER_REJECTED = 1;

  /**
   * The sender could not process or would not accept some part of a request
   * (e.g. a valid phone number that cannot receive SMS messages).
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_SENDER_ILLEGAL_ARGUMENT = 2;

  /**
   * A verification could could not be sent via the requested channel due to
   * timing/rate restrictions. The response object containing this error should
   * include session metadata that indicates when the next attempt is allowed.
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_RATE_LIMITED = 3;

  /**
   * No session was found with the given ID.
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_SESSION_NOT_FOUND = 4;

  /**
   * A new verification could could not be sent because the session has already
   * been verified.
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_SESSION_ALREADY_VERIFIED = 5;

  /**
   * A verification code could not be sent via the requested transport because
   * the destination phone number (or the sender) does not support the requested
   * transport.
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_TRANSPORT_NOT_ALLOWED = 6;

  /**
   * The sender declined to send the verification code due to suspected fraud
   */
  SEND_VERIFICATION_CODE_ERROR_TYPE_SUSPECTED_FRAUD = 7;

}

message CheckVerificationCodeRequest {
  /**
   * The session ID returned when sending a verification code.
   */
  bytes session_id = 1;

  /**
   * The client-provided verification code.
   */
  string verification_code = 2;
}

message CheckVerificationCodeResponse {
  reserved 1;

  /**
   * Metadata for the named session. May be absent if the session could not be
   * found or has expired.
   */
  RegistrationSessionMetadata session_metadata = 2;

  /**
   * If a code could not be checked, explains the underlying error. Will be
   * absent if no error occurred. Note that both an error and session
   * metadata may be present in the same response because the session metadata
   * may include information helpful for resolving the underlying error (i.e.
   * "next attempt" times).
   */
  CheckVerificationCodeError error = 3;
}

message CheckVerificationCodeError {
  /**
   * The type of error that prevented a verification code from being checked.
   */
  CheckVerificationCodeErrorType error_type = 1;

  /**
   * Indicates that this error may succeed if retried without modification after
   * a delay indicated by `retry_after_seconds`. If false, callers should not
   * retry the request without modification.
   */
  bool may_retry = 2;

  /**
   * If this error may be retried,, indicates the duration in seconds from the
   * present after which the request may be retried without modification. This
   * value has no meaning otherwise.
   */
  uint64 retry_after_seconds = 3;
}

enum CheckVerificationCodeErrorType {
  CHECK_VERIFICATION_CODE_ERROR_TYPE_UNSPECIFIED = 0;

  /**
   * The caller has attempted to submit a verification code even though no
   * verification codes have been sent within the scope of this session. The
   * caller must issue a "send code" request before trying again.
   */
  CHECK_VERIFICATION_CODE_ERROR_TYPE_NO_CODE_SENT = 1;

  /**
   * The caller has made too many guesses within some period of time. Callers
   * should wait for the duration prescribed in the session metadata object
   * elsewhere in the response before trying again.
   */
  CHECK_VERIFICATION_CODE_ERROR_TYPE_RATE_LIMITED = 2;

  /**
   * The session identified in this request could not be found (possibly due to
   * session expiration).
   */
  CHECK_VERIFICATION_CODE_ERROR_TYPE_SESSION_NOT_FOUND = 3;

  /**
   * The session identified in this request is still active, but the most
   * recently-sent code has expired. Callers should request a new code, then
   * try again.
   */
  CHECK_VERIFICATION_CODE_ERROR_TYPE_ATTEMPT_EXPIRED = 4;
}
