syntax = "proto3";

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

package signalservice;

option java_package        = "org.whispersystems.signalservice.protos.groups";
option java_multiple_files = true;

message AvatarUploadAttributes {
  string key        = 1;
  string credential = 2;
  string acl        = 3;
  string algorithm  = 4;
  string date       = 5;
  string policy     = 6;
  string signature  = 7;
}

message Member {
  enum Role {
    UNKNOWN       = 0;
    DEFAULT       = 1; // Normal member
    ADMINISTRATOR = 2; // Group admin
  }

  bytes  userId          = 1; // The UuidCiphertext
  Role   role            = 2;
  bytes  profileKey      = 3; // The ProfileKeyCiphertext
  bytes  presentation    = 4; // ProfileKeyCredentialPresentation
  uint32 joinedAtVersion = 5; // The Group.version this member joined at
}

message MemberPendingProfileKey {
  Member member        = 1; // The “invited” member
  bytes  addedByUserId = 2; // The UID who invited this member
  uint64 timestamp     = 3; // The time the invitation occurred
}

message MemberPendingAdminApproval {
  bytes  userId       = 1;
  bytes  profileKey   = 2;
  bytes  presentation = 3;
  uint64 timestamp    = 4;
}

message MemberBanned {
  bytes userId        = 1;
  uint64 timestamp    = 2;  // ms since epoch
}

message AccessControl {
  enum AccessRequired {
    UNKNOWN       = 0;
    ANY           = 1;
    MEMBER        = 2; // Any group member can make the modification
    ADMINISTRATOR = 3; // Only administrators can make the modification
    UNSATISFIABLE = 4;
  }

  AccessRequired attributes        = 1; // Who can modify the group title, avatar, disappearing messages timer
  AccessRequired members           = 2; // Who can add people to the group
  AccessRequired addFromInviteLink = 3;
}

message Group {
           bytes                      publicKey                   = 1; // GroupPublicParams
           bytes                      title                       = 2; // Encrypted title
           string                     avatar                      = 3; // Pointer to encrypted avatar (‘key’ from AvatarUploadAttributes)
           bytes                      disappearingMessagesTimer   = 4; // Encrypted timer
           AccessControl              accessControl               = 5;
           uint32                     version                     = 6; // Current group version number
  repeated Member                     members                     = 7;
  repeated MemberPendingProfileKey    membersPendingProfileKey    = 8;
  repeated MemberPendingAdminApproval membersPendingAdminApproval = 9;
           bytes                      inviteLinkPassword          = 10;
           bytes                      descriptionBytes            = 11;
           bool                       announcementsOnly           = 12;
  repeated MemberBanned               membersBanned               = 13;
  // next: 14
}

