// Copyright 2014 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

// Source: https://github.com/signalapp/libsignal-service-java/blob/4684a49b2ed8f32be619e0d0eea423626b6cb2cb/protobuf/SignalService.proto
package signalservice;

option java_package = "org.whispersystems.signalservice.internal.push";
option java_outer_classname = "SignalServiceProtos";

message Envelope {
  enum Type {
    UNKNOWN             = 0;
    CIPHERTEXT          = 1;
    KEY_EXCHANGE        = 2;
    PREKEY_BUNDLE       = 3;
    RECEIPT             = 5;
    UNIDENTIFIED_SENDER = 6;

    // Our parser does not handle reserved in enums: DESKTOP-1569
    // reserved           7;

    PLAINTEXT_CONTENT   = 8;
  }

  optional Type   type            = 1;
  optional string sourceUuid      = 11;
  optional uint32 sourceDevice    = 7;
  optional string destinationUuid = 13;
  // reserved                          3; // formerly optional string relay = 3;
  optional uint64 timestamp       = 5;
  // reserved                          6; // formerly optional bytes legacyMessage = 6;
  optional bytes  content         = 8; // Contains an encrypted Content
  optional string serverGuid      = 9;
  optional uint64 serverTimestamp = 10;
  optional bool ephemeral = 12; // indicates that the message should not be persisted if the recipient is offline
  optional bool urgent = 14 [default=true];  // indicates that the content is considered timely by the sender; defaults to true so senders have to opt-out to say something isn't time critical
  optional string updated_pni = 15;
  optional bool story = 16;  // indicates that the content is a story.
  optional bytes reporting_token = 17;
  // next: 18
}

message Content {
  optional DataMessage         dataMessage                  = 1;
  optional SyncMessage         syncMessage                  = 2;
  optional CallingMessage      callingMessage               = 3;
  optional NullMessage         nullMessage                  = 4;
  optional ReceiptMessage      receiptMessage               = 5;
  optional TypingMessage       typingMessage                = 6;
  optional bytes               senderKeyDistributionMessage = 7;
  optional bytes               decryptionErrorMessage       = 8;
  optional StoryMessage        storyMessage                 = 9;
  optional PniSignatureMessage pniSignatureMessage          = 10;
}

// Everything in CallingMessage must be kept in sync with RingRTC (ringrtc-node).
// Whenever you change this, make sure you change textsecure.d.ts and RingRTC.
message CallingMessage {
  message Offer {
    enum Type {
      OFFER_AUDIO_CALL = 0;
      OFFER_VIDEO_CALL = 1;
    }

    optional uint64 callId = 1;
    // Legacy/deprecated; replaced by 'opaque'
    optional string sdp    = 2;
    optional Type   type   = 3;
    optional bytes  opaque = 4;
  }

  message Answer {
    optional uint64 callId = 1;
    // Legacy/deprecated; replaced by 'opaque'
    optional string sdp    = 2;
    optional bytes  opaque = 3;
  }

  message IceCandidate {
    optional uint64 callId = 1;
    // Legacy/deprecated; remove when old clients are gone.
    optional string mid    = 2;
    // Legacy/deprecated; remove when old clients are gone.
    optional uint32 line   = 3;
    // Legacy/deprecated; replaced by 'opaque'
    optional string sdp    = 4;
    optional bytes  opaque = 5;
  }

  message Busy {
    optional uint64 callId = 1;
  }

  message Hangup {
    enum Type {
      HANGUP_NORMAL          = 0;
      HANGUP_ACCEPTED        = 1;
      HANGUP_DECLINED        = 2;
      HANGUP_BUSY            = 3;
      HANGUP_NEED_PERMISSION = 4;
    }

    optional uint64 callId   = 1;
    optional Type   type     = 2;
    optional uint32 deviceId = 3;
  }

  message Opaque {
    enum Urgency {
      DROPPABLE          = 0;
      HANDLE_IMMEDIATELY = 1;
    }

    optional bytes   data    = 1;
    optional Urgency urgency = 2;
  }

  optional Offer        offer               = 1;
  optional Answer       answer              = 2;
  repeated IceCandidate iceCandidates       = 3;
  optional Hangup       legacyHangup        = 4;
  optional Busy         busy                = 5;
  optional Hangup       hangup              = 7;
  optional bool         supportsMultiRing   = 8;
  optional uint32       destinationDeviceId = 9;
  optional Opaque       opaque              = 10;
}