message GroupChange {

  message Actions {

    message AddMemberAction {
      Member added              = 1;
      bool   joinFromInviteLink = 2;
    }

    message DeleteMemberAction {
      bytes deletedUserId = 1;
    }

    message ModifyMemberRoleAction {
      bytes       userId = 1;
      Member.Role role   = 2;
    }

    message ModifyMemberProfileKeyAction {
      bytes presentation = 1;
      bytes user_id = 2;
      bytes profile_key = 3;
    }

    message AddMemberPendingProfileKeyAction {
      MemberPendingProfileKey added = 1;
    }

    message DeleteMemberPendingProfileKeyAction {
      bytes deletedUserId = 1;
    }

    message PromoteMemberPendingProfileKeyAction {
      bytes presentation = 1;
      bytes user_id = 2;
      bytes profile_key = 3;
    }

    message PromoteMemberPendingPniAciProfileKeyAction {
      bytes presentation = 1;
      bytes user_id = 2;
      bytes pni = 3;
      bytes profile_key = 4;
    }

    message AddMemberPendingAdminApprovalAction {
      MemberPendingAdminApproval added = 1;
    }

    message DeleteMemberPendingAdminApprovalAction {
      bytes deletedUserId = 1;
    }

    message PromoteMemberPendingAdminApprovalAction {
      bytes       userId = 1;
      Member.Role role   = 2;
    }

    message AddMemberBannedAction {
      MemberBanned added = 1;
    }

    message DeleteMemberBannedAction {
      bytes deletedUserId = 1;
    }

    message ModifyTitleAction {
      bytes title = 1;
    }

    message ModifyAvatarAction {
      string avatar = 1;
    }

    message ModifyDisappearingMessagesTimerAction {
      bytes timer = 1;
    }

    message ModifyAttributesAccessControlAction {
      AccessControl.AccessRequired attributesAccess = 1;
    }

    message ModifyAvatarAccessControlAction {
      AccessControl.AccessRequired avatarAccess = 1;
    }

    message ModifyMembersAccessControlAction {
      AccessControl.AccessRequired membersAccess = 1;
    }

    message ModifyAddFromInviteLinkAccessControlAction {
        AccessControl.AccessRequired addFromInviteLinkAccess = 1;
    }

    message ModifyInviteLinkPasswordAction {
        bytes inviteLinkPassword = 1;
    }

    message ModifyDescriptionAction {
        bytes descriptionBytes = 1;
    }

    message ModifyAnnouncementsOnlyAction {
        bool announcementsOnly = 1;
    }


             bytes                                      sourceUserId                       = 1; // Who made the change
             uint32                                     version                            = 2; // The change version number
    // clients should not provide this value; the server will provide it in the response buffer to ensure the signature is binding to a particular group
    // if clients set it during a request the server will respond with 400.
    bytes                                               groupId                            = 25;
    repeated AddMemberAction                            addMembers                         = 3; // Members added
    repeated DeleteMemberAction                         deleteMembers                      = 4; // Members deleted
    repeated ModifyMemberRoleAction                     modifyMemberRoles                  = 5; // Modified member roles
    repeated ModifyMemberProfileKeyAction               modifyMemberProfileKeys            = 6; // Modified member profile keys
    repeated AddMemberPendingProfileKeyAction           addPendingMembers                  = 7; // Pending members added
    repeated DeleteMemberPendingProfileKeyAction        deletePendingMembers               = 8; // Pending members deleted
    repeated PromoteMemberPendingProfileKeyAction       promotePendingMembers              = 9; // Pending invitations accepted
             ModifyTitleAction                          modifyTitle                        = 10; // Changed title
             ModifyAvatarAction                         modifyAvatar                       = 11; // Changed avatar
             ModifyDisappearingMessagesTimerAction      modifyDisappearingMessagesTimer    = 12; // Changed timer
             ModifyAttributesAccessControlAction        modifyAttributesAccess             = 13; // Changed attributes access control
             ModifyMembersAccessControlAction           modifyMemberAccess                 = 14; // Changed membership access control
             ModifyAddFromInviteLinkAccessControlAction modifyAddFromInviteLinkAccess      = 15; // change epoch = 1
    repeated AddMemberPendingAdminApprovalAction        addMemberPendingAdminApprovals     = 16; // change epoch = 1
    repeated DeleteMemberPendingAdminApprovalAction     deleteMemberPendingAdminApprovals  = 17; // change epoch = 1
    repeated PromoteMemberPendingAdminApprovalAction    promoteMemberPendingAdminApprovals = 18; // change epoch = 1
             ModifyInviteLinkPasswordAction             modifyInviteLinkPassword           = 19; // change epoch = 1
             ModifyDescriptionAction                    modifyDescription                  = 20; // change epoch = 2
             ModifyAnnouncementsOnlyAction              modifyAnnouncementsOnly            = 21; // change epoch = 3
    repeated AddMemberBannedAction                      addMembersBanned                   = 22; // change epoch = 4
    repeated DeleteMemberBannedAction                   deleteMembersBanned                = 23; // change epoch = 4
    repeated PromoteMemberPendingPniAciProfileKeyAction promoteMembersPendingPniAciProfileKey = 24;  // change epoch = 5
    // next: 26
  }

  bytes  actions         = 1; // The serialized actions
  bytes  serverSignature = 2; // Server’s signature over serialized actions
  uint32 changeEpoch     = 3; // Allows clients to decide whether their change logic can successfully apply this diff
}

// External credentials

message ExternalGroupCredential {
  string token = 1;
}

// API responses

message GroupResponse {
  Group group = 1;
  bytes groupSendEndorsementResponse = 2;
}

message GroupChanges {
  message GroupChangeState {
    GroupChange groupChange = 1;
    Group       groupState  = 2;
  }

  repeated GroupChangeState groupChanges = 1;
  bytes groupSendEndorsementResponse = 2;
}

message GroupChangeResponse {
  GroupChange groupChange = 1;
  bytes groupSendEndorsementResponse = 2;
}

message GroupAttributeBlob {
  oneof content {
    string title                        = 1;
    bytes  avatar                       = 2;
    uint32 disappearingMessagesDuration = 3;
    string descriptionText              = 4;
  }
}

message GroupInviteLink {
  message GroupInviteLinkContentsV1 {
      bytes groupMasterKey     = 1;
      bytes inviteLinkPassword = 2;
  }

  oneof contents {
    GroupInviteLinkContentsV1 v1Contents = 1;
  }
}

message GroupJoinInfo {
  bytes                        publicKey            = 1;
  bytes                        title                = 2;
  string                       avatar               = 3;
  uint32                       memberCount          = 4;
  AccessControl.AccessRequired addFromInviteLink    = 5;
  uint32                       version              = 6;
  bool                         pendingAdminApproval = 7;
  bytes                        descriptionBytes     = 8;
}