message DataMessage {
  enum Flags {
    END_SESSION             = 1;
    EXPIRATION_TIMER_UPDATE = 2;
    PROFILE_KEY_UPDATE      = 4;
  }

  message Payment {
    message Amount {
      message MobileCoin {
        optional uint64 picoMob = 1;  // 1,000,000,000,000 picoMob per Mob
      }

      oneof Amount {
        MobileCoin mobileCoin = 1;
      }
    }

    message RequestId {
      optional string uuid = 1;
    }

    message Request {
      optional RequestId requestId = 1;
      optional Amount    amount    = 2;
      optional string    note      = 3;
    }

    message Notification {
      message MobileCoin {
        optional bytes  receipt = 1;
      }

      oneof Transaction {
        MobileCoin mobileCoin = 1;
      }

      // Optional, Refers to the PaymentRequest message, if any.
      optional string    note          = 2;
      optional RequestId requestId     = 1003;
    }

    message Cancellation {
      optional RequestId requestId = 1;
    }

    message Activation {
      enum Type {
        REQUEST = 0;
        ACTIVATED = 1;
      }

      optional Type type = 1;
    }

    oneof Item {
      Notification notification = 1;
      Activation activation = 2;
      Request request  = 1002;
      Cancellation cancellation = 1003;
    }
  }

  message Quote {
    enum Type {
      NORMAL = 0;
      GIFT_BADGE = 1;
    }

    message QuotedAttachment {
      optional string            contentType = 1;
      optional string            fileName    = 2;
      optional AttachmentPointer thumbnail   = 3;
    }

    optional uint64           id          = 1;
    reserved                  /* author */  2; // removed
    optional string           authorUuid  = 5;
    optional string           text        = 3;
    repeated QuotedAttachment attachments = 4;
    repeated BodyRange        bodyRanges  = 6;
    optional Type             type        = 7;
  }

  message Contact {
    message Name {
      optional string givenName   = 1;
      optional string familyName  = 2;
      optional string prefix      = 3;
      optional string suffix      = 4;
      optional string middleName  = 5;
      optional string displayName = 6;
    }

    message Phone {
      enum Type {
        HOME   = 1;
        MOBILE = 2;
        WORK   = 3;
        CUSTOM = 4;
      }

      optional string value = 1;
      optional Type   type  = 2;
      optional string label = 3;
    }

    message Email {
      enum Type {
        HOME   = 1;
        MOBILE = 2;
        WORK   = 3;
        CUSTOM = 4;
      }

      optional string value = 1;
      optional Type   type  = 2;
      optional string label = 3;
    }

    message PostalAddress {
      enum Type {
        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;
    }

    message Avatar {
      optional AttachmentPointer avatar    = 1;
      optional bool              isProfile = 2;
    }

    optional Name              name            = 1;
    repeated Phone             number          = 3;
    repeated Email             email           = 4;
    repeated PostalAddress     address         = 5;
    optional Avatar            avatar          = 6;
    optional string            organization    = 7;
  }

  message Preview {
    optional string            url   = 1;
    optional string            title = 2;
    optional AttachmentPointer image = 3;
    optional string            description = 4;
    optional uint64            date        = 5;
  }

  message Sticker {
    optional bytes             packId    = 1;
    optional bytes             packKey   = 2;
    optional uint32            stickerId = 3;
    optional AttachmentPointer data      = 4;
    optional string            emoji     = 5;
  }

  message Reaction {
    optional string emoji            = 1;
    optional bool   remove           = 2;
    reserved /* targetAuthorE164 */    3; // removed
    optional string targetAuthorUuid = 4;
    optional uint64 targetTimestamp  = 5;
  }

  message Delete {
    optional uint64 targetSentTimestamp = 1;
  }

  message BodyRange {
    optional uint32 start  = 1;
    optional uint32 length = 2;

    // oneof associatedValue {
      optional string mentionUuid = 3;
    //}
  }

  message GroupCallUpdate {
    optional string eraId = 1;
  }

  message StoryContext {
    optional string authorUuid = 1;
    optional uint64 sentTimestamp = 2;
  }

  enum ProtocolVersion {
    option allow_alias = true;

    INITIAL = 0;
    MESSAGE_TIMERS = 1;
    VIEW_ONCE = 2;
    VIEW_ONCE_VIDEO = 3;
    REACTIONS = 4;
    CDN_SELECTOR_ATTACHMENTS = 5;
    MENTIONS = 6;
    PAYMENTS = 7;
    CURRENT = 7;
  }

  message GiftBadge {
    optional bytes receiptCredentialPresentation = 1;
  }

  optional string             body                    = 1;
  repeated AttachmentPointer  attachments             = 2;
  optional GroupContext       group                   = 3;
  optional GroupContextV2     groupV2                 = 15;
  optional uint32             flags                   = 4;
  optional uint32             expireTimer             = 5;
  optional bytes              profileKey              = 6;
  optional uint64             timestamp               = 7;
  optional Quote              quote                   = 8;
  repeated Contact            contact                 = 9;
  repeated Preview            preview                 = 10;
  optional Sticker            sticker                 = 11;
  optional uint32             requiredProtocolVersion = 12;
  optional bool               isViewOnce              = 14;
  optional Reaction           reaction                = 16;
  optional Delete             delete                  = 17;
  repeated BodyRange          bodyRanges              = 18;
  optional GroupCallUpdate    groupCallUpdate         = 19;
  optional Payment            payment                 = 20;
  optional StoryContext       storyContext            = 21;
  optional GiftBadge          giftBadge               = 22;
}

message NullMessage {
  optional bytes padding = 1;
}

message ReceiptMessage {
  enum Type {
    DELIVERY = 0;
    READ     = 1;
    VIEWED   = 2;
  }

  optional Type   type      = 1;
  repeated uint64 timestamp = 2;
}

message TypingMessage {
    enum Action {
        STARTED = 0;
        STOPPED = 1;
    }

    optional uint64 timestamp = 1;
    optional Action action    = 2;
    optional bytes  groupId   = 3;
}

message StoryMessage {
  optional bytes profileKey = 1;
  optional GroupContextV2 group = 2;
  oneof attachment {
    AttachmentPointer fileAttachment = 3;
    TextAttachment textAttachment = 4;
  }
  optional bool allowsReplies = 5;
}

message TextAttachment {
  enum Style {
    DEFAULT = 0;
    REGULAR = 1;
    BOLD = 2;
    SERIF = 3;
    SCRIPT = 4;
    CONDENSED = 5;
  }

  message Gradient {
    optional uint32 startColor = 1;
    optional uint32 endColor = 2;
    optional uint32 angle = 3; // degrees
  }

  optional string text = 1;
  optional Style textStyle = 2;
  optional uint32 textForegroundColor = 3; // integer representation of hex color
  optional uint32 textBackgroundColor = 4;
  optional Preview preview = 5;
  oneof background {
    Gradient gradient = 6;
    uint32 color = 7;
  }
}

message Verified {
  enum State {
    DEFAULT    = 0;
    VERIFIED   = 1;
    UNVERIFIED = 2;
  }

  optional string destination     = 1;
  optional string destinationUuid = 5;
  optional bytes  identityKey     = 2;
  optional State  state           = 3;
  optional bytes  nullMessage     = 4;
}

message SyncMessage {
  message Sent {
    message UnidentifiedDeliveryStatus {
      optional string destination     = 1;
      optional string destinationUuid = 3;
      optional bool   unidentified    = 2;
    }

    message StoryMessageRecipient {
      optional string destinationUuid = 1;
      repeated string distributionListIds = 2;
      optional bool isAllowedToReply = 3;
    }

    optional string                     destination              = 1;
    optional string                     destinationUuid          = 7;
    optional uint64                     timestamp                = 2;
    optional DataMessage                message                  = 3;
    optional uint64                     expirationStartTimestamp = 4;
    repeated UnidentifiedDeliveryStatus unidentifiedStatus       = 5;
    optional bool                       isRecipientUpdate        = 6 [default = false];
    optional StoryMessage storyMessage = 8;
    repeated StoryMessageRecipient storyMessageRecipients = 9;
  }

  message Contacts {
    optional AttachmentPointer blob     = 1;
    optional bool              complete = 2 [default = false];
  }

  message Groups {
    optional AttachmentPointer blob = 1;
  }

  message Blocked {
    repeated string numbers  = 1;
    repeated string uuids    = 3;
    repeated bytes  groupIds = 2;
  }

  message Request {
    enum Type {
      UNKNOWN       = 0;
      CONTACTS      = 1;
      GROUPS        = 2;
      BLOCKED       = 3;
      CONFIGURATION = 4;
      KEYS          = 5;
      PNI_IDENTITY  = 6;
    }

    optional Type type = 1;
  }

  message Keys {
    optional bytes storageService = 1;
  }

  message PniIdentity {
    optional bytes publicKey = 1;
    optional bytes privateKey = 2;
  }

  message Read {
    optional string sender     = 1;
    optional string senderUuid = 3;
    optional uint64 timestamp  = 2;
  }

  message Viewed {
    optional string senderE164 = 1;
    optional string senderUuid = 3;
    optional uint64 timestamp = 2;
  }

  message Configuration {
    optional bool   readReceipts                   = 1;
    optional bool   unidentifiedDeliveryIndicators = 2;
    optional bool   typingIndicators               = 3;
    reserved                                         4;
    optional uint32 provisioningVersion            = 5;
    optional bool   linkPreviews                   = 6;
  }

  message StickerPackOperation {
    enum Type {
      INSTALL = 0;
      REMOVE  = 1;
    }

    optional bytes packId  = 1;
    optional bytes packKey = 2;
    optional Type  type    = 3;
  }

  message ViewOnceOpen {
    optional string sender     = 1;
    optional string senderUuid = 3;
    optional uint64 timestamp  = 2;
  }

  message MessageRequestResponse {
    enum Type {
      UNKNOWN          = 0;
      ACCEPT           = 1;
      DELETE           = 2;
      BLOCK            = 3;
      BLOCK_AND_DELETE = 4;
    }

    optional string threadE164 = 1;
    optional string threadUuid = 2;
    optional bytes  groupId    = 3;
    optional Type   type       = 4;
  }

  message FetchLatest {
    enum Type {
      UNKNOWN             = 0;
      LOCAL_PROFILE       = 1;
      STORAGE_MANIFEST    = 2;
      SUBSCRIPTION_STATUS = 3;
    }

    optional Type type = 1;
  }

  message PniChangeNumber {
    optional bytes identityKeyPair = 1; // Serialized libsignal-client IdentityKeyPair
    optional bytes signedPreKey    = 2; // Serialized libsignal-client SignedPreKeyRecord
    optional uint32 registrationId = 3;
  }

  message CallEvent {
    enum Type {
      UNKNOWN    = 0;
      AUDIO_CALL = 1;
      VIDEO_CALL = 2;
    }

    enum Direction {
      UNKNOWN  = 0;
      INCOMING = 1;
      OUTGOING = 2;
    }

    enum Event {
      UNKNOWN      = 0;
      ACCEPTED     = 1;
      NOT_ACCEPTED = 2;
    }

    optional bytes     peerUuid  = 1;
    optional uint64    callId    = 2;
    optional uint64    timestamp = 3;
    optional Type      type      = 4;
    optional Direction direction = 5;
    optional Event     event     = 6;
  }

  optional Sent                   sent                   = 1;
  optional Contacts               contacts               = 2;
  optional Groups                 groups                 = 3;
  optional Request                request                = 4;
  repeated Read                   read                   = 5;
  optional Blocked                blocked                = 6;
  optional Verified               verified               = 7;
  optional Configuration          configuration          = 9;
  optional bytes                  padding                = 8;
  repeated StickerPackOperation   stickerPackOperation   = 10;
  optional ViewOnceOpen           viewOnceOpen           = 11;
  optional FetchLatest            fetchLatest            = 12;
  optional Keys                   keys                   = 13;
  optional MessageRequestResponse messageRequestResponse = 14;
  reserved                                                 15; // not yet added
  repeated Viewed                 viewed                 = 16;
  optional PniIdentity            pniIdentity            = 17;
  optional PniChangeNumber        pniChangeNumber        = 18;
  optional CallEvent              callEvent              = 19;
}

message AttachmentPointer {
  enum Flags {
    VOICE_MESSAGE = 1;
    BORDERLESS    = 2;
    // Our parser does not handle reserved in enums: DESKTOP-1569
    // reserved        4;
    GIF           = 8;
  }

  oneof attachment_identifier {
    fixed64        cdnId           = 1;
    string         cdnKey          = 15;
  }
  optional string  contentType     = 2;
  optional bytes   key             = 3;
  optional uint32  size            = 4;
  optional bytes   thumbnail       = 5;
  optional bytes   digest          = 6;
  optional string  fileName        = 7;
  optional uint32  flags           = 8;
  optional uint32  width           = 9;
  optional uint32  height          = 10;
  optional string  caption         = 11;
  optional string  blurHash        = 12;
  optional uint64  uploadTimestamp = 13;
  optional uint32  cdnNumber       = 14;
  // Next ID: 16
}

message GroupContext {
  enum Type {
    UNKNOWN      = 0;
    UPDATE       = 1;
    DELIVER      = 2;
    QUIT         = 3;
    REQUEST_INFO = 4;
  }

  optional bytes             id          = 1;
  optional Type              type        = 2;
  optional string            name        = 3;
  repeated string            membersE164 = 4;
  // field 6 was removed; do not use
  optional AttachmentPointer avatar      = 5;
}

message GroupContextV2 {
  optional bytes  masterKey   = 1;
  optional uint32 revision    = 2;
  optional bytes  groupChange = 3;
}

message ContactDetails {
  message Avatar {
    optional string contentType = 1;
    optional uint32 length      = 2;
  }

  optional string   number        = 1;
  optional string   uuid          = 9;
  optional string   name          = 2;
  optional Avatar   avatar        = 3;
  optional string   color         = 4;
  optional Verified verified      = 5;
  optional bytes    profileKey    = 6;
  optional bool     blocked       = 7;
  optional uint32   expireTimer   = 8;
  optional uint32   inboxPosition = 10;
}

message GroupDetails {
  message Avatar {
    optional string contentType = 1;
    optional uint32 length      = 2;
  }

  message Member {
    optional string uuid = 1;
    optional string e164 = 2;
  }

  optional bytes  id              = 1;
  optional string name            = 2;
  repeated string membersE164     = 3;
  repeated Member members         = 9;
  optional Avatar avatar          = 4;
  optional bool   active          = 5 [default = true];
  optional uint32 expireTimer     = 6;
  optional string color           = 7;
  optional bool   blocked         = 8;
  optional uint32 inboxPosition   = 10;
}

message PniSignatureMessage {
  optional bytes pni = 1;
  // Signature *by* the PNI identity key *of* the ACI identity key
  optional bytes signature = 2;
}